~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
#ifdef HAVE_OPENSSL
1411
  if (opt_use_ssl)
1412
    mysql_ssl_set(&mysql_connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
1413
                  opt_ssl_capath, opt_ssl_cipher);
1414
  mysql_options(&mysql_connection,MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
1415
                (char*)&opt_ssl_verify_server_cert);
1416
#endif
1417
  if (opt_protocol)
1418
    mysql_options(&mysql_connection,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
1419
#ifdef HAVE_SMEM
1420
  if (shared_memory_base_name)
1421
    mysql_options(&mysql_connection,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
1422
#endif
1423
  mysql_options(&mysql_connection, MYSQL_SET_CHARSET_NAME, default_charset);
1424
  if (!(mysql= mysql_real_connect(&mysql_connection,host,user,passwd,
1425
                                  NULL,opt_mysql_port,opt_mysql_unix_port,
1426
                                  0)))
1427
  {
1428
    DB_error(&mysql_connection, "when trying to connect");
1429
    DBUG_RETURN(1);
1430
  }
1431
  if (mysql_get_server_version(&mysql_connection) < 40100)
1432
  {
1433
    /* Don't dump SET NAMES with a pre-4.1 server (bug#7997).  */
1434
    opt_set_charset= 0;
1435
1436
    /* Don't switch charsets for 4.1 and earlier.  (bug#34192). */
1437
    server_supports_switching_charsets= FALSE;
1438
  } 
1439
  /*
1440
    set time_zone to UTC to allow dumping date types between servers with
1441
    different time zone settings
1442
  */
1443
  if (opt_tz_utc)
1444
  {
1445
    my_snprintf(buff, sizeof(buff), "/*!40103 SET TIME_ZONE='+00:00' */");
1446
    if (mysql_query_with_error_report(mysql, 0, buff))
1447
      DBUG_RETURN(1);
1448
  }
1449
  DBUG_RETURN(0);
1450
} /* connect_to_db */
1451
1452
1453
/*
1454
** dbDisconnect -- disconnects from the host.
1455
*/
1456
static void dbDisconnect(char *host)
1457
{
1458
  verbose_msg("-- Disconnecting from %s...\n", host ? host : "localhost");
1459
  mysql_close(mysql);
1460
} /* dbDisconnect */
1461
1462
1463
static void unescape(FILE *file,char *pos,uint length)
1464
{
1465
  char *tmp;
1466
  DBUG_ENTER("unescape");
1467
  if (!(tmp=(char*) my_malloc(length*2+1, MYF(MY_WME))))
1468
    die(EX_MYSQLERR, "Couldn't allocate memory");
1469
1470
  mysql_real_escape_string(&mysql_connection, tmp, pos, length);
1471
  fputc('\'', file);
1472
  fputs(tmp, file);
1473
  fputc('\'', file);
1474
  check_io(file);
1475
  my_free(tmp, MYF(MY_WME));
1476
  DBUG_VOID_RETURN;
1477
} /* unescape */
1478
1479
1480
static my_bool test_if_special_chars(const char *str)
1481
{
1482
#if MYSQL_VERSION_ID >= 32300
1483
  for ( ; *str ; str++)
1484
    if (!my_isvar(charset_info,*str) && *str != '$')
1485
      return 1;
1486
#endif
1487
  return 0;
1488
} /* test_if_special_chars */
1489
1490
1491
1492
/*
1493
  quote_name(name, buff, force)
1494
1495
  Quotes char string, taking into account compatible mode
1496
1497
  Args
1498
1499
  name                 Unquoted string containing that which will be quoted
1500
  buff                 The buffer that contains the quoted value, also returned
1501
  force                Flag to make it ignore 'test_if_special_chars'
1502
1503
  Returns
1504
1505
  buff                 quoted string
1506
1507
*/
1508
static char *quote_name(const char *name, char *buff, my_bool force)
1509
{
1510
  char *to= buff;
1511
  char qtype= (opt_compatible_mode & MASK_ANSI_QUOTES) ? '\"' : '`';
1512
1513
  if (!force && !opt_quoted && !test_if_special_chars(name))
1514
    return (char*) name;
1515
  *to++= qtype;
1516
  while (*name)
1517
  {
1518
    if (*name == qtype)
1519
      *to++= qtype;
1520
    *to++= *name++;
1521
  }
1522
  to[0]= qtype;
1523
  to[1]= 0;
1524
  return buff;
1525
} /* quote_name */
1526
1527
1528
/*
1529
  Quote a table name so it can be used in "SHOW TABLES LIKE <tabname>"
1530
1531
  SYNOPSIS
1532
    quote_for_like()
1533
    name     name of the table
1534
    buff     quoted name of the table
1535
1536
  DESCRIPTION
1537
    Quote \, _, ' and % characters
1538
1539
    Note: Because MySQL uses the C escape syntax in strings
1540
    (for example, '\n' to represent newline), you must double
1541
    any '\' that you use in your LIKE  strings. For example, to
1542
    search for '\n', specify it as '\\n'. To search for '\', specify
1543
    it as '\\\\' (the backslashes are stripped once by the parser
1544
    and another time when the pattern match is done, leaving a
1545
    single backslash to be matched).
1546
1547
    Example: "t\1" => "t\\\\1"
1548
1549
*/
1550
static char *quote_for_like(const char *name, char *buff)
1551
{
1552
  char *to= buff;
1553
  *to++= '\'';
1554
  while (*name)
1555
  {
1556
    if (*name == '\\')
1557
    {
1558
      *to++='\\';
1559
      *to++='\\';
1560
      *to++='\\';
1561
    }
1562
    else if (*name == '\'' || *name == '_'  || *name == '%')
1563
      *to++= '\\';
1564
    *to++= *name++;
1565
  }
1566
  to[0]= '\'';
1567
  to[1]= 0;
1568
  return buff;
1569
}
1570
1571
1572
/*
1573
  Quote and print a string.
1574
1575
  SYNOPSIS
1576
    print_quoted_xml()
1577
    xml_file    - output file
1578
    str         - string to print
1579
    len         - its length
1580
1581
  DESCRIPTION
1582
    Quote '<' '>' '&' '\"' chars and print a string to the xml_file.
1583
*/
1584
1585
static void print_quoted_xml(FILE *xml_file, const char *str, ulong len)
1586
{
1587
  const char *end;
1588
1589
  for (end= str + len; str != end; str++)
1590
  {
1591
    switch (*str) {
1592
    case '<':
1593
      fputs("&lt;", xml_file);
1594
      break;
1595
    case '>':
1596
      fputs("&gt;", xml_file);
1597
      break;
1598
    case '&':
1599
      fputs("&amp;", xml_file);
1600
      break;
1601
    case '\"':
1602
      fputs("&quot;", xml_file);
1603
      break;
1604
    default:
1605
      fputc(*str, xml_file);
1606
      break;
1607
    }
1608
  }
1609
  check_io(xml_file);
1610
}
1611
1612
1613
/*
1614
  Print xml tag. Optionally add attribute(s).
1615
1616
  SYNOPSIS
1617
    print_xml_tag(xml_file, sbeg, send, tag_name, first_attribute_name, 
1618
                    ..., attribute_name_n, attribute_value_n, NullS)
1619
    xml_file              - output file
1620
    sbeg                  - line beginning
1621
    line_end              - line ending
1622
    tag_name              - XML tag name.
1623
    first_attribute_name  - tag and first attribute
1624
    first_attribute_value - (Implied) value of first attribute
1625
    attribute_name_n      - attribute n
1626
    attribute_value_n     - value of attribute n
1627
1628
  DESCRIPTION
1629
    Print XML tag with any number of attribute="value" pairs to the xml_file.
1630
1631
    Format is:
1632
      sbeg<tag_name first_attribute_name="first_attribute_value" ... 
1633
      attribute_name_n="attribute_value_n">send
1634
  NOTE
1635
    Additional arguments must be present in attribute/value pairs.
1636
    The last argument should be the null character pointer.
1637
    All attribute_value arguments MUST be NULL terminated strings.
1638
    All attribute_value arguments will be quoted before output.
1639
*/
1640
1641
static void print_xml_tag(FILE * xml_file, const char* sbeg,
1642
                          const char* line_end, 
1643
                          const char* tag_name, 
1644
                          const char* first_attribute_name, ...)
1645
{
1646
  va_list arg_list;
1647
  const char *attribute_name, *attribute_value;
1648
1649
  fputs(sbeg, xml_file);
1650
  fputc('<', xml_file);
1651
  fputs(tag_name, xml_file);  
1652
1653
  va_start(arg_list, first_attribute_name);
1654
  attribute_name= first_attribute_name;
1655
  while (attribute_name != NullS)
1656
  {
1657
    attribute_value= va_arg(arg_list, char *);
1658
    DBUG_ASSERT(attribute_value != NullS);
1659
1660
    fputc(' ', xml_file);
1661
    fputs(attribute_name, xml_file);    
1662
    fputc('\"', xml_file);
1663
    
1664
    print_quoted_xml(xml_file, attribute_value, strlen(attribute_value));
1665
    fputc('\"', xml_file);
1666
1667
    attribute_name= va_arg(arg_list, char *);
1668
  }
1669
  va_end(arg_list);
1670
1671
  fputc('>', xml_file);
1672
  fputs(line_end, xml_file);
1673
  check_io(xml_file);
1674
}
1675
1676
1677
/*
1678
  Print xml tag with for a field that is null
1679
1680
  SYNOPSIS
1681
    print_xml_null_tag()
1682
    xml_file    - output file
1683
    sbeg        - line beginning
1684
    stag_atr    - tag and attribute
1685
    sval        - value of attribute
1686
    line_end        - line ending
1687
1688
  DESCRIPTION
1689
    Print tag with one attribute to the xml_file. Format is:
1690
      <stag_atr="sval" xsi:nil="true"/>
1691
  NOTE
1692
    sval MUST be a NULL terminated string.
1693
    sval string will be qouted before output.
1694
*/
1695
1696
static void print_xml_null_tag(FILE * xml_file, const char* sbeg,
1697
                               const char* stag_atr, const char* sval,
1698
                               const char* line_end)
1699
{
1700
  fputs(sbeg, xml_file);
1701
  fputs("<", xml_file);
1702
  fputs(stag_atr, xml_file);
1703
  fputs("\"", xml_file);
1704
  print_quoted_xml(xml_file, sval, strlen(sval));
1705
  fputs("\" xsi:nil=\"true\" />", xml_file);
1706
  fputs(line_end, xml_file);
1707
  check_io(xml_file);
1708
}
1709
1710
1711
/*
1712
  Print xml tag with many attributes.
1713
1714
  SYNOPSIS
1715
    print_xml_row()
1716
    xml_file    - output file
1717
    row_name    - xml tag name
1718
    tableRes    - query result
1719
    row         - result row
1720
1721
  DESCRIPTION
1722
    Print tag with many attribute to the xml_file. Format is:
1723
      \t\t<row_name Atr1="Val1" Atr2="Val2"... />
1724
  NOTE
1725
    All atributes and values will be quoted before output.
1726
*/
1727
1728
static void print_xml_row(FILE *xml_file, const char *row_name,
1729
                          MYSQL_RES *tableRes, MYSQL_ROW *row)
1730
{
1731
  uint i;
1732
  MYSQL_FIELD *field;
1733
  ulong *lengths= mysql_fetch_lengths(tableRes);
1734
1735
  fprintf(xml_file, "\t\t<%s", row_name);
1736
  check_io(xml_file);
1737
  mysql_field_seek(tableRes, 0);
1738
  for (i= 0; (field= mysql_fetch_field(tableRes)); i++)
1739
  {
1740
    if ((*row)[i])
1741
    {
1742
      fputc(' ', xml_file);
1743
      print_quoted_xml(xml_file, field->name, field->name_length);
1744
      fputs("=\"", xml_file);
1745
      print_quoted_xml(xml_file, (*row)[i], lengths[i]);
1746
      fputc('"', xml_file);
1747
      check_io(xml_file);
1748
    }
1749
  }
1750
  fputs(" />\n", xml_file);
1751
  check_io(xml_file);
1752
}
1753
1754
1755
/*
1756
 create_delimiter
1757
 Generate a new (null-terminated) string that does not exist in  query 
1758
 and is therefore suitable for use as a query delimiter.  Store this
1759
 delimiter in  delimiter_buff .
1760
 
1761
 This is quite simple in that it doesn't even try to parse statements as an
1762
 interpreter would.  It merely returns a string that is not in the query, which
1763
 is much more than adequate for constructing a delimiter.
1764
1765
 RETURN
1766
   ptr to the delimiter  on Success
1767
   NULL                  on Failure
1768
*/
1769
static char *create_delimiter(char *query, char *delimiter_buff, 
1770
                              int delimiter_max_size) 
1771
{
1772
  int proposed_length;
1773
  char *presence;
1774
1775
  delimiter_buff[0]= ';';  /* start with one semicolon, and */
1776
1777
  for (proposed_length= 2; proposed_length < delimiter_max_size; 
1778
      delimiter_max_size++) {
1779
1780
    delimiter_buff[proposed_length-1]= ';';  /* add semicolons, until */
1781
    delimiter_buff[proposed_length]= '\0';
1782
1783
    presence = strstr(query, delimiter_buff);
1784
    if (presence == NULL) { /* the proposed delimiter is not in the query. */
1785
       return delimiter_buff;
1786
    }
1787
1788
  }
1789
  return NULL;  /* but if we run out of space, return nothing at all. */
1790
}
1791
1792
1793
/*
1794
  dump_events_for_db
1795
  -- retrieves list of events for a given db, and prints out
1796
  the CREATE EVENT statement into the output (the dump).
1797
1798
  RETURN
1799
    0  Success
1800
    1  Error
1801
*/
1802
static uint dump_events_for_db(char *db)
1803
{
1804
  char       query_buff[QUERY_LENGTH];
1805
  char       db_name_buff[NAME_LEN*2+3], name_buff[NAME_LEN*2+3];
1806
  char       *event_name;
1807
  char       delimiter[QUERY_LENGTH];
1808
  FILE       *sql_file= md_result_file;
1809
  MYSQL_RES  *event_res, *event_list_res;
1810
  MYSQL_ROW  row, event_list_row;
1811
1812
  char       db_cl_name[MY_CS_NAME_SIZE];
1813
  int        db_cl_altered= FALSE;
1814
1815
  DBUG_ENTER("dump_events_for_db");
1816
  DBUG_PRINT("enter", ("db: '%s'", db));
1817
1818
  mysql_real_escape_string(mysql, db_name_buff, db, strlen(db));
1819
1820
  /* nice comments */
1821
  if (opt_comments)
1822
    fprintf(sql_file, "\n--\n-- Dumping events for database '%s'\n--\n", db);
1823
1824
  /*
1825
    not using "mysql_query_with_error_report" because we may have not
1826
    enough privileges to lock mysql.events.
1827
  */
1828
  if (lock_tables)
1829
    mysql_query(mysql, "LOCK TABLES mysql.event READ");
1830
1831
  if (mysql_query_with_error_report(mysql, &event_list_res, "show events"))
1832
    DBUG_RETURN(0);
1833
1834
  strcpy(delimiter, ";");
1835
  if (mysql_num_rows(event_list_res) > 0)
1836
  {
1837
    fprintf(sql_file, "/*!50106 SET @save_time_zone= @@TIME_ZONE */ ;\n");
1838
1839
    /* Get database collation. */
1840
1841
    if (fetch_db_collation(db_name_buff, db_cl_name, sizeof (db_cl_name)))
1842
      DBUG_RETURN(1);
1843
1844
    if (switch_character_set_results(mysql, "binary"))
1845
      DBUG_RETURN(1);
1846
1847
    while ((event_list_row= mysql_fetch_row(event_list_res)) != NULL)
1848
    {
1849
      event_name= quote_name(event_list_row[1], name_buff, 0);
1850
      DBUG_PRINT("info", ("retrieving CREATE EVENT for %s", name_buff));
1851
      my_snprintf(query_buff, sizeof(query_buff), "SHOW CREATE EVENT %s", 
1852
          event_name);
1853
1854
      if (mysql_query_with_error_report(mysql, &event_res, query_buff))
1855
        DBUG_RETURN(1);
1856
1857
      while ((row= mysql_fetch_row(event_res)) != NULL)
1858
      {
1859
        /*
1860
          if the user has EXECUTE privilege he can see event names, but not the
1861
          event body!
1862
        */
1863
        if (strlen(row[3]) != 0)
1864
        {
1865
          if (opt_drop)
1866
            fprintf(sql_file, "/*!50106 DROP EVENT IF EXISTS %s */%s\n", 
1867
                event_name, delimiter);
1868
1869
          if (create_delimiter(row[3], delimiter, sizeof(delimiter)) == NULL)
1870
          {
1871
            fprintf(stderr, "%s: Warning: Can't create delimiter for event '%s'\n",
1872
                    my_progname, event_name);
1873
            DBUG_RETURN(1);
1874
          }
1875
1876
          fprintf(sql_file, "DELIMITER %s\n", delimiter);
1877
1878
          if (mysql_num_fields(event_res) >= 7)
1879
          {
1880
            if (switch_db_collation(sql_file, db_name_buff, delimiter,
1881
                                    db_cl_name, row[6], &db_cl_altered))
1882
            {
1883
              DBUG_RETURN(1);
1884
            }
1885
1886
            switch_cs_variables(sql_file, delimiter,
1887
                                row[4],   /* character_set_client */
1888
                                row[4],   /* character_set_results */
1889
                                row[5]);  /* collation_connection */
1890
          }
1891
            else
1892
            {
1893
              /*
1894
                mysqldump is being run against the server, that does not
1895
                provide character set information in SHOW CREATE
1896
                statements.
1897
1898
                NOTE: the dump may be incorrect, since character set
1899
                information is required in order to restore event properly.
1900
              */
1901
1902
              fprintf(sql_file,
1903
                      "--\n"
1904
                      "-- WARNING: old server version. "
1905
                        "The following dump may be incomplete.\n"
1906
                      "--\n");
1907
            }
1908
1909
          switch_sql_mode(sql_file, delimiter, row[1]);
1910
1911
          switch_time_zone(sql_file, delimiter, row[2]);
1912
1913
          fprintf(sql_file,
1914
                  "/*!50106 %s */ %s\n",
1915
                  (const char *) row[3],
1916
                  (const char *) delimiter);
1917
1918
          restore_time_zone(sql_file, delimiter);
1919
          restore_sql_mode(sql_file, delimiter);
1920
1921
          if (mysql_num_fields(event_res) >= 7)
1922
          {
1923
            restore_cs_variables(sql_file, delimiter);
1924
1925
            if (db_cl_altered)
1926
            {
1927
              if (restore_db_collation(sql_file, db_name_buff, delimiter,
1928
                                       db_cl_name))
1929
                DBUG_RETURN(1);
1930
            }
1931
          }
1932
        }
1933
      } /* end of event printing */
1934
      mysql_free_result(event_res);
1935
1936
    } /* end of list of events */
1937
    fprintf(sql_file, "DELIMITER ;\n");
1938
    fprintf(sql_file, "/*!50106 SET TIME_ZONE= @save_time_zone */ ;\n");
1939
1940
    if (switch_character_set_results(mysql, default_charset))
1941
      DBUG_RETURN(1);
1942
  }
1943
  mysql_free_result(event_list_res);
1944
1945
  if (lock_tables)
1946
    VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES"));
1947
  DBUG_RETURN(0);
1948
}
1949
1950
1951
/*
1952
  Print hex value for blob data.
1953
1954
  SYNOPSIS
1955
    print_blob_as_hex()
1956
    output_file         - output file
1957
    str                 - string to print
1958
    len                 - its length
1959
1960
  DESCRIPTION
1961
    Print hex value for blob data.
1962
*/
1963
1964
static void print_blob_as_hex(FILE *output_file, const char *str, ulong len)
1965
{
1966
    /* sakaik got the idea to to provide blob's in hex notation. */
1967
    const char *ptr= str, *end= ptr + len;
1968
    for (; ptr < end ; ptr++)
1969
      fprintf(output_file, "%02X", *((uchar *)ptr));
1970
    check_io(output_file);
1971
}
1972
1973
/*
1974
  dump_routines_for_db
1975
  -- retrieves list of routines for a given db, and prints out
1976
  the CREATE PROCEDURE definition into the output (the dump).
1977
1978
  This function has logic to print the appropriate syntax depending on whether
1979
  this is a procedure or functions
1980
1981
  RETURN
1982
    0  Success
1983
    1  Error
1984
*/
1985
1986
static uint dump_routines_for_db(char *db)
1987
{
1988
  char       query_buff[QUERY_LENGTH];
1989
  const char *routine_type[]= {"FUNCTION", "PROCEDURE"};
1990
  char       db_name_buff[NAME_LEN*2+3], name_buff[NAME_LEN*2+3];
1991
  char       *routine_name;
1992
  int        i;
1993
  FILE       *sql_file= md_result_file;
1994
  MYSQL_RES  *routine_res, *routine_list_res;
1995
  MYSQL_ROW  row, routine_list_row;
1996
1997
  char       db_cl_name[MY_CS_NAME_SIZE];
1998
  int        db_cl_altered= FALSE;
1999
2000
  DBUG_ENTER("dump_routines_for_db");
2001
  DBUG_PRINT("enter", ("db: '%s'", db));
2002
2003
  mysql_real_escape_string(mysql, db_name_buff, db, strlen(db));
2004
2005
  /* nice comments */
2006
  if (opt_comments)
2007
    fprintf(sql_file, "\n--\n-- Dumping routines for database '%s'\n--\n", db);
2008
2009
  /*
2010
    not using "mysql_query_with_error_report" because we may have not
2011
    enough privileges to lock mysql.proc.
2012
  */
2013
  if (lock_tables)
2014
    mysql_query(mysql, "LOCK TABLES mysql.proc READ");
2015
2016
  /* Get database collation. */
2017
2018
  if (fetch_db_collation(db_name_buff, db_cl_name, sizeof (db_cl_name)))
2019
    DBUG_RETURN(1);
2020
2021
  if (switch_character_set_results(mysql, "binary"))
2022
    DBUG_RETURN(1);
2023
2024
  /* 0, retrieve and dump functions, 1, procedures */
2025
  for (i= 0; i <= 1; i++)
2026
  {
2027
    my_snprintf(query_buff, sizeof(query_buff),
2028
                "SHOW %s STATUS WHERE Db = '%s'",
2029
                routine_type[i], db_name_buff);
2030
2031
    if (mysql_query_with_error_report(mysql, &routine_list_res, query_buff))
2032
      DBUG_RETURN(1);
2033
2034
    if (mysql_num_rows(routine_list_res))
2035
    {
2036
2037
      while ((routine_list_row= mysql_fetch_row(routine_list_res)))
2038
      {
2039
        routine_name= quote_name(routine_list_row[1], name_buff, 0);
2040
        DBUG_PRINT("info", ("retrieving CREATE %s for %s", routine_type[i],
2041
                            name_buff));
2042
        my_snprintf(query_buff, sizeof(query_buff), "SHOW CREATE %s %s",
2043
                    routine_type[i], routine_name);
2044
2045
        if (mysql_query_with_error_report(mysql, &routine_res, query_buff))
2046
          DBUG_RETURN(1);
2047
2048
        while ((row= mysql_fetch_row(routine_res)))
2049
        {
2050
          /*
2051
            if the user has EXECUTE privilege he see routine names, but NOT the
2052
            routine body of other routines that are not the creator of!
2053
          */
2054
          DBUG_PRINT("info",("length of body for %s row[2] '%s' is %d",
2055
                             routine_name, row[2] ? row[2] : "(null)",
2056
                             row[2] ? (int) strlen(row[2]) : 0));
2057
          if (row[2] == NULL)
2058
          {
2059
            fprintf(sql_file, "\n-- insufficient privileges to %s\n", query_buff);
2060
            fprintf(sql_file, "-- does %s have permissions on mysql.proc?\n\n", current_user);
2061
            maybe_die(EX_MYSQLERR,"%s has insufficent privileges to %s!", current_user, query_buff);
2062
          }
2063
          else if (strlen(row[2]))
2064
          {
2065
            char *query_str;
2066
            if (opt_drop)
2067
              fprintf(sql_file, "/*!50003 DROP %s IF EXISTS %s */;\n",
2068
                      routine_type[i], routine_name);
2069
2070
            query_str= cover_definer_clause_in_sp(row[2], strlen(row[2]));
2071
2072
            if (mysql_num_fields(routine_res) >= 6)
2073
            {
2074
              if (switch_db_collation(sql_file, db_name_buff, ";",
2075
                                      db_cl_name, row[5], &db_cl_altered))
2076
              {
2077
                DBUG_RETURN(1);
2078
              }
2079
2080
              switch_cs_variables(sql_file, ";",
2081
                                  row[3],   /* character_set_client */
2082
                                  row[3],   /* character_set_results */
2083
                                  row[4]);  /* collation_connection */
2084
            }
2085
            else
2086
            {
2087
              /*
2088
                mysqldump is being run against the server, that does not
2089
                provide character set information in SHOW CREATE
2090
                statements.
2091
2092
                NOTE: the dump may be incorrect, since character set
2093
                information is required in order to restore stored
2094
                procedure/function properly.
2095
              */
2096
2097
              fprintf(sql_file,
2098
                      "--\n"
2099
                      "-- WARNING: old server version. "
2100
                        "The following dump may be incomplete.\n"
2101
                      "--\n");
2102
            }
2103
2104
2105
            switch_sql_mode(sql_file, ";", row[1]);
2106
2107
            fprintf(sql_file,
2108
                    "DELIMITER ;;\n"
2109
                    "/*!50003 %s */;;\n"
2110
                    "DELIMITER ;\n",
2111
                    (const char *) (query_str != NULL ? query_str : row[2]));
2112
2113
            restore_sql_mode(sql_file, ";");
2114
2115
            if (mysql_num_fields(routine_res) >= 6)
2116
            {
2117
              restore_cs_variables(sql_file, ";");
2118
2119
              if (db_cl_altered)
2120
              {
2121
                if (restore_db_collation(sql_file, db_name_buff, ";", db_cl_name))
2122
                  DBUG_RETURN(1);
2123
              }
2124
            }
2125
2126
            my_free(query_str, MYF(MY_ALLOW_ZERO_PTR));
2127
          }
2128
        } /* end of routine printing */
2129
        mysql_free_result(routine_res);
2130
2131
      } /* end of list of routines */
2132
    }
2133
    mysql_free_result(routine_list_res);
2134
  } /* end of for i (0 .. 1)  */
2135
2136
  if (switch_character_set_results(mysql, default_charset))
2137
    DBUG_RETURN(1);
2138
2139
  if (lock_tables)
2140
    VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES"));
2141
  DBUG_RETURN(0);
2142
}
2143
2144
/*
2145
  get_table_structure -- retrievs database structure, prints out corresponding
2146
  CREATE statement and fills out insert_pat if the table is the type we will
2147
  be dumping.
2148
2149
  ARGS
2150
    table       - table name
2151
    db          - db name
2152
    table_type  - table type, e.g. "MyISAM" or "InnoDB", but also "VIEW"
2153
    ignore_flag - what we must particularly ignore - see IGNORE_ defines above
2154
2155
  RETURN
2156
    number of fields in table, 0 if error
2157
*/
2158
2159
static uint get_table_structure(char *table, char *db, char *table_type,
2160
                                char *ignore_flag)
2161
{
2162
  my_bool    init=0, delayed, write_data, complete_insert;
2163
  my_ulonglong num_fields;
2164
  char       *result_table, *opt_quoted_table;
2165
  const char *insert_option;
2166
  char	     name_buff[NAME_LEN+3],table_buff[NAME_LEN*2+3];
2167
  char       table_buff2[NAME_LEN*2+3], query_buff[QUERY_LENGTH];
2168
  FILE       *sql_file= md_result_file;
2169
  int        len;
2170
  MYSQL_RES  *result;
2171
  MYSQL_ROW  row;
2172
  DBUG_ENTER("get_table_structure");
2173
  DBUG_PRINT("enter", ("db: %s  table: %s", db, table));
2174
2175
  *ignore_flag= check_if_ignore_table(table, table_type);
2176
2177
  delayed= opt_delayed;
2178
  if (delayed && (*ignore_flag & IGNORE_INSERT_DELAYED))
2179
  {
2180
    delayed= 0;
2181
    verbose_msg("-- Warning: Unable to use delayed inserts for table '%s' "
2182
                "because it's of type %s\n", table, table_type);
2183
  }
2184
2185
  complete_insert= 0;
2186
  if ((write_data= !(*ignore_flag & IGNORE_DATA)))
2187
  {
2188
    complete_insert= opt_complete_insert;
2189
    if (!insert_pat_inited)
2190
    {
2191
      insert_pat_inited= 1;
2192
      init_dynamic_string_checked(&insert_pat, "", 1024, 1024);
2193
    }
2194
    else
2195
      dynstr_set_checked(&insert_pat, "");
2196
  }
2197
2198
  insert_option= ((delayed && opt_ignore) ? " DELAYED IGNORE " :
2199
                  delayed ? " DELAYED " : opt_ignore ? " IGNORE " : "");
2200
2201
  verbose_msg("-- Retrieving table structure for table %s...\n", table);
2202
2203
  len= my_snprintf(query_buff, sizeof(query_buff),
2204
                   "SET OPTION SQL_QUOTE_SHOW_CREATE=%d",
2205
                   (opt_quoted || opt_keywords));
2206
2207
  result_table=     quote_name(table, table_buff, 1);
2208
  opt_quoted_table= quote_name(table, table_buff2, 0);
2209
2210
  if (opt_order_by_primary)
2211
  {
2212
    my_free(order_by, MYF(MY_ALLOW_ZERO_PTR));
2213
    order_by= primary_key_fields(result_table);
2214
  }
2215
2216
  if (!opt_xml && !mysql_query_with_error_report(mysql, 0, query_buff))
2217
  {
2218
    /* using SHOW CREATE statement */
2219
    if (!opt_no_create_info)
2220
    {
2221
      /* Make an sql-file, if path was given iow. option -T was given */
2222
      char buff[20+FN_REFLEN];
2223
      MYSQL_FIELD *field;
2224
2225
      my_snprintf(buff, sizeof(buff), "show create table %s", result_table);
2226
2227
      if (switch_character_set_results(mysql, "binary") ||
2228
          mysql_query_with_error_report(mysql, &result, buff) ||
2229
          switch_character_set_results(mysql, default_charset))
2230
        DBUG_RETURN(0);
2231
2232
      if (path)
2233
      {
2234
        if (!(sql_file= open_sql_file_for_table(table)))
2235
          DBUG_RETURN(0);
2236
2237
        write_header(sql_file, db);
2238
      }
2239
      if (!opt_xml && opt_comments)
2240
      {
2241
      if (strcmp (table_type, "VIEW") == 0)         /* view */
2242
        fprintf(sql_file, "\n--\n-- Temporary table structure for view %s\n--\n\n",
2243
                result_table);
2244
      else
2245
        fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n",
2246
                result_table);
2247
        check_io(sql_file);
2248
      }
2249
      if (opt_drop)
2250
      {
2251
      /*
2252
        Even if the "table" is a view, we do a DROP TABLE here.  The
2253
        view-specific code below fills in the DROP VIEW.
2254
       */
2255
        fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n",
2256
                opt_quoted_table);
2257
        check_io(sql_file);
2258
      }
2259
2260
      field= mysql_fetch_field_direct(result, 0);
2261
      if (strcmp(field->name, "View") == 0)
2262
      {
2263
        char *scv_buff= NULL;
2264
2265
        verbose_msg("-- It's a view, create dummy table for view\n");
2266
2267
        /* save "show create" statement for later */
2268
        if ((row= mysql_fetch_row(result)) && (scv_buff=row[1]))
2269
          scv_buff= my_strdup(scv_buff, MYF(0));
2270
2271
        mysql_free_result(result);
2272
2273
        /*
2274
          Create a table with the same name as the view and with columns of
2275
          the same name in order to satisfy views that depend on this view.
2276
          The table will be removed when the actual view is created.
2277
2278
          The properties of each column, aside from the data type, are not
2279
          preserved in this temporary table, because they are not necessary.
2280
2281
          This will not be necessary once we can determine dependencies
2282
          between views and can simply dump them in the appropriate order.
2283
        */
2284
        my_snprintf(query_buff, sizeof(query_buff),
2285
                    "SHOW FIELDS FROM %s", result_table);
2286
        if (switch_character_set_results(mysql, "binary") ||
2287
            mysql_query_with_error_report(mysql, &result, query_buff) ||
2288
            switch_character_set_results(mysql, default_charset))
2289
        {
2290
          /*
2291
            View references invalid or privileged table/col/fun (err 1356),
2292
            so we cannot create a stand-in table.  Be defensive and dump
2293
            a comment with the view's 'show create' statement. (Bug #17371)
2294
          */
2295
2296
          if (mysql_errno(mysql) == ER_VIEW_INVALID)
2297
            fprintf(sql_file, "\n-- failed on view %s: %s\n\n", result_table, scv_buff ? scv_buff : "");
2298
2299
          my_free(scv_buff, MYF(MY_ALLOW_ZERO_PTR));
2300
2301
          DBUG_RETURN(0);
2302
        }
2303
        else
2304
          my_free(scv_buff, MYF(MY_ALLOW_ZERO_PTR));
2305
2306
        if (mysql_num_rows(result))
2307
        {
2308
          if (opt_drop)
2309
          {
2310
            /*
2311
              We have already dropped any table of the same name above, so
2312
              here we just drop the view.
2313
            */
2314
2315
            fprintf(sql_file, "/*!50001 DROP VIEW IF EXISTS %s*/;\n",
2316
                    opt_quoted_table);
2317
            check_io(sql_file);
2318
          }
2319
2320
          fprintf(sql_file,
2321
                  "SET @saved_cs_client     = @@character_set_client;\n"
2322
                  "SET character_set_client = utf8;\n"
2323
                  "/*!50001 CREATE TABLE %s (\n",
2324
                  result_table);
2325
2326
          /*
2327
            Get first row, following loop will prepend comma - keeps from
2328
            having to know if the row being printed is last to determine if
2329
            there should be a _trailing_ comma.
2330
          */
2331
2332
          row= mysql_fetch_row(result);
2333
2334
          fprintf(sql_file, "  %s %s", quote_name(row[0], name_buff, 0),
2335
                  row[1]);
2336
2337
          while((row= mysql_fetch_row(result)))
2338
          {
2339
            /* col name, col type */
2340
            fprintf(sql_file, ",\n  %s %s",
2341
                    quote_name(row[0], name_buff, 0), row[1]);
2342
          }
2343
          fprintf(sql_file,
2344
                  "\n) */;\n"
2345
                  "SET character_set_client = @saved_cs_client;\n");
2346
2347
          check_io(sql_file);
2348
        }
2349
2350
        mysql_free_result(result);
2351
2352
        if (path)
2353
          my_fclose(sql_file, MYF(MY_WME));
2354
2355
        seen_views= 1;
2356
        DBUG_RETURN(0);
2357
      }
2358
2359
      row= mysql_fetch_row(result);
2360
2361
      fprintf(sql_file,
2362
              "SET @saved_cs_client     = @@character_set_client;\n"
2363
              "SET character_set_client = utf8;\n"
2364
              "%s;\n"
2365
              "SET character_set_client = @saved_cs_client;\n",
2366
              row[1]);
2367
2368
      check_io(sql_file);
2369
      mysql_free_result(result);
2370
    }
2371
    my_snprintf(query_buff, sizeof(query_buff), "show fields from %s",
2372
                result_table);
2373
    if (mysql_query_with_error_report(mysql, &result, query_buff))
2374
    {
2375
      if (path)
2376
        my_fclose(sql_file, MYF(MY_WME));
2377
      DBUG_RETURN(0);
2378
    }
2379
2380
    /*
2381
      If write_data is true, then we build up insert statements for
2382
      the table's data. Note: in subsequent lines of code, this test
2383
      will have to be performed each time we are appending to
2384
      insert_pat.
2385
    */
2386
    if (write_data)
2387
    {
2388
      if (opt_replace_into)
2389
        dynstr_append_checked(&insert_pat, "REPLACE ");
2390
      else
2391
        dynstr_append_checked(&insert_pat, "INSERT ");
2392
      dynstr_append_checked(&insert_pat, insert_option);
2393
      dynstr_append_checked(&insert_pat, "INTO ");
2394
      dynstr_append_checked(&insert_pat, opt_quoted_table);
2395
      if (complete_insert)
2396
      {
2397
        dynstr_append_checked(&insert_pat, " (");
2398
      }
2399
      else
2400
      {
2401
        dynstr_append_checked(&insert_pat, " VALUES ");
2402
        if (!extended_insert)
2403
          dynstr_append_checked(&insert_pat, "(");
2404
      }
2405
    }
2406
2407
    while ((row= mysql_fetch_row(result)))
2408
    {
2409
      if (complete_insert)
2410
      {
2411
        if (init)
2412
        {
2413
          dynstr_append_checked(&insert_pat, ", ");
2414
        }
2415
        init=1;
2416
        dynstr_append_checked(&insert_pat,
2417
                      quote_name(row[SHOW_FIELDNAME], name_buff, 0));
2418
      }
2419
    }
2420
    num_fields= mysql_num_rows(result);
2421
    mysql_free_result(result);
2422
  }
2423
  else
2424
  {
2425
    verbose_msg("%s: Warning: Can't set SQL_QUOTE_SHOW_CREATE option (%s)\n",
2426
                my_progname, mysql_error(mysql));
2427
2428
    my_snprintf(query_buff, sizeof(query_buff), "show fields from %s",
2429
                result_table);
2430
    if (mysql_query_with_error_report(mysql, &result, query_buff))
2431
      DBUG_RETURN(0);
2432
2433
    /* Make an sql-file, if path was given iow. option -T was given */
2434
    if (!opt_no_create_info)
2435
    {
2436
      if (path)
2437
      {
2438
        if (!(sql_file= open_sql_file_for_table(table)))
2439
          DBUG_RETURN(0);
2440
        write_header(sql_file, db);
2441
      }
2442
      if (!opt_xml && opt_comments)
2443
        fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n",
2444
                result_table);
2445
      if (opt_drop)
2446
        fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", result_table);
2447
      if (!opt_xml)
2448
        fprintf(sql_file, "CREATE TABLE %s (\n", result_table);
2449
      else
2450
        print_xml_tag(sql_file, "\t", "\n", "table_structure", "name=", table, 
2451
                NullS);
2452
      check_io(sql_file);
2453
    }
2454
2455
    if (write_data)
2456
    {
2457
      if (opt_replace_into)
2458
        dynstr_append_checked(&insert_pat, "REPLACE ");
2459
      else
2460
        dynstr_append_checked(&insert_pat, "INSERT ");
2461
      dynstr_append_checked(&insert_pat, insert_option);
2462
      dynstr_append_checked(&insert_pat, "INTO ");
2463
      dynstr_append_checked(&insert_pat, result_table);
2464
      if (complete_insert)
2465
        dynstr_append_checked(&insert_pat, " (");
2466
      else
2467
      {
2468
        dynstr_append_checked(&insert_pat, " VALUES ");
2469
        if (!extended_insert)
2470
          dynstr_append_checked(&insert_pat, "(");
2471
      }
2472
    }
2473
2474
    while ((row= mysql_fetch_row(result)))
2475
    {
2476
      ulong *lengths= mysql_fetch_lengths(result);
2477
      if (init)
2478
      {
2479
        if (!opt_xml && !opt_no_create_info)
2480
        {
2481
          fputs(",\n",sql_file);
2482
          check_io(sql_file);
2483
        }
2484
        if (complete_insert)
2485
          dynstr_append_checked(&insert_pat, ", ");
2486
      }
2487
      init=1;
2488
      if (complete_insert)
2489
        dynstr_append_checked(&insert_pat,
2490
                      quote_name(row[SHOW_FIELDNAME], name_buff, 0));
2491
      if (!opt_no_create_info)
2492
      {
2493
        if (opt_xml)
2494
        {
2495
          print_xml_row(sql_file, "field", result, &row);
2496
          continue;
2497
        }
2498
2499
        if (opt_keywords)
2500
          fprintf(sql_file, "  %s.%s %s", result_table,
2501
                  quote_name(row[SHOW_FIELDNAME],name_buff, 0),
2502
                  row[SHOW_TYPE]);
2503
        else
2504
          fprintf(sql_file, "  %s %s", quote_name(row[SHOW_FIELDNAME],
2505
                                                  name_buff, 0),
2506
                  row[SHOW_TYPE]);
2507
        if (row[SHOW_DEFAULT])
2508
        {
2509
          fputs(" DEFAULT ", sql_file);
2510
          unescape(sql_file, row[SHOW_DEFAULT], lengths[SHOW_DEFAULT]);
2511
        }
2512
        if (!row[SHOW_NULL][0])
2513
          fputs(" NOT NULL", sql_file);
2514
        if (row[SHOW_EXTRA][0])
2515
          fprintf(sql_file, " %s",row[SHOW_EXTRA]);
2516
        check_io(sql_file);
2517
      }
2518
    }
2519
    num_fields= mysql_num_rows(result);
2520
    mysql_free_result(result);
2521
    if (!opt_no_create_info)
2522
    {
2523
      /* Make an sql-file, if path was given iow. option -T was given */
2524
      char buff[20+FN_REFLEN];
2525
      uint keynr,primary_key;
2526
      my_snprintf(buff, sizeof(buff), "show keys from %s", result_table);
2527
      if (mysql_query_with_error_report(mysql, &result, buff))
2528
      {
2529
        if (mysql_errno(mysql) == ER_WRONG_OBJECT)
2530
        {
2531
          /* it is VIEW */
2532
          fputs("\t\t<options Comment=\"view\" />\n", sql_file);
2533
          goto continue_xml;
2534
        }
2535
        fprintf(stderr, "%s: Can't get keys for table %s (%s)\n",
2536
                my_progname, result_table, mysql_error(mysql));
2537
        if (path)
2538
          my_fclose(sql_file, MYF(MY_WME));
2539
        DBUG_RETURN(0);
2540
      }
2541
2542
      /* Find first which key is primary key */
2543
      keynr=0;
2544
      primary_key=INT_MAX;
2545
      while ((row= mysql_fetch_row(result)))
2546
      {
2547
        if (atoi(row[3]) == 1)
2548
        {
2549
          keynr++;
2550
#ifdef FORCE_PRIMARY_KEY
2551
          if (atoi(row[1]) == 0 && primary_key == INT_MAX)
2552
            primary_key=keynr;
2553
#endif
2554
          if (!strcmp(row[2],"PRIMARY"))
2555
          {
2556
            primary_key=keynr;
2557
            break;
2558
          }
2559
        }
2560
      }
2561
      mysql_data_seek(result,0);
2562
      keynr=0;
2563
      while ((row= mysql_fetch_row(result)))
2564
      {
2565
        if (opt_xml)
2566
        {
2567
          print_xml_row(sql_file, "key", result, &row);
2568
          continue;
2569
        }
2570
2571
        if (atoi(row[3]) == 1)
2572
        {
2573
          if (keynr++)
2574
            putc(')', sql_file);
2575
          if (atoi(row[1]))       /* Test if duplicate key */
2576
            /* Duplicate allowed */
2577
            fprintf(sql_file, ",\n  KEY %s (",quote_name(row[2],name_buff,0));
2578
          else if (keynr == primary_key)
2579
            fputs(",\n  PRIMARY KEY (",sql_file); /* First UNIQUE is primary */
2580
          else
2581
            fprintf(sql_file, ",\n  UNIQUE %s (",quote_name(row[2],name_buff,
2582
                                                            0));
2583
        }
2584
        else
2585
          putc(',', sql_file);
2586
        fputs(quote_name(row[4], name_buff, 0), sql_file);
2587
        if (row[7])
2588
          fprintf(sql_file, " (%s)",row[7]);      /* Sub key */
2589
        check_io(sql_file);
2590
      }
2591
      mysql_free_result(result);
2592
      if (!opt_xml)
2593
      {
2594
        if (keynr)
2595
          putc(')', sql_file);
2596
        fputs("\n)",sql_file);
2597
        check_io(sql_file);
2598
      }
2599
2600
      /* Get MySQL specific create options */
2601
      if (create_options)
2602
      {
2603
        char show_name_buff[NAME_LEN*2+2+24];
2604
2605
        /* Check memory for quote_for_like() */
2606
        my_snprintf(buff, sizeof(buff), "show table status like %s",
2607
                    quote_for_like(table, show_name_buff));
2608
2609
        if (mysql_query_with_error_report(mysql, &result, buff))
2610
        {
2611
          if (mysql_errno(mysql) != ER_PARSE_ERROR)
2612
          {                                     /* If old MySQL version */
2613
            verbose_msg("-- Warning: Couldn't get status information for " \
2614
                        "table %s (%s)\n", result_table,mysql_error(mysql));
2615
          }
2616
        }
2617
        else if (!(row= mysql_fetch_row(result)))
2618
        {
2619
          fprintf(stderr,
2620
                  "Error: Couldn't read status information for table %s (%s)\n",
2621
                  result_table,mysql_error(mysql));
2622
        }
2623
        else
2624
        {
2625
          if (opt_xml)
2626
            print_xml_row(sql_file, "options", result, &row);
2627
          else
2628
          {
2629
            fputs("/*!",sql_file);
2630
            print_value(sql_file,result,row,"engine=","Engine",0);
2631
            print_value(sql_file,result,row,"","Create_options",0);
2632
            print_value(sql_file,result,row,"comment=","Comment",1);
2633
            fputs(" */",sql_file);
2634
            check_io(sql_file);
2635
          }
2636
        }
2637
        mysql_free_result(result);              /* Is always safe to free */
2638
      }
2639
continue_xml:
2640
      if (!opt_xml)
2641
        fputs(";\n", sql_file);
2642
      else
2643
        fputs("\t</table_structure>\n", sql_file);
2644
      check_io(sql_file);
2645
    }
2646
  }
2647
  if (complete_insert)
2648
  {
2649
    dynstr_append_checked(&insert_pat, ") VALUES ");
2650
    if (!extended_insert)
2651
      dynstr_append_checked(&insert_pat, "(");
2652
  }
2653
  if (sql_file != md_result_file)
2654
  {
2655
    fputs("\n", sql_file);
2656
    write_footer(sql_file);
2657
    my_fclose(sql_file, MYF(MY_WME));
2658
  }
2659
  DBUG_RETURN((uint) num_fields);
2660
} /* get_table_structure */
2661
2662
static void add_load_option(DYNAMIC_STRING *str, const char *option,
2663
                             const char *option_value)
2664
{
2665
  if (!option_value)
2666
  {
2667
    /* Null value means we don't add this option. */
2668
    return;
2669
  }
2670
2671
  dynstr_append_checked(str, option);
2672
  
2673
  if (strncmp(option_value, "0x", sizeof("0x")-1) == 0)
2674
  {
2675
    /* It's a hex constant, don't escape */
2676
    dynstr_append_checked(str, option_value);
2677
  }
2678
  else
2679
  {
2680
    /* char constant; escape */
2681
    field_escape(str, option_value);
2682
  }
2683
}
2684
2685
2686
/*
2687
  Allow the user to specify field terminator strings like:
2688
  "'", "\", "\\" (escaped backslash), "\t" (tab), "\n" (newline)
2689
  This is done by doubling ' and add a end -\ if needed to avoid
2690
  syntax errors from the SQL parser.
2691
*/
2692
2693
static void field_escape(DYNAMIC_STRING* in, const char *from)
2694
{
2695
  uint end_backslashes= 0; 
2696
2697
  dynstr_append_checked(in, "'");
2698
2699
  while (*from)
2700
  {
2701
    dynstr_append_mem_checked(in, from, 1);
2702
2703
    if (*from == '\\')
2704
      end_backslashes^=1;    /* find odd number of backslashes */
2705
    else
2706
    {
2707
      if (*from == '\'' && !end_backslashes)
2708
      {
2709
        /* We want a duplicate of "'" for MySQL */
2710
        dynstr_append_checked(in, "\'");
2711
      }
2712
      end_backslashes=0;
2713
    }
2714
    from++;
2715
  }
2716
  /* Add missing backslashes if user has specified odd number of backs.*/
2717
  if (end_backslashes)
2718
    dynstr_append_checked(in, "\\");
2719
  
2720
  dynstr_append_checked(in, "'");
2721
}
2722
2723
2724
2725
static char *alloc_query_str(ulong size)
2726
{
2727
  char *query;
2728
2729
  if (!(query= (char*) my_malloc(size, MYF(MY_WME))))
2730
    die(EX_MYSQLERR, "Couldn't allocate a query string.");
2731
2732
  return query;
2733
}
2734
2735
2736
/*
2737
2738
 SYNOPSIS
2739
  dump_table()
2740
2741
  dump_table saves database contents as a series of INSERT statements.
2742
2743
  ARGS
2744
   table - table name
2745
   db    - db name
2746
2747
   RETURNS
2748
    void
2749
*/
2750
2751
2752
static void dump_table(char *table, char *db)
2753
{
2754
  char ignore_flag;
2755
  char buf[200], table_buff[NAME_LEN+3];
2756
  DYNAMIC_STRING query_string;
2757
  char table_type[NAME_LEN];
2758
  char *result_table, table_buff2[NAME_LEN*2+3], *opt_quoted_table;
2759
  int error= 0;
2760
  ulong         rownr, row_break, total_length, init_length;
2761
  uint num_fields;
2762
  MYSQL_RES     *res;
2763
  MYSQL_FIELD   *field;
2764
  MYSQL_ROW     row;
2765
  DBUG_ENTER("dump_table");
2766
2767
  /*
2768
    Make sure you get the create table info before the following check for
2769
    --no-data flag below. Otherwise, the create table info won't be printed.
2770
  */
2771
  num_fields= get_table_structure(table, db, table_type, &ignore_flag);
2772
2773
  /*
2774
    The "table" could be a view.  If so, we don't do anything here.
2775
  */
2776
  if (strcmp(table_type, "VIEW") == 0)
2777
    DBUG_VOID_RETURN;
2778
2779
  /* Check --no-data flag */
2780
  if (opt_no_data)
2781
  {
2782
    verbose_msg("-- Skipping dump data for table '%s', --no-data was used\n",
2783
                table);
2784
    DBUG_VOID_RETURN;
2785
  }
2786
2787
  DBUG_PRINT("info",
2788
             ("ignore_flag: %x  num_fields: %d", (int) ignore_flag,
2789
              num_fields));
2790
  /*
2791
    If the table type is a merge table or any type that has to be
2792
     _completely_ ignored and no data dumped
2793
  */
2794
  if (ignore_flag & IGNORE_DATA)
2795
  {
2796
    verbose_msg("-- Warning: Skipping data for table '%s' because " \
2797
                "it's of type %s\n", table, table_type);
2798
    DBUG_VOID_RETURN;
2799
  }
2800
  /* Check that there are any fields in the table */
2801
  if (num_fields == 0)
2802
  {
2803
    verbose_msg("-- Skipping dump data for table '%s', it has no fields\n",
2804
                table);
2805
    DBUG_VOID_RETURN;
2806
  }
2807
2808
  /*
2809
     Check --skip-events flag: it is not enough to skip creation of events
2810
     discarding SHOW CREATE EVENT statements generation. The myslq.event
2811
     table data should be skipped too.
2812
  */
2813
  if (!opt_events && !my_strcasecmp(&my_charset_latin1, db, "mysql") &&
2814
      !my_strcasecmp(&my_charset_latin1, table, "event"))
2815
  {
2816
    verbose_msg("-- Skipping data table mysql.event, --skip-events was used\n");
2817
    DBUG_VOID_RETURN;
2818
  }
2819
2820
  result_table= quote_name(table,table_buff, 1);
2821
  opt_quoted_table= quote_name(table, table_buff2, 0);
2822
2823
  verbose_msg("-- Sending SELECT query...\n");
2824
2825
  init_dynamic_string_checked(&query_string, "", 1024, 1024);
2826
2827
  if (path)
2828
  {
2829
    char filename[FN_REFLEN], tmp_path[FN_REFLEN];
2830
2831
    /*
2832
      Convert the path to native os format
2833
      and resolve to the full filepath.
2834
    */
2835
    convert_dirname(tmp_path,path,NullS);    
2836
    my_load_path(tmp_path, tmp_path, NULL);
2837
    fn_format(filename, table, tmp_path, ".txt", MYF(MY_UNPACK_FILENAME));
2838
2839
    /* Must delete the file that 'INTO OUTFILE' will write to */
2840
    my_delete(filename, MYF(0));
2841
2842
    /* convert to a unix path name to stick into the query */
2843
    to_unix_path(filename);
2844
2845
    /* now build the query string */
2846
2847
    dynstr_append_checked(&query_string, "SELECT /*!40001 SQL_NO_CACHE */ * INTO OUTFILE '");
2848
    dynstr_append_checked(&query_string, filename);
2849
    dynstr_append_checked(&query_string, "'");
2850
2851
    if (fields_terminated || enclosed || opt_enclosed || escaped)
2852
      dynstr_append_checked(&query_string, " FIELDS");
2853
    
2854
    add_load_option(&query_string, " TERMINATED BY ", fields_terminated);
2855
    add_load_option(&query_string, " ENCLOSED BY ", enclosed);
2856
    add_load_option(&query_string, " OPTIONALLY ENCLOSED BY ", opt_enclosed);
2857
    add_load_option(&query_string, " ESCAPED BY ", escaped);
2858
    add_load_option(&query_string, " LINES TERMINATED BY ", lines_terminated);
2859
2860
    dynstr_append_checked(&query_string, " FROM ");
2861
    dynstr_append_checked(&query_string, result_table);
2862
2863
    if (where)
2864
    {
2865
      dynstr_append_checked(&query_string, " WHERE ");
2866
      dynstr_append_checked(&query_string, where);
2867
    }
2868
2869
    if (order_by)
2870
    {
2871
      dynstr_append_checked(&query_string, " ORDER BY ");
2872
      dynstr_append_checked(&query_string, order_by);
2873
    }
2874
2875
    if (mysql_real_query(mysql, query_string.str, query_string.length))
2876
    {
2877
      DB_error(mysql, "when executing 'SELECT INTO OUTFILE'");
2878
      dynstr_free(&query_string);
2879
      DBUG_VOID_RETURN;
2880
    }
2881
  }
2882
  else
2883
  {
2884
    if (!opt_xml && opt_comments)
2885
    {
2886
      fprintf(md_result_file,"\n--\n-- Dumping data for table %s\n--\n",
2887
              result_table);
2888
      check_io(md_result_file);
2889
    }
2890
    
2891
    dynstr_append_checked(&query_string, "SELECT /*!40001 SQL_NO_CACHE */ * FROM ");
2892
    dynstr_append_checked(&query_string, result_table);
2893
2894
    if (where)
2895
    {
2896
      if (!opt_xml && opt_comments)
2897
      {
2898
        fprintf(md_result_file, "-- WHERE:  %s\n", where);
2899
        check_io(md_result_file);
2900
      }
2901
      
2902
      dynstr_append_checked(&query_string, " WHERE ");
2903
      dynstr_append_checked(&query_string, where);
2904
    }
2905
    if (order_by)
2906
    {
2907
      if (!opt_xml && opt_comments)
2908
      {
2909
        fprintf(md_result_file, "-- ORDER BY:  %s\n", order_by);
2910
        check_io(md_result_file);
2911
      }
2912
      dynstr_append_checked(&query_string, " ORDER BY ");
2913
      dynstr_append_checked(&query_string, order_by);
2914
    }
2915
2916
    if (!opt_xml && !opt_compact)
2917
    {
2918
      fputs("\n", md_result_file);
2919
      check_io(md_result_file);
2920
    }
2921
    if (mysql_query_with_error_report(mysql, 0, query_string.str))
2922
    {
2923
      DB_error(mysql, "when retrieving data from server");
2924
      goto err;
2925
    }
2926
    if (quick)
2927
      res=mysql_use_result(mysql);
2928
    else
2929
      res=mysql_store_result(mysql);
2930
    if (!res)
2931
    {
2932
      DB_error(mysql, "when retrieving data from server");
2933
      goto err;
2934
    }
2935
2936
    verbose_msg("-- Retrieving rows...\n");
2937
    if (mysql_num_fields(res) != num_fields)
2938
    {
2939
      fprintf(stderr,"%s: Error in field count for table: %s !  Aborting.\n",
2940
              my_progname, result_table);
2941
      error= EX_CONSCHECK;
2942
      goto err;
2943
    }
2944
2945
    if (opt_lock)
2946
    {
2947
      fprintf(md_result_file,"LOCK TABLES %s WRITE;\n", opt_quoted_table);
2948
      check_io(md_result_file);
2949
    }
2950
    /* Moved disable keys to after lock per bug 15977 */
2951
    if (opt_disable_keys)
2952
    {
2953
      fprintf(md_result_file, "/*!40000 ALTER TABLE %s DISABLE KEYS */;\n",
2954
	      opt_quoted_table);
2955
      check_io(md_result_file);
2956
    }
2957
2958
    total_length= opt_net_buffer_length;                /* Force row break */
2959
    row_break=0;
2960
    rownr=0;
2961
    init_length=(uint) insert_pat.length+4;
2962
    if (opt_xml)
2963
      print_xml_tag(md_result_file, "\t", "\n", "table_data", "name=", table,
2964
              NullS);
2965
    if (opt_autocommit)
2966
    {
2967
      fprintf(md_result_file, "set autocommit=0;\n");
2968
      check_io(md_result_file);
2969
    }
2970
2971
    while ((row= mysql_fetch_row(res)))
2972
    {
2973
      uint i;
2974
      ulong *lengths= mysql_fetch_lengths(res);
2975
      rownr++;
2976
      if (!extended_insert && !opt_xml)
2977
      {
2978
        fputs(insert_pat.str,md_result_file);
2979
        check_io(md_result_file);
2980
      }
2981
      mysql_field_seek(res,0);
2982
2983
      if (opt_xml)
2984
      {
2985
        fputs("\t<row>\n", md_result_file);
2986
        check_io(md_result_file);
2987
      }
2988
2989
      for (i= 0; i < mysql_num_fields(res); i++)
2990
      {
2991
        int is_blob;
2992
        ulong length= lengths[i];
2993
2994
        if (!(field= mysql_fetch_field(res)))
2995
          die(EX_CONSCHECK,
2996
                      "Not enough fields from table %s! Aborting.\n",
2997
                      result_table);
2998
2999
        /*
3000
           63 is my_charset_bin. If charsetnr is not 63,
3001
           we have not a BLOB but a TEXT column.
3002
           we'll dump in hex only BLOB columns.
3003
        */
3004
        is_blob= (opt_hex_blob && field->charsetnr == 63 &&
3005
                  (field->type == MYSQL_TYPE_BIT ||
3006
                   field->type == MYSQL_TYPE_STRING ||
3007
                   field->type == MYSQL_TYPE_VAR_STRING ||
3008
                   field->type == MYSQL_TYPE_VARCHAR ||
3009
                   field->type == MYSQL_TYPE_BLOB ||
3010
                   field->type == MYSQL_TYPE_LONG_BLOB ||
3011
                   field->type == MYSQL_TYPE_MEDIUM_BLOB ||
3012
                   field->type == MYSQL_TYPE_TINY_BLOB)) ? 1 : 0;
3013
        if (extended_insert && !opt_xml)
3014
        {
3015
          if (i == 0)
3016
            dynstr_set_checked(&extended_row,"(");
3017
          else
3018
            dynstr_append_checked(&extended_row,",");
3019
3020
          if (row[i])
3021
          {
3022
            if (length)
3023
            {
3024
              if (!IS_NUM_FIELD(field))
3025
              {
3026
                /*
3027
                  "length * 2 + 2" is OK for both HEX and non-HEX modes:
3028
                  - In HEX mode we need exactly 2 bytes per character
3029
                  plus 2 bytes for '0x' prefix.
3030
                  - In non-HEX mode we need up to 2 bytes per character,
3031
                  plus 2 bytes for leading and trailing '\'' characters.
3032
                  Also we need to reserve 1 byte for terminating '\0'.
3033
                */
3034
                dynstr_realloc_checked(&extended_row,length * 2 + 2 + 1);
3035
                if (opt_hex_blob && is_blob)
3036
                {
3037
                  dynstr_append_checked(&extended_row, "0x");
3038
                  extended_row.length+= mysql_hex_string(extended_row.str +
3039
                                                         extended_row.length,
3040
                                                         row[i], length);
3041
                  DBUG_ASSERT(extended_row.length+1 <= extended_row.max_length);
3042
                  /* mysql_hex_string() already terminated string by '\0' */
3043
                  DBUG_ASSERT(extended_row.str[extended_row.length] == '\0');
3044
                }
3045
                else
3046
                {
3047
                  dynstr_append_checked(&extended_row,"'");
3048
                  extended_row.length +=
3049
                  mysql_real_escape_string(&mysql_connection,
3050
                                           &extended_row.str[extended_row.length],
3051
                                           row[i],length);
3052
                  extended_row.str[extended_row.length]='\0';
3053
                  dynstr_append_checked(&extended_row,"'");
3054
                }
3055
              }
3056
              else
3057
              {
3058
                /* change any strings ("inf", "-inf", "nan") into NULL */
3059
                char *ptr= row[i];
3060
                if (my_isalpha(charset_info, *ptr) || (*ptr == '-' &&
3061
                    my_isalpha(charset_info, ptr[1])))
3062
                  dynstr_append_checked(&extended_row, "NULL");
3063
                else
3064
                {
3065
                  if (field->type == MYSQL_TYPE_DECIMAL)
3066
                  {
3067
                    /* add " signs around */
3068
                    dynstr_append_checked(&extended_row, "'");
3069
                    dynstr_append_checked(&extended_row, ptr);
3070
                    dynstr_append_checked(&extended_row, "'");
3071
                  }
3072
                  else
3073
                    dynstr_append_checked(&extended_row, ptr);
3074
                }
3075
              }
3076
            }
3077
            else
3078
              dynstr_append_checked(&extended_row,"''");
3079
          }
3080
          else
3081
            dynstr_append_checked(&extended_row,"NULL");
3082
        }
3083
        else
3084
        {
3085
          if (i && !opt_xml)
3086
          {
3087
            fputc(',', md_result_file);
3088
            check_io(md_result_file);
3089
          }
3090
          if (row[i])
3091
          {
3092
            if (!IS_NUM_FIELD(field))
3093
            {
3094
              if (opt_xml)
3095
              {
3096
                if (opt_hex_blob && is_blob && length)
3097
                {
3098
                  /* Define xsi:type="xs:hexBinary" for hex encoded data */
3099
                  print_xml_tag(md_result_file, "\t\t", "", "field", "name=",
3100
                                field->name, "xsi:type=", "xs:hexBinary", NullS);
3101
                  print_blob_as_hex(md_result_file, row[i], length);
3102
                }
3103
                else
3104
                {
3105
                  print_xml_tag(md_result_file, "\t\t", "", "field", "name=", 
3106
                                field->name, NullS);
3107
                  print_quoted_xml(md_result_file, row[i], length);
3108
                }
3109
                fputs("</field>\n", md_result_file);
3110
              }
3111
              else if (opt_hex_blob && is_blob && length)
3112
              {
3113
                fputs("0x", md_result_file);
3114
                print_blob_as_hex(md_result_file, row[i], length);
3115
              }
3116
              else
3117
                unescape(md_result_file, row[i], length);
3118
            }
3119
            else
3120
            {
3121
              /* change any strings ("inf", "-inf", "nan") into NULL */
3122
              char *ptr= row[i];
3123
              if (opt_xml)
3124
              {
3125
                print_xml_tag(md_result_file, "\t\t", "", "field", "name=",
3126
                        field->name, NullS);
3127
                fputs(!my_isalpha(charset_info, *ptr) ? ptr: "NULL",
3128
                      md_result_file);
3129
                fputs("</field>\n", md_result_file);
3130
              }
3131
              else if (my_isalpha(charset_info, *ptr) ||
3132
                       (*ptr == '-' && my_isalpha(charset_info, ptr[1])))
3133
                fputs("NULL", md_result_file);
3134
              else if (field->type == MYSQL_TYPE_DECIMAL)
3135
              {
3136
                /* add " signs around */
3137
                fputc('\'', md_result_file);
3138
                fputs(ptr, md_result_file);
3139
                fputc('\'', md_result_file);
3140
              }
3141
              else
3142
                fputs(ptr, md_result_file);
3143
            }
3144
          }
3145
          else
3146
          {
3147
            /* The field value is NULL */
3148
            if (!opt_xml)
3149
              fputs("NULL", md_result_file);
3150
            else
3151
              print_xml_null_tag(md_result_file, "\t\t", "field name=",
3152
                                 field->name, "\n");
3153
          }
3154
          check_io(md_result_file);
3155
        }
3156
      }
3157
3158
      if (opt_xml)
3159
      {
3160
        fputs("\t</row>\n", md_result_file);
3161
        check_io(md_result_file);
3162
      }
3163
3164
      if (extended_insert)
3165
      {
3166
        ulong row_length;
3167
        dynstr_append_checked(&extended_row,")");
3168
        row_length= 2 + extended_row.length;
3169
        if (total_length + row_length < opt_net_buffer_length)
3170
        {
3171
          total_length+= row_length;
3172
          fputc(',',md_result_file);            /* Always row break */
3173
          fputs(extended_row.str,md_result_file);
3174
        }
3175
        else
3176
        {
3177
          if (row_break)
3178
            fputs(";\n", md_result_file);
3179
          row_break=1;                          /* This is first row */
3180
3181
          fputs(insert_pat.str,md_result_file);
3182
          fputs(extended_row.str,md_result_file);
3183
          total_length= row_length+init_length;
3184
        }
3185
        check_io(md_result_file);
3186
      }
3187
      else if (!opt_xml)
3188
      {
3189
        fputs(");\n", md_result_file);
3190
        check_io(md_result_file);
3191
      }
3192
    }
3193
3194
    /* XML - close table tag and supress regular output */
3195
    if (opt_xml)
3196
        fputs("\t</table_data>\n", md_result_file);
3197
    else if (extended_insert && row_break)
3198
      fputs(";\n", md_result_file);             /* If not empty table */
3199
    fflush(md_result_file);
3200
    check_io(md_result_file);
3201
    if (mysql_errno(mysql))
3202
    {
3203
      my_snprintf(buf, sizeof(buf),
3204
                  "%s: Error %d: %s when dumping table %s at row: %ld\n",
3205
                  my_progname,
3206
                  mysql_errno(mysql),
3207
                  mysql_error(mysql),
3208
                  result_table,
3209
                  rownr);
3210
      fputs(buf,stderr);
3211
      error= EX_CONSCHECK;
3212
      goto err;
3213
    }
3214
3215
    /* Moved enable keys to before unlock per bug 15977 */
3216
    if (opt_disable_keys)
3217
    {
3218
      fprintf(md_result_file,"/*!40000 ALTER TABLE %s ENABLE KEYS */;\n",
3219
              opt_quoted_table);
3220
      check_io(md_result_file);
3221
    }
3222
    if (opt_lock)
3223
    {
3224
      fputs("UNLOCK TABLES;\n", md_result_file);
3225
      check_io(md_result_file);
3226
    }
3227
    if (opt_autocommit)
3228
    {
3229
      fprintf(md_result_file, "commit;\n");
3230
      check_io(md_result_file);
3231
    }
3232
    mysql_free_result(res);
3233
  }
3234
  dynstr_free(&query_string);
3235
  DBUG_VOID_RETURN;
3236
3237
err:
3238
  dynstr_free(&query_string);
3239
  maybe_exit(error);
3240
  DBUG_VOID_RETURN;
3241
} /* dump_table */
3242
3243
3244
static char *getTableName(int reset)
3245
{
3246
  static MYSQL_RES *res= NULL;
3247
  MYSQL_ROW    row;
3248
3249
  if (!res)
3250
  {
3251
    if (!(res= mysql_list_tables(mysql,NullS)))
3252
      return(NULL);
3253
  }
3254
  if ((row= mysql_fetch_row(res)))
3255
    return((char*) row[0]);
3256
3257
  if (reset)
3258
    mysql_data_seek(res,0);      /* We want to read again */
3259
  else
3260
  {
3261
    mysql_free_result(res);
3262
    res= NULL;
3263
  }
3264
  return(NULL);
3265
} /* getTableName */
3266
3267
3268
/*
3269
  dump all logfile groups and tablespaces
3270
*/
3271
3272
static int dump_all_tablespaces()
3273
{
3274
  return dump_tablespaces(NULL);
3275
}
3276
3277
static int dump_tablespaces_for_tables(char *db, char **table_names, int tables)
3278
{
3279
  DYNAMIC_STRING where;
3280
  int r;
3281
  int i;
3282
  char name_buff[NAME_LEN*2+3];
3283
3284
  mysql_real_escape_string(mysql, name_buff, db, strlen(db));
3285
3286
  init_dynamic_string_checked(&where, " AND TABLESPACE_NAME IN ("
3287
                      "SELECT DISTINCT TABLESPACE_NAME FROM"
3288
                      " INFORMATION_SCHEMA.PARTITIONS"
3289
                      " WHERE"
3290
                      " TABLE_SCHEMA='", 256, 1024);
3291
  dynstr_append_checked(&where, name_buff);
3292
  dynstr_append_checked(&where, "' AND TABLE_NAME IN (");
3293
3294
  for (i=0 ; i<tables ; i++)
3295
  {
3296
    mysql_real_escape_string(mysql, name_buff,
3297
                             table_names[i], strlen(table_names[i]));
3298
3299
    dynstr_append_checked(&where, "'");
3300
    dynstr_append_checked(&where, name_buff);
3301
    dynstr_append_checked(&where, "',");
3302
  }
3303
  dynstr_trunc(&where, 1);
3304
  dynstr_append_checked(&where,"))");
3305
3306
  DBUG_PRINT("info",("Dump TS for Tables where: %s",where.str));
3307
  r= dump_tablespaces(where.str);
3308
  dynstr_free(&where);
3309
  return r;
3310
}
3311
3312
static int dump_tablespaces_for_databases(char** databases)
3313
{
3314
  DYNAMIC_STRING where;
3315
  int r;
3316
  int i;
3317
3318
  init_dynamic_string_checked(&where, " AND TABLESPACE_NAME IN ("
3319
                      "SELECT DISTINCT TABLESPACE_NAME FROM"
3320
                      " INFORMATION_SCHEMA.PARTITIONS"
3321
                      " WHERE"
3322
                      " TABLE_SCHEMA IN (", 256, 1024);
3323
3324
  for (i=0 ; databases[i]!=NULL ; i++)
3325
  {
3326
    char db_name_buff[NAME_LEN*2+3];
3327
    mysql_real_escape_string(mysql, db_name_buff,
3328
                             databases[i], strlen(databases[i]));
3329
    dynstr_append_checked(&where, "'");
3330
    dynstr_append_checked(&where, db_name_buff);
3331
    dynstr_append_checked(&where, "',");
3332
  }
3333
  dynstr_trunc(&where, 1);
3334
  dynstr_append_checked(&where,"))");
3335
3336
  DBUG_PRINT("info",("Dump TS for DBs where: %s",where.str));
3337
  r= dump_tablespaces(where.str);
3338
  dynstr_free(&where);
3339
  return r;
3340
}
3341
3342
static int dump_tablespaces(char* ts_where)
3343
{
3344
  MYSQL_ROW row;
3345
  MYSQL_RES *tableres;
3346
  char buf[FN_REFLEN];
3347
  DYNAMIC_STRING sqlbuf;
3348
  int first= 0;
3349
  /*
3350
    The following are used for parsing the EXTRA field
3351
  */
3352
  char extra_format[]= "UNDO_BUFFER_SIZE=";
3353
  char *ubs;
3354
  char *endsemi;
3355
  DBUG_ENTER("dump_tablespaces");
3356
3357
  init_dynamic_string_checked(&sqlbuf,
3358
                      "SELECT LOGFILE_GROUP_NAME,"
3359
                      " FILE_NAME,"
3360
                      " TOTAL_EXTENTS,"
3361
                      " INITIAL_SIZE,"
3362
                      " ENGINE,"
3363
                      " EXTRA"
3364
                      " FROM INFORMATION_SCHEMA.FILES"
3365
                      " WHERE FILE_TYPE = 'UNDO LOG'"
3366
                      " AND FILE_NAME IS NOT NULL",
3367
                      256, 1024);
3368
  if(ts_where)
3369
  {
3370
    dynstr_append_checked(&sqlbuf,
3371
                  " AND LOGFILE_GROUP_NAME IN ("
3372
                  "SELECT DISTINCT LOGFILE_GROUP_NAME"
3373
                  " FROM INFORMATION_SCHEMA.FILES"
3374
                  " WHERE FILE_TYPE = 'DATAFILE'"
3375
                  );
3376
    dynstr_append_checked(&sqlbuf, ts_where);
3377
    dynstr_append_checked(&sqlbuf, ")");
3378
  }
3379
  dynstr_append_checked(&sqlbuf,
3380
                " GROUP BY LOGFILE_GROUP_NAME, FILE_NAME"
3381
                ", ENGINE"
3382
                " ORDER BY LOGFILE_GROUP_NAME");
3383
3384
  if (mysql_query(mysql, sqlbuf.str) ||
3385
      !(tableres = mysql_store_result(mysql)))
3386
  {
3387
    dynstr_free(&sqlbuf);
3388
    if (mysql_errno(mysql) == ER_BAD_TABLE_ERROR ||
3389
        mysql_errno(mysql) == ER_BAD_DB_ERROR ||
3390
        mysql_errno(mysql) == ER_UNKNOWN_TABLE)
3391
    {
3392
      fprintf(md_result_file,
3393
              "\n--\n-- Not dumping tablespaces as no INFORMATION_SCHEMA.FILES"
3394
              " table on this server\n--\n");
3395
      check_io(md_result_file);
3396
      DBUG_RETURN(0);
3397
    }
3398
3399
    my_printf_error(0, "Error: '%s' when trying to dump tablespaces",
3400
                    MYF(0), mysql_error(mysql));
3401
    DBUG_RETURN(1);
3402
  }
3403
3404
  buf[0]= 0;
3405
  while ((row= mysql_fetch_row(tableres)))
3406
  {
3407
    if (strcmp(buf, row[0]) != 0)
3408
      first= 1;
3409
    if (first)
3410
    {
3411
      if (!opt_xml && opt_comments)
3412
      {
3413
	fprintf(md_result_file,"\n--\n-- Logfile group: %s\n--\n", row[0]);
3414
	check_io(md_result_file);
3415
      }
3416
      fprintf(md_result_file, "\nCREATE");
3417
    }
3418
    else
3419
    {
3420
      fprintf(md_result_file, "\nALTER");
3421
    }
3422
    fprintf(md_result_file,
3423
            " LOGFILE GROUP %s\n"
3424
            "  ADD UNDOFILE '%s'\n",
3425
            row[0],
3426
            row[1]);
3427
    if (first)
3428
    {
3429
      ubs= strstr(row[5],extra_format);
3430
      if(!ubs)
3431
        break;
3432
      ubs+= strlen(extra_format);
3433
      endsemi= strstr(ubs,";");
3434
      if(endsemi)
3435
        endsemi[0]= '\0';
3436
      fprintf(md_result_file,
3437
              "  UNDO_BUFFER_SIZE %s\n",
3438
              ubs);
3439
    }
3440
    fprintf(md_result_file,
3441
            "  INITIAL_SIZE %s\n"
3442
            "  ENGINE=%s;\n",
3443
            row[3],
3444
            row[4]);
3445
    check_io(md_result_file);
3446
    if (first)
3447
    {
3448
      first= 0;
3449
      strxmov(buf, row[0], NullS);
3450
    }
3451
  }
3452
  dynstr_free(&sqlbuf);
3453
  mysql_free_result(tableres);
3454
  init_dynamic_string_checked(&sqlbuf,
3455
                      "SELECT DISTINCT TABLESPACE_NAME,"
3456
                      " FILE_NAME,"
3457
                      " LOGFILE_GROUP_NAME,"
3458
                      " EXTENT_SIZE,"
3459
                      " INITIAL_SIZE,"
3460
                      " ENGINE"
3461
                      " FROM INFORMATION_SCHEMA.FILES"
3462
                      " WHERE FILE_TYPE = 'DATAFILE'",
3463
                      256, 1024);
3464
3465
  if(ts_where)
3466
    dynstr_append_checked(&sqlbuf, ts_where);
3467
3468
  dynstr_append_checked(&sqlbuf, " ORDER BY TABLESPACE_NAME, LOGFILE_GROUP_NAME");
3469
3470
  if (mysql_query_with_error_report(mysql, &tableres, sqlbuf.str))
3471
  {
3472
    dynstr_free(&sqlbuf);
3473
    DBUG_RETURN(1);
3474
  }
3475
3476
  buf[0]= 0;
3477
  while ((row= mysql_fetch_row(tableres)))
3478
  {
3479
    if (strcmp(buf, row[0]) != 0)
3480
      first= 1;
3481
    if (first)
3482
    {
3483
      if (!opt_xml && opt_comments)
3484
      {
3485
	fprintf(md_result_file,"\n--\n-- Tablespace: %s\n--\n", row[0]);
3486
	check_io(md_result_file);
3487
      }
3488
      fprintf(md_result_file, "\nCREATE");
3489
    }
3490
    else
3491
    {
3492
      fprintf(md_result_file, "\nALTER");
3493
    }
3494
    fprintf(md_result_file,
3495
            " TABLESPACE %s\n"
3496
            "  ADD DATAFILE '%s'\n",
3497
            row[0],
3498
            row[1]);
3499
    if (first)
3500
    {
3501
      fprintf(md_result_file,
3502
              "  USE LOGFILE GROUP %s\n"
3503
              "  EXTENT_SIZE %s\n",
3504
              row[2],
3505
              row[3]);
3506
    }
3507
    fprintf(md_result_file,
3508
            "  INITIAL_SIZE %s\n"
3509
            "  ENGINE=%s;\n",
3510
            row[4],
3511
            row[5]);
3512
    check_io(md_result_file);
3513
    if (first)
3514
    {
3515
      first= 0;
3516
      strxmov(buf, row[0], NullS);
3517
    }
3518
  }
3519
3520
  mysql_free_result(tableres);
3521
  dynstr_free(&sqlbuf);
3522
  DBUG_RETURN(0);
3523
}
3524
3525
static int dump_all_databases()
3526
{
3527
  MYSQL_ROW row;
3528
  MYSQL_RES *tableres;
3529
  int result=0;
3530
3531
  if (mysql_query_with_error_report(mysql, &tableres, "SHOW DATABASES"))
3532
    return 1;
3533
  while ((row= mysql_fetch_row(tableres)))
3534
  {
3535
    if (dump_all_tables_in_db(row[0]))
3536
      result=1;
3537
  }
3538
  if (seen_views)
3539
  {
3540
    if (mysql_query(mysql, "SHOW DATABASES") ||
3541
        !(tableres= mysql_store_result(mysql)))
3542
    {
3543
      my_printf_error(0, "Error: Couldn't execute 'SHOW DATABASES': %s",
3544
                      MYF(0), mysql_error(mysql));
3545
      return 1;
3546
    }
3547
    while ((row= mysql_fetch_row(tableres)))
3548
    {
3549
      if (dump_all_views_in_db(row[0]))
3550
        result=1;
3551
    }
3552
  }
3553
  return result;
3554
}
3555
/* dump_all_databases */
3556
3557
3558
static int dump_databases(char **db_names)
3559
{
3560
  int result=0;
3561
  char **db;
3562
  DBUG_ENTER("dump_databases");
3563
3564
  for (db= db_names ; *db ; db++)
3565
  {
3566
    if (dump_all_tables_in_db(*db))
3567
      result=1;
3568
  }
3569
  if (!result && seen_views)
3570
  {
3571
    for (db= db_names ; *db ; db++)
3572
    {
3573
      if (dump_all_views_in_db(*db))
3574
        result=1;
3575
    }
3576
  }
3577
  DBUG_RETURN(result);
3578
} /* dump_databases */
3579
3580
3581
/*
3582
View Specific database initalization.
3583
3584
SYNOPSIS
3585
  init_dumping_views
3586
  qdatabase      quoted name of the database
3587
3588
RETURN VALUES
3589
  0        Success.
3590
  1        Failure.
3591
*/
3592
int init_dumping_views(char *qdatabase __attribute__((unused)))
3593
{
3594
    return 0;
3595
} /* init_dumping_views */
3596
3597
3598
/*
3599
Table Specific database initalization.
3600
3601
SYNOPSIS
3602
  init_dumping_tables
3603
  qdatabase      quoted name of the database
3604
3605
RETURN VALUES
3606
  0        Success.
3607
  1        Failure.
3608
*/
3609
3610
int init_dumping_tables(char *qdatabase)
3611
{
3612
  DBUG_ENTER("init_dumping_tables");
3613
3614
  if (!opt_create_db)
3615
  {
3616
    char qbuf[256];
3617
    MYSQL_ROW row;
3618
    MYSQL_RES *dbinfo;
3619
3620
    my_snprintf(qbuf, sizeof(qbuf),
3621
                "SHOW CREATE DATABASE IF NOT EXISTS %s",
3622
                qdatabase);
3623
3624
    if (mysql_query(mysql, qbuf) || !(dbinfo = mysql_store_result(mysql)))
3625
    {
3626
      /* Old server version, dump generic CREATE DATABASE */
3627
      if (opt_drop_database)
3628
        fprintf(md_result_file,
3629
                "\n/*!40000 DROP DATABASE IF EXISTS %s*/;\n",
3630
                qdatabase);
3631
      fprintf(md_result_file,
3632
              "\nCREATE DATABASE /*!32312 IF NOT EXISTS*/ %s;\n",
3633
              qdatabase);
3634
    }
3635
    else
3636
    {
3637
      if (opt_drop_database)
3638
        fprintf(md_result_file,
3639
                "\n/*!40000 DROP DATABASE IF EXISTS %s*/;\n",
3640
                qdatabase);
3641
      row = mysql_fetch_row(dbinfo);
3642
      if (row[1])
3643
      {
3644
        fprintf(md_result_file,"\n%s;\n",row[1]);
3645
      }
3646
      mysql_free_result(dbinfo);
3647
    }
3648
  }
3649
  DBUG_RETURN(0);
3650
} /* init_dumping_tables */
3651
3652
3653
static int init_dumping(char *database, int init_func(char*))
3654
{
3655
  if (mysql_get_server_version(mysql) >= 50003 &&
3656
      !my_strcasecmp(&my_charset_latin1, database, "information_schema"))
3657
    return 1;
3658
3659
  if (mysql_select_db(mysql, database))
3660
  {
3661
    DB_error(mysql, "when selecting the database");
3662
    return 1;                   /* If --force */
3663
  }
3664
  if (!path && !opt_xml)
3665
  {
3666
    if (opt_databases || opt_alldbs)
3667
    {
3668
      /*
3669
        length of table name * 2 (if name contains quotes), 2 quotes and 0
3670
      */
3671
      char quoted_database_buf[NAME_LEN*2+3];
3672
      char *qdatabase= quote_name(database,quoted_database_buf,opt_quoted);
3673
      if (opt_comments)
3674
      {
3675
        fprintf(md_result_file,"\n--\n-- Current Database: %s\n--\n", qdatabase);
3676
        check_io(md_result_file);
3677
      }
3678
3679
      /* Call the view or table specific function */
3680
      init_func(qdatabase);
3681
3682
      fprintf(md_result_file,"\nUSE %s;\n", qdatabase);
3683
      check_io(md_result_file);
3684
    }
3685
  }
3686
  if (extended_insert)
3687
    init_dynamic_string_checked(&extended_row, "", 1024, 1024);
3688
  return 0;
3689
} /* init_dumping */
3690
3691
3692
/* Return 1 if we should copy the table */
3693
3694
my_bool include_table(const uchar *hash_key, size_t len)
3695
{
3696
  return !hash_search(&ignore_table, hash_key, len);
3697
}
3698
3699
3700
static int dump_all_tables_in_db(char *database)
3701
{
3702
  char *table;
3703
  uint numrows;
3704
  char table_buff[NAME_LEN*2+3];
3705
  char hash_key[2*NAME_LEN+2];  /* "db.tablename" */
3706
  char *afterdot;
3707
  int using_mysql_db= my_strcasecmp(&my_charset_latin1, database, "mysql");
3708
  DBUG_ENTER("dump_all_tables_in_db");
3709
3710
  afterdot= strmov(hash_key, database);
3711
  *afterdot++= '.';
3712
3713
  if (init_dumping(database, init_dumping_tables))
3714
    DBUG_RETURN(1);
3715
  if (opt_xml)
3716
    print_xml_tag(md_result_file, "", "\n", "database", "name=", database, NullS);
3717
  if (lock_tables)
3718
  {
3719
    DYNAMIC_STRING query;
3720
    init_dynamic_string_checked(&query, "LOCK TABLES ", 256, 1024);
3721
    for (numrows= 0 ; (table= getTableName(1)) ; )
3722
    {
3723
      char *end= strmov(afterdot, table);
3724
      if (include_table((uchar*) hash_key,end - hash_key))
3725
      {
3726
        numrows++;
3727
        dynstr_append_checked(&query, quote_name(table, table_buff, 1));
3728
        dynstr_append_checked(&query, " READ /*!32311 LOCAL */,");
3729
      }
3730
    }
3731
    if (numrows && mysql_real_query(mysql, query.str, query.length-1))
3732
      DB_error(mysql, "when using LOCK TABLES");
3733
            /* We shall continue here, if --force was given */
3734
    dynstr_free(&query);
3735
  }
3736
  if (flush_logs)
3737
  {
3738
    if (mysql_refresh(mysql, REFRESH_LOG))
3739
      DB_error(mysql, "when doing refresh");
3740
           /* We shall continue here, if --force was given */
3741
  }
3742
  while ((table= getTableName(0)))
3743
  {
3744
    char *end= strmov(afterdot, table);
3745
    if (include_table((uchar*) hash_key, end - hash_key))
3746
    {
3747
      dump_table(table,database);
3748
      my_free(order_by, MYF(MY_ALLOW_ZERO_PTR));
3749
      order_by= 0;
3750
    }
3751
  }
3752
  if (opt_events && !opt_xml &&
3753
      mysql_get_server_version(mysql) >= 50106)
3754
  {
3755
    DBUG_PRINT("info", ("Dumping events for database %s", database));
3756
    dump_events_for_db(database);
3757
  }
3758
  if (opt_routines && !opt_xml &&
3759
      mysql_get_server_version(mysql) >= 50009)
3760
  {
3761
    DBUG_PRINT("info", ("Dumping routines for database %s", database));
3762
    dump_routines_for_db(database);
3763
  }
3764
  if (opt_xml)
3765
  {
3766
    fputs("</database>\n", md_result_file);
3767
    check_io(md_result_file);
3768
  }
3769
  if (lock_tables)
3770
    VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES"));
3771
  if (flush_privileges && using_mysql_db == 0)
3772
  {
3773
    fprintf(md_result_file,"\n--\n-- Flush Grant Tables \n--\n");
3774
    fprintf(md_result_file,"\n/*! FLUSH PRIVILEGES */;\n");
3775
  }
3776
  DBUG_RETURN(0);
3777
} /* dump_all_tables_in_db */
3778
3779
3780
/*
3781
   dump structure of views of database
3782
3783
   SYNOPSIS
3784
     dump_all_views_in_db()
3785
     database  database name
3786
3787
  RETURN
3788
    0 OK
3789
    1 ERROR
3790
*/
3791
3792
static my_bool dump_all_views_in_db(char *database)
3793
{
3794
  char *table;
3795
  uint numrows;
3796
  char table_buff[NAME_LEN*2+3];
3797
  char hash_key[2*NAME_LEN+2];  /* "db.tablename" */
3798
  char *afterdot;
3799
3800
  afterdot= strmov(hash_key, database);
3801
  *afterdot++= '.';
3802
3803
  if (init_dumping(database, init_dumping_views))
3804
    return 1;
3805
  if (opt_xml)
3806
    print_xml_tag(md_result_file, "", "\n", "database", "name=", database, NullS);
3807
  if (lock_tables)
3808
  {
3809
    DYNAMIC_STRING query;
3810
    init_dynamic_string_checked(&query, "LOCK TABLES ", 256, 1024);
3811
    for (numrows= 0 ; (table= getTableName(1)); )
3812
    {
3813
      char *end= strmov(afterdot, table);
3814
      if (include_table((uchar*) hash_key,end - hash_key))
3815
      {
3816
        numrows++;
3817
        dynstr_append_checked(&query, quote_name(table, table_buff, 1));
3818
        dynstr_append_checked(&query, " READ /*!32311 LOCAL */,");
3819
      }
3820
    }
3821
    if (numrows && mysql_real_query(mysql, query.str, query.length-1))
3822
      DB_error(mysql, "when using LOCK TABLES");
3823
            /* We shall continue here, if --force was given */
3824
    dynstr_free(&query);
3825
  }
3826
  if (flush_logs)
3827
  {
3828
    if (mysql_refresh(mysql, REFRESH_LOG))
3829
      DB_error(mysql, "when doing refresh");
3830
           /* We shall continue here, if --force was given */
3831
  }
3832
  while ((table= getTableName(0)))
3833
  {
3834
    char *end= strmov(afterdot, table);
3835
    if (include_table((uchar*) hash_key, end - hash_key))
3836
      get_view_structure(table, database);
3837
  }
3838
  if (opt_xml)
3839
  {
3840
    fputs("</database>\n", md_result_file);
3841
    check_io(md_result_file);
3842
  }
3843
  if (lock_tables)
3844
    VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES"));
3845
  return 0;
3846
} /* dump_all_tables_in_db */
3847
3848
3849
/*
3850
  get_actual_table_name -- executes a SHOW TABLES LIKE '%s' to get the actual
3851
  table name from the server for the table name given on the command line.
3852
  we do this because the table name given on the command line may be a
3853
  different case (e.g.  T1 vs t1)
3854
3855
  RETURN
3856
    pointer to the table name
3857
    0 if error
3858
*/
3859
3860
static char *get_actual_table_name(const char *old_table_name, MEM_ROOT *root)
3861
{
3862
  char *name= 0;
3863
  MYSQL_RES  *table_res;
3864
  MYSQL_ROW  row;
3865
  char query[50 + 2*NAME_LEN];
3866
  char show_name_buff[FN_REFLEN];
3867
  DBUG_ENTER("get_actual_table_name");
3868
3869
  /* Check memory for quote_for_like() */
3870
  DBUG_ASSERT(2*sizeof(old_table_name) < sizeof(show_name_buff));
3871
  my_snprintf(query, sizeof(query), "SHOW TABLES LIKE %s",
3872
              quote_for_like(old_table_name, show_name_buff));
3873
3874
  if (mysql_query_with_error_report(mysql, 0, query))
3875
    return NullS;
3876
3877
  if ((table_res= mysql_store_result(mysql)))
3878
  {
3879
    my_ulonglong num_rows= mysql_num_rows(table_res);
3880
    if (num_rows > 0)
3881
    {
3882
      ulong *lengths;
3883
      /*
3884
        Return first row
3885
        TODO: Return all matching rows
3886
      */
3887
      row= mysql_fetch_row(table_res);
3888
      lengths= mysql_fetch_lengths(table_res);
3889
      name= strmake_root(root, row[0], lengths[0]);
3890
    }
3891
    mysql_free_result(table_res);
3892
  }
3893
  DBUG_PRINT("exit", ("new_table_name: %s", name));
3894
  DBUG_RETURN(name);
3895
}
3896
3897
3898
static int dump_selected_tables(char *db, char **table_names, int tables)
3899
{
3900
  char table_buff[NAME_LEN*2+3];
3901
  DYNAMIC_STRING lock_tables_query;
3902
  MEM_ROOT root;
3903
  char **dump_tables, **pos, **end;
3904
  DBUG_ENTER("dump_selected_tables");
3905
3906
  if (init_dumping(db, init_dumping_tables))
3907
    DBUG_RETURN(1);
3908
3909
  init_alloc_root(&root, 8192, 0);
3910
  if (!(dump_tables= pos= (char**) alloc_root(&root, tables * sizeof(char *))))
3911
     die(EX_EOM, "alloc_root failure.");
3912
3913
  init_dynamic_string_checked(&lock_tables_query, "LOCK TABLES ", 256, 1024);
3914
  for (; tables > 0 ; tables-- , table_names++)
3915
  {
3916
    /* the table name passed on commandline may be wrong case */
3917
    if ((*pos= get_actual_table_name(*table_names, &root)))
3918
    {
3919
      /* Add found table name to lock_tables_query */
3920
      if (lock_tables)
3921
      {
3922
        dynstr_append_checked(&lock_tables_query, quote_name(*pos, table_buff, 1));
3923
        dynstr_append_checked(&lock_tables_query, " READ /*!32311 LOCAL */,");
3924
      }
3925
      pos++;
3926
    }
3927
    else
3928
    {
3929
      if (!ignore_errors)
3930
      {
3931
        dynstr_free(&lock_tables_query);
3932
        free_root(&root, MYF(0));
3933
      }
3934
      maybe_die(EX_ILLEGAL_TABLE, "Couldn't find table: \"%s\"", *table_names);
3935
      /* We shall countinue here, if --force was given */
3936
    }
3937
  }
3938
  end= pos;
3939
3940
  if (lock_tables)
3941
  {
3942
    if (mysql_real_query(mysql, lock_tables_query.str,
3943
                         lock_tables_query.length-1))
3944
    {
3945
      if (!ignore_errors)
3946
      {
3947
        dynstr_free(&lock_tables_query);
3948
        free_root(&root, MYF(0));
3949
      }
3950
      DB_error(mysql, "when doing LOCK TABLES");
3951
       /* We shall countinue here, if --force was given */
3952
    }
3953
  }
3954
  dynstr_free(&lock_tables_query);
3955
  if (flush_logs)
3956
  {
3957
    if (mysql_refresh(mysql, REFRESH_LOG))
3958
    {
3959
      if (!ignore_errors)
3960
        free_root(&root, MYF(0));
3961
      DB_error(mysql, "when doing refresh");
3962
    }
3963
     /* We shall countinue here, if --force was given */
3964
  }
3965
  if (opt_xml)
3966
    print_xml_tag(md_result_file, "", "\n", "database", "name=", db, NullS);
3967
3968
  /* Dump each selected table */
3969
  for (pos= dump_tables; pos < end; pos++)
3970
  {
3971
    DBUG_PRINT("info",("Dumping table %s", *pos));
3972
    dump_table(*pos, db);
3973
  }
3974
3975
  /* Dump each selected view */
3976
  if (seen_views)
3977
  {
3978
    for (pos= dump_tables; pos < end; pos++)
3979
      get_view_structure(*pos, db);
3980
  }
3981
  if (opt_events && !opt_xml &&
3982
      mysql_get_server_version(mysql) >= 50106)
3983
  {
3984
    DBUG_PRINT("info", ("Dumping events for database %s", db));
3985
    dump_events_for_db(db);
3986
  }
3987
  /* obtain dump of routines (procs/functions) */
3988
  if (opt_routines  && !opt_xml &&
3989
      mysql_get_server_version(mysql) >= 50009)
3990
  {
3991
    DBUG_PRINT("info", ("Dumping routines for database %s", db));
3992
    dump_routines_for_db(db);
3993
  }
3994
  free_root(&root, MYF(0));
3995
  my_free(order_by, MYF(MY_ALLOW_ZERO_PTR));
3996
  order_by= 0;
3997
  if (opt_xml)
3998
  {
3999
    fputs("</database>\n", md_result_file);
4000
    check_io(md_result_file);
4001
  }
4002
  if (lock_tables)
4003
    VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES"));
4004
  DBUG_RETURN(0);
4005
} /* dump_selected_tables */
4006
4007
4008
static int do_show_master_status(MYSQL *mysql_con)
4009
{
4010
  MYSQL_ROW row;
4011
  MYSQL_RES *master;
4012
  const char *comment_prefix=
4013
    (opt_master_data == MYSQL_OPT_MASTER_DATA_COMMENTED_SQL) ? "-- " : "";
4014
  if (mysql_query_with_error_report(mysql_con, &master, "SHOW MASTER STATUS"))
4015
  {
4016
    return 1;
4017
  }
4018
  else
4019
  {
4020
    row= mysql_fetch_row(master);
4021
    if (row && row[0] && row[1])
4022
    {
4023
      /* SHOW MASTER STATUS reports file and position */
4024
      if (opt_comments)
4025
        fprintf(md_result_file,
4026
                "\n--\n-- Position to start replication or point-in-time "
4027
                "recovery from\n--\n\n");
4028
      fprintf(md_result_file,
4029
              "%sCHANGE MASTER TO MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n",
4030
              comment_prefix, row[0], row[1]);
4031
      check_io(md_result_file);
4032
    }
4033
    else if (!ignore_errors)
4034
    {
4035
      /* SHOW MASTER STATUS reports nothing and --force is not enabled */
4036
      my_printf_error(0, "Error: Binlogging on server not active",
4037
                      MYF(0));
4038
      mysql_free_result(master);
4039
      maybe_exit(EX_MYSQLERR);
4040
      return 1;
4041
    }
4042
    mysql_free_result(master);
4043
  }
4044
  return 0;
4045
}
4046
4047
static int do_stop_slave_sql(MYSQL *mysql_con)
4048
{
4049
  MYSQL_RES *slave;
4050
  /* We need to check if the slave sql is running in the first place */
4051
  if (mysql_query_with_error_report(mysql_con, &slave, "SHOW SLAVE STATUS"))
4052
    return(1);
4053
  else
4054
  {
4055
    MYSQL_ROW row= mysql_fetch_row(slave);
4056
    if (row && row[11])
4057
    {
4058
      /* if SLAVE SQL is not running, we don't stop it */
4059
      if (!strcmp(row[11],"No"))
4060
      {
4061
        mysql_free_result(slave);
4062
        /* Silently assume that they don't have the slave running */
4063
        return(0);
4064
      }
4065
    }
4066
  }
4067
  mysql_free_result(slave);
4068
4069
  /* now, stop slave if running */
4070
  if (mysql_query_with_error_report(mysql_con, 0, "STOP SLAVE SQL_THREAD"))
4071
    return(1);
4072
4073
  return(0);
4074
}
4075
4076
static int add_stop_slave(void)
4077
{
4078
  if (opt_comments)
4079
    fprintf(md_result_file,
4080
            "\n--\n-- stop slave statement to make a recovery dump)\n--\n\n");
4081
  fprintf(md_result_file, "STOP SLAVE;\n");
4082
  return(0);
4083
}
4084
4085
static int add_slave_statements(void)
4086
{
4087
  if (opt_comments)
4088
    fprintf(md_result_file,
4089
            "\n--\n-- start slave statement to make a recovery dump)\n--\n\n");
4090
  fprintf(md_result_file, "START SLAVE;\n");
4091
  return(0);
4092
}
4093
4094
static int do_show_slave_status(MYSQL *mysql_con)
4095
{
4096
  MYSQL_RES *slave;
4097
  const char *comment_prefix=
4098
    (opt_slave_data == MYSQL_OPT_SLAVE_DATA_COMMENTED_SQL) ? "-- " : "";
4099
  if (mysql_query_with_error_report(mysql_con, &slave, "SHOW SLAVE STATUS"))
4100
  {
4101
    if (!ignore_errors)
4102
    {
4103
      /* SHOW SLAVE STATUS reports nothing and --force is not enabled */
4104
      my_printf_error(0, "Error: Slave not set up", MYF(0));
4105
    }
4106
    return 1;
4107
  }
4108
  else
4109
  {
4110
    MYSQL_ROW row= mysql_fetch_row(slave);
4111
    if (row && row[9] && row[21])
4112
    {
4113
      /* SHOW MASTER STATUS reports file and position */
4114
      if (opt_comments)
4115
        fprintf(md_result_file,
4116
                "\n--\n-- Position to start replication or point-in-time "
4117
                "recovery from (the master of this slave)\n--\n\n");
4118
4119
      fprintf(md_result_file, "%sCHANGE MASTER TO ", comment_prefix);
4120
4121
      if (opt_include_master_host_port)
4122
      {
4123
        if (row[1])
4124
          fprintf(md_result_file, "MASTER_HOST='%s', ", row[1]);
4125
        if (row[3])
4126
          fprintf(md_result_file, "MASTER_PORT='%s', ", row[3]);
4127
      }
4128
      fprintf(md_result_file,
4129
              "MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n", row[9], row[21]);
4130
4131
      check_io(md_result_file);
4132
    }
4133
    mysql_free_result(slave);
4134
  }
4135
  return 0;
4136
}
4137
4138
static int do_start_slave_sql(MYSQL *mysql_con)
4139
{
4140
  MYSQL_RES *slave;
4141
  /* We need to check if the slave sql is stopped in the first place */
4142
  if (mysql_query_with_error_report(mysql_con, &slave, "SHOW SLAVE STATUS"))
4143
    return(1);
4144
  else
4145
  {
4146
    MYSQL_ROW row= mysql_fetch_row(slave);
4147
    if (row && row[11])
4148
    {
4149
      /* if SLAVE SQL is not running, we don't start it */
4150
      if (!strcmp(row[11],"Yes"))
4151
      {
4152
        mysql_free_result(slave);
4153
        /* Silently assume that they don't have the slave running */
4154
        return(0);
4155
      }
4156
    }
4157
  }
4158
  mysql_free_result(slave);
4159
4160
  /* now, start slave if stopped */
4161
  if (mysql_query_with_error_report(mysql_con, 0, "START SLAVE"))
4162
  {
4163
    my_printf_error(0, "Error: Unable to start slave", MYF(0));
4164
    return 1;
4165
  }
4166
  return(0);
4167
}
4168
4169
4170
4171
static int do_flush_tables_read_lock(MYSQL *mysql_con)
4172
{
4173
  /*
4174
    We do first a FLUSH TABLES. If a long update is running, the FLUSH TABLES
4175
    will wait but will not stall the whole mysqld, and when the long update is
4176
    done the FLUSH TABLES WITH READ LOCK will start and succeed quickly. So,
4177
    FLUSH TABLES is to lower the probability of a stage where both mysqldump
4178
    and most client connections are stalled. Of course, if a second long
4179
    update starts between the two FLUSHes, we have that bad stall.
4180
  */
4181
  return
4182
    ( mysql_query_with_error_report(mysql_con, 0, "FLUSH TABLES") ||
4183
      mysql_query_with_error_report(mysql_con, 0,
4184
                                    "FLUSH TABLES WITH READ LOCK") );
4185
}
4186
4187
4188
static int do_unlock_tables(MYSQL *mysql_con)
4189
{
4190
  return mysql_query_with_error_report(mysql_con, 0, "UNLOCK TABLES");
4191
}
4192
4193
static int get_bin_log_name(MYSQL *mysql_con,
4194
                            char* buff_log_name, uint buff_len)
4195
{
4196
  MYSQL_RES *res;
4197
  MYSQL_ROW row;
4198
4199
  if (mysql_query(mysql_con, "SHOW MASTER STATUS") ||
4200
      !(res= mysql_store_result(mysql)))
4201
    return 1;
4202
4203
  if (!(row= mysql_fetch_row(res)))
4204
  {
4205
    mysql_free_result(res);
4206
    return 1;
4207
  }
4208
  /*
4209
    Only one row is returned, and the first column is the name of the
4210
    active log.
4211
  */
4212
  strmake(buff_log_name, row[0], buff_len - 1);
4213
4214
  mysql_free_result(res);
4215
  return 0;
4216
}
4217
4218
static int purge_bin_logs_to(MYSQL *mysql_con, char* log_name)
4219
{
4220
  DYNAMIC_STRING str;
4221
  int err;
4222
  init_dynamic_string_checked(&str, "PURGE BINARY LOGS TO '", 1024, 1024);
4223
  dynstr_append_checked(&str, log_name);
4224
  dynstr_append_checked(&str, "'");
4225
  err = mysql_query_with_error_report(mysql_con, 0, str.str);
4226
  dynstr_free(&str);
4227
  return err;
4228
}
4229
4230
4231
static int start_transaction(MYSQL *mysql_con)
4232
{
4233
  /*
4234
    We use BEGIN for old servers. --single-transaction --master-data will fail
4235
    on old servers, but that's ok as it was already silently broken (it didn't
4236
    do a consistent read, so better tell people frankly, with the error).
4237
4238
    We want the first consistent read to be used for all tables to dump so we
4239
    need the REPEATABLE READ level (not anything lower, for example READ
4240
    COMMITTED would give one new consistent read per dumped table).
4241
  */
4242
  if ((mysql_get_server_version(mysql_con) < 40100) && opt_master_data)
4243
  {
4244
    fprintf(stderr, "-- %s: the combination of --single-transaction and "
4245
            "--master-data requires a MySQL server version of at least 4.1 "
4246
            "(current server's version is %s). %s\n",
4247
            ignore_errors ? "Warning" : "Error",
4248
            mysql_con->server_version ? mysql_con->server_version : "unknown",
4249
            ignore_errors ? "Continuing due to --force, backup may not be consistent across all tables!" : "Aborting.");
4250
    if (!ignore_errors)
4251
      exit(EX_MYSQLERR);
4252
  }
4253
4254
  return (mysql_query_with_error_report(mysql_con, 0,
4255
                                        "SET SESSION TRANSACTION ISOLATION "
4256
                                        "LEVEL REPEATABLE READ") ||
4257
          mysql_query_with_error_report(mysql_con, 0,
4258
                                        "START TRANSACTION "
4259
                                        "/*!40100 WITH CONSISTENT SNAPSHOT */"));
4260
}
4261
4262
4263
static ulong find_set(TYPELIB *lib, const char *x, uint length,
4264
                      char **err_pos, uint *err_len)
4265
{
4266
  const char *end= x + length;
4267
  ulong found= 0;
4268
  uint find;
4269
  char buff[255];
4270
4271
  *err_pos= 0;                  /* No error yet */
4272
  while (end > x && my_isspace(charset_info, end[-1]))
4273
    end--;
4274
4275
  *err_len= 0;
4276
  if (x != end)
4277
  {
4278
    const char *start= x;
4279
    for (;;)
4280
    {
4281
      const char *pos= start;
4282
      uint var_len;
4283
4284
      for (; pos != end && *pos != ','; pos++) ;
4285
      var_len= (uint) (pos - start);
4286
      strmake(buff, start, min(sizeof(buff), var_len));
4287
      find= find_type(buff, lib, var_len);
4288
      if (!find)
4289
      {
4290
        *err_pos= (char*) start;
4291
        *err_len= var_len;
4292
      }
4293
      else
4294
        found|= ((longlong) 1 << (find - 1));
4295
      if (pos == end)
4296
        break;
4297
      start= pos + 1;
4298
    }
4299
  }
4300
  return found;
4301
}
4302
4303
4304
/* Print a value with a prefix on file */
4305
static void print_value(FILE *file, MYSQL_RES  *result, MYSQL_ROW row,
4306
                        const char *prefix, const char *name,
4307
                        int string_value)
4308
{
4309
  MYSQL_FIELD   *field;
4310
  mysql_field_seek(result, 0);
4311
4312
  for ( ; (field= mysql_fetch_field(result)) ; row++)
4313
  {
4314
    if (!strcmp(field->name,name))
4315
    {
4316
      if (row[0] && row[0][0] && strcmp(row[0],"0")) /* Skip default */
4317
      {
4318
        fputc(' ',file);
4319
        fputs(prefix, file);
4320
        if (string_value)
4321
          unescape(file,row[0],(uint) strlen(row[0]));
4322
        else
4323
          fputs(row[0], file);
4324
        check_io(file);
4325
        return;
4326
      }
4327
    }
4328
  }
4329
  return;                                       /* This shouldn't happen */
4330
} /* print_value */
4331
4332
4333
/*
4334
  SYNOPSIS
4335
4336
  Check if we the table is one of the table types that should be ignored:
4337
  MRG_ISAM, MRG_MYISAM, if opt_delayed, if that table supports delayed inserts.
4338
  If the table should be altogether ignored, it returns a TRUE, FALSE if it
4339
  should not be ignored. If the user has selected to use INSERT DELAYED, it
4340
  sets the value of the bool pointer supports_delayed_inserts to 0 if not
4341
  supported, 1 if it is supported.
4342
4343
  ARGS
4344
4345
    check_if_ignore_table()
4346
    table_name                  Table name to check
4347
    table_type                  Type of table
4348
4349
  GLOBAL VARIABLES
4350
    mysql                       MySQL connection
4351
    verbose                     Write warning messages
4352
4353
  RETURN
4354
    char (bit value)            See IGNORE_ values at top
4355
*/
4356
4357
char check_if_ignore_table(const char *table_name, char *table_type)
4358
{
4359
  char result= IGNORE_NONE;
4360
  char buff[FN_REFLEN+80], show_name_buff[FN_REFLEN];
4361
  MYSQL_RES *res= NULL;
4362
  MYSQL_ROW row;
4363
  DBUG_ENTER("check_if_ignore_table");
4364
4365
  /* Check memory for quote_for_like() */
4366
  DBUG_ASSERT(2*sizeof(table_name) < sizeof(show_name_buff));
4367
  my_snprintf(buff, sizeof(buff), "show table status like %s",
4368
              quote_for_like(table_name, show_name_buff));
4369
  if (mysql_query_with_error_report(mysql, &res, buff))
4370
  {
4371
    if (mysql_errno(mysql) != ER_PARSE_ERROR)
4372
    {                                   /* If old MySQL version */
4373
      verbose_msg("-- Warning: Couldn't get status information for "
4374
                  "table %s (%s)\n", table_name, mysql_error(mysql));
4375
      DBUG_RETURN(result);                       /* assume table is ok */
4376
    }
4377
  }
4378
  if (!(row= mysql_fetch_row(res)))
4379
  {
4380
    fprintf(stderr,
4381
            "Error: Couldn't read status information for table %s (%s)\n",
4382
            table_name, mysql_error(mysql));
4383
    mysql_free_result(res);
4384
    DBUG_RETURN(result);                         /* assume table is ok */
4385
  }
4386
  if (!(row[1]))
4387
    strmake(table_type, "VIEW", NAME_LEN-1);
4388
  else
4389
  {
4390
    /*
4391
      If the table type matches any of these, we do support delayed inserts.
4392
      Note: we do not want to skip dumping this table if if is not one of
4393
      these types, but we do want to use delayed inserts in the dump if
4394
      the table type is _NOT_ one of these types
4395
    */
4396
    strmake(table_type, row[1], NAME_LEN-1);
4397
    if (opt_delayed)
4398
    {
4399
      if (strcmp(table_type,"MyISAM") &&
4400
          strcmp(table_type,"ISAM") &&
4401
          strcmp(table_type,"ARCHIVE") &&
4402
          strcmp(table_type,"HEAP") &&
4403
          strcmp(table_type,"MEMORY"))
4404
        result= IGNORE_INSERT_DELAYED;
4405
    }
4406
4407
    /*
4408
      If these two types, we do want to skip dumping the table
4409
    */
4410
    if (!opt_no_data &&
4411
        (!my_strcasecmp(&my_charset_latin1, table_type, "MRG_MyISAM") ||
4412
         !strcmp(table_type,"MRG_ISAM")))
4413
      result= IGNORE_DATA;
4414
  }
4415
  mysql_free_result(res);
4416
  DBUG_RETURN(result);
4417
}
4418
4419
4420
/*
4421
  Get string of comma-separated primary key field names
4422
4423
  SYNOPSIS
4424
    char *primary_key_fields(const char *table_name)
4425
    RETURNS     pointer to allocated buffer (must be freed by caller)
4426
    table_name  quoted table name
4427
4428
  DESCRIPTION
4429
    Use SHOW KEYS FROM table_name, allocate a buffer to hold the
4430
    field names, and then build that string and return the pointer
4431
    to that buffer.
4432
4433
    Returns NULL if there is no PRIMARY or UNIQUE key on the table,
4434
    or if there is some failure.  It is better to continue to dump
4435
    the table unsorted, rather than exit without dumping the data.
4436
*/
4437
4438
static char *primary_key_fields(const char *table_name)
4439
{
4440
  MYSQL_RES  *res= NULL;
4441
  MYSQL_ROW  row;
4442
  /* SHOW KEYS FROM + table name * 2 (escaped) + 2 quotes + \0 */
4443
  char show_keys_buff[15 + NAME_LEN * 2 + 3];
4444
  uint result_length= 0;
4445
  char *result= 0;
4446
  char buff[NAME_LEN * 2 + 3];
4447
  char *quoted_field;
4448
4449
  my_snprintf(show_keys_buff, sizeof(show_keys_buff),
4450
              "SHOW KEYS FROM %s", table_name);
4451
  if (mysql_query(mysql, show_keys_buff) ||
4452
      !(res= mysql_store_result(mysql)))
4453
  {
4454
    fprintf(stderr, "Warning: Couldn't read keys from table %s;"
4455
            " records are NOT sorted (%s)\n",
4456
            table_name, mysql_error(mysql));
4457
    /* Don't exit, because it's better to print out unsorted records */
4458
    goto cleanup;
4459
  }
4460
4461
  /*
4462
   * Figure out the length of the ORDER BY clause result.
4463
   * Note that SHOW KEYS is ordered:  a PRIMARY key is always the first
4464
   * row, and UNIQUE keys come before others.  So we only need to check
4465
   * the first key, not all keys.
4466
   */
4467
  if ((row= mysql_fetch_row(res)) && atoi(row[1]) == 0)
4468
  {
4469
    /* Key is unique */
4470
    do
4471
    {
4472
      quoted_field= quote_name(row[4], buff, 0);
4473
      result_length+= strlen(quoted_field) + 1; /* + 1 for ',' or \0 */
4474
    } while ((row= mysql_fetch_row(res)) && atoi(row[3]) > 1);
4475
  }
4476
4477
  /* Build the ORDER BY clause result */
4478
  if (result_length)
4479
  {
4480
    char *end;
4481
    /* result (terminating \0 is already in result_length) */
4482
    result= my_malloc(result_length + 10, MYF(MY_WME));
4483
    if (!result)
4484
    {
4485
      fprintf(stderr, "Error: Not enough memory to store ORDER BY clause\n");
4486
      goto cleanup;
4487
    }
4488
    mysql_data_seek(res, 0);
4489
    row= mysql_fetch_row(res);
4490
    quoted_field= quote_name(row[4], buff, 0);
4491
    end= strmov(result, quoted_field);
4492
    while ((row= mysql_fetch_row(res)) && atoi(row[3]) > 1)
4493
    {
4494
      quoted_field= quote_name(row[4], buff, 0);
4495
      end= strxmov(end, ",", quoted_field, NullS);
4496
    }
4497
  }
4498
4499
cleanup:
4500
  if (res)
4501
    mysql_free_result(res);
4502
4503
  return result;
4504
}
4505
4506
4507
/*
4508
  Replace a substring
4509
4510
  SYNOPSIS
4511
    replace
4512
    ds_str      The string to search and perform the replace in
4513
    search_str  The string to search for
4514
    search_len  Length of the string to search for
4515
    replace_str The string to replace with
4516
    replace_len Length of the string to replace with
4517
4518
  RETURN
4519
    0 String replaced
4520
    1 Could not find search_str in str
4521
*/
4522
4523
static int replace(DYNAMIC_STRING *ds_str,
4524
                   const char *search_str, ulong search_len,
4525
                   const char *replace_str, ulong replace_len)
4526
{
4527
  DYNAMIC_STRING ds_tmp;
4528
  const char *start= strstr(ds_str->str, search_str);
4529
  if (!start)
4530
    return 1;
4531
  init_dynamic_string_checked(&ds_tmp, "",
4532
                      ds_str->length + replace_len, 256);
4533
  dynstr_append_mem_checked(&ds_tmp, ds_str->str, start - ds_str->str);
4534
  dynstr_append_mem_checked(&ds_tmp, replace_str, replace_len);
4535
  dynstr_append_checked(&ds_tmp, start + search_len);
4536
  dynstr_set_checked(ds_str, ds_tmp.str);
4537
  dynstr_free(&ds_tmp);
4538
  return 0;
4539
}
4540
4541
4542
/*
4543
  Getting VIEW structure
4544
4545
  SYNOPSIS
4546
    get_view_structure()
4547
    table   view name
4548
    db      db name
4549
4550
  RETURN
4551
    0 OK
4552
    1 ERROR
4553
*/
4554
4555
static my_bool get_view_structure(char *table, char* db)
4556
{
4557
  MYSQL_RES  *table_res;
4558
  MYSQL_ROW  row;
4559
  MYSQL_FIELD *field;
4560
  char       *result_table, *opt_quoted_table;
4561
  char       table_buff[NAME_LEN*2+3];
4562
  char       table_buff2[NAME_LEN*2+3];
4563
  char       query[QUERY_LENGTH];
4564
  FILE       *sql_file= md_result_file;
4565
  DBUG_ENTER("get_view_structure");
4566
4567
  if (opt_no_create_info) /* Don't write table creation info */
4568
    DBUG_RETURN(0);
4569
4570
  verbose_msg("-- Retrieving view structure for table %s...\n", table);
4571
4572
#ifdef NOT_REALLY_USED_YET
4573
  sprintf(insert_pat,"SET OPTION SQL_QUOTE_SHOW_CREATE=%d",
4574
          (opt_quoted || opt_keywords));
4575
#endif
4576
4577
  result_table=     quote_name(table, table_buff, 1);
4578
  opt_quoted_table= quote_name(table, table_buff2, 0);
4579
4580
  if (switch_character_set_results(mysql, "binary"))
4581
    DBUG_RETURN(1);
4582
4583
  my_snprintf(query, sizeof(query), "SHOW CREATE TABLE %s", result_table);
4584
4585
  if (mysql_query_with_error_report(mysql, &table_res, query))
4586
  {
4587
    switch_character_set_results(mysql, default_charset);
4588
    DBUG_RETURN(0);
4589
  }
4590
4591
  /* Check if this is a view */
4592
  field= mysql_fetch_field_direct(table_res, 0);
4593
  if (strcmp(field->name, "View") != 0)
4594
  {
4595
    switch_character_set_results(mysql, default_charset);
4596
    verbose_msg("-- It's base table, skipped\n");
4597
    DBUG_RETURN(0);
4598
  }
4599
4600
  /* If requested, open separate .sql file for this view */
4601
  if (path)
4602
  {
4603
    if (!(sql_file= open_sql_file_for_table(table)))
4604
      DBUG_RETURN(1);
4605
4606
    write_header(sql_file, db);
4607
  }
4608
4609
  if (!opt_xml && opt_comments)
4610
  {
4611
    fprintf(sql_file, "\n--\n-- Final view structure for view %s\n--\n\n",
4612
            result_table);
4613
    check_io(sql_file);
4614
  }
4615
  fprintf(sql_file, "/*!50001 DROP TABLE %s*/;\n", opt_quoted_table);
4616
  if (opt_drop)
4617
  {
4618
    fprintf(sql_file, "/*!50001 DROP VIEW IF EXISTS %s*/;\n",
4619
            opt_quoted_table);
4620
    check_io(sql_file);
4621
  }
4622
4623
4624
  my_snprintf(query, sizeof(query),
4625
              "SELECT CHECK_OPTION, DEFINER, SECURITY_TYPE, "
4626
              "       CHARACTER_SET_CLIENT, COLLATION_CONNECTION "
4627
              "FROM information_schema.views "
4628
              "WHERE table_name=\"%s\" AND table_schema=\"%s\"", table, db);
4629
4630
  if (mysql_query(mysql, query))
4631
  {
4632
    /*
4633
      Use the raw output from SHOW CREATE TABLE if
4634
       information_schema query fails.
4635
     */
4636
    row= mysql_fetch_row(table_res);
4637
    fprintf(sql_file, "/*!50001 %s */;\n", row[1]);
4638
    check_io(sql_file);
4639
    mysql_free_result(table_res);
4640
  }
4641
  else
4642
  {
4643
    char *ptr;
4644
    ulong *lengths;
4645
    char search_buf[256], replace_buf[256];
4646
    ulong search_len, replace_len;
4647
    DYNAMIC_STRING ds_view;
4648
4649
    /* Save the result of SHOW CREATE TABLE in ds_view */
4650
    row= mysql_fetch_row(table_res);
4651
    lengths= mysql_fetch_lengths(table_res);
4652
    init_dynamic_string_checked(&ds_view, row[1], lengths[1] + 1, 1024);
4653
    mysql_free_result(table_res);
4654
4655
    /* Get the result from "select ... information_schema" */
4656
    if (!(table_res= mysql_store_result(mysql)) ||
4657
        !(row= mysql_fetch_row(table_res)))
4658
    {
4659
      if (table_res)
4660
        mysql_free_result(table_res);
4661
      dynstr_free(&ds_view);
4662
      DB_error(mysql, "when trying to save the result of SHOW CREATE TABLE in ds_view.");
4663
      DBUG_RETURN(1);
4664
    }
4665
4666
    lengths= mysql_fetch_lengths(table_res);
4667
4668
    /*
4669
      "WITH %s CHECK OPTION" is available from 5.0.2
4670
      Surround it with !50002 comments
4671
    */
4672
    if (strcmp(row[0], "NONE"))
4673
    {
4674
4675
      ptr= search_buf;
4676
      search_len= (ulong)(strxmov(ptr, "WITH ", row[0],
4677
                                  " CHECK OPTION", NullS) - ptr);
4678
      ptr= replace_buf;
4679
      replace_len=(ulong)(strxmov(ptr, "*/\n/*!50002 WITH ", row[0],
4680
                                  " CHECK OPTION", NullS) - ptr);
4681
      replace(&ds_view, search_buf, search_len, replace_buf, replace_len);
4682
    }
4683
4684
    /*
4685
      "DEFINER=%s SQL SECURITY %s" is available from 5.0.13
4686
      Surround it with !50013 comments
4687
    */
4688
    {
4689
      size_t     user_name_len;
4690
      char       user_name_str[USERNAME_LENGTH + 1];
4691
      char       quoted_user_name_str[USERNAME_LENGTH * 2 + 3];
4692
      size_t     host_name_len;
4693
      char       host_name_str[HOSTNAME_LENGTH + 1];
4694
      char       quoted_host_name_str[HOSTNAME_LENGTH * 2 + 3];
4695
4696
      parse_user(row[1], lengths[1], user_name_str, &user_name_len,
4697
                 host_name_str, &host_name_len);
4698
4699
      ptr= search_buf;
4700
      search_len=
4701
        (ulong)(strxmov(ptr, "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], NullS) - ptr);
4706
      ptr= replace_buf;
4707
      replace_len=
4708
        (ulong)(strxmov(ptr, "*/\n/*!50013 DEFINER=",
4709
                        quote_name(user_name_str, quoted_user_name_str, FALSE),
4710
                        "@",
4711
                        quote_name(host_name_str, quoted_host_name_str, FALSE),
4712
                        " SQL SECURITY ", row[2],
4713
                        " */\n/*!50001", NullS) - ptr);
4714
      replace(&ds_view, search_buf, search_len, replace_buf, replace_len);
4715
    }
4716
4717
    /* Dump view structure to file */
4718
4719
    fprintf(sql_file,
4720
            "/*!50001 SET @saved_cs_client          = @@character_set_client */;\n"
4721
            "/*!50001 SET @saved_cs_results         = @@character_set_results */;\n"
4722
            "/*!50001 SET @saved_col_connection     = @@collation_connection */;\n"
4723
            "/*!50001 SET character_set_client      = %s */;\n"
4724
            "/*!50001 SET character_set_results     = %s */;\n"
4725
            "/*!50001 SET collation_connection      = %s */;\n"
4726
            "/*!50001 %s */;\n"
4727
            "/*!50001 SET character_set_client      = @saved_cs_client */;\n"
4728
            "/*!50001 SET character_set_results     = @saved_cs_results */;\n"
4729
            "/*!50001 SET collation_connection      = @saved_col_connection */;\n",
4730
            (const char *) row[3],
4731
            (const char *) row[3],
4732
            (const char *) row[4],
4733
            (const char *) ds_view.str);
4734
4735
    check_io(sql_file);
4736
    mysql_free_result(table_res);
4737
    dynstr_free(&ds_view);
4738
  }
4739
4740
  if (switch_character_set_results(mysql, default_charset))
4741
    DBUG_RETURN(1);
4742
4743
  /* If a separate .sql file was opened, close it now */
4744
  if (sql_file != md_result_file)
4745
  {
4746
    fputs("\n", sql_file);
4747
    write_footer(sql_file);
4748
    my_fclose(sql_file, MYF(MY_WME));
4749
  }
4750
  DBUG_RETURN(0);
4751
}
4752
4753
/*
4754
  The following functions are wrappers for the dynamic string functions
4755
  and if they fail, the wrappers will terminate the current process.
4756
*/
4757
4758
#define DYNAMIC_STR_ERROR_MSG "Couldn't perform DYNAMIC_STRING operation"
4759
4760
static void init_dynamic_string_checked(DYNAMIC_STRING *str, const char *init_str,
4761
			    uint init_alloc, uint alloc_increment)
4762
{
4763
  if (init_dynamic_string(str, init_str, init_alloc, alloc_increment))
4764
    die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG);
4765
}
4766
4767
static void dynstr_append_checked(DYNAMIC_STRING* dest, const char* src)
4768
{
4769
  if (dynstr_append(dest, src))
4770
    die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG);
4771
}
4772
4773
static void dynstr_set_checked(DYNAMIC_STRING *str, const char *init_str)
4774
{
4775
  if (dynstr_set(str, init_str))
4776
    die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG);
4777
}
4778
4779
static void dynstr_append_mem_checked(DYNAMIC_STRING *str, const char *append,
4780
			  uint length)
4781
{
4782
  if (dynstr_append_mem(str, append, length))
4783
    die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG);
4784
}
4785
4786
static void dynstr_realloc_checked(DYNAMIC_STRING *str, ulong additional_size)
4787
{
4788
  if (dynstr_realloc(str, additional_size))
4789
    die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG);
4790
}
4791
4792
4793
int main(int argc, char **argv)
4794
{
4795
  char bin_log_name[FN_REFLEN];
4796
  int exit_code;
4797
  MY_INIT("mysqldump");
4798
4799
  compatible_mode_normal_str[0]= 0;
4800
  default_charset= (char *)mysql_universal_client_charset;
4801
  bzero((char*) &ignore_table, sizeof(ignore_table));
4802
4803
  exit_code= get_options(&argc, &argv);
4804
  if (exit_code)
4805
  {
4806
    free_resources(0);
4807
    exit(exit_code);
4808
  }
4809
4810
  if (log_error_file)
4811
  {
4812
    if(!(stderror_file= freopen(log_error_file, "a+", stderr)))
4813
    {
4814
      free_resources(0);
4815
      exit(EX_MYSQLERR);
4816
    }
4817
  }
4818
4819
  if (connect_to_db(current_host, current_user, opt_password))
4820
  {
4821
    free_resources(0);
4822
    exit(EX_MYSQLERR);
4823
  }
4824
  if (!path)
4825
    write_header(md_result_file, *argv);
4826
4827
  if (opt_slave_data && do_stop_slave_sql(mysql))
4828
    goto err;
4829
4830
  if ((opt_lock_all_tables || opt_master_data) &&
4831
      do_flush_tables_read_lock(mysql))
4832
    goto err;
4833
  if (opt_single_transaction && start_transaction(mysql))
4834
      goto err;
4835
  if (opt_delete_master_logs)
4836
  {
4837
    if (mysql_refresh(mysql, REFRESH_LOG) ||
4838
        get_bin_log_name(mysql, bin_log_name, sizeof(bin_log_name)))
4839
      goto err;
4840
    flush_logs= 0;
4841
  }
4842
  if (opt_lock_all_tables || opt_master_data)
4843
  {
4844
    if (flush_logs && mysql_refresh(mysql, REFRESH_LOG))
4845
      goto err;
4846
    flush_logs= 0; /* not anymore; that would not be sensible */
4847
  }
4848
  /* Add 'STOP SLAVE to beginning of dump */
4849
  if (opt_slave_apply && add_stop_slave())
4850
    goto err;
4851
  if (opt_master_data && do_show_master_status(mysql))
4852
    goto err;
4853
  if (opt_slave_data && do_show_slave_status(mysql))
4854
    goto err;
4855
  if (opt_single_transaction && do_unlock_tables(mysql)) /* unlock but no commit! */
4856
    goto err;
4857
4858
  if (opt_alltspcs)
4859
    dump_all_tablespaces();
4860
4861
  if (opt_alldbs)
4862
  {
4863
    if (!opt_alltspcs && !opt_notspcs)
4864
      dump_all_tablespaces();
4865
    dump_all_databases();
4866
  }
4867
  else if (argc > 1 && !opt_databases)
4868
  {
4869
    /* Only one database and selected table(s) */
4870
    if (!opt_alltspcs && !opt_notspcs)
4871
      dump_tablespaces_for_tables(*argv, (argv + 1), (argc -1));
4872
    dump_selected_tables(*argv, (argv + 1), (argc - 1));
4873
  }
4874
  else
4875
  {
4876
    /* One or more databases, all tables */
4877
    if (!opt_alltspcs && !opt_notspcs)
4878
      dump_tablespaces_for_databases(argv);
4879
    dump_databases(argv);
4880
  }
4881
4882
  /* if --dump-slave , start the slave sql thread */
4883
  if (opt_slave_data && do_start_slave_sql(mysql))
4884
    goto err;
4885
4886
  /* add 'START SLAVE' to end of dump */
4887
  if (opt_slave_apply && add_slave_statements())
4888
    goto err;
4889
4890
  /* ensure dumped data flushed */
4891
  if (md_result_file && fflush(md_result_file))
4892
  {
4893
    if (!first_error)
4894
      first_error= EX_MYSQLERR;
4895
    goto err;
4896
  }
4897
  /* everything successful, purge the old logs files */
4898
  if (opt_delete_master_logs && purge_bin_logs_to(mysql, bin_log_name))
4899
    goto err;
4900
4901
#ifdef HAVE_SMEM
4902
  my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR));
4903
#endif
4904
  /*
4905
    No reason to explicitely COMMIT the transaction, neither to explicitely
4906
    UNLOCK TABLES: these will be automatically be done by the server when we
4907
    disconnect now. Saves some code here, some network trips, adds nothing to
4908
    server.
4909
  */
4910
err:
4911
  dbDisconnect(current_host);
4912
  if (!path)
4913
    write_footer(md_result_file);
4914
  free_resources();
4915
4916
  if (stderror_file)
4917
    fclose(stderror_file);
4918
4919
  return(first_error);
4920
} /* main */