~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to client/drizzledump.c

  • Committer: Jay Pipes
  • Date: 2008-07-17 18:48:58 UTC
  • mto: This revision was merged to the branch mainline in revision 182.
  • Revision ID: jay@mysql.com-20080717184858-2mbouxl8xi41gcge
Removed DBUG from CSV and Blackhole storage engines

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright 2000-2008 MySQL AB, 2008, 2009 Sun Microsystems, Inc.
2
 
 * Copyright (C) 2010 Vijay Samuel
3
 
 * Copyright (C) 2010 Andrew Hutchings
4
 
 
5
 
  This program is free software; you can redistribute it and/or modify
6
 
  it under the terms of the GNU General Public License as published by
7
 
  the Free Software Foundation; version 2 of the License.
8
 
 
9
 
  This program is distributed in the hope that it will be useful,
10
 
  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 
  GNU General Public License for more details.
13
 
 
14
 
  You should have received a copy of the GNU General Public License
15
 
  along with this program; if not, write to the Free Software
16
 
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
17
 
 
18
 
/* drizzledump.cc  - Dump a tables contents and format to an ASCII file
19
 
 
20
 
 * Derived from mysqldump, which originally came from:
21
 
 **
22
 
 ** The author's original notes follow :-
23
 
 **
24
 
 ** AUTHOR: Igor Romanenko (igor@frog.kiev.ua)
25
 
 ** DATE:   December 3, 1994
26
 
 ** WARRANTY: None, expressed, impressed, implied
27
 
 **          or other
28
 
 ** STATUS: Public domain
29
 
 
30
 
 * and more work by Monty, Jani & Sinisa
31
 
 * and all the MySQL developers over the years.
 
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
32
37
*/
33
38
 
 
39
#define DUMP_VERSION "10.13"
 
40
 
 
41
#include <my_global.h>
 
42
#include <my_sys.h>
 
43
#include <m_string.h>
 
44
#include <m_ctype.h>
 
45
#include <hash.h>
 
46
#include <stdarg.h>
 
47
 
34
48
#include "client_priv.h"
35
 
#include <string>
36
 
#include <iostream>
37
 
#include <stdarg.h>
38
 
#include <boost/unordered_set.hpp>
39
 
#include <algorithm>
40
 
#include <fstream>
41
 
#include <drizzled/gettext.h>
42
 
#include <drizzled/configmake.h>
43
 
#include <drizzled/error.h>
44
 
#include <boost/program_options.hpp>
45
 
#include <boost/regex.hpp>
46
 
#include <boost/date_time/posix_time/posix_time.hpp>
47
 
#include "drizzledump_data.h"
48
 
#include "drizzledump_mysql.h"
49
 
#include "drizzledump_drizzle.h"
50
 
 
51
 
using namespace std;
52
 
using namespace drizzled;
53
 
namespace po= boost::program_options;
 
49
#include "drizzle_version.h"
 
50
#include "mysqld_error.h"
54
51
 
55
52
/* Exit codes */
56
53
 
57
54
#define EX_USAGE 1
58
 
#define EX_DRIZZLEERR 2
 
55
#define EX_MYSQLERR 2
 
56
#define EX_CONSCHECK 3
 
57
#define EX_EOM 4
59
58
#define EX_EOF 5 /* ferror for output file was got */
60
 
 
61
 
bool  verbose= false;
62
 
static bool use_drizzle_protocol= false;
63
 
bool ignore_errors= false;
64
 
static bool flush_logs= false;
65
 
static bool create_options= true; 
66
 
static bool opt_quoted= false;
67
 
bool opt_databases= false; 
68
 
bool opt_alldbs= false; 
69
 
static bool opt_lock_all_tables= false;
70
 
static bool opt_dump_date= true;
71
 
bool opt_autocommit= false; 
72
 
static bool opt_single_transaction= false; 
73
 
static bool opt_comments;
74
 
static bool opt_compact;
75
 
bool opt_ignore= false;
76
 
bool opt_drop_database;
77
 
bool opt_no_create_info;
78
 
bool opt_no_data= false;
79
 
bool opt_create_db= false;
80
 
bool opt_disable_keys= true;
81
 
bool extended_insert= true;
82
 
bool opt_replace_into= false;
83
 
bool opt_drop= true; 
84
 
bool opt_data_is_mangled= false;
85
 
uint32_t show_progress_size= 0;
86
 
static string insert_pat;
87
 
static uint32_t opt_drizzle_port= 0;
88
 
static int first_error= 0;
89
 
static string extended_row;
 
59
#define EX_ILLEGAL_TABLE 6
 
60
 
 
61
/* index into 'show fields from table' */
 
62
 
 
63
#define SHOW_FIELDNAME  0
 
64
#define SHOW_TYPE  1
 
65
#define SHOW_NULL  2
 
66
#define SHOW_DEFAULT  4
 
67
#define SHOW_EXTRA  5
 
68
 
 
69
/* Size of buffer for dump's select query */
 
70
#define QUERY_LENGTH 1536
 
71
 
 
72
/* ignore table flags */
 
73
#define IGNORE_NONE 0x00 /* no ignore */
 
74
#define IGNORE_DATA 0x01 /* don't dump data for this table */
 
75
#define IGNORE_INSERT_DELAYED 0x02 /* table doesn't support INSERT DELAYED */
 
76
 
 
77
static void add_load_option(DYNAMIC_STRING *str, const char *option,
 
78
                             const char *option_value);
 
79
static ulong find_set(TYPELIB *lib, const char *x, uint length,
 
80
                      char **err_pos, uint *err_len);
 
81
 
 
82
static void field_escape(DYNAMIC_STRING* in, const char *from);
 
83
static bool  verbose= 0, opt_no_create_info= 0, opt_no_data= 0,
 
84
                quick= 1, extended_insert= 1,
 
85
                lock_tables=1,ignore_errors=0,flush_logs=0,flush_privileges=0,
 
86
                opt_drop=1,opt_keywords=0,opt_lock=1,opt_compress=0,
 
87
                opt_delayed=0,create_options=1,opt_quoted=0,opt_databases=0,
 
88
                opt_alldbs=0,opt_create_db=0,opt_lock_all_tables=0,
 
89
                opt_set_charset=0, opt_dump_date=1,
 
90
                opt_autocommit=0,opt_disable_keys=1,opt_xml=0,
 
91
                opt_delete_master_logs=0, tty_password=0,
 
92
                opt_single_transaction=0, opt_comments= 0, opt_compact= 0,
 
93
                opt_hex_blob=0, opt_order_by_primary=0, opt_ignore=0,
 
94
                opt_complete_insert= 0, opt_drop_database= 0,
 
95
                opt_replace_into= 0,
 
96
                opt_routines=0, opt_tz_utc=1,
 
97
                opt_slave_apply= 0, 
 
98
                opt_include_master_host_port= 0,
 
99
                opt_events= 0,
 
100
                opt_alltspcs=0, opt_notspcs= 0;
 
101
static bool insert_pat_inited= 0, debug_info_flag= 0, debug_check_flag= 0;
 
102
static ulong opt_max_allowed_packet, opt_net_buffer_length;
 
103
static MYSQL mysql_connection,*mysql=0;
 
104
static DYNAMIC_STRING insert_pat;
 
105
static char  *opt_password=0,*current_user=0,
 
106
             *current_host=0,*path=0,*fields_terminated=0,
 
107
             *lines_terminated=0, *enclosed=0, *opt_enclosed=0, *escaped=0,
 
108
             *where=0, *order_by=0,
 
109
             *opt_compatible_mode_str= 0,
 
110
             *err_ptr= 0,
 
111
             *log_error_file= NULL;
 
112
static char **defaults_argv= 0;
 
113
static char compatible_mode_normal_str[255];
 
114
/* Server supports character_set_results session variable? */
 
115
static bool server_supports_switching_charsets= true;
 
116
static ulong opt_compatible_mode= 0;
 
117
#define MYSQL_OPT_MASTER_DATA_EFFECTIVE_SQL 1
 
118
#define MYSQL_OPT_MASTER_DATA_COMMENTED_SQL 2
 
119
#define MYSQL_OPT_SLAVE_DATA_EFFECTIVE_SQL 1
 
120
#define MYSQL_OPT_SLAVE_DATA_COMMENTED_SQL 2
 
121
static uint opt_mysql_port= 0, opt_master_data;
 
122
static uint opt_slave_data;
 
123
static uint my_end_arg;
 
124
static int   first_error=0;
 
125
static DYNAMIC_STRING extended_row;
90
126
FILE *md_result_file= 0;
91
 
FILE *stderror_file= 0;
92
 
std::vector<DrizzleDumpDatabase*> database_store;
93
 
DrizzleDumpConnection* db_connection;
94
 
DrizzleDumpConnection* destination_connection;
95
 
 
96
 
enum destinations {
97
 
  DESTINATION_DB,
98
 
  DESTINATION_FILES,
99
 
  DESTINATION_STDOUT
100
 
};
101
 
 
102
 
int opt_destination= DESTINATION_STDOUT;
103
 
std::string opt_destination_host;
104
 
uint16_t opt_destination_port;
105
 
std::string opt_destination_user;
106
 
std::string opt_destination_password;
107
 
std::string opt_destination_database;
108
 
 
109
 
const string progname= "drizzledump";
110
 
 
111
 
string password,
112
 
  enclosed,
113
 
  escaped,
114
 
  current_host,
115
 
  path,
116
 
  current_user,
117
 
  opt_password,
118
 
  opt_protocol,
119
 
  where;
120
 
 
121
 
boost::unordered_set<string> ignore_table;
122
 
 
123
 
void maybe_exit(int error);
 
127
FILE *stderror_file=0;
 
128
 
 
129
static uint opt_protocol= MYSQL_PROTOCOL_TCP;
 
130
 
 
131
/*
 
132
Dynamic_string wrapper functions. In this file use these
 
133
wrappers, they will terminate the process if there is
 
134
an allocation failure.
 
135
*/
 
136
static void init_dynamic_string_checked(DYNAMIC_STRING *str, const char *init_str,
 
137
                            uint init_alloc, uint alloc_increment);
 
138
static void dynstr_append_checked(DYNAMIC_STRING* dest, const char* src);
 
139
static void dynstr_set_checked(DYNAMIC_STRING *str, const char *init_str);
 
140
static void dynstr_append_mem_checked(DYNAMIC_STRING *str, const char *append,
 
141
                          uint length);
 
142
static void dynstr_realloc_checked(DYNAMIC_STRING *str, ulong additional_size);
 
143
/*
 
144
  Constant for detection of default value of default_charset.
 
145
  If default_charset is equal to mysql_universal_client_charset, then
 
146
  it is the default value which assigned at the very beginning of main().
 
147
*/
 
148
static const char *mysql_universal_client_charset=
 
149
  MYSQL_UNIVERSAL_CLIENT_CHARSET;
 
150
static char *default_charset;
 
151
static CHARSET_INFO *charset_info= &my_charset_latin1;
 
152
const char *default_dbug_option="d:t:o,/tmp/mysqldump.trace";
 
153
/* have we seen any VIEWs during table scanning? */
 
154
bool seen_views= 0;
 
155
const char *compatible_mode_names[]=
 
156
{
 
157
  "MYSQL323", "MYSQL40", "POSTGRESQL", "ORACLE", "MSSQL", "DB2",
 
158
  "MAXDB", "NO_KEY_OPTIONS", "NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS",
 
159
  "ANSI",
 
160
  NullS
 
161
};
 
162
#define MASK_ANSI_QUOTES \
 
163
(\
 
164
 (1<<2)  | /* POSTGRESQL */\
 
165
 (1<<3)  | /* ORACLE     */\
 
166
 (1<<4)  | /* MSSQL      */\
 
167
 (1<<5)  | /* DB2        */\
 
168
 (1<<6)  | /* MAXDB      */\
 
169
 (1<<10)   /* ANSI       */\
 
170
)
 
171
TYPELIB compatible_mode_typelib= {array_elements(compatible_mode_names) - 1,
 
172
                                  "", compatible_mode_names, NULL};
 
173
 
 
174
HASH ignore_table;
 
175
 
 
176
static struct my_option my_long_options[] =
 
177
{
 
178
  {"all", 'a', "Deprecated. Use --create-options instead.",
 
179
   (char**) &create_options, (char**) &create_options, 0, GET_BOOL, NO_ARG, 1,
 
180
   0, 0, 0, 0, 0},
 
181
  {"all-databases", 'A',
 
182
   "Dump all the databases. This will be same as --databases with all databases selected.",
 
183
   (char**) &opt_alldbs, (char**) &opt_alldbs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
 
184
   0, 0},
 
185
  {"all-tablespaces", 'Y',
 
186
   "Dump all the tablespaces.",
 
187
   (char**) &opt_alltspcs, (char**) &opt_alltspcs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
 
188
   0, 0},
 
189
  {"no-tablespaces", 'y',
 
190
   "Do not dump any tablespace information.",
 
191
   (char**) &opt_notspcs, (char**) &opt_notspcs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
 
192
   0, 0},
 
193
  {"add-drop-database", OPT_DROP_DATABASE, "Add a 'DROP DATABASE' before each create.",
 
194
   (char**) &opt_drop_database, (char**) &opt_drop_database, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
 
195
   0},
 
196
  {"add-drop-table", OPT_DROP, "Add a 'drop table' before each create.",
 
197
   (char**) &opt_drop, (char**) &opt_drop, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0,
 
198
   0},
 
199
  {"add-locks", OPT_LOCKS, "Add locks around insert statements.",
 
200
   (char**) &opt_lock, (char**) &opt_lock, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0,
 
201
   0},
 
202
  {"allow-keywords", OPT_KEYWORDS,
 
203
   "Allow creation of column names that are keywords.", (char**) &opt_keywords,
 
204
   (char**) &opt_keywords, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
205
  {"apply-slave-statements", OPT_MYSQLDUMP_SLAVE_APPLY,
 
206
   "Adds 'STOP SLAVE' prior to 'CHANGE MASTER' and 'START SLAVE' to bottom of dump.",
 
207
   (char**) &opt_slave_apply, (char**) &opt_slave_apply, 0, GET_BOOL, NO_ARG,
 
208
   0, 0, 0, 0, 0, 0},
 
209
  {"character-sets-dir", OPT_CHARSETS_DIR,
 
210
   "Directory where character sets are.", (char**) &charsets_dir,
 
211
   (char**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
212
  {"comments", 'i', "Write additional information.",
 
213
   (char**) &opt_comments, (char**) &opt_comments, 0, GET_BOOL, NO_ARG,
 
214
   1, 0, 0, 0, 0, 0},
 
215
  {"compatible", OPT_COMPATIBLE,
 
216
   "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.",
 
217
   (char**) &opt_compatible_mode_str, (char**) &opt_compatible_mode_str, 0,
 
218
   GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
219
  {"compact", OPT_COMPACT,
 
220
   "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",
 
221
   (char**) &opt_compact, (char**) &opt_compact, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
 
222
   0, 0},
 
223
  {"complete-insert", 'c', "Use complete insert statements.",
 
224
   (char**) &opt_complete_insert, (char**) &opt_complete_insert, 0, GET_BOOL,
 
225
   NO_ARG, 0, 0, 0, 0, 0, 0},
 
226
  {"compress", 'C', "Use compression in server/client protocol.",
 
227
   (char**) &opt_compress, (char**) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
 
228
   0, 0, 0},
 
229
  {"create-options", OPT_CREATE_OPTIONS,
 
230
   "Include all MySQL specific create options.",
 
231
   (char**) &create_options, (char**) &create_options, 0, GET_BOOL, NO_ARG, 1,
 
232
   0, 0, 0, 0, 0},
 
233
  {"databases", 'B',
 
234
   "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.",
 
235
   (char**) &opt_databases, (char**) &opt_databases, 0, GET_BOOL, NO_ARG, 0, 0,
 
236
   0, 0, 0, 0},
 
237
  {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
 
238
   (char**) &debug_check_flag, (char**) &debug_check_flag, 0,
 
239
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
240
  {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
 
241
   (char**) &debug_info_flag, (char**) &debug_info_flag,
 
242
   0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
243
  {"default-character-set", OPT_DEFAULT_CHARSET,
 
244
   "Set the default character set.", (char**) &default_charset,
 
245
   (char**) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
246
  {"delayed-insert", OPT_DELAYED, "Insert rows with INSERT DELAYED; ",
 
247
   (char**) &opt_delayed, (char**) &opt_delayed, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
 
248
   0, 0},
 
249
  {"delete-master-logs", OPT_DELETE_MASTER_LOGS,
 
250
   "Delete logs on master after backup. This automatically enables --master-data.",
 
251
   (char**) &opt_delete_master_logs, (char**) &opt_delete_master_logs, 0,
 
252
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
253
  {"disable-keys", 'K',
 
254
   "'/*!40000 ALTER TABLE tb_name DISABLE KEYS */; and '/*!40000 ALTER TABLE tb_name ENABLE KEYS */; will be put in the output.", (char**) &opt_disable_keys,
 
255
   (char**) &opt_disable_keys, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
 
256
  {"dump-slave", OPT_MYSQLDUMP_SLAVE_DATA,
 
257
   "This causes the binary log position and filename of the master to be "
 
258
   "appended to the dumped data output. Setting the value to 1, will print"
 
259
   "it as a CHANGE MASTER command in the dumped data output; if equal"
 
260
   " to 2, that command will be prefixed with a comment symbol. "
 
261
   "This option will turn --lock-all-tables on, unless "
 
262
   "--single-transaction is specified too (in which case a "
 
263
   "global read lock is only taken a short time at the beginning of the dump "
 
264
   "- don't forget to read about --single-transaction below). In all cases "
 
265
   "any action on logs will happen at the exact moment of the dump."
 
266
   "Option automatically turns --lock-tables off.",
 
267
   (char**) &opt_slave_data, (char**) &opt_slave_data, 0,
 
268
   GET_UINT, OPT_ARG, 0, 0, MYSQL_OPT_SLAVE_DATA_COMMENTED_SQL, 0, 0, 0},
 
269
  {"events", 'E', "Dump events.",
 
270
     (char**) &opt_events, (char**) &opt_events, 0, GET_BOOL,
 
271
     NO_ARG, 0, 0, 0, 0, 0, 0},
 
272
  {"extended-insert", 'e',
 
273
   "Allows utilization of the new, much faster INSERT syntax.",
 
274
   (char**) &extended_insert, (char**) &extended_insert, 0, GET_BOOL, NO_ARG,
 
275
   1, 0, 0, 0, 0, 0},
 
276
  {"fields-terminated-by", OPT_FTB,
 
277
   "Fields in the textfile are terminated by ...", (char**) &fields_terminated,
 
278
   (char**) &fields_terminated, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
279
  {"fields-enclosed-by", OPT_ENC,
 
280
   "Fields in the importfile are enclosed by ...", (char**) &enclosed,
 
281
   (char**) &enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0 ,0, 0},
 
282
  {"fields-optionally-enclosed-by", OPT_O_ENC,
 
283
   "Fields in the i.file are opt. enclosed by ...", (char**) &opt_enclosed,
 
284
   (char**) &opt_enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0 ,0, 0},
 
285
  {"fields-escaped-by", OPT_ESC, "Fields in the i.file are escaped by ...",
 
286
   (char**) &escaped, (char**) &escaped, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
287
  {"first-slave", 'x', "Deprecated, renamed to --lock-all-tables.",
 
288
   (char**) &opt_lock_all_tables, (char**) &opt_lock_all_tables, 0, GET_BOOL, NO_ARG,
 
289
   0, 0, 0, 0, 0, 0},
 
290
  {"flush-logs", 'F', "Flush logs file in server before starting dump. "
 
291
   "Note that if you dump many databases at once (using the option "
 
292
   "--databases= or --all-databases), the logs will be flushed for "
 
293
   "each database dumped. The exception is when using --lock-all-tables "
 
294
   "or --master-data: "
 
295
   "in this case the logs will be flushed only once, corresponding "
 
296
   "to the moment all tables are locked. So if you want your dump and "
 
297
   "the log flush to happen at the same exact moment you should use "
 
298
   "--lock-all-tables or --master-data with --flush-logs",
 
299
   (char**) &flush_logs, (char**) &flush_logs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
 
300
   0, 0},
 
301
  {"flush-privileges", OPT_ESC, "Emit a FLUSH PRIVILEGES statement "
 
302
   "after dumping the mysql database.  This option should be used any "
 
303
   "time the dump contains the mysql database and any other database "
 
304
   "that depends on the data in the mysql database for proper restore. ",
 
305
   (char**) &flush_privileges, (char**) &flush_privileges, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
 
306
   0, 0},
 
307
  {"force", 'f', "Continue even if we get an sql-error.",
 
308
   (char**) &ignore_errors, (char**) &ignore_errors, 0, GET_BOOL, NO_ARG,
 
309
   0, 0, 0, 0, 0, 0},
 
310
  {"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG,
 
311
   NO_ARG, 0, 0, 0, 0, 0, 0},
 
312
  {"hex-blob", OPT_HEXBLOB, "Dump binary strings (BINARY, "
 
313
    "VARBINARY, BLOB) in hexadecimal format.",
 
314
   (char**) &opt_hex_blob, (char**) &opt_hex_blob, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
315
  {"host", 'h', "Connect to host.", (char**) &current_host,
 
316
   (char**) &current_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
317
  {"ignore-table", OPT_IGNORE_TABLE,
 
318
   "Do not dump the specified table. To specify more than one table to ignore, "
 
319
   "use the directive multiple times, once for each table.  Each table must "
 
320
   "be specified with both database and table names, e.g. --ignore-table=database.table",
 
321
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
322
  {"include-master-host-port", OPT_MYSQLDUMP_INCLUDE_MASTER_HOST_PORT,
 
323
   "Adds 'MASTER_HOST=<host>, MASTER_PORT=<port>' to 'CHANGE MASTER TO..' in dump produced with --dump-slave.",
 
324
   (char**) &opt_include_master_host_port, 
 
325
   (char**) &opt_include_master_host_port, 
 
326
   0, GET_BOOL, NO_ARG,
 
327
   0, 0, 0, 0, 0, 0},
 
328
  {"insert-ignore", OPT_INSERT_IGNORE, "Insert rows with INSERT IGNORE.",
 
329
   (char**) &opt_ignore, (char**) &opt_ignore, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
 
330
   0, 0},
 
331
  {"lines-terminated-by", OPT_LTB, "Lines in the i.file are terminated by ...",
 
332
   (char**) &lines_terminated, (char**) &lines_terminated, 0, GET_STR,
 
333
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
334
  {"lock-all-tables", 'x', "Locks all tables across all databases. This "
 
335
   "is achieved by taking a global read lock for the duration of the whole "
 
336
   "dump. Automatically turns --single-transaction and --lock-tables off.",
 
337
   (char**) &opt_lock_all_tables, (char**) &opt_lock_all_tables, 0, GET_BOOL, NO_ARG,
 
338
   0, 0, 0, 0, 0, 0},
 
339
  {"lock-tables", 'l', "Lock all tables for read.", (char**) &lock_tables,
 
340
   (char**) &lock_tables, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
 
341
  {"log-error", OPT_ERROR_LOG_FILE, "Append warnings and errors to given file.",
 
342
   (char**) &log_error_file, (char**) &log_error_file, 0, GET_STR,
 
343
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
344
  {"master-data", OPT_MASTER_DATA,
 
345
   "This causes the binary log position and filename to be appended to the "
 
346
   "output. If equal to 1, will print it as a CHANGE MASTER command; if equal"
 
347
   " to 2, that command will be prefixed with a comment symbol. "
 
348
   "This option will turn --lock-all-tables on, unless "
 
349
   "--single-transaction is specified too (in which case a "
 
350
   "global read lock is only taken a short time at the beginning of the dump "
 
351
   "- don't forget to read about --single-transaction below). In all cases "
 
352
   "any action on logs will happen at the exact moment of the dump."
 
353
   "Option automatically turns --lock-tables off.",
 
354
   (char**) &opt_master_data, (char**) &opt_master_data, 0,
 
355
   GET_UINT, OPT_ARG, 0, 0, MYSQL_OPT_MASTER_DATA_COMMENTED_SQL, 0, 0, 0},
 
356
  {"max_allowed_packet", OPT_MAX_ALLOWED_PACKET, "",
 
357
    (char**) &opt_max_allowed_packet, (char**) &opt_max_allowed_packet, 0,
 
358
    GET_ULONG, REQUIRED_ARG, 24*1024*1024, 4096,
 
359
   (int64_t) 2L*1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0},
 
360
  {"net_buffer_length", OPT_NET_BUFFER_LENGTH, "",
 
361
    (char**) &opt_net_buffer_length, (char**) &opt_net_buffer_length, 0,
 
362
    GET_ULONG, REQUIRED_ARG, 1024*1024L-1025, 4096, 16*1024L*1024L,
 
363
   MALLOC_OVERHEAD-1024, 1024, 0},
 
364
  {"no-autocommit", OPT_AUTOCOMMIT,
 
365
   "Wrap tables with autocommit/commit statements.",
 
366
   (char**) &opt_autocommit, (char**) &opt_autocommit, 0, GET_BOOL, NO_ARG,
 
367
   0, 0, 0, 0, 0, 0},
 
368
  {"no-create-db", 'n',
 
369
   "'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.}.",
 
370
   (char**) &opt_create_db, (char**) &opt_create_db, 0, GET_BOOL, NO_ARG, 0, 0,
 
371
   0, 0, 0, 0},
 
372
  {"no-create-info", 't', "Don't write table creation info.",
 
373
   (char**) &opt_no_create_info, (char**) &opt_no_create_info, 0, GET_BOOL,
 
374
   NO_ARG, 0, 0, 0, 0, 0, 0},
 
375
  {"no-data", 'd', "No row information.", (char**) &opt_no_data,
 
376
   (char**) &opt_no_data, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
377
  {"no-set-names", 'N',
 
378
   "Deprecated. Use --skip-set-charset instead.",
 
379
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
 
380
  {"opt", OPT_OPTIMIZE,
 
381
   "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.",
 
382
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
 
383
  {"order-by-primary", OPT_ORDER_BY_PRIMARY,
 
384
   "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.",
 
385
   (char**) &opt_order_by_primary, (char**) &opt_order_by_primary, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
386
  {"password", 'p',
 
387
   "Password to use when connecting to server. If password is not given it's solicited on the tty.",
 
388
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
 
389
  {"port", 'P', "Port number to use for connection.", (char**) &opt_mysql_port,
 
390
   (char**) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0,
 
391
   0},
 
392
  {"quick", 'q', "Don't buffer query, dump directly to stdout.",
 
393
   (char**) &quick, (char**) &quick, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
 
394
  {"quote-names",'Q', "Quote table and column names with backticks (`).",
 
395
   (char**) &opt_quoted, (char**) &opt_quoted, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0,
 
396
   0, 0},
 
397
  {"replace", OPT_MYSQL_REPLACE_INTO, "Use REPLACE INTO instead of INSERT INTO.",
 
398
   (char**) &opt_replace_into, (char**) &opt_replace_into, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
 
399
   0, 0},
 
400
  {"result-file", 'r',
 
401
   "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).",
 
402
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
403
  {"routines", 'R', "Dump stored routines (functions and procedures).",
 
404
     (char**) &opt_routines, (char**) &opt_routines, 0, GET_BOOL,
 
405
     NO_ARG, 0, 0, 0, 0, 0, 0},
 
406
  {"set-charset", OPT_SET_CHARSET,
 
407
   "Add 'SET NAMES default_character_set' to the output.",
 
408
   (char**) &opt_set_charset, (char**) &opt_set_charset, 0, GET_BOOL, NO_ARG, 1,
 
409
   0, 0, 0, 0, 0},
 
410
  {"set-variable", 'O',
 
411
   "Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.",
 
412
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
413
  /*
 
414
    Note that the combination --single-transaction --master-data
 
415
    will give bullet-proof binlog position only if server >=4.1.3. That's the
 
416
    old "FLUSH TABLES WITH READ LOCK does not block commit" fixed bug.
 
417
  */
 
418
  {"single-transaction", OPT_TRANSACTION,
 
419
   "Creates a consistent snapshot by dumping all tables in a single "
 
420
   "transaction. Works ONLY for tables stored in storage engines which "
 
421
   "support multiversioning (currently only InnoDB does); the dump is NOT "
 
422
   "guaranteed to be consistent for other storage engines. "
 
423
   "While a --single-transaction dump is in process, to ensure a valid "
 
424
   "dump file (correct table contents and binary log position), no other "
 
425
   "connection should use the following statements: ALTER TABLE, DROP "
 
426
   "TABLE, RENAME TABLE, TRUNCATE TABLE, as consistent snapshot is not "
 
427
   "isolated from them. Option automatically turns off --lock-tables.",
 
428
   (char**) &opt_single_transaction, (char**) &opt_single_transaction, 0,
 
429
   GET_BOOL, NO_ARG,  0, 0, 0, 0, 0, 0},
 
430
  {"dump-date", OPT_DUMP_DATE, "Put a dump date to the end of the output.",
 
431
   (char**) &opt_dump_date, (char**) &opt_dump_date, 0,
 
432
   GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
 
433
  {"skip-opt", OPT_SKIP_OPTIMIZATION,
 
434
   "Disable --opt. Disables --add-drop-table, --add-locks, --create-options, --quick, --extended-insert, --lock-tables, --set-charset, and --disable-keys.",
 
435
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
 
436
  {"tab",'T',
 
437
   "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.",
 
438
   (char**) &path, (char**) &path, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
439
  {"tables", OPT_TABLES, "Overrides option --databases (-B).",
 
440
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
 
441
  {"tz-utc", OPT_TZ_UTC,
 
442
    "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.",
 
443
    (char**) &opt_tz_utc, (char**) &opt_tz_utc, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
 
444
#ifndef DONT_ALLOW_USER_CHANGE
 
445
  {"user", 'u', "User for login if not current user.",
 
446
   (char**) &current_user, (char**) &current_user, 0, GET_STR, REQUIRED_ARG,
 
447
   0, 0, 0, 0, 0, 0},
 
448
#endif
 
449
  {"verbose", 'v', "Print info about the various stages.",
 
450
   (char**) &verbose, (char**) &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
451
  {"version",'V', "Output version information and exit.", 0, 0, 0,
 
452
   GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
 
453
  {"where", 'w', "Dump only selected records; QUOTES mandatory!",
 
454
   (char**) &where, (char**) &where, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
455
  {"xml", 'X', "Dump a database as well formed XML.", 0, 0, 0, GET_NO_ARG,
 
456
   NO_ARG, 0, 0, 0, 0, 0, 0},
 
457
  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
 
458
};
 
459
 
 
460
static const char *load_default_groups[]= { "mysqldump","client",0 };
 
461
 
 
462
static void maybe_exit(int error);
124
463
static void die(int error, const char* reason, ...);
125
 
static void write_header(char *db_name);
126
 
static int dump_selected_tables(const string &db, const vector<string> &table_names);
127
 
static int dump_databases(const vector<string> &db_names);
 
464
static void maybe_die(int error, const char* reason, ...);
 
465
static void write_header(FILE *sql_file, char *db_name);
 
466
static void print_value(FILE *file, MYSQL_RES  *result, MYSQL_ROW row,
 
467
                        const char *prefix,const char *name,
 
468
                        int string_value);
 
469
static int dump_selected_tables(char *db, char **table_names, int tables);
 
470
static int dump_all_tables_in_db(char *db);
 
471
static int init_dumping_tables(char *);
 
472
static int init_dumping(char *, int init_func(char*));
 
473
static int dump_databases(char **);
128
474
static int dump_all_databases(void);
129
 
int get_server_type();
130
 
void dump_all_tables(void);
131
 
void generate_dump(void);
132
 
void generate_dump_db(void);
133
 
 
134
 
void dump_all_tables(void)
135
 
{
136
 
  std::vector<DrizzleDumpDatabase*>::iterator i;
137
 
  for (i= database_store.begin(); i != database_store.end(); ++i)
138
 
  {
139
 
    if ((not (*i)->populateTables()) && (not ignore_errors))
140
 
      maybe_exit(EX_DRIZZLEERR);
141
 
  }
142
 
}
143
 
 
144
 
void generate_dump(void)
145
 
{
146
 
  std::vector<DrizzleDumpDatabase*>::iterator i;
147
 
 
148
 
  if (path.empty())
149
 
  {
150
 
    cout << endl << "SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;"
151
 
      << endl << "SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;" << endl;
152
 
  }
153
 
 
154
 
  if (opt_autocommit)
155
 
    cout << "SET AUTOCOMMIT=0;" << endl;
156
 
 
157
 
  for (i= database_store.begin(); i != database_store.end(); ++i)
158
 
  {
159
 
    DrizzleDumpDatabase *database= *i;
160
 
    cout << *database;
161
 
  }
162
 
 
163
 
  if (path.empty())
164
 
  {
165
 
    cout << "SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;"
166
 
      << endl << "SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;" << endl;
167
 
  }
168
 
}
169
 
 
170
 
void generate_dump_db(void)
171
 
{
172
 
  std::vector<DrizzleDumpDatabase*>::iterator i;
173
 
  DrizzleStringBuf sbuf(1024);
174
 
  try
175
 
  {
176
 
    destination_connection= new DrizzleDumpConnection(opt_destination_host,
177
 
      opt_destination_port, opt_destination_user, opt_destination_password,
178
 
      false);
179
 
  }
180
 
  catch (std::exception&)
181
 
  {
182
 
    cerr << "Could not connect to destination database server" << endl;
183
 
    maybe_exit(EX_DRIZZLEERR);
184
 
  }
185
 
  sbuf.setConnection(destination_connection);
186
 
  std::ostream sout(&sbuf);
187
 
  sout.exceptions(ios_base::badbit);
188
 
 
189
 
  if (path.empty())
190
 
  {
191
 
    sout << "SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;" << endl;
192
 
    sout << "SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;" << endl;
193
 
  }
194
 
 
195
 
  if (opt_autocommit)
196
 
    cout << "SET AUTOCOMMIT=0;" << endl;
197
 
 
198
 
  for (i= database_store.begin(); i != database_store.end(); ++i)
199
 
  {
200
 
    try
201
 
    {
202
 
      DrizzleDumpDatabase *database= *i;
203
 
      sout << *database;
204
 
    }
205
 
    catch (std::exception&)
206
 
    {
207
 
      std::cout << _("Error inserting into destination database") << std::endl;
208
 
      if (not ignore_errors)
209
 
        maybe_exit(EX_DRIZZLEERR);
210
 
    }
211
 
  }
212
 
 
213
 
  if (path.empty())
214
 
  {
215
 
    sout << "SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;" << endl;
216
 
    sout << "SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;" << endl;
217
 
  }
 
475
static char *quote_name(const char *name, char *buff, bool force);
 
476
char check_if_ignore_table(const char *table_name, char *table_type);
 
477
static char *primary_key_fields(const char *table_name);
 
478
 
 
479
#include <help_start.h>
 
480
 
 
481
/*
 
482
  Print the supplied message if in verbose mode
 
483
 
 
484
  SYNOPSIS
 
485
    verbose_msg()
 
486
    fmt   format specifier
 
487
    ...   variable number of parameters
 
488
*/
 
489
 
 
490
static void verbose_msg(const char *fmt, ...)
 
491
{
 
492
  va_list args;
 
493
 
 
494
 
 
495
  if (!verbose)
 
496
    return;
 
497
 
 
498
  va_start(args, fmt);
 
499
  vfprintf(stderr, fmt, args);
 
500
  va_end(args);
 
501
 
 
502
  return;
218
503
}
219
504
 
220
505
/*
221
506
  exit with message if ferror(file)
222
507
 
223
508
  SYNOPSIS
224
 
  check_io()
225
 
  file        - checked file
 
509
    check_io()
 
510
    file        - checked file
226
511
*/
227
512
 
228
513
static void check_io(FILE *file)
229
514
{
230
515
  if (ferror(file))
231
 
    die(EX_EOF, _("Got errno %d on write"), errno);
232
 
}
233
 
 
234
 
static void write_header(char *db_name)
235
 
{
236
 
  if ((not opt_compact) and (opt_comments))
237
 
  {
238
 
    cout << "-- drizzledump " << VERSION << " libdrizzle "
239
 
      << drizzle_version() << ", for " << HOST_VENDOR << "-" << HOST_OS
240
 
      << " (" << HOST_CPU << ")" << endl << "--" << endl;
241
 
    cout << "-- Host: " << current_host << "    Database: " << db_name << endl;
242
 
    cout << "-- ------------------------------------------------------" << endl;
243
 
    cout << "-- Server version\t" << db_connection->getServerVersion();
244
 
    if (db_connection->getServerType() == ServerDetect::SERVER_MYSQL_FOUND)
245
 
      cout << " (MySQL server)";
246
 
    else if (db_connection->getServerType() == ServerDetect::SERVER_DRIZZLE_FOUND)
247
 
      cout << " (Drizzle server)";
248
 
    cout << endl << endl;
 
516
    die(EX_EOF, "Got errno %d on write", errno);
 
517
}
 
518
 
 
519
static void print_version(void)
 
520
{
 
521
  printf("%s  Ver %s Distrib %s, for %s (%s)\n",my_progname,DUMP_VERSION,
 
522
         MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
 
523
} /* print_version */
 
524
 
 
525
 
 
526
static void short_usage_sub(void)
 
527
{
 
528
  printf("Usage: %s [OPTIONS] database [tables]\n", my_progname);
 
529
  printf("OR     %s [OPTIONS] --databases [OPTIONS] DB1 [DB2 DB3...]\n",
 
530
         my_progname);
 
531
  printf("OR     %s [OPTIONS] --all-databases [OPTIONS]\n", my_progname);
 
532
}
 
533
 
 
534
 
 
535
static void usage(void)
 
536
{
 
537
  print_version();
 
538
  puts("By Igor Romanenko, Monty, Jani & Sinisa");
 
539
  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");
 
540
  puts("Dumping definition and data mysql database or table");
 
541
  short_usage_sub();
 
542
  print_defaults("my",load_default_groups);
 
543
  my_print_help(my_long_options);
 
544
  my_print_variables(my_long_options);
 
545
} /* usage */
 
546
 
 
547
 
 
548
static void short_usage(void)
 
549
{
 
550
  short_usage_sub();
 
551
  printf("For more options, use %s --help\n", my_progname);
 
552
}
 
553
 
 
554
#include <help_end.h>
 
555
 
 
556
 
 
557
static void write_header(FILE *sql_file, char *db_name)
 
558
{
 
559
  if (opt_xml)
 
560
  {
 
561
    fputs("<?xml version=\"1.0\"?>\n", sql_file);
 
562
    /*
 
563
      Schema reference.  Allows use of xsi:nil for NULL values and 
 
564
      xsi:type to define an element's data type.
 
565
    */
 
566
    fputs("<mysqldump ", sql_file);
 
567
    fputs("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"",
 
568
          sql_file);
 
569
    fputs(">\n", sql_file);
 
570
    check_io(sql_file);
 
571
  }
 
572
  else if (!opt_compact)
 
573
  {
 
574
    if (opt_comments)
 
575
    {
 
576
      fprintf(sql_file,
 
577
              "-- MySQL dump %s  Distrib %s, for %s (%s)\n--\n",
 
578
              DUMP_VERSION, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE);
 
579
      fprintf(sql_file, "-- Host: %s    Database: %s\n",
 
580
              current_host ? current_host : "localhost", db_name ? db_name :
 
581
              "");
 
582
      fputs("-- ------------------------------------------------------\n",
 
583
            sql_file);
 
584
      fprintf(sql_file, "-- Server version\t%s\n",
 
585
              mysql_get_server_info(&mysql_connection));
 
586
    }
 
587
    if (opt_set_charset)
 
588
      fprintf(sql_file,
 
589
"\n/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;"
 
590
"\n/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;"
 
591
"\n/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;"
 
592
"\n/*!40101 SET NAMES %s */;\n",default_charset);
 
593
 
 
594
    if (opt_tz_utc)
 
595
    {
 
596
      fprintf(sql_file, "/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;\n");
 
597
      fprintf(sql_file, "/*!40103 SET TIME_ZONE='+00:00' */;\n");
 
598
    }
 
599
 
 
600
    if (!path)
 
601
    {
 
602
      fprintf(md_result_file,"\
 
603
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;\n\
 
604
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;\n\
 
605
");
 
606
    }
 
607
    check_io(sql_file);
249
608
  }
250
609
} /* write_header */
251
610
 
252
611
 
253
612
static void write_footer(FILE *sql_file)
254
613
{
255
 
  if (! opt_compact)
256
 
  {
 
614
  if (opt_xml)
 
615
  {
 
616
    fputs("</mysqldump>\n", sql_file);
 
617
    check_io(sql_file);
 
618
  }
 
619
  else if (!opt_compact)
 
620
  {
 
621
    if (opt_tz_utc)
 
622
      fprintf(sql_file,"/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;\n");
 
623
 
 
624
    if (!path)
 
625
    {
 
626
      fprintf(md_result_file,"\
 
627
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;\n\
 
628
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;\n");
 
629
    }
 
630
    if (opt_set_charset)
 
631
      fprintf(sql_file,
 
632
"/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;\n"
 
633
"/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;\n"
 
634
"/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;\n");
 
635
    fprintf(sql_file,
 
636
            "/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;\n");
 
637
    fputs("\n", sql_file);
257
638
    if (opt_comments)
258
639
    {
259
640
      if (opt_dump_date)
260
641
      {
261
 
        boost::posix_time::ptime time(boost::posix_time::second_clock::local_time());
 
642
        char time_str[20];
 
643
        get_date(time_str, GETDATE_DATE_TIME, 0);
262
644
        fprintf(sql_file, "-- Dump completed on %s\n",
263
 
          boost::posix_time::to_simple_string(time).c_str());
 
645
                time_str);
264
646
      }
265
647
      else
266
648
        fprintf(sql_file, "-- Dump completed\n");
269
651
  }
270
652
} /* write_footer */
271
653
 
272
 
static int get_options(void)
273
 
{
 
654
 
 
655
static void free_table_ent(char *key)
 
656
{
 
657
  my_free(key, MYF(0));
 
658
}
 
659
 
 
660
 
 
661
static uchar* get_table_key(const char *entry, size_t *length,
 
662
                            bool not_used __attribute__((unused)))
 
663
{
 
664
  *length= strlen(entry);
 
665
  return (uchar*) entry;
 
666
}
 
667
 
 
668
 
 
669
static bool
 
670
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
 
671
               char *argument)
 
672
{
 
673
  switch (optid) {
 
674
  case 'p':
 
675
    if (argument)
 
676
    {
 
677
      char *start=argument;
 
678
      my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
 
679
      opt_password=my_strdup(argument,MYF(MY_FAE));
 
680
      while (*argument) *argument++= 'x';               /* Destroy argument */
 
681
      if (*start)
 
682
        start[1]=0;                             /* Cut length of argument */
 
683
      tty_password= 0;
 
684
    }
 
685
    else
 
686
      tty_password=1;
 
687
    break;
 
688
  case 'r':
 
689
    if (!(md_result_file= my_fopen(argument, O_WRONLY | FILE_BINARY,
 
690
                                    MYF(MY_WME))))
 
691
      exit(1);
 
692
    break;
 
693
  case 'N':
 
694
    opt_set_charset= 0;
 
695
    break;
 
696
  case 'T':
 
697
    opt_disable_keys=0;
 
698
 
 
699
    if (strlen(argument) >= FN_REFLEN)
 
700
    {
 
701
      /*
 
702
        This check is made because the some the file functions below
 
703
        have FN_REFLEN sized stack allocated buffers and will cause
 
704
        a crash even if the input destination buffer is large enough
 
705
        to hold the output.
 
706
      */
 
707
      die(EX_USAGE, "Input filename too long: %s", argument);
 
708
    }
 
709
 
 
710
    break;
 
711
  case 'V': print_version(); exit(0);
 
712
  case 'X':
 
713
    opt_xml= 1;
 
714
    extended_insert= opt_drop= opt_lock=
 
715
      opt_disable_keys= opt_autocommit= opt_create_db= 0;
 
716
    break;
 
717
  case 'I':
 
718
  case '?':
 
719
    usage();
 
720
    exit(0);
 
721
  case (int) OPT_MASTER_DATA:
 
722
    if (!argument) /* work like in old versions */
 
723
      opt_master_data= MYSQL_OPT_MASTER_DATA_EFFECTIVE_SQL;
 
724
    break;
 
725
  case (int) OPT_MYSQLDUMP_SLAVE_DATA:
 
726
    if (!argument) /* work like in old versions */
 
727
      opt_slave_data= MYSQL_OPT_SLAVE_DATA_EFFECTIVE_SQL;
 
728
    break;
 
729
  case (int) OPT_OPTIMIZE:
 
730
    extended_insert= opt_drop= opt_lock= quick= create_options=
 
731
      opt_disable_keys= lock_tables= opt_set_charset= 1;
 
732
    break;
 
733
  case (int) OPT_SKIP_OPTIMIZATION:
 
734
    extended_insert= opt_drop= opt_lock= quick= create_options=
 
735
      opt_disable_keys= lock_tables= opt_set_charset= 0;
 
736
    break;
 
737
  case (int) OPT_COMPACT:
 
738
  if (opt_compact)
 
739
  {
 
740
    opt_comments= opt_drop= opt_disable_keys= opt_lock= 0;
 
741
    opt_set_charset= 0;
 
742
  }
 
743
  case (int) OPT_TABLES:
 
744
    opt_databases=0;
 
745
    break;
 
746
  case (int) OPT_IGNORE_TABLE:
 
747
  {
 
748
    if (!strchr(argument, '.'))
 
749
    {
 
750
      fprintf(stderr, "Illegal use of option --ignore-table=<database>.<table>\n");
 
751
      exit(1);
 
752
    }
 
753
    if (my_hash_insert(&ignore_table, (uchar*)my_strdup(argument, MYF(0))))
 
754
      exit(EX_EOM);
 
755
    break;
 
756
  }
 
757
  case (int) OPT_COMPATIBLE:
 
758
    {
 
759
      char buff[255];
 
760
      char *end= compatible_mode_normal_str;
 
761
      int i;
 
762
      ulong mode;
 
763
      uint err_len;
 
764
 
 
765
      opt_quoted= 1;
 
766
      opt_set_charset= 0;
 
767
      opt_compatible_mode_str= argument;
 
768
      opt_compatible_mode= find_set(&compatible_mode_typelib,
 
769
                                    argument, strlen(argument),
 
770
                                    &err_ptr, &err_len);
 
771
      if (err_len)
 
772
      {
 
773
        strmake(buff, err_ptr, min(sizeof(buff), err_len));
 
774
        fprintf(stderr, "Invalid mode to --compatible: %s\n", buff);
 
775
        exit(1);
 
776
      }
 
777
      mode= opt_compatible_mode;
 
778
      for (i= 0, mode= opt_compatible_mode; mode; mode>>= 1, i++)
 
779
      {
 
780
        if (mode & 1)
 
781
        {
 
782
          end= strmov(end, compatible_mode_names[i]);
 
783
          end= strmov(end, ",");
 
784
        }
 
785
      }
 
786
      if (end!=compatible_mode_normal_str)
 
787
        end[-1]= 0;
 
788
      /*
 
789
        Set charset to the default compiled value if it hasn't
 
790
        been reset yet by --default-character-set=xxx.
 
791
      */
 
792
      if (default_charset == mysql_universal_client_charset)
 
793
        default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME;
 
794
      break;
 
795
    }
 
796
  }
 
797
  return 0;
 
798
}
 
799
 
 
800
static int get_options(int *argc, char ***argv)
 
801
{
 
802
  int ho_error;
 
803
  MYSQL_PARAMETERS *mysql_params= mysql_get_parameters();
 
804
 
 
805
  opt_max_allowed_packet= *mysql_params->p_max_allowed_packet;
 
806
  opt_net_buffer_length= *mysql_params->p_net_buffer_length;
 
807
 
 
808
  md_result_file= stdout;
 
809
  load_defaults("my",load_default_groups,argc,argv);
 
810
  defaults_argv= *argv;
 
811
 
 
812
  if (hash_init(&ignore_table, charset_info, 16, 0, 0,
 
813
                (hash_get_key) get_table_key,
 
814
                (hash_free_key) free_table_ent, 0))
 
815
    return(EX_EOM);
 
816
  /* Don't copy internal log tables */
 
817
  if (my_hash_insert(&ignore_table,
 
818
                     (uchar*) my_strdup("mysql.apply_status", MYF(MY_WME))) ||
 
819
      my_hash_insert(&ignore_table,
 
820
                     (uchar*) my_strdup("mysql.schema", MYF(MY_WME))) ||
 
821
      my_hash_insert(&ignore_table,
 
822
                     (uchar*) my_strdup("mysql.general_log", MYF(MY_WME))) ||
 
823
      my_hash_insert(&ignore_table,
 
824
                     (uchar*) my_strdup("mysql.slow_log", MYF(MY_WME))) ||
 
825
      my_hash_insert(&ignore_table,
 
826
                     (uchar*) my_strdup("mysql.online_backup", MYF(MY_WME))) ||
 
827
      my_hash_insert(&ignore_table,
 
828
                     (uchar*) my_strdup("mysql.online_backup_progress", MYF(MY_WME))))
 
829
    return(EX_EOM);
 
830
 
 
831
  if ((ho_error= handle_options(argc, argv, my_long_options, get_one_option)))
 
832
    return(ho_error);
 
833
 
 
834
  *mysql_params->p_max_allowed_packet= opt_max_allowed_packet;
 
835
  *mysql_params->p_net_buffer_length= opt_net_buffer_length;
 
836
  if (debug_info_flag)
 
837
    my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
 
838
  if (debug_check_flag)
 
839
    my_end_arg= MY_CHECK_ERROR;
 
840
 
 
841
  if (opt_delayed)
 
842
    opt_lock=0;                         /* Can't have lock with delayed */
 
843
  if (!path && (enclosed || opt_enclosed || escaped || lines_terminated ||
 
844
                fields_terminated))
 
845
  {
 
846
    fprintf(stderr,
 
847
            "%s: You must use option --tab with --fields-...\n", my_progname);
 
848
    return(EX_USAGE);
 
849
  }
 
850
 
 
851
  /* We don't delete master logs if slave data option */
 
852
  if (opt_slave_data)
 
853
  {
 
854
    opt_lock_all_tables= !opt_single_transaction;
 
855
    opt_master_data= 0;
 
856
    opt_delete_master_logs= 0;
 
857
  }
 
858
 
 
859
  /* Ensure consistency of the set of binlog & locking options */
 
860
  if (opt_delete_master_logs && !opt_master_data)
 
861
    opt_master_data= MYSQL_OPT_MASTER_DATA_COMMENTED_SQL;
274
862
  if (opt_single_transaction && opt_lock_all_tables)
275
863
  {
276
 
    fprintf(stderr, _("%s: You can't use --single-transaction and "
277
 
                      "--lock-all-tables at the same time.\n"), progname.c_str());
278
 
    return(EX_USAGE);
279
 
  }
280
 
  if ((opt_databases || opt_alldbs) && ! path.empty())
 
864
    fprintf(stderr, "%s: You can't use --single-transaction and "
 
865
            "--lock-all-tables at the same time.\n", my_progname);
 
866
    return(EX_USAGE);
 
867
  }
 
868
  if (opt_master_data)
 
869
  {
 
870
    opt_lock_all_tables= !opt_single_transaction;
 
871
    opt_slave_data= 0;
 
872
  }
 
873
  if (opt_single_transaction || opt_lock_all_tables)
 
874
    lock_tables= 0;
 
875
  if (enclosed && opt_enclosed)
 
876
  {
 
877
    fprintf(stderr, "%s: You can't use ..enclosed.. and ..optionally-enclosed.. at the same time.\n", my_progname);
 
878
    return(EX_USAGE);
 
879
  }
 
880
  if ((opt_databases || opt_alldbs) && path)
281
881
  {
282
882
    fprintf(stderr,
283
 
            _("%s: --databases or --all-databases can't be used with --tab.\n"),
284
 
            progname.c_str());
 
883
            "%s: --databases or --all-databases can't be used with --tab.\n",
 
884
            my_progname);
285
885
    return(EX_USAGE);
286
886
  }
287
 
 
 
887
  if (strcmp(default_charset, charset_info->csname) &&
 
888
      !(charset_info= get_charset_by_csname(default_charset,
 
889
                                            MY_CS_PRIMARY, MYF(MY_WME))))
 
890
    exit(1);
 
891
  if ((*argc < 1 && !opt_alldbs) || (*argc > 0 && opt_alldbs))
 
892
  {
 
893
    short_usage();
 
894
    return EX_USAGE;
 
895
  }
288
896
  if (tty_password)
289
 
    opt_password=client_get_tty_password(NULL);
 
897
    opt_password=get_tty_password(NullS);
290
898
  return(0);
291
899
} /* get_options */
292
900
 
293
901
 
294
902
/*
 
903
** DB_error -- prints mysql error message and exits the program.
 
904
*/
 
905
static void DB_error(MYSQL *mysql_arg, const char *when)
 
906
{
 
907
 
 
908
  maybe_die(EX_MYSQLERR, "Got error: %d: %s %s",
 
909
          mysql_errno(mysql_arg), mysql_error(mysql_arg), when);
 
910
  return;
 
911
}
 
912
 
 
913
 
 
914
 
 
915
/*
295
916
  Prints out an error message and kills the process.
296
917
 
297
918
  SYNOPSIS
298
 
  die()
299
 
  error_num   - process return value
300
 
  fmt_reason  - a format string for use by vsnprintf.
301
 
  ...         - variable arguments for above fmt_reason string
302
 
 
 
919
    die()
 
920
    error_num   - process return value
 
921
    fmt_reason  - a format string for use by vsnprintf.
 
922
    ...         - variable arguments for above fmt_reason string
 
923
  
303
924
  DESCRIPTION
304
 
  This call prints out the formatted error message to stderr and then
305
 
  terminates the process.
 
925
    This call prints out the formatted error message to stderr and then
 
926
    terminates the process.
306
927
*/
307
928
static void die(int error_num, const char* fmt_reason, ...)
308
929
{
312
933
  vsnprintf(buffer, sizeof(buffer), fmt_reason, args);
313
934
  va_end(args);
314
935
 
315
 
  fprintf(stderr, "%s: %s\n", progname.c_str(), buffer);
 
936
  fprintf(stderr, "%s: %s\n", my_progname, buffer);
316
937
  fflush(stderr);
317
938
 
318
939
  ignore_errors= 0; /* force the exit */
319
940
  maybe_exit(error_num);
320
941
}
321
942
 
 
943
 
 
944
/*
 
945
  Prints out an error message and maybe kills the process.
 
946
 
 
947
  SYNOPSIS
 
948
    maybe_die()
 
949
    error_num   - process return value
 
950
    fmt_reason  - a format string for use by vsnprintf.
 
951
    ...         - variable arguments for above fmt_reason string
 
952
  
 
953
  DESCRIPTION
 
954
    This call prints out the formatted error message to stderr and then
 
955
    terminates the process, unless the --force command line option is used.
 
956
    
 
957
    This call should be used for non-fatal errors (such as database
 
958
    errors) that the code may still be able to continue to the next unit
 
959
    of work.
 
960
    
 
961
*/
 
962
static void maybe_die(int error_num, const char* fmt_reason, ...)
 
963
{
 
964
  char buffer[1000];
 
965
  va_list args;
 
966
  va_start(args,fmt_reason);
 
967
  vsnprintf(buffer, sizeof(buffer), fmt_reason, args);
 
968
  va_end(args);
 
969
 
 
970
  fprintf(stderr, "%s: %s\n", my_progname, buffer);
 
971
  fflush(stderr);
 
972
 
 
973
  maybe_exit(error_num);
 
974
}
 
975
 
 
976
 
 
977
 
 
978
/*
 
979
  Sends a query to server, optionally reads result, prints error message if
 
980
  some.
 
981
 
 
982
  SYNOPSIS
 
983
    mysql_query_with_error_report()
 
984
    mysql_con       connection to use
 
985
    res             if non zero, result will be put there with
 
986
                    mysql_store_result()
 
987
    query           query to send to server
 
988
 
 
989
  RETURN VALUES
 
990
    0               query sending and (if res!=0) result reading went ok
 
991
    1               error
 
992
*/
 
993
 
 
994
static int mysql_query_with_error_report(MYSQL *mysql_con, MYSQL_RES **res,
 
995
                                         const char *query)
 
996
{
 
997
  if (mysql_query(mysql_con, query) ||
 
998
      (res && !((*res)= mysql_store_result(mysql_con))))
 
999
  {
 
1000
    maybe_die(EX_MYSQLERR, "Couldn't execute '%s': %s (%d)",
 
1001
            query, mysql_error(mysql_con), mysql_errno(mysql_con));
 
1002
    return 1;
 
1003
  }
 
1004
  return 0;
 
1005
}
 
1006
 
 
1007
 
 
1008
/**
 
1009
  Switch charset for results to some specified charset.  If the server does not
 
1010
  support character_set_results variable, nothing can be done here.  As for
 
1011
  whether something should be done here, future new callers of this function
 
1012
  should be aware that the server lacking the facility of switching charsets is
 
1013
  treated as success.
 
1014
 
 
1015
  @note  If the server lacks support, then nothing is changed and no error
 
1016
         condition is returned.
 
1017
 
 
1018
  @returns  whether there was an error or not
 
1019
*/
 
1020
static int switch_character_set_results(MYSQL *mysql, const char *cs_name)
 
1021
{
 
1022
  char query_buffer[QUERY_LENGTH];
 
1023
  size_t query_length;
 
1024
 
 
1025
  /* Server lacks facility.  This is not an error, by arbitrary decision . */
 
1026
  if (!server_supports_switching_charsets)
 
1027
    return false;
 
1028
 
 
1029
  query_length= snprintf(query_buffer,
 
1030
                         sizeof (query_buffer),
 
1031
                         "SET SESSION character_set_results = '%s'",
 
1032
                         (const char *) cs_name);
 
1033
 
 
1034
  return mysql_real_query(mysql, query_buffer, query_length);
 
1035
}
 
1036
 
 
1037
/*
 
1038
  Open a new .sql file to dump the table or view into
 
1039
 
 
1040
  SYNOPSIS
 
1041
    open_sql_file_for_table
 
1042
    name      name of the table or view
 
1043
 
 
1044
  RETURN VALUES
 
1045
    0        Failed to open file
 
1046
    > 0      Handle of the open file
 
1047
*/
 
1048
static FILE* open_sql_file_for_table(const char* table)
 
1049
{
 
1050
  FILE* res;
 
1051
  char filename[FN_REFLEN], tmp_path[FN_REFLEN];
 
1052
  convert_dirname(tmp_path,path,NullS);
 
1053
  res= my_fopen(fn_format(filename, table, tmp_path, ".sql", 4),
 
1054
                O_WRONLY, MYF(MY_WME));
 
1055
  return res;
 
1056
}
 
1057
 
 
1058
 
322
1059
static void free_resources(void)
323
1060
{
324
1061
  if (md_result_file && md_result_file != stdout)
325
 
    fclose(md_result_file);
326
 
  opt_password.erase();
 
1062
    my_fclose(md_result_file, MYF(0));
 
1063
  my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR));
 
1064
  if (hash_inited(&ignore_table))
 
1065
    hash_free(&ignore_table);
 
1066
  if (extended_insert)
 
1067
    dynstr_free(&extended_row);
 
1068
  if (insert_pat_inited)
 
1069
    dynstr_free(&insert_pat);
 
1070
  if (defaults_argv)
 
1071
    free_defaults(defaults_argv);
 
1072
  my_end(my_end_arg);
327
1073
}
328
1074
 
329
1075
 
330
 
void maybe_exit(int error)
 
1076
static void maybe_exit(int error)
331
1077
{
332
1078
  if (!first_error)
333
1079
    first_error= error;
334
1080
  if (ignore_errors)
335
1081
    return;
336
 
  delete db_connection;
337
 
  delete destination_connection;
 
1082
  if (mysql)
 
1083
    mysql_close(mysql);
338
1084
  free_resources();
339
1085
  exit(error);
340
1086
}
341
1087
 
 
1088
 
 
1089
/*
 
1090
  db_connect -- connects to the host and selects DB.
 
1091
*/
 
1092
 
 
1093
static int connect_to_db(char *host, char *user,char *passwd)
 
1094
{
 
1095
  char buff[20+FN_REFLEN];
 
1096
 
 
1097
 
 
1098
  verbose_msg("-- Connecting to %s...\n", host ? host : "localhost");
 
1099
  mysql_init(&mysql_connection);
 
1100
  if (opt_compress)
 
1101
    mysql_options(&mysql_connection,MYSQL_OPT_COMPRESS,NullS);
 
1102
  if (opt_protocol)
 
1103
    mysql_options(&mysql_connection,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
 
1104
  mysql_options(&mysql_connection, MYSQL_SET_CHARSET_NAME, default_charset);
 
1105
  if (!(mysql= mysql_real_connect(&mysql_connection,host,user,passwd,
 
1106
                                  NULL,opt_mysql_port, NULL,
 
1107
                                  0)))
 
1108
  {
 
1109
    DB_error(&mysql_connection, "when trying to connect");
 
1110
    return(1);
 
1111
  }
 
1112
  if (mysql_get_server_version(&mysql_connection) < 40100)
 
1113
  {
 
1114
    /* Don't dump SET NAMES with a pre-4.1 server (bug#7997).  */
 
1115
    opt_set_charset= 0;
 
1116
 
 
1117
    /* Don't switch charsets for 4.1 and earlier.  (bug#34192). */
 
1118
    server_supports_switching_charsets= false;
 
1119
  } 
 
1120
  /*
 
1121
    set time_zone to UTC to allow dumping date types between servers with
 
1122
    different time zone settings
 
1123
  */
 
1124
  if (opt_tz_utc)
 
1125
  {
 
1126
    snprintf(buff, sizeof(buff), "/*!40103 SET TIME_ZONE='+00:00' */");
 
1127
    if (mysql_query_with_error_report(mysql, 0, buff))
 
1128
      return(1);
 
1129
  }
 
1130
  return(0);
 
1131
} /* connect_to_db */
 
1132
 
 
1133
 
 
1134
/*
 
1135
** dbDisconnect -- disconnects from the host.
 
1136
*/
 
1137
static void dbDisconnect(char *host)
 
1138
{
 
1139
  verbose_msg("-- Disconnecting from %s...\n", host ? host : "localhost");
 
1140
  mysql_close(mysql);
 
1141
} /* dbDisconnect */
 
1142
 
 
1143
 
 
1144
static void unescape(FILE *file,char *pos,uint length)
 
1145
{
 
1146
  char *tmp;
 
1147
 
 
1148
  if (!(tmp=(char*) my_malloc(length*2+1, MYF(MY_WME))))
 
1149
    die(EX_MYSQLERR, "Couldn't allocate memory");
 
1150
 
 
1151
  mysql_real_escape_string(&mysql_connection, tmp, pos, length);
 
1152
  fputc('\'', file);
 
1153
  fputs(tmp, file);
 
1154
  fputc('\'', file);
 
1155
  check_io(file);
 
1156
  my_free(tmp, MYF(MY_WME));
 
1157
  return;
 
1158
} /* unescape */
 
1159
 
 
1160
 
 
1161
static bool test_if_special_chars(const char *str)
 
1162
{
 
1163
#if MYSQL_VERSION_ID >= 32300
 
1164
  for ( ; *str ; str++)
 
1165
    if (!my_isvar(charset_info,*str) && *str != '$')
 
1166
      return 1;
 
1167
#endif
 
1168
  return 0;
 
1169
} /* test_if_special_chars */
 
1170
 
 
1171
 
 
1172
 
 
1173
/*
 
1174
  quote_name(name, buff, force)
 
1175
 
 
1176
  Quotes char string, taking into account compatible mode
 
1177
 
 
1178
  Args
 
1179
 
 
1180
  name                 Unquoted string containing that which will be quoted
 
1181
  buff                 The buffer that contains the quoted value, also returned
 
1182
  force                Flag to make it ignore 'test_if_special_chars'
 
1183
 
 
1184
  Returns
 
1185
 
 
1186
  buff                 quoted string
 
1187
 
 
1188
*/
 
1189
static char *quote_name(const char *name, char *buff, bool force)
 
1190
{
 
1191
  char *to= buff;
 
1192
  char qtype= (opt_compatible_mode & MASK_ANSI_QUOTES) ? '\"' : '`';
 
1193
 
 
1194
  if (!force && !opt_quoted && !test_if_special_chars(name))
 
1195
    return (char*) name;
 
1196
  *to++= qtype;
 
1197
  while (*name)
 
1198
  {
 
1199
    if (*name == qtype)
 
1200
      *to++= qtype;
 
1201
    *to++= *name++;
 
1202
  }
 
1203
  to[0]= qtype;
 
1204
  to[1]= 0;
 
1205
  return buff;
 
1206
} /* quote_name */
 
1207
 
 
1208
 
 
1209
/*
 
1210
  Quote a table name so it can be used in "SHOW TABLES LIKE <tabname>"
 
1211
 
 
1212
  SYNOPSIS
 
1213
    quote_for_like()
 
1214
    name     name of the table
 
1215
    buff     quoted name of the table
 
1216
 
 
1217
  DESCRIPTION
 
1218
    Quote \, _, ' and % characters
 
1219
 
 
1220
    Note: Because MySQL uses the C escape syntax in strings
 
1221
    (for example, '\n' to represent newline), you must double
 
1222
    any '\' that you use in your LIKE  strings. For example, to
 
1223
    search for '\n', specify it as '\\n'. To search for '\', specify
 
1224
    it as '\\\\' (the backslashes are stripped once by the parser
 
1225
    and another time when the pattern match is done, leaving a
 
1226
    single backslash to be matched).
 
1227
 
 
1228
    Example: "t\1" => "t\\\\1"
 
1229
 
 
1230
*/
 
1231
static char *quote_for_like(const char *name, char *buff)
 
1232
{
 
1233
  char *to= buff;
 
1234
  *to++= '\'';
 
1235
  while (*name)
 
1236
  {
 
1237
    if (*name == '\\')
 
1238
    {
 
1239
      *to++='\\';
 
1240
      *to++='\\';
 
1241
      *to++='\\';
 
1242
    }
 
1243
    else if (*name == '\'' || *name == '_'  || *name == '%')
 
1244
      *to++= '\\';
 
1245
    *to++= *name++;
 
1246
  }
 
1247
  to[0]= '\'';
 
1248
  to[1]= 0;
 
1249
  return buff;
 
1250
}
 
1251
 
 
1252
 
 
1253
/*
 
1254
  Quote and print a string.
 
1255
 
 
1256
  SYNOPSIS
 
1257
    print_quoted_xml()
 
1258
    xml_file    - output file
 
1259
    str         - string to print
 
1260
    len         - its length
 
1261
 
 
1262
  DESCRIPTION
 
1263
    Quote '<' '>' '&' '\"' chars and print a string to the xml_file.
 
1264
*/
 
1265
 
 
1266
static void print_quoted_xml(FILE *xml_file, const char *str, ulong len)
 
1267
{
 
1268
  const char *end;
 
1269
 
 
1270
  for (end= str + len; str != end; str++)
 
1271
  {
 
1272
    switch (*str) {
 
1273
    case '<':
 
1274
      fputs("&lt;", xml_file);
 
1275
      break;
 
1276
    case '>':
 
1277
      fputs("&gt;", xml_file);
 
1278
      break;
 
1279
    case '&':
 
1280
      fputs("&amp;", xml_file);
 
1281
      break;
 
1282
    case '\"':
 
1283
      fputs("&quot;", xml_file);
 
1284
      break;
 
1285
    default:
 
1286
      fputc(*str, xml_file);
 
1287
      break;
 
1288
    }
 
1289
  }
 
1290
  check_io(xml_file);
 
1291
}
 
1292
 
 
1293
 
 
1294
/*
 
1295
  Print xml tag. Optionally add attribute(s).
 
1296
 
 
1297
  SYNOPSIS
 
1298
    print_xml_tag(xml_file, sbeg, send, tag_name, first_attribute_name, 
 
1299
                    ..., attribute_name_n, attribute_value_n, NullS)
 
1300
    xml_file              - output file
 
1301
    sbeg                  - line beginning
 
1302
    line_end              - line ending
 
1303
    tag_name              - XML tag name.
 
1304
    first_attribute_name  - tag and first attribute
 
1305
    first_attribute_value - (Implied) value of first attribute
 
1306
    attribute_name_n      - attribute n
 
1307
    attribute_value_n     - value of attribute n
 
1308
 
 
1309
  DESCRIPTION
 
1310
    Print XML tag with any number of attribute="value" pairs to the xml_file.
 
1311
 
 
1312
    Format is:
 
1313
      sbeg<tag_name first_attribute_name="first_attribute_value" ... 
 
1314
      attribute_name_n="attribute_value_n">send
 
1315
  NOTE
 
1316
    Additional arguments must be present in attribute/value pairs.
 
1317
    The last argument should be the null character pointer.
 
1318
    All attribute_value arguments MUST be NULL terminated strings.
 
1319
    All attribute_value arguments will be quoted before output.
 
1320
*/
 
1321
 
 
1322
static void print_xml_tag(FILE * xml_file, const char* sbeg,
 
1323
                          const char* line_end, 
 
1324
                          const char* tag_name, 
 
1325
                          const char* first_attribute_name, ...)
 
1326
{
 
1327
  va_list arg_list;
 
1328
  const char *attribute_name, *attribute_value;
 
1329
 
 
1330
  fputs(sbeg, xml_file);
 
1331
  fputc('<', xml_file);
 
1332
  fputs(tag_name, xml_file);  
 
1333
 
 
1334
  va_start(arg_list, first_attribute_name);
 
1335
  attribute_name= first_attribute_name;
 
1336
  while (attribute_name != NullS)
 
1337
  {
 
1338
    attribute_value= va_arg(arg_list, char *);
 
1339
    assert(attribute_value != NullS);
 
1340
 
 
1341
    fputc(' ', xml_file);
 
1342
    fputs(attribute_name, xml_file);    
 
1343
    fputc('\"', xml_file);
 
1344
    
 
1345
    print_quoted_xml(xml_file, attribute_value, strlen(attribute_value));
 
1346
    fputc('\"', xml_file);
 
1347
 
 
1348
    attribute_name= va_arg(arg_list, char *);
 
1349
  }
 
1350
  va_end(arg_list);
 
1351
 
 
1352
  fputc('>', xml_file);
 
1353
  fputs(line_end, xml_file);
 
1354
  check_io(xml_file);
 
1355
}
 
1356
 
 
1357
 
 
1358
/*
 
1359
  Print xml tag with for a field that is null
 
1360
 
 
1361
  SYNOPSIS
 
1362
    print_xml_null_tag()
 
1363
    xml_file    - output file
 
1364
    sbeg        - line beginning
 
1365
    stag_atr    - tag and attribute
 
1366
    sval        - value of attribute
 
1367
    line_end        - line ending
 
1368
 
 
1369
  DESCRIPTION
 
1370
    Print tag with one attribute to the xml_file. Format is:
 
1371
      <stag_atr="sval" xsi:nil="true"/>
 
1372
  NOTE
 
1373
    sval MUST be a NULL terminated string.
 
1374
    sval string will be qouted before output.
 
1375
*/
 
1376
 
 
1377
static void print_xml_null_tag(FILE * xml_file, const char* sbeg,
 
1378
                               const char* stag_atr, const char* sval,
 
1379
                               const char* line_end)
 
1380
{
 
1381
  fputs(sbeg, xml_file);
 
1382
  fputs("<", xml_file);
 
1383
  fputs(stag_atr, xml_file);
 
1384
  fputs("\"", xml_file);
 
1385
  print_quoted_xml(xml_file, sval, strlen(sval));
 
1386
  fputs("\" xsi:nil=\"true\" />", xml_file);
 
1387
  fputs(line_end, xml_file);
 
1388
  check_io(xml_file);
 
1389
}
 
1390
 
 
1391
 
 
1392
/*
 
1393
  Print xml tag with many attributes.
 
1394
 
 
1395
  SYNOPSIS
 
1396
    print_xml_row()
 
1397
    xml_file    - output file
 
1398
    row_name    - xml tag name
 
1399
    tableRes    - query result
 
1400
    row         - result row
 
1401
 
 
1402
  DESCRIPTION
 
1403
    Print tag with many attribute to the xml_file. Format is:
 
1404
      \t\t<row_name Atr1="Val1" Atr2="Val2"... />
 
1405
  NOTE
 
1406
    All atributes and values will be quoted before output.
 
1407
*/
 
1408
 
 
1409
static void print_xml_row(FILE *xml_file, const char *row_name,
 
1410
                          MYSQL_RES *tableRes, MYSQL_ROW *row)
 
1411
{
 
1412
  uint i;
 
1413
  MYSQL_FIELD *field;
 
1414
  uint32_t *lengths= mysql_fetch_lengths(tableRes);
 
1415
 
 
1416
  fprintf(xml_file, "\t\t<%s", row_name);
 
1417
  check_io(xml_file);
 
1418
  mysql_field_seek(tableRes, 0);
 
1419
  for (i= 0; (field= mysql_fetch_field(tableRes)); i++)
 
1420
  {
 
1421
    if ((*row)[i])
 
1422
    {
 
1423
      fputc(' ', xml_file);
 
1424
      print_quoted_xml(xml_file, field->name, field->name_length);
 
1425
      fputs("=\"", xml_file);
 
1426
      print_quoted_xml(xml_file, (*row)[i], lengths[i]);
 
1427
      fputc('"', xml_file);
 
1428
      check_io(xml_file);
 
1429
    }
 
1430
  }
 
1431
  fputs(" />\n", xml_file);
 
1432
  check_io(xml_file);
 
1433
}
 
1434
 
 
1435
 
 
1436
/*
 
1437
  Print hex value for blob data.
 
1438
 
 
1439
  SYNOPSIS
 
1440
    print_blob_as_hex()
 
1441
    output_file         - output file
 
1442
    str                 - string to print
 
1443
    len                 - its length
 
1444
 
 
1445
  DESCRIPTION
 
1446
    Print hex value for blob data.
 
1447
*/
 
1448
 
 
1449
static void print_blob_as_hex(FILE *output_file, const char *str, ulong len)
 
1450
{
 
1451
    /* sakaik got the idea to to provide blob's in hex notation. */
 
1452
    const char *ptr= str, *end= ptr + len;
 
1453
    for (; ptr < end ; ptr++)
 
1454
      fprintf(output_file, "%02X", *((uchar *)ptr));
 
1455
    check_io(output_file);
 
1456
}
 
1457
 
 
1458
/*
 
1459
  get_table_structure -- retrievs database structure, prints out corresponding
 
1460
  CREATE statement and fills out insert_pat if the table is the type we will
 
1461
  be dumping.
 
1462
 
 
1463
  ARGS
 
1464
    table       - table name
 
1465
    db          - db name
 
1466
    table_type  - table type, e.g. "MyISAM" or "InnoDB", but also "VIEW"
 
1467
    ignore_flag - what we must particularly ignore - see IGNORE_ defines above
 
1468
 
 
1469
  RETURN
 
1470
    number of fields in table, 0 if error
 
1471
*/
 
1472
 
 
1473
static uint get_table_structure(char *table, char *db, char *table_type,
 
1474
                                char *ignore_flag)
 
1475
{
 
1476
  bool    init=0, delayed, write_data, complete_insert;
 
1477
  uint64_t num_fields;
 
1478
  char       *result_table, *opt_quoted_table;
 
1479
  const char *insert_option;
 
1480
  char       name_buff[NAME_LEN+3],table_buff[NAME_LEN*2+3];
 
1481
  char       table_buff2[NAME_LEN*2+3], query_buff[QUERY_LENGTH];
 
1482
  FILE       *sql_file= md_result_file;
 
1483
  int        len;
 
1484
  MYSQL_RES  *result;
 
1485
  MYSQL_ROW  row;
 
1486
 
 
1487
  *ignore_flag= check_if_ignore_table(table, table_type);
 
1488
 
 
1489
  delayed= opt_delayed;
 
1490
  if (delayed && (*ignore_flag & IGNORE_INSERT_DELAYED))
 
1491
  {
 
1492
    delayed= 0;
 
1493
    verbose_msg("-- Warning: Unable to use delayed inserts for table '%s' "
 
1494
                "because it's of type %s\n", table, table_type);
 
1495
  }
 
1496
 
 
1497
  complete_insert= 0;
 
1498
  if ((write_data= !(*ignore_flag & IGNORE_DATA)))
 
1499
  {
 
1500
    complete_insert= opt_complete_insert;
 
1501
    if (!insert_pat_inited)
 
1502
    {
 
1503
      insert_pat_inited= 1;
 
1504
      init_dynamic_string_checked(&insert_pat, "", 1024, 1024);
 
1505
    }
 
1506
    else
 
1507
      dynstr_set_checked(&insert_pat, "");
 
1508
  }
 
1509
 
 
1510
  insert_option= ((delayed && opt_ignore) ? " DELAYED IGNORE " :
 
1511
                  delayed ? " DELAYED " : opt_ignore ? " IGNORE " : "");
 
1512
 
 
1513
  verbose_msg("-- Retrieving table structure for table %s...\n", table);
 
1514
 
 
1515
  len= snprintf(query_buff, sizeof(query_buff),
 
1516
                "SET OPTION SQL_QUOTE_SHOW_CREATE=%d",
 
1517
                (opt_quoted || opt_keywords));
 
1518
 
 
1519
  result_table=     quote_name(table, table_buff, 1);
 
1520
  opt_quoted_table= quote_name(table, table_buff2, 0);
 
1521
 
 
1522
  if (opt_order_by_primary)
 
1523
  {
 
1524
    my_free(order_by, MYF(MY_ALLOW_ZERO_PTR));
 
1525
    order_by= primary_key_fields(result_table);
 
1526
  }
 
1527
 
 
1528
  if (!opt_xml && !mysql_query_with_error_report(mysql, 0, query_buff))
 
1529
  {
 
1530
    /* using SHOW CREATE statement */
 
1531
    if (!opt_no_create_info)
 
1532
    {
 
1533
      /* Make an sql-file, if path was given iow. option -T was given */
 
1534
      char buff[20+FN_REFLEN];
 
1535
      MYSQL_FIELD *field;
 
1536
 
 
1537
      snprintf(buff, sizeof(buff), "show create table %s", result_table);
 
1538
 
 
1539
      if (switch_character_set_results(mysql, "binary") ||
 
1540
          mysql_query_with_error_report(mysql, &result, buff) ||
 
1541
          switch_character_set_results(mysql, default_charset))
 
1542
        return(0);
 
1543
 
 
1544
      if (path)
 
1545
      {
 
1546
        if (!(sql_file= open_sql_file_for_table(table)))
 
1547
          return(0);
 
1548
 
 
1549
        write_header(sql_file, db);
 
1550
      }
 
1551
      if (!opt_xml && opt_comments)
 
1552
      {
 
1553
      if (strcmp (table_type, "VIEW") == 0)         /* view */
 
1554
        fprintf(sql_file, "\n--\n-- Temporary table structure for view %s\n--\n\n",
 
1555
                result_table);
 
1556
      else
 
1557
        fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n",
 
1558
                result_table);
 
1559
        check_io(sql_file);
 
1560
      }
 
1561
      if (opt_drop)
 
1562
      {
 
1563
      /*
 
1564
        Even if the "table" is a view, we do a DROP TABLE here.  The
 
1565
        view-specific code below fills in the DROP VIEW.
 
1566
       */
 
1567
        fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n",
 
1568
                opt_quoted_table);
 
1569
        check_io(sql_file);
 
1570
      }
 
1571
 
 
1572
      field= mysql_fetch_field_direct(result, 0);
 
1573
      if (strcmp(field->name, "View") == 0)
 
1574
      {
 
1575
        char *scv_buff= NULL;
 
1576
 
 
1577
        verbose_msg("-- It's a view, create dummy table for view\n");
 
1578
 
 
1579
        /* save "show create" statement for later */
 
1580
        if ((row= mysql_fetch_row(result)) && (scv_buff=row[1]))
 
1581
          scv_buff= my_strdup(scv_buff, MYF(0));
 
1582
 
 
1583
        mysql_free_result(result);
 
1584
 
 
1585
        /*
 
1586
          Create a table with the same name as the view and with columns of
 
1587
          the same name in order to satisfy views that depend on this view.
 
1588
          The table will be removed when the actual view is created.
 
1589
 
 
1590
          The properties of each column, aside from the data type, are not
 
1591
          preserved in this temporary table, because they are not necessary.
 
1592
 
 
1593
          This will not be necessary once we can determine dependencies
 
1594
          between views and can simply dump them in the appropriate order.
 
1595
        */
 
1596
        snprintf(query_buff, sizeof(query_buff),
 
1597
                 "SHOW FIELDS FROM %s", result_table);
 
1598
        if (switch_character_set_results(mysql, "binary") ||
 
1599
            mysql_query_with_error_report(mysql, &result, query_buff) ||
 
1600
            switch_character_set_results(mysql, default_charset))
 
1601
        {
 
1602
          /*
 
1603
            View references invalid or privileged table/col/fun (err 1356),
 
1604
            so we cannot create a stand-in table.  Be defensive and dump
 
1605
            a comment with the view's 'show create' statement. (Bug #17371)
 
1606
          */
 
1607
 
 
1608
          if (mysql_errno(mysql) == ER_VIEW_INVALID)
 
1609
            fprintf(sql_file, "\n-- failed on view %s: %s\n\n", result_table, scv_buff ? scv_buff : "");
 
1610
 
 
1611
          my_free(scv_buff, MYF(MY_ALLOW_ZERO_PTR));
 
1612
 
 
1613
          return(0);
 
1614
        }
 
1615
        else
 
1616
          my_free(scv_buff, MYF(MY_ALLOW_ZERO_PTR));
 
1617
 
 
1618
        if (mysql_num_rows(result))
 
1619
        {
 
1620
          if (opt_drop)
 
1621
          {
 
1622
            /*
 
1623
              We have already dropped any table of the same name above, so
 
1624
              here we just drop the view.
 
1625
            */
 
1626
 
 
1627
            fprintf(sql_file, "/*!50001 DROP VIEW IF EXISTS %s*/;\n",
 
1628
                    opt_quoted_table);
 
1629
            check_io(sql_file);
 
1630
          }
 
1631
 
 
1632
          fprintf(sql_file,
 
1633
                  "SET @saved_cs_client     = @@character_set_client;\n"
 
1634
                  "SET character_set_client = utf8;\n"
 
1635
                  "/*!50001 CREATE TABLE %s (\n",
 
1636
                  result_table);
 
1637
 
 
1638
          /*
 
1639
            Get first row, following loop will prepend comma - keeps from
 
1640
            having to know if the row being printed is last to determine if
 
1641
            there should be a _trailing_ comma.
 
1642
          */
 
1643
 
 
1644
          row= mysql_fetch_row(result);
 
1645
 
 
1646
          fprintf(sql_file, "  %s %s", quote_name(row[0], name_buff, 0),
 
1647
                  row[1]);
 
1648
 
 
1649
          while((row= mysql_fetch_row(result)))
 
1650
          {
 
1651
            /* col name, col type */
 
1652
            fprintf(sql_file, ",\n  %s %s",
 
1653
                    quote_name(row[0], name_buff, 0), row[1]);
 
1654
          }
 
1655
          fprintf(sql_file,
 
1656
                  "\n) */;\n"
 
1657
                  "SET character_set_client = @saved_cs_client;\n");
 
1658
 
 
1659
          check_io(sql_file);
 
1660
        }
 
1661
 
 
1662
        mysql_free_result(result);
 
1663
 
 
1664
        if (path)
 
1665
          my_fclose(sql_file, MYF(MY_WME));
 
1666
 
 
1667
        seen_views= 1;
 
1668
        return(0);
 
1669
      }
 
1670
 
 
1671
      row= mysql_fetch_row(result);
 
1672
 
 
1673
      fprintf(sql_file,
 
1674
              "SET @saved_cs_client     = @@character_set_client;\n"
 
1675
              "SET character_set_client = utf8;\n"
 
1676
              "%s;\n"
 
1677
              "SET character_set_client = @saved_cs_client;\n",
 
1678
              row[1]);
 
1679
 
 
1680
      check_io(sql_file);
 
1681
      mysql_free_result(result);
 
1682
    }
 
1683
    snprintf(query_buff, sizeof(query_buff), "show fields from %s",
 
1684
             result_table);
 
1685
    if (mysql_query_with_error_report(mysql, &result, query_buff))
 
1686
    {
 
1687
      if (path)
 
1688
        my_fclose(sql_file, MYF(MY_WME));
 
1689
      return(0);
 
1690
    }
 
1691
 
 
1692
    /*
 
1693
      If write_data is true, then we build up insert statements for
 
1694
      the table's data. Note: in subsequent lines of code, this test
 
1695
      will have to be performed each time we are appending to
 
1696
      insert_pat.
 
1697
    */
 
1698
    if (write_data)
 
1699
    {
 
1700
      if (opt_replace_into)
 
1701
        dynstr_append_checked(&insert_pat, "REPLACE ");
 
1702
      else
 
1703
        dynstr_append_checked(&insert_pat, "INSERT ");
 
1704
      dynstr_append_checked(&insert_pat, insert_option);
 
1705
      dynstr_append_checked(&insert_pat, "INTO ");
 
1706
      dynstr_append_checked(&insert_pat, opt_quoted_table);
 
1707
      if (complete_insert)
 
1708
      {
 
1709
        dynstr_append_checked(&insert_pat, " (");
 
1710
      }
 
1711
      else
 
1712
      {
 
1713
        dynstr_append_checked(&insert_pat, " VALUES ");
 
1714
        if (!extended_insert)
 
1715
          dynstr_append_checked(&insert_pat, "(");
 
1716
      }
 
1717
    }
 
1718
 
 
1719
    while ((row= mysql_fetch_row(result)))
 
1720
    {
 
1721
      if (complete_insert)
 
1722
      {
 
1723
        if (init)
 
1724
        {
 
1725
          dynstr_append_checked(&insert_pat, ", ");
 
1726
        }
 
1727
        init=1;
 
1728
        dynstr_append_checked(&insert_pat,
 
1729
                      quote_name(row[SHOW_FIELDNAME], name_buff, 0));
 
1730
      }
 
1731
    }
 
1732
    num_fields= mysql_num_rows(result);
 
1733
    mysql_free_result(result);
 
1734
  }
 
1735
  else
 
1736
  {
 
1737
    verbose_msg("%s: Warning: Can't set SQL_QUOTE_SHOW_CREATE option (%s)\n",
 
1738
                my_progname, mysql_error(mysql));
 
1739
 
 
1740
    snprintf(query_buff, sizeof(query_buff), "show fields from %s",
 
1741
             result_table);
 
1742
    if (mysql_query_with_error_report(mysql, &result, query_buff))
 
1743
      return(0);
 
1744
 
 
1745
    /* Make an sql-file, if path was given iow. option -T was given */
 
1746
    if (!opt_no_create_info)
 
1747
    {
 
1748
      if (path)
 
1749
      {
 
1750
        if (!(sql_file= open_sql_file_for_table(table)))
 
1751
          return(0);
 
1752
        write_header(sql_file, db);
 
1753
      }
 
1754
      if (!opt_xml && opt_comments)
 
1755
        fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n",
 
1756
                result_table);
 
1757
      if (opt_drop)
 
1758
        fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", result_table);
 
1759
      if (!opt_xml)
 
1760
        fprintf(sql_file, "CREATE TABLE %s (\n", result_table);
 
1761
      else
 
1762
        print_xml_tag(sql_file, "\t", "\n", "table_structure", "name=", table, 
 
1763
                NullS);
 
1764
      check_io(sql_file);
 
1765
    }
 
1766
 
 
1767
    if (write_data)
 
1768
    {
 
1769
      if (opt_replace_into)
 
1770
        dynstr_append_checked(&insert_pat, "REPLACE ");
 
1771
      else
 
1772
        dynstr_append_checked(&insert_pat, "INSERT ");
 
1773
      dynstr_append_checked(&insert_pat, insert_option);
 
1774
      dynstr_append_checked(&insert_pat, "INTO ");
 
1775
      dynstr_append_checked(&insert_pat, result_table);
 
1776
      if (complete_insert)
 
1777
        dynstr_append_checked(&insert_pat, " (");
 
1778
      else
 
1779
      {
 
1780
        dynstr_append_checked(&insert_pat, " VALUES ");
 
1781
        if (!extended_insert)
 
1782
          dynstr_append_checked(&insert_pat, "(");
 
1783
      }
 
1784
    }
 
1785
 
 
1786
    while ((row= mysql_fetch_row(result)))
 
1787
    {
 
1788
      uint32_t *lengths= mysql_fetch_lengths(result);
 
1789
      if (init)
 
1790
      {
 
1791
        if (!opt_xml && !opt_no_create_info)
 
1792
        {
 
1793
          fputs(",\n",sql_file);
 
1794
          check_io(sql_file);
 
1795
        }
 
1796
        if (complete_insert)
 
1797
          dynstr_append_checked(&insert_pat, ", ");
 
1798
      }
 
1799
      init=1;
 
1800
      if (complete_insert)
 
1801
        dynstr_append_checked(&insert_pat,
 
1802
                      quote_name(row[SHOW_FIELDNAME], name_buff, 0));
 
1803
      if (!opt_no_create_info)
 
1804
      {
 
1805
        if (opt_xml)
 
1806
        {
 
1807
          print_xml_row(sql_file, "field", result, &row);
 
1808
          continue;
 
1809
        }
 
1810
 
 
1811
        if (opt_keywords)
 
1812
          fprintf(sql_file, "  %s.%s %s", result_table,
 
1813
                  quote_name(row[SHOW_FIELDNAME],name_buff, 0),
 
1814
                  row[SHOW_TYPE]);
 
1815
        else
 
1816
          fprintf(sql_file, "  %s %s", quote_name(row[SHOW_FIELDNAME],
 
1817
                                                  name_buff, 0),
 
1818
                  row[SHOW_TYPE]);
 
1819
        if (row[SHOW_DEFAULT])
 
1820
        {
 
1821
          fputs(" DEFAULT ", sql_file);
 
1822
          unescape(sql_file, row[SHOW_DEFAULT], lengths[SHOW_DEFAULT]);
 
1823
        }
 
1824
        if (!row[SHOW_NULL][0])
 
1825
          fputs(" NOT NULL", sql_file);
 
1826
        if (row[SHOW_EXTRA][0])
 
1827
          fprintf(sql_file, " %s",row[SHOW_EXTRA]);
 
1828
        check_io(sql_file);
 
1829
      }
 
1830
    }
 
1831
    num_fields= mysql_num_rows(result);
 
1832
    mysql_free_result(result);
 
1833
    if (!opt_no_create_info)
 
1834
    {
 
1835
      /* Make an sql-file, if path was given iow. option -T was given */
 
1836
      char buff[20+FN_REFLEN];
 
1837
      uint keynr,primary_key;
 
1838
      snprintf(buff, sizeof(buff), "show keys from %s", result_table);
 
1839
      if (mysql_query_with_error_report(mysql, &result, buff))
 
1840
      {
 
1841
        if (mysql_errno(mysql) == ER_WRONG_OBJECT)
 
1842
        {
 
1843
          /* it is VIEW */
 
1844
          fputs("\t\t<options Comment=\"view\" />\n", sql_file);
 
1845
          goto continue_xml;
 
1846
        }
 
1847
        fprintf(stderr, "%s: Can't get keys for table %s (%s)\n",
 
1848
                my_progname, result_table, mysql_error(mysql));
 
1849
        if (path)
 
1850
          my_fclose(sql_file, MYF(MY_WME));
 
1851
        return(0);
 
1852
      }
 
1853
 
 
1854
      /* Find first which key is primary key */
 
1855
      keynr=0;
 
1856
      primary_key=INT_MAX;
 
1857
      while ((row= mysql_fetch_row(result)))
 
1858
      {
 
1859
        if (atoi(row[3]) == 1)
 
1860
        {
 
1861
          keynr++;
 
1862
#ifdef FORCE_PRIMARY_KEY
 
1863
          if (atoi(row[1]) == 0 && primary_key == INT_MAX)
 
1864
            primary_key=keynr;
 
1865
#endif
 
1866
          if (!strcmp(row[2],"PRIMARY"))
 
1867
          {
 
1868
            primary_key=keynr;
 
1869
            break;
 
1870
          }
 
1871
        }
 
1872
      }
 
1873
      mysql_data_seek(result,0);
 
1874
      keynr=0;
 
1875
      while ((row= mysql_fetch_row(result)))
 
1876
      {
 
1877
        if (opt_xml)
 
1878
        {
 
1879
          print_xml_row(sql_file, "key", result, &row);
 
1880
          continue;
 
1881
        }
 
1882
 
 
1883
        if (atoi(row[3]) == 1)
 
1884
        {
 
1885
          if (keynr++)
 
1886
            putc(')', sql_file);
 
1887
          if (atoi(row[1]))       /* Test if duplicate key */
 
1888
            /* Duplicate allowed */
 
1889
            fprintf(sql_file, ",\n  KEY %s (",quote_name(row[2],name_buff,0));
 
1890
          else if (keynr == primary_key)
 
1891
            fputs(",\n  PRIMARY KEY (",sql_file); /* First UNIQUE is primary */
 
1892
          else
 
1893
            fprintf(sql_file, ",\n  UNIQUE %s (",quote_name(row[2],name_buff,
 
1894
                                                            0));
 
1895
        }
 
1896
        else
 
1897
          putc(',', sql_file);
 
1898
        fputs(quote_name(row[4], name_buff, 0), sql_file);
 
1899
        if (row[7])
 
1900
          fprintf(sql_file, " (%s)",row[7]);      /* Sub key */
 
1901
        check_io(sql_file);
 
1902
      }
 
1903
      mysql_free_result(result);
 
1904
      if (!opt_xml)
 
1905
      {
 
1906
        if (keynr)
 
1907
          putc(')', sql_file);
 
1908
        fputs("\n)",sql_file);
 
1909
        check_io(sql_file);
 
1910
      }
 
1911
 
 
1912
      /* Get MySQL specific create options */
 
1913
      if (create_options)
 
1914
      {
 
1915
        char show_name_buff[NAME_LEN*2+2+24];
 
1916
 
 
1917
        /* Check memory for quote_for_like() */
 
1918
        snprintf(buff, sizeof(buff), "show table status like %s",
 
1919
                 quote_for_like(table, show_name_buff));
 
1920
 
 
1921
        if (mysql_query_with_error_report(mysql, &result, buff))
 
1922
        {
 
1923
          if (mysql_errno(mysql) != ER_PARSE_ERROR)
 
1924
          {                                     /* If old MySQL version */
 
1925
            verbose_msg("-- Warning: Couldn't get status information for " \
 
1926
                        "table %s (%s)\n", result_table,mysql_error(mysql));
 
1927
          }
 
1928
        }
 
1929
        else if (!(row= mysql_fetch_row(result)))
 
1930
        {
 
1931
          fprintf(stderr,
 
1932
                  "Error: Couldn't read status information for table %s (%s)\n",
 
1933
                  result_table,mysql_error(mysql));
 
1934
        }
 
1935
        else
 
1936
        {
 
1937
          if (opt_xml)
 
1938
            print_xml_row(sql_file, "options", result, &row);
 
1939
          else
 
1940
          {
 
1941
            fputs("/*!",sql_file);
 
1942
            print_value(sql_file,result,row,"engine=","Engine",0);
 
1943
            print_value(sql_file,result,row,"","Create_options",0);
 
1944
            print_value(sql_file,result,row,"comment=","Comment",1);
 
1945
            fputs(" */",sql_file);
 
1946
            check_io(sql_file);
 
1947
          }
 
1948
        }
 
1949
        mysql_free_result(result);              /* Is always safe to free */
 
1950
      }
 
1951
continue_xml:
 
1952
      if (!opt_xml)
 
1953
        fputs(";\n", sql_file);
 
1954
      else
 
1955
        fputs("\t</table_structure>\n", sql_file);
 
1956
      check_io(sql_file);
 
1957
    }
 
1958
  }
 
1959
  if (complete_insert)
 
1960
  {
 
1961
    dynstr_append_checked(&insert_pat, ") VALUES ");
 
1962
    if (!extended_insert)
 
1963
      dynstr_append_checked(&insert_pat, "(");
 
1964
  }
 
1965
  if (sql_file != md_result_file)
 
1966
  {
 
1967
    fputs("\n", sql_file);
 
1968
    write_footer(sql_file);
 
1969
    my_fclose(sql_file, MYF(MY_WME));
 
1970
  }
 
1971
  return((uint) num_fields);
 
1972
} /* get_table_structure */
 
1973
 
 
1974
static void add_load_option(DYNAMIC_STRING *str, const char *option,
 
1975
                             const char *option_value)
 
1976
{
 
1977
  if (!option_value)
 
1978
  {
 
1979
    /* Null value means we don't add this option. */
 
1980
    return;
 
1981
  }
 
1982
 
 
1983
  dynstr_append_checked(str, option);
 
1984
  
 
1985
  if (strncmp(option_value, "0x", sizeof("0x")-1) == 0)
 
1986
  {
 
1987
    /* It's a hex constant, don't escape */
 
1988
    dynstr_append_checked(str, option_value);
 
1989
  }
 
1990
  else
 
1991
  {
 
1992
    /* char constant; escape */
 
1993
    field_escape(str, option_value);
 
1994
  }
 
1995
}
 
1996
 
 
1997
 
 
1998
/*
 
1999
  Allow the user to specify field terminator strings like:
 
2000
  "'", "\", "\\" (escaped backslash), "\t" (tab), "\n" (newline)
 
2001
  This is done by doubling ' and add a end -\ if needed to avoid
 
2002
  syntax errors from the SQL parser.
 
2003
*/
 
2004
 
 
2005
static void field_escape(DYNAMIC_STRING* in, const char *from)
 
2006
{
 
2007
  uint end_backslashes= 0; 
 
2008
 
 
2009
  dynstr_append_checked(in, "'");
 
2010
 
 
2011
  while (*from)
 
2012
  {
 
2013
    dynstr_append_mem_checked(in, from, 1);
 
2014
 
 
2015
    if (*from == '\\')
 
2016
      end_backslashes^=1;    /* find odd number of backslashes */
 
2017
    else
 
2018
    {
 
2019
      if (*from == '\'' && !end_backslashes)
 
2020
      {
 
2021
        /* We want a duplicate of "'" for MySQL */
 
2022
        dynstr_append_checked(in, "\'");
 
2023
      }
 
2024
      end_backslashes=0;
 
2025
    }
 
2026
    from++;
 
2027
  }
 
2028
  /* Add missing backslashes if user has specified odd number of backs.*/
 
2029
  if (end_backslashes)
 
2030
    dynstr_append_checked(in, "\\");
 
2031
  
 
2032
  dynstr_append_checked(in, "'");
 
2033
}
 
2034
 
 
2035
 
 
2036
 
 
2037
/*
 
2038
 
 
2039
 SYNOPSIS
 
2040
  dump_table()
 
2041
 
 
2042
  dump_table saves database contents as a series of INSERT statements.
 
2043
 
 
2044
  ARGS
 
2045
   table - table name
 
2046
   db    - db name
 
2047
 
 
2048
   RETURNS
 
2049
    void
 
2050
*/
 
2051
 
 
2052
 
 
2053
static void dump_table(char *table, char *db)
 
2054
{
 
2055
  char ignore_flag;
 
2056
  char buf[200], table_buff[NAME_LEN+3];
 
2057
  DYNAMIC_STRING query_string;
 
2058
  char table_type[NAME_LEN];
 
2059
  char *result_table, table_buff2[NAME_LEN*2+3], *opt_quoted_table;
 
2060
  int error= 0;
 
2061
  ulong         rownr, row_break, total_length, init_length;
 
2062
  uint num_fields;
 
2063
  MYSQL_RES     *res;
 
2064
  MYSQL_FIELD   *field;
 
2065
  MYSQL_ROW     row;
 
2066
 
 
2067
 
 
2068
  /*
 
2069
    Make sure you get the create table info before the following check for
 
2070
    --no-data flag below. Otherwise, the create table info won't be printed.
 
2071
  */
 
2072
  num_fields= get_table_structure(table, db, table_type, &ignore_flag);
 
2073
 
 
2074
  /*
 
2075
    The "table" could be a view.  If so, we don't do anything here.
 
2076
  */
 
2077
  if (strcmp(table_type, "VIEW") == 0)
 
2078
    return;
 
2079
 
 
2080
  /* Check --no-data flag */
 
2081
  if (opt_no_data)
 
2082
  {
 
2083
    verbose_msg("-- Skipping dump data for table '%s', --no-data was used\n",
 
2084
                table);
 
2085
    return;
 
2086
  }
 
2087
 
 
2088
  /*
 
2089
    If the table type is a merge table or any type that has to be
 
2090
     _completely_ ignored and no data dumped
 
2091
  */
 
2092
  if (ignore_flag & IGNORE_DATA)
 
2093
  {
 
2094
    verbose_msg("-- Warning: Skipping data for table '%s' because " \
 
2095
                "it's of type %s\n", table, table_type);
 
2096
    return;
 
2097
  }
 
2098
  /* Check that there are any fields in the table */
 
2099
  if (num_fields == 0)
 
2100
  {
 
2101
    verbose_msg("-- Skipping dump data for table '%s', it has no fields\n",
 
2102
                table);
 
2103
    return;
 
2104
  }
 
2105
 
 
2106
  /*
 
2107
     Check --skip-events flag: it is not enough to skip creation of events
 
2108
     discarding SHOW CREATE EVENT statements generation. The myslq.event
 
2109
     table data should be skipped too.
 
2110
  */
 
2111
  if (!opt_events && !my_strcasecmp(&my_charset_latin1, db, "mysql") &&
 
2112
      !my_strcasecmp(&my_charset_latin1, table, "event"))
 
2113
  {
 
2114
    verbose_msg("-- Skipping data table mysql.event, --skip-events was used\n");
 
2115
    return;
 
2116
  }
 
2117
 
 
2118
  result_table= quote_name(table,table_buff, 1);
 
2119
  opt_quoted_table= quote_name(table, table_buff2, 0);
 
2120
 
 
2121
  verbose_msg("-- Sending SELECT query...\n");
 
2122
 
 
2123
  init_dynamic_string_checked(&query_string, "", 1024, 1024);
 
2124
 
 
2125
  if (path)
 
2126
  {
 
2127
    char filename[FN_REFLEN], tmp_path[FN_REFLEN];
 
2128
 
 
2129
    /*
 
2130
      Convert the path to native os format
 
2131
      and resolve to the full filepath.
 
2132
    */
 
2133
    convert_dirname(tmp_path,path,NullS);    
 
2134
    my_load_path(tmp_path, tmp_path, NULL);
 
2135
    fn_format(filename, table, tmp_path, ".txt", MYF(MY_UNPACK_FILENAME));
 
2136
 
 
2137
    /* Must delete the file that 'INTO OUTFILE' will write to */
 
2138
    my_delete(filename, MYF(0));
 
2139
 
 
2140
    /* convert to a unix path name to stick into the query */
 
2141
    to_unix_path(filename);
 
2142
 
 
2143
    /* now build the query string */
 
2144
 
 
2145
    dynstr_append_checked(&query_string, "SELECT * INTO OUTFILE '");
 
2146
    dynstr_append_checked(&query_string, filename);
 
2147
    dynstr_append_checked(&query_string, "'");
 
2148
 
 
2149
    if (fields_terminated || enclosed || opt_enclosed || escaped)
 
2150
      dynstr_append_checked(&query_string, " FIELDS");
 
2151
    
 
2152
    add_load_option(&query_string, " TERMINATED BY ", fields_terminated);
 
2153
    add_load_option(&query_string, " ENCLOSED BY ", enclosed);
 
2154
    add_load_option(&query_string, " OPTIONALLY ENCLOSED BY ", opt_enclosed);
 
2155
    add_load_option(&query_string, " ESCAPED BY ", escaped);
 
2156
    add_load_option(&query_string, " LINES TERMINATED BY ", lines_terminated);
 
2157
 
 
2158
    dynstr_append_checked(&query_string, " FROM ");
 
2159
    dynstr_append_checked(&query_string, result_table);
 
2160
 
 
2161
    if (where)
 
2162
    {
 
2163
      dynstr_append_checked(&query_string, " WHERE ");
 
2164
      dynstr_append_checked(&query_string, where);
 
2165
    }
 
2166
 
 
2167
    if (order_by)
 
2168
    {
 
2169
      dynstr_append_checked(&query_string, " ORDER BY ");
 
2170
      dynstr_append_checked(&query_string, order_by);
 
2171
    }
 
2172
 
 
2173
    if (mysql_real_query(mysql, query_string.str, query_string.length))
 
2174
    {
 
2175
      DB_error(mysql, "when executing 'SELECT INTO OUTFILE'");
 
2176
      dynstr_free(&query_string);
 
2177
      return;
 
2178
    }
 
2179
  }
 
2180
  else
 
2181
  {
 
2182
    if (!opt_xml && opt_comments)
 
2183
    {
 
2184
      fprintf(md_result_file,"\n--\n-- Dumping data for table %s\n--\n",
 
2185
              result_table);
 
2186
      check_io(md_result_file);
 
2187
    }
 
2188
    
 
2189
    dynstr_append_checked(&query_string, "SELECT * FROM ");
 
2190
    dynstr_append_checked(&query_string, result_table);
 
2191
 
 
2192
    if (where)
 
2193
    {
 
2194
      if (!opt_xml && opt_comments)
 
2195
      {
 
2196
        fprintf(md_result_file, "-- WHERE:  %s\n", where);
 
2197
        check_io(md_result_file);
 
2198
      }
 
2199
      
 
2200
      dynstr_append_checked(&query_string, " WHERE ");
 
2201
      dynstr_append_checked(&query_string, where);
 
2202
    }
 
2203
    if (order_by)
 
2204
    {
 
2205
      if (!opt_xml && opt_comments)
 
2206
      {
 
2207
        fprintf(md_result_file, "-- ORDER BY:  %s\n", order_by);
 
2208
        check_io(md_result_file);
 
2209
      }
 
2210
      dynstr_append_checked(&query_string, " ORDER BY ");
 
2211
      dynstr_append_checked(&query_string, order_by);
 
2212
    }
 
2213
 
 
2214
    if (!opt_xml && !opt_compact)
 
2215
    {
 
2216
      fputs("\n", md_result_file);
 
2217
      check_io(md_result_file);
 
2218
    }
 
2219
    if (mysql_query_with_error_report(mysql, 0, query_string.str))
 
2220
    {
 
2221
      DB_error(mysql, "when retrieving data from server");
 
2222
      goto err;
 
2223
    }
 
2224
    if (quick)
 
2225
      res=mysql_use_result(mysql);
 
2226
    else
 
2227
      res=mysql_store_result(mysql);
 
2228
    if (!res)
 
2229
    {
 
2230
      DB_error(mysql, "when retrieving data from server");
 
2231
      goto err;
 
2232
    }
 
2233
 
 
2234
    verbose_msg("-- Retrieving rows...\n");
 
2235
    if (mysql_num_fields(res) != num_fields)
 
2236
    {
 
2237
      fprintf(stderr,"%s: Error in field count for table: %s !  Aborting.\n",
 
2238
              my_progname, result_table);
 
2239
      error= EX_CONSCHECK;
 
2240
      goto err;
 
2241
    }
 
2242
 
 
2243
    if (opt_lock)
 
2244
    {
 
2245
      fprintf(md_result_file,"LOCK TABLES %s WRITE;\n", opt_quoted_table);
 
2246
      check_io(md_result_file);
 
2247
    }
 
2248
    /* Moved disable keys to after lock per bug 15977 */
 
2249
    if (opt_disable_keys)
 
2250
    {
 
2251
      fprintf(md_result_file, "/*!40000 ALTER TABLE %s DISABLE KEYS */;\n",
 
2252
              opt_quoted_table);
 
2253
      check_io(md_result_file);
 
2254
    }
 
2255
 
 
2256
    total_length= opt_net_buffer_length;                /* Force row break */
 
2257
    row_break=0;
 
2258
    rownr=0;
 
2259
    init_length=(uint) insert_pat.length+4;
 
2260
    if (opt_xml)
 
2261
      print_xml_tag(md_result_file, "\t", "\n", "table_data", "name=", table,
 
2262
              NullS);
 
2263
    if (opt_autocommit)
 
2264
    {
 
2265
      fprintf(md_result_file, "set autocommit=0;\n");
 
2266
      check_io(md_result_file);
 
2267
    }
 
2268
 
 
2269
    while ((row= mysql_fetch_row(res)))
 
2270
    {
 
2271
      uint i;
 
2272
      uint32_t *lengths= mysql_fetch_lengths(res);
 
2273
      rownr++;
 
2274
      if (!extended_insert && !opt_xml)
 
2275
      {
 
2276
        fputs(insert_pat.str,md_result_file);
 
2277
        check_io(md_result_file);
 
2278
      }
 
2279
      mysql_field_seek(res,0);
 
2280
 
 
2281
      if (opt_xml)
 
2282
      {
 
2283
        fputs("\t<row>\n", md_result_file);
 
2284
        check_io(md_result_file);
 
2285
      }
 
2286
 
 
2287
      for (i= 0; i < mysql_num_fields(res); i++)
 
2288
      {
 
2289
        int is_blob;
 
2290
        ulong length= lengths[i];
 
2291
 
 
2292
        if (!(field= mysql_fetch_field(res)))
 
2293
          die(EX_CONSCHECK,
 
2294
                      "Not enough fields from table %s! Aborting.\n",
 
2295
                      result_table);
 
2296
 
 
2297
        /*
 
2298
           63 is my_charset_bin. If charsetnr is not 63,
 
2299
           we have not a BLOB but a TEXT column.
 
2300
           we'll dump in hex only BLOB columns.
 
2301
        */
 
2302
        is_blob= (opt_hex_blob && field->charsetnr == 63 &&
 
2303
                  (field->type == MYSQL_TYPE_STRING ||
 
2304
                   field->type == MYSQL_TYPE_VARCHAR ||
 
2305
                   field->type == MYSQL_TYPE_BLOB)) ? 1 : 0;
 
2306
        if (extended_insert && !opt_xml)
 
2307
        {
 
2308
          if (i == 0)
 
2309
            dynstr_set_checked(&extended_row,"(");
 
2310
          else
 
2311
            dynstr_append_checked(&extended_row,",");
 
2312
 
 
2313
          if (row[i])
 
2314
          {
 
2315
            if (length)
 
2316
            {
 
2317
              if (!IS_NUM_FIELD(field))
 
2318
              {
 
2319
                /*
 
2320
                  "length * 2 + 2" is OK for both HEX and non-HEX modes:
 
2321
                  - In HEX mode we need exactly 2 bytes per character
 
2322
                  plus 2 bytes for '0x' prefix.
 
2323
                  - In non-HEX mode we need up to 2 bytes per character,
 
2324
                  plus 2 bytes for leading and trailing '\'' characters.
 
2325
                  Also we need to reserve 1 byte for terminating '\0'.
 
2326
                */
 
2327
                dynstr_realloc_checked(&extended_row,length * 2 + 2 + 1);
 
2328
                if (opt_hex_blob && is_blob)
 
2329
                {
 
2330
                  dynstr_append_checked(&extended_row, "0x");
 
2331
                  extended_row.length+= mysql_hex_string(extended_row.str +
 
2332
                                                         extended_row.length,
 
2333
                                                         row[i], length);
 
2334
                  assert(extended_row.length+1 <= extended_row.max_length);
 
2335
                  /* mysql_hex_string() already terminated string by '\0' */
 
2336
                  assert(extended_row.str[extended_row.length] == '\0');
 
2337
                }
 
2338
                else
 
2339
                {
 
2340
                  dynstr_append_checked(&extended_row,"'");
 
2341
                  extended_row.length +=
 
2342
                  mysql_real_escape_string(&mysql_connection,
 
2343
                                           &extended_row.str[extended_row.length],
 
2344
                                           row[i],length);
 
2345
                  extended_row.str[extended_row.length]='\0';
 
2346
                  dynstr_append_checked(&extended_row,"'");
 
2347
                }
 
2348
              }
 
2349
              else
 
2350
              {
 
2351
                /* change any strings ("inf", "-inf", "nan") into NULL */
 
2352
                char *ptr= row[i];
 
2353
                if (my_isalpha(charset_info, *ptr) || (*ptr == '-' &&
 
2354
                    my_isalpha(charset_info, ptr[1])))
 
2355
                  dynstr_append_checked(&extended_row, "NULL");
 
2356
                else
 
2357
                {
 
2358
                  dynstr_append_checked(&extended_row, ptr);
 
2359
                }
 
2360
              }
 
2361
            }
 
2362
            else
 
2363
              dynstr_append_checked(&extended_row,"''");
 
2364
          }
 
2365
          else
 
2366
            dynstr_append_checked(&extended_row,"NULL");
 
2367
        }
 
2368
        else
 
2369
        {
 
2370
          if (i && !opt_xml)
 
2371
          {
 
2372
            fputc(',', md_result_file);
 
2373
            check_io(md_result_file);
 
2374
          }
 
2375
          if (row[i])
 
2376
          {
 
2377
            if (!IS_NUM_FIELD(field))
 
2378
            {
 
2379
              if (opt_xml)
 
2380
              {
 
2381
                if (opt_hex_blob && is_blob && length)
 
2382
                {
 
2383
                  /* Define xsi:type="xs:hexBinary" for hex encoded data */
 
2384
                  print_xml_tag(md_result_file, "\t\t", "", "field", "name=",
 
2385
                                field->name, "xsi:type=", "xs:hexBinary", NullS);
 
2386
                  print_blob_as_hex(md_result_file, row[i], length);
 
2387
                }
 
2388
                else
 
2389
                {
 
2390
                  print_xml_tag(md_result_file, "\t\t", "", "field", "name=", 
 
2391
                                field->name, NullS);
 
2392
                  print_quoted_xml(md_result_file, row[i], length);
 
2393
                }
 
2394
                fputs("</field>\n", md_result_file);
 
2395
              }
 
2396
              else if (opt_hex_blob && is_blob && length)
 
2397
              {
 
2398
                fputs("0x", md_result_file);
 
2399
                print_blob_as_hex(md_result_file, row[i], length);
 
2400
              }
 
2401
              else
 
2402
                unescape(md_result_file, row[i], length);
 
2403
            }
 
2404
            else
 
2405
            {
 
2406
              /* change any strings ("inf", "-inf", "nan") into NULL */
 
2407
              char *ptr= row[i];
 
2408
              if (opt_xml)
 
2409
              {
 
2410
                print_xml_tag(md_result_file, "\t\t", "", "field", "name=",
 
2411
                        field->name, NullS);
 
2412
                fputs(!my_isalpha(charset_info, *ptr) ? ptr: "NULL",
 
2413
                      md_result_file);
 
2414
                fputs("</field>\n", md_result_file);
 
2415
              }
 
2416
              else if (my_isalpha(charset_info, *ptr) ||
 
2417
                       (*ptr == '-' && my_isalpha(charset_info, ptr[1])))
 
2418
                fputs("NULL", md_result_file);
 
2419
              else
 
2420
                fputs(ptr, md_result_file);
 
2421
            }
 
2422
          }
 
2423
          else
 
2424
          {
 
2425
            /* The field value is NULL */
 
2426
            if (!opt_xml)
 
2427
              fputs("NULL", md_result_file);
 
2428
            else
 
2429
              print_xml_null_tag(md_result_file, "\t\t", "field name=",
 
2430
                                 field->name, "\n");
 
2431
          }
 
2432
          check_io(md_result_file);
 
2433
        }
 
2434
      }
 
2435
 
 
2436
      if (opt_xml)
 
2437
      {
 
2438
        fputs("\t</row>\n", md_result_file);
 
2439
        check_io(md_result_file);
 
2440
      }
 
2441
 
 
2442
      if (extended_insert)
 
2443
      {
 
2444
        ulong row_length;
 
2445
        dynstr_append_checked(&extended_row,")");
 
2446
        row_length= 2 + extended_row.length;
 
2447
        if (total_length + row_length < opt_net_buffer_length)
 
2448
        {
 
2449
          total_length+= row_length;
 
2450
          fputc(',',md_result_file);            /* Always row break */
 
2451
          fputs(extended_row.str,md_result_file);
 
2452
        }
 
2453
        else
 
2454
        {
 
2455
          if (row_break)
 
2456
            fputs(";\n", md_result_file);
 
2457
          row_break=1;                          /* This is first row */
 
2458
 
 
2459
          fputs(insert_pat.str,md_result_file);
 
2460
          fputs(extended_row.str,md_result_file);
 
2461
          total_length= row_length+init_length;
 
2462
        }
 
2463
        check_io(md_result_file);
 
2464
      }
 
2465
      else if (!opt_xml)
 
2466
      {
 
2467
        fputs(");\n", md_result_file);
 
2468
        check_io(md_result_file);
 
2469
      }
 
2470
    }
 
2471
 
 
2472
    /* XML - close table tag and supress regular output */
 
2473
    if (opt_xml)
 
2474
        fputs("\t</table_data>\n", md_result_file);
 
2475
    else if (extended_insert && row_break)
 
2476
      fputs(";\n", md_result_file);             /* If not empty table */
 
2477
    fflush(md_result_file);
 
2478
    check_io(md_result_file);
 
2479
    if (mysql_errno(mysql))
 
2480
    {
 
2481
      snprintf(buf, sizeof(buf),
 
2482
               "%s: Error %d: %s when dumping table %s at row: %ld\n",
 
2483
               my_progname,
 
2484
               mysql_errno(mysql),
 
2485
               mysql_error(mysql),
 
2486
               result_table,
 
2487
               rownr);
 
2488
      fputs(buf,stderr);
 
2489
      error= EX_CONSCHECK;
 
2490
      goto err;
 
2491
    }
 
2492
 
 
2493
    /* Moved enable keys to before unlock per bug 15977 */
 
2494
    if (opt_disable_keys)
 
2495
    {
 
2496
      fprintf(md_result_file,"/*!40000 ALTER TABLE %s ENABLE KEYS */;\n",
 
2497
              opt_quoted_table);
 
2498
      check_io(md_result_file);
 
2499
    }
 
2500
    if (opt_lock)
 
2501
    {
 
2502
      fputs("UNLOCK TABLES;\n", md_result_file);
 
2503
      check_io(md_result_file);
 
2504
    }
 
2505
    if (opt_autocommit)
 
2506
    {
 
2507
      fprintf(md_result_file, "commit;\n");
 
2508
      check_io(md_result_file);
 
2509
    }
 
2510
    mysql_free_result(res);
 
2511
  }
 
2512
  dynstr_free(&query_string);
 
2513
  return;
 
2514
 
 
2515
err:
 
2516
  dynstr_free(&query_string);
 
2517
  maybe_exit(error);
 
2518
  return;
 
2519
} /* dump_table */
 
2520
 
 
2521
 
 
2522
static char *getTableName(int reset)
 
2523
{
 
2524
  static MYSQL_RES *res= NULL;
 
2525
  MYSQL_ROW    row;
 
2526
 
 
2527
  if (!res)
 
2528
  {
 
2529
    if (!(res= mysql_list_tables(mysql,NullS)))
 
2530
      return(NULL);
 
2531
  }
 
2532
  if ((row= mysql_fetch_row(res)))
 
2533
    return((char*) row[0]);
 
2534
 
 
2535
  if (reset)
 
2536
    mysql_data_seek(res,0);      /* We want to read again */
 
2537
  else
 
2538
  {
 
2539
    mysql_free_result(res);
 
2540
    res= NULL;
 
2541
  }
 
2542
  return(NULL);
 
2543
} /* getTableName */
 
2544
 
 
2545
 
342
2546
static int dump_all_databases()
343
2547
{
344
 
  drizzle_row_t row;
345
 
  drizzle_result_st *tableres;
 
2548
  MYSQL_ROW row;
 
2549
  MYSQL_RES *tableres;
346
2550
  int result=0;
347
 
  std::string query;
348
 
  DrizzleDumpDatabase *database;
349
 
 
350
 
  if (verbose)
351
 
    std::cerr << _("-- Retrieving database structures...") << std::endl;
352
 
 
353
 
  /* Blocking the MySQL privilege tables too because we can't import them due to bug#646187 */
354
 
  if (db_connection->getServerType() == ServerDetect::SERVER_MYSQL_FOUND)
355
 
    query= "SELECT SCHEMA_NAME, DEFAULT_COLLATION_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME NOT IN ('information_schema', 'performance_schema', 'mysql')";
356
 
  else
357
 
    query= "SELECT SCHEMA_NAME, DEFAULT_COLLATION_NAME FROM DATA_DICTIONARY.SCHEMAS WHERE SCHEMA_NAME NOT IN ('information_schema','data_dictionary')";
358
 
 
359
 
  tableres= db_connection->query(query);
360
 
  while ((row= drizzle_row_next(tableres)))
 
2551
 
 
2552
  if (mysql_query_with_error_report(mysql, &tableres, "SHOW DATABASES"))
 
2553
    return 1;
 
2554
  while ((row= mysql_fetch_row(tableres)))
361
2555
  {
362
 
    std::string database_name(row[0]);
363
 
    if (db_connection->getServerType() == ServerDetect::SERVER_MYSQL_FOUND)
364
 
      database= new DrizzleDumpDatabaseMySQL(database_name, db_connection);
365
 
    else
366
 
      database= new DrizzleDumpDatabaseDrizzle(database_name, db_connection);
367
 
 
368
 
    database->setCollate(row[1]);
369
 
    database_store.push_back(database);
 
2556
    if (dump_all_tables_in_db(row[0]))
 
2557
      result=1;
370
2558
  }
371
 
  db_connection->freeResult(tableres);
372
2559
  return result;
373
2560
}
374
2561
/* dump_all_databases */
375
2562
 
376
2563
 
377
 
static int dump_databases(const vector<string> &db_names)
 
2564
static int dump_databases(char **db_names)
378
2565
{
379
2566
  int result=0;
380
 
  string temp;
381
 
  DrizzleDumpDatabase *database;
382
 
 
383
 
  for (vector<string>::const_iterator it= db_names.begin(); it != db_names.end(); ++it)
 
2567
  char **db;
 
2568
 
 
2569
 
 
2570
  for (db= db_names ; *db ; db++)
384
2571
  {
385
 
    temp= *it;
386
 
    if (db_connection->getServerType() == ServerDetect::SERVER_MYSQL_FOUND)
387
 
      database= new DrizzleDumpDatabaseMySQL(temp, db_connection);
388
 
    else
389
 
      database= new DrizzleDumpDatabaseDrizzle(temp, db_connection);
390
 
    database_store.push_back(database);
 
2572
    if (dump_all_tables_in_db(*db))
 
2573
      result=1;
391
2574
  }
392
2575
  return(result);
393
2576
} /* dump_databases */
394
2577
 
395
 
static int dump_selected_tables(const string &db, const vector<string> &table_names)
396
 
{
397
 
  DrizzleDumpDatabase *database;
398
 
 
399
 
  if (db_connection->getServerType() == ServerDetect::SERVER_MYSQL_FOUND)
400
 
    database= new DrizzleDumpDatabaseMySQL(db, db_connection);
401
 
  else
402
 
    database= new DrizzleDumpDatabaseDrizzle(db, db_connection);
403
 
 
404
 
  if (not database->populateTables(table_names))
405
 
  {
406
 
    delete database;
407
 
    if (not ignore_errors)
408
 
      maybe_exit(EX_DRIZZLEERR);
409
 
  }
410
 
 
411
 
  database_store.push_back(database); 
412
 
 
 
2578
 
 
2579
/*
 
2580
Table Specific database initalization.
 
2581
 
 
2582
SYNOPSIS
 
2583
  init_dumping_tables
 
2584
  qdatabase      quoted name of the database
 
2585
 
 
2586
RETURN VALUES
 
2587
  0        Success.
 
2588
  1        Failure.
 
2589
*/
 
2590
 
 
2591
int init_dumping_tables(char *qdatabase)
 
2592
{
 
2593
 
 
2594
 
 
2595
  if (!opt_create_db)
 
2596
  {
 
2597
    char qbuf[256];
 
2598
    MYSQL_ROW row;
 
2599
    MYSQL_RES *dbinfo;
 
2600
 
 
2601
    snprintf(qbuf, sizeof(qbuf),
 
2602
             "SHOW CREATE DATABASE IF NOT EXISTS %s",
 
2603
             qdatabase);
 
2604
 
 
2605
    if (mysql_query(mysql, qbuf) || !(dbinfo = mysql_store_result(mysql)))
 
2606
    {
 
2607
      /* Old server version, dump generic CREATE DATABASE */
 
2608
      if (opt_drop_database)
 
2609
        fprintf(md_result_file,
 
2610
                "\n/*!40000 DROP DATABASE IF EXISTS %s*/;\n",
 
2611
                qdatabase);
 
2612
      fprintf(md_result_file,
 
2613
              "\nCREATE DATABASE /*!32312 IF NOT EXISTS*/ %s;\n",
 
2614
              qdatabase);
 
2615
    }
 
2616
    else
 
2617
    {
 
2618
      if (opt_drop_database)
 
2619
        fprintf(md_result_file,
 
2620
                "\n/*!40000 DROP DATABASE IF EXISTS %s*/;\n",
 
2621
                qdatabase);
 
2622
      row = mysql_fetch_row(dbinfo);
 
2623
      if (row[1])
 
2624
      {
 
2625
        fprintf(md_result_file,"\n%s;\n",row[1]);
 
2626
      }
 
2627
      mysql_free_result(dbinfo);
 
2628
    }
 
2629
  }
 
2630
  return(0);
 
2631
} /* init_dumping_tables */
 
2632
 
 
2633
 
 
2634
static int init_dumping(char *database, int init_func(char*))
 
2635
{
 
2636
  if (mysql_get_server_version(mysql) >= 50003 &&
 
2637
      !my_strcasecmp(&my_charset_latin1, database, "information_schema"))
 
2638
    return 1;
 
2639
 
 
2640
  if (mysql_select_db(mysql, database))
 
2641
  {
 
2642
    DB_error(mysql, "when selecting the database");
 
2643
    return 1;                   /* If --force */
 
2644
  }
 
2645
  if (!path && !opt_xml)
 
2646
  {
 
2647
    if (opt_databases || opt_alldbs)
 
2648
    {
 
2649
      /*
 
2650
        length of table name * 2 (if name contains quotes), 2 quotes and 0
 
2651
      */
 
2652
      char quoted_database_buf[NAME_LEN*2+3];
 
2653
      char *qdatabase= quote_name(database,quoted_database_buf,opt_quoted);
 
2654
      if (opt_comments)
 
2655
      {
 
2656
        fprintf(md_result_file,"\n--\n-- Current Database: %s\n--\n", qdatabase);
 
2657
        check_io(md_result_file);
 
2658
      }
 
2659
 
 
2660
      /* Call the view or table specific function */
 
2661
      init_func(qdatabase);
 
2662
 
 
2663
      fprintf(md_result_file,"\nUSE %s;\n", qdatabase);
 
2664
      check_io(md_result_file);
 
2665
    }
 
2666
  }
 
2667
  if (extended_insert)
 
2668
    init_dynamic_string_checked(&extended_row, "", 1024, 1024);
413
2669
  return 0;
 
2670
} /* init_dumping */
 
2671
 
 
2672
 
 
2673
/* Return 1 if we should copy the table */
 
2674
 
 
2675
static bool include_table(const uchar *hash_key, size_t len)
 
2676
{
 
2677
  return !hash_search(&ignore_table, hash_key, len);
 
2678
}
 
2679
 
 
2680
 
 
2681
static int dump_all_tables_in_db(char *database)
 
2682
{
 
2683
  char *table;
 
2684
  uint numrows;
 
2685
  char table_buff[NAME_LEN*2+3];
 
2686
  char hash_key[2*NAME_LEN+2];  /* "db.tablename" */
 
2687
  char *afterdot;
 
2688
  int using_mysql_db= my_strcasecmp(&my_charset_latin1, database, "mysql");
 
2689
 
 
2690
 
 
2691
  afterdot= strmov(hash_key, database);
 
2692
  *afterdot++= '.';
 
2693
 
 
2694
  if (init_dumping(database, init_dumping_tables))
 
2695
    return(1);
 
2696
  if (opt_xml)
 
2697
    print_xml_tag(md_result_file, "", "\n", "database", "name=", database, NullS);
 
2698
  if (lock_tables)
 
2699
  {
 
2700
    DYNAMIC_STRING query;
 
2701
    init_dynamic_string_checked(&query, "LOCK TABLES ", 256, 1024);
 
2702
    for (numrows= 0 ; (table= getTableName(1)) ; )
 
2703
    {
 
2704
      char *end= strmov(afterdot, table);
 
2705
      if (include_table((uchar*) hash_key,end - hash_key))
 
2706
      {
 
2707
        numrows++;
 
2708
        dynstr_append_checked(&query, quote_name(table, table_buff, 1));
 
2709
        dynstr_append_checked(&query, " READ /*!32311 LOCAL */,");
 
2710
      }
 
2711
    }
 
2712
    if (numrows && mysql_real_query(mysql, query.str, query.length-1))
 
2713
      DB_error(mysql, "when using LOCK TABLES");
 
2714
            /* We shall continue here, if --force was given */
 
2715
    dynstr_free(&query);
 
2716
  }
 
2717
  if (flush_logs)
 
2718
  {
 
2719
    if (mysql_refresh(mysql, REFRESH_LOG))
 
2720
      DB_error(mysql, "when doing refresh");
 
2721
           /* We shall continue here, if --force was given */
 
2722
  }
 
2723
  while ((table= getTableName(0)))
 
2724
  {
 
2725
    char *end= strmov(afterdot, table);
 
2726
    if (include_table((uchar*) hash_key, end - hash_key))
 
2727
    {
 
2728
      dump_table(table,database);
 
2729
      my_free(order_by, MYF(MY_ALLOW_ZERO_PTR));
 
2730
      order_by= 0;
 
2731
    }
 
2732
  }
 
2733
  if (opt_xml)
 
2734
  {
 
2735
    fputs("</database>\n", md_result_file);
 
2736
    check_io(md_result_file);
 
2737
  }
 
2738
  if (lock_tables)
 
2739
    VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES"));
 
2740
  if (flush_privileges && using_mysql_db == 0)
 
2741
  {
 
2742
    fprintf(md_result_file,"\n--\n-- Flush Grant Tables \n--\n");
 
2743
    fprintf(md_result_file,"\n/*! FLUSH PRIVILEGES */;\n");
 
2744
  }
 
2745
  return(0);
 
2746
} /* dump_all_tables_in_db */
 
2747
 
 
2748
 
 
2749
/*
 
2750
  get_actual_table_name -- executes a SHOW TABLES LIKE '%s' to get the actual
 
2751
  table name from the server for the table name given on the command line.
 
2752
  we do this because the table name given on the command line may be a
 
2753
  different case (e.g.  T1 vs t1)
 
2754
 
 
2755
  RETURN
 
2756
    pointer to the table name
 
2757
    0 if error
 
2758
*/
 
2759
 
 
2760
static char *get_actual_table_name(const char *old_table_name, MEM_ROOT *root)
 
2761
{
 
2762
  char *name= 0;
 
2763
  MYSQL_RES  *table_res;
 
2764
  MYSQL_ROW  row;
 
2765
  char query[50 + 2*NAME_LEN];
 
2766
  char show_name_buff[FN_REFLEN];
 
2767
 
 
2768
 
 
2769
  /* Check memory for quote_for_like() */
 
2770
  assert(2*sizeof(old_table_name) < sizeof(show_name_buff));
 
2771
  snprintf(query, sizeof(query), "SHOW TABLES LIKE %s",
 
2772
           quote_for_like(old_table_name, show_name_buff));
 
2773
 
 
2774
  if (mysql_query_with_error_report(mysql, 0, query))
 
2775
    return NullS;
 
2776
 
 
2777
  if ((table_res= mysql_store_result(mysql)))
 
2778
  {
 
2779
    uint64_t num_rows= mysql_num_rows(table_res);
 
2780
    if (num_rows > 0)
 
2781
    {
 
2782
      uint32_t *lengths;
 
2783
      /*
 
2784
        Return first row
 
2785
        TODO: Return all matching rows
 
2786
      */
 
2787
      row= mysql_fetch_row(table_res);
 
2788
      lengths= mysql_fetch_lengths(table_res);
 
2789
      name= strmake_root(root, row[0], lengths[0]);
 
2790
    }
 
2791
    mysql_free_result(table_res);
 
2792
  }
 
2793
  return(name);
 
2794
}
 
2795
 
 
2796
 
 
2797
static int dump_selected_tables(char *db, char **table_names, int tables)
 
2798
{
 
2799
  char table_buff[NAME_LEN*2+3];
 
2800
  DYNAMIC_STRING lock_tables_query;
 
2801
  MEM_ROOT root;
 
2802
  char **dump_tables, **pos, **end;
 
2803
 
 
2804
 
 
2805
  if (init_dumping(db, init_dumping_tables))
 
2806
    return(1);
 
2807
 
 
2808
  init_alloc_root(&root, 8192, 0);
 
2809
  if (!(dump_tables= pos= (char**) alloc_root(&root, tables * sizeof(char *))))
 
2810
     die(EX_EOM, "alloc_root failure.");
 
2811
 
 
2812
  init_dynamic_string_checked(&lock_tables_query, "LOCK TABLES ", 256, 1024);
 
2813
  for (; tables > 0 ; tables-- , table_names++)
 
2814
  {
 
2815
    /* the table name passed on commandline may be wrong case */
 
2816
    if ((*pos= get_actual_table_name(*table_names, &root)))
 
2817
    {
 
2818
      /* Add found table name to lock_tables_query */
 
2819
      if (lock_tables)
 
2820
      {
 
2821
        dynstr_append_checked(&lock_tables_query, quote_name(*pos, table_buff, 1));
 
2822
        dynstr_append_checked(&lock_tables_query, " READ /*!32311 LOCAL */,");
 
2823
      }
 
2824
      pos++;
 
2825
    }
 
2826
    else
 
2827
    {
 
2828
      if (!ignore_errors)
 
2829
      {
 
2830
        dynstr_free(&lock_tables_query);
 
2831
        free_root(&root, MYF(0));
 
2832
      }
 
2833
      maybe_die(EX_ILLEGAL_TABLE, "Couldn't find table: \"%s\"", *table_names);
 
2834
      /* We shall countinue here, if --force was given */
 
2835
    }
 
2836
  }
 
2837
  end= pos;
 
2838
 
 
2839
  if (lock_tables)
 
2840
  {
 
2841
    if (mysql_real_query(mysql, lock_tables_query.str,
 
2842
                         lock_tables_query.length-1))
 
2843
    {
 
2844
      if (!ignore_errors)
 
2845
      {
 
2846
        dynstr_free(&lock_tables_query);
 
2847
        free_root(&root, MYF(0));
 
2848
      }
 
2849
      DB_error(mysql, "when doing LOCK TABLES");
 
2850
       /* We shall countinue here, if --force was given */
 
2851
    }
 
2852
  }
 
2853
  dynstr_free(&lock_tables_query);
 
2854
  if (flush_logs)
 
2855
  {
 
2856
    if (mysql_refresh(mysql, REFRESH_LOG))
 
2857
    {
 
2858
      if (!ignore_errors)
 
2859
        free_root(&root, MYF(0));
 
2860
      DB_error(mysql, "when doing refresh");
 
2861
    }
 
2862
     /* We shall countinue here, if --force was given */
 
2863
  }
 
2864
  if (opt_xml)
 
2865
    print_xml_tag(md_result_file, "", "\n", "database", "name=", db, NullS);
 
2866
 
 
2867
  /* Dump each selected table */
 
2868
  for (pos= dump_tables; pos < end; pos++)
 
2869
    dump_table(*pos, db);
 
2870
 
 
2871
  free_root(&root, MYF(0));
 
2872
  my_free(order_by, MYF(MY_ALLOW_ZERO_PTR));
 
2873
  order_by= 0;
 
2874
  if (opt_xml)
 
2875
  {
 
2876
    fputs("</database>\n", md_result_file);
 
2877
    check_io(md_result_file);
 
2878
  }
 
2879
  if (lock_tables)
 
2880
    VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES"));
 
2881
  return(0);
414
2882
} /* dump_selected_tables */
415
2883
 
416
 
static int do_flush_tables_read_lock()
 
2884
 
 
2885
static int do_show_master_status(MYSQL *mysql_con)
 
2886
{
 
2887
  MYSQL_ROW row;
 
2888
  MYSQL_RES *master;
 
2889
  const char *comment_prefix=
 
2890
    (opt_master_data == MYSQL_OPT_MASTER_DATA_COMMENTED_SQL) ? "-- " : "";
 
2891
  if (mysql_query_with_error_report(mysql_con, &master, "SHOW MASTER STATUS"))
 
2892
  {
 
2893
    return 1;
 
2894
  }
 
2895
  else
 
2896
  {
 
2897
    row= mysql_fetch_row(master);
 
2898
    if (row && row[0] && row[1])
 
2899
    {
 
2900
      /* SHOW MASTER STATUS reports file and position */
 
2901
      if (opt_comments)
 
2902
        fprintf(md_result_file,
 
2903
                "\n--\n-- Position to start replication or point-in-time "
 
2904
                "recovery from\n--\n\n");
 
2905
      fprintf(md_result_file,
 
2906
              "%sCHANGE MASTER TO MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n",
 
2907
              comment_prefix, row[0], row[1]);
 
2908
      check_io(md_result_file);
 
2909
    }
 
2910
    else if (!ignore_errors)
 
2911
    {
 
2912
      /* SHOW MASTER STATUS reports nothing and --force is not enabled */
 
2913
      my_printf_error(0, "Error: Binlogging on server not active",
 
2914
                      MYF(0));
 
2915
      mysql_free_result(master);
 
2916
      maybe_exit(EX_MYSQLERR);
 
2917
      return 1;
 
2918
    }
 
2919
    mysql_free_result(master);
 
2920
  }
 
2921
  return 0;
 
2922
}
 
2923
 
 
2924
static int do_stop_slave_sql(MYSQL *mysql_con)
 
2925
{
 
2926
  MYSQL_RES *slave;
 
2927
  /* We need to check if the slave sql is running in the first place */
 
2928
  if (mysql_query_with_error_report(mysql_con, &slave, "SHOW SLAVE STATUS"))
 
2929
    return(1);
 
2930
  else
 
2931
  {
 
2932
    MYSQL_ROW row= mysql_fetch_row(slave);
 
2933
    if (row && row[11])
 
2934
    {
 
2935
      /* if SLAVE SQL is not running, we don't stop it */
 
2936
      if (!strcmp(row[11],"No"))
 
2937
      {
 
2938
        mysql_free_result(slave);
 
2939
        /* Silently assume that they don't have the slave running */
 
2940
        return(0);
 
2941
      }
 
2942
    }
 
2943
  }
 
2944
  mysql_free_result(slave);
 
2945
 
 
2946
  /* now, stop slave if running */
 
2947
  if (mysql_query_with_error_report(mysql_con, 0, "STOP SLAVE SQL_THREAD"))
 
2948
    return(1);
 
2949
 
 
2950
  return(0);
 
2951
}
 
2952
 
 
2953
static int add_stop_slave(void)
 
2954
{
 
2955
  if (opt_comments)
 
2956
    fprintf(md_result_file,
 
2957
            "\n--\n-- stop slave statement to make a recovery dump)\n--\n\n");
 
2958
  fprintf(md_result_file, "STOP SLAVE;\n");
 
2959
  return(0);
 
2960
}
 
2961
 
 
2962
static int add_slave_statements(void)
 
2963
{
 
2964
  if (opt_comments)
 
2965
    fprintf(md_result_file,
 
2966
            "\n--\n-- start slave statement to make a recovery dump)\n--\n\n");
 
2967
  fprintf(md_result_file, "START SLAVE;\n");
 
2968
  return(0);
 
2969
}
 
2970
 
 
2971
static int do_show_slave_status(MYSQL *mysql_con)
 
2972
{
 
2973
  MYSQL_RES *slave;
 
2974
  const char *comment_prefix=
 
2975
    (opt_slave_data == MYSQL_OPT_SLAVE_DATA_COMMENTED_SQL) ? "-- " : "";
 
2976
  if (mysql_query_with_error_report(mysql_con, &slave, "SHOW SLAVE STATUS"))
 
2977
  {
 
2978
    if (!ignore_errors)
 
2979
    {
 
2980
      /* SHOW SLAVE STATUS reports nothing and --force is not enabled */
 
2981
      my_printf_error(0, "Error: Slave not set up", MYF(0));
 
2982
    }
 
2983
    return 1;
 
2984
  }
 
2985
  else
 
2986
  {
 
2987
    MYSQL_ROW row= mysql_fetch_row(slave);
 
2988
    if (row && row[9] && row[21])
 
2989
    {
 
2990
      /* SHOW MASTER STATUS reports file and position */
 
2991
      if (opt_comments)
 
2992
        fprintf(md_result_file,
 
2993
                "\n--\n-- Position to start replication or point-in-time "
 
2994
                "recovery from (the master of this slave)\n--\n\n");
 
2995
 
 
2996
      fprintf(md_result_file, "%sCHANGE MASTER TO ", comment_prefix);
 
2997
 
 
2998
      if (opt_include_master_host_port)
 
2999
      {
 
3000
        if (row[1])
 
3001
          fprintf(md_result_file, "MASTER_HOST='%s', ", row[1]);
 
3002
        if (row[3])
 
3003
          fprintf(md_result_file, "MASTER_PORT='%s', ", row[3]);
 
3004
      }
 
3005
      fprintf(md_result_file,
 
3006
              "MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n", row[9], row[21]);
 
3007
 
 
3008
      check_io(md_result_file);
 
3009
    }
 
3010
    mysql_free_result(slave);
 
3011
  }
 
3012
  return 0;
 
3013
}
 
3014
 
 
3015
static int do_start_slave_sql(MYSQL *mysql_con)
 
3016
{
 
3017
  MYSQL_RES *slave;
 
3018
  /* We need to check if the slave sql is stopped in the first place */
 
3019
  if (mysql_query_with_error_report(mysql_con, &slave, "SHOW SLAVE STATUS"))
 
3020
    return(1);
 
3021
  else
 
3022
  {
 
3023
    MYSQL_ROW row= mysql_fetch_row(slave);
 
3024
    if (row && row[11])
 
3025
    {
 
3026
      /* if SLAVE SQL is not running, we don't start it */
 
3027
      if (!strcmp(row[11],"Yes"))
 
3028
      {
 
3029
        mysql_free_result(slave);
 
3030
        /* Silently assume that they don't have the slave running */
 
3031
        return(0);
 
3032
      }
 
3033
    }
 
3034
  }
 
3035
  mysql_free_result(slave);
 
3036
 
 
3037
  /* now, start slave if stopped */
 
3038
  if (mysql_query_with_error_report(mysql_con, 0, "START SLAVE"))
 
3039
  {
 
3040
    my_printf_error(0, "Error: Unable to start slave", MYF(0));
 
3041
    return 1;
 
3042
  }
 
3043
  return(0);
 
3044
}
 
3045
 
 
3046
 
 
3047
 
 
3048
static int do_flush_tables_read_lock(MYSQL *mysql_con)
417
3049
{
418
3050
  /*
419
3051
    We do first a FLUSH TABLES. If a long update is running, the FLUSH TABLES
420
3052
    will wait but will not stall the whole mysqld, and when the long update is
421
3053
    done the FLUSH TABLES WITH READ LOCK will start and succeed quickly. So,
422
 
    FLUSH TABLES is to lower the probability of a stage where both drizzled
 
3054
    FLUSH TABLES is to lower the probability of a stage where both mysqldump
423
3055
    and most client connections are stalled. Of course, if a second long
424
3056
    update starts between the two FLUSHes, we have that bad stall.
425
3057
  */
426
 
 
427
 
   db_connection->queryNoResult("FLUSH TABLES");
428
 
   db_connection->queryNoResult("FLUSH TABLES WITH READ LOCK");
429
 
 
430
 
  return 0;
431
 
}
432
 
 
433
 
static int do_unlock_tables()
434
 
{
435
 
  db_connection->queryNoResult("UNLOCK TABLES");
436
 
  return 0;
437
 
}
438
 
 
439
 
static int start_transaction()
440
 
{
441
 
  db_connection->queryNoResult("SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ");
442
 
  db_connection->queryNoResult("START TRANSACTION WITH CONSISTENT SNAPSHOT");
443
 
  return 0;
444
 
}
 
3058
  return
 
3059
    ( mysql_query_with_error_report(mysql_con, 0, "FLUSH TABLES") ||
 
3060
      mysql_query_with_error_report(mysql_con, 0,
 
3061
                                    "FLUSH TABLES WITH READ LOCK") );
 
3062
}
 
3063
 
 
3064
 
 
3065
static int do_unlock_tables(MYSQL *mysql_con)
 
3066
{
 
3067
  return mysql_query_with_error_report(mysql_con, 0, "UNLOCK TABLES");
 
3068
}
 
3069
 
 
3070
static int get_bin_log_name(MYSQL *mysql_con,
 
3071
                            char* buff_log_name, uint buff_len)
 
3072
{
 
3073
  MYSQL_RES *res;
 
3074
  MYSQL_ROW row;
 
3075
 
 
3076
  if (mysql_query(mysql_con, "SHOW MASTER STATUS") ||
 
3077
      !(res= mysql_store_result(mysql)))
 
3078
    return 1;
 
3079
 
 
3080
  if (!(row= mysql_fetch_row(res)))
 
3081
  {
 
3082
    mysql_free_result(res);
 
3083
    return 1;
 
3084
  }
 
3085
  /*
 
3086
    Only one row is returned, and the first column is the name of the
 
3087
    active log.
 
3088
  */
 
3089
  strmake(buff_log_name, row[0], buff_len - 1);
 
3090
 
 
3091
  mysql_free_result(res);
 
3092
  return 0;
 
3093
}
 
3094
 
 
3095
static int purge_bin_logs_to(MYSQL *mysql_con, char* log_name)
 
3096
{
 
3097
  DYNAMIC_STRING str;
 
3098
  int err;
 
3099
  init_dynamic_string_checked(&str, "PURGE BINARY LOGS TO '", 1024, 1024);
 
3100
  dynstr_append_checked(&str, log_name);
 
3101
  dynstr_append_checked(&str, "'");
 
3102
  err = mysql_query_with_error_report(mysql_con, 0, str.str);
 
3103
  dynstr_free(&str);
 
3104
  return err;
 
3105
}
 
3106
 
 
3107
 
 
3108
static int start_transaction(MYSQL *mysql_con)
 
3109
{
 
3110
  /*
 
3111
    We use BEGIN for old servers. --single-transaction --master-data will fail
 
3112
    on old servers, but that's ok as it was already silently broken (it didn't
 
3113
    do a consistent read, so better tell people frankly, with the error).
 
3114
 
 
3115
    We want the first consistent read to be used for all tables to dump so we
 
3116
    need the REPEATABLE READ level (not anything lower, for example READ
 
3117
    COMMITTED would give one new consistent read per dumped table).
 
3118
  */
 
3119
  if ((mysql_get_server_version(mysql_con) < 40100) && opt_master_data)
 
3120
  {
 
3121
    fprintf(stderr, "-- %s: the combination of --single-transaction and "
 
3122
            "--master-data requires a MySQL server version of at least 4.1 "
 
3123
            "(current server's version is %s). %s\n",
 
3124
            ignore_errors ? "Warning" : "Error",
 
3125
            mysql_con->server_version ? mysql_con->server_version : "unknown",
 
3126
            ignore_errors ? "Continuing due to --force, backup may not be consistent across all tables!" : "Aborting.");
 
3127
    if (!ignore_errors)
 
3128
      exit(EX_MYSQLERR);
 
3129
  }
 
3130
 
 
3131
  return (mysql_query_with_error_report(mysql_con, 0,
 
3132
                                        "SET SESSION TRANSACTION ISOLATION "
 
3133
                                        "LEVEL REPEATABLE READ") ||
 
3134
          mysql_query_with_error_report(mysql_con, 0,
 
3135
                                        "START TRANSACTION "
 
3136
                                        "/*!40100 WITH CONSISTENT SNAPSHOT */"));
 
3137
}
 
3138
 
 
3139
 
 
3140
static ulong find_set(TYPELIB *lib, const char *x, uint length,
 
3141
                      char **err_pos, uint *err_len)
 
3142
{
 
3143
  const char *end= x + length;
 
3144
  ulong found= 0;
 
3145
  uint find;
 
3146
  char buff[255];
 
3147
 
 
3148
  *err_pos= 0;                  /* No error yet */
 
3149
  while (end > x && my_isspace(charset_info, end[-1]))
 
3150
    end--;
 
3151
 
 
3152
  *err_len= 0;
 
3153
  if (x != end)
 
3154
  {
 
3155
    const char *start= x;
 
3156
    for (;;)
 
3157
    {
 
3158
      const char *pos= start;
 
3159
      uint var_len;
 
3160
 
 
3161
      for (; pos != end && *pos != ','; pos++) ;
 
3162
      var_len= (uint) (pos - start);
 
3163
      strmake(buff, start, min(sizeof(buff), var_len));
 
3164
      find= find_type(buff, lib, var_len);
 
3165
      if (!find)
 
3166
      {
 
3167
        *err_pos= (char*) start;
 
3168
        *err_len= var_len;
 
3169
      }
 
3170
      else
 
3171
        found|= ((int64_t) 1 << (find - 1));
 
3172
      if (pos == end)
 
3173
        break;
 
3174
      start= pos + 1;
 
3175
    }
 
3176
  }
 
3177
  return found;
 
3178
}
 
3179
 
 
3180
 
 
3181
/* Print a value with a prefix on file */
 
3182
static void print_value(FILE *file, MYSQL_RES  *result, MYSQL_ROW row,
 
3183
                        const char *prefix, const char *name,
 
3184
                        int string_value)
 
3185
{
 
3186
  MYSQL_FIELD   *field;
 
3187
  mysql_field_seek(result, 0);
 
3188
 
 
3189
  for ( ; (field= mysql_fetch_field(result)) ; row++)
 
3190
  {
 
3191
    if (!strcmp(field->name,name))
 
3192
    {
 
3193
      if (row[0] && row[0][0] && strcmp(row[0],"0")) /* Skip default */
 
3194
      {
 
3195
        fputc(' ',file);
 
3196
        fputs(prefix, file);
 
3197
        if (string_value)
 
3198
          unescape(file,row[0],(uint) strlen(row[0]));
 
3199
        else
 
3200
          fputs(row[0], file);
 
3201
        check_io(file);
 
3202
        return;
 
3203
      }
 
3204
    }
 
3205
  }
 
3206
  return;                                       /* This shouldn't happen */
 
3207
} /* print_value */
 
3208
 
 
3209
 
 
3210
/*
 
3211
  SYNOPSIS
 
3212
 
 
3213
  Check if we the table is one of the table types that should be ignored:
 
3214
  MRG_ISAM, MRG_MYISAM, if opt_delayed, if that table supports delayed inserts.
 
3215
  If the table should be altogether ignored, it returns a true, false if it
 
3216
  should not be ignored. If the user has selected to use INSERT DELAYED, it
 
3217
  sets the value of the bool pointer supports_delayed_inserts to 0 if not
 
3218
  supported, 1 if it is supported.
 
3219
 
 
3220
  ARGS
 
3221
 
 
3222
    check_if_ignore_table()
 
3223
    table_name                  Table name to check
 
3224
    table_type                  Type of table
 
3225
 
 
3226
  GLOBAL VARIABLES
 
3227
    mysql                       MySQL connection
 
3228
    verbose                     Write warning messages
 
3229
 
 
3230
  RETURN
 
3231
    char (bit value)            See IGNORE_ values at top
 
3232
*/
 
3233
 
 
3234
char check_if_ignore_table(const char *table_name, char *table_type)
 
3235
{
 
3236
  char result= IGNORE_NONE;
 
3237
  char buff[FN_REFLEN+80], show_name_buff[FN_REFLEN];
 
3238
  MYSQL_RES *res= NULL;
 
3239
  MYSQL_ROW row;
 
3240
 
 
3241
 
 
3242
  /* Check memory for quote_for_like() */
 
3243
  assert(2*sizeof(table_name) < sizeof(show_name_buff));
 
3244
  snprintf(buff, sizeof(buff), "show table status like %s",
 
3245
           quote_for_like(table_name, show_name_buff));
 
3246
  if (mysql_query_with_error_report(mysql, &res, buff))
 
3247
  {
 
3248
    if (mysql_errno(mysql) != ER_PARSE_ERROR)
 
3249
    {                                   /* If old MySQL version */
 
3250
      verbose_msg("-- Warning: Couldn't get status information for "
 
3251
                  "table %s (%s)\n", table_name, mysql_error(mysql));
 
3252
      return(result);                       /* assume table is ok */
 
3253
    }
 
3254
  }
 
3255
  if (!(row= mysql_fetch_row(res)))
 
3256
  {
 
3257
    fprintf(stderr,
 
3258
            "Error: Couldn't read status information for table %s (%s)\n",
 
3259
            table_name, mysql_error(mysql));
 
3260
    mysql_free_result(res);
 
3261
    return(result);                         /* assume table is ok */
 
3262
  }
 
3263
  if (!(row[1]))
 
3264
    strmake(table_type, "VIEW", NAME_LEN-1);
 
3265
  else
 
3266
  {
 
3267
    /*
 
3268
      If the table type matches any of these, we do support delayed inserts.
 
3269
      Note: we do not want to skip dumping this table if if is not one of
 
3270
      these types, but we do want to use delayed inserts in the dump if
 
3271
      the table type is _NOT_ one of these types
 
3272
    */
 
3273
    strmake(table_type, row[1], NAME_LEN-1);
 
3274
    if (opt_delayed)
 
3275
    {
 
3276
      if (strcmp(table_type,"MyISAM") &&
 
3277
          strcmp(table_type,"ISAM") &&
 
3278
          strcmp(table_type,"ARCHIVE") &&
 
3279
          strcmp(table_type,"HEAP") &&
 
3280
          strcmp(table_type,"MEMORY"))
 
3281
        result= IGNORE_INSERT_DELAYED;
 
3282
    }
 
3283
 
 
3284
    /*
 
3285
      If these two types, we do want to skip dumping the table
 
3286
    */
 
3287
    if (!opt_no_data &&
 
3288
        (!my_strcasecmp(&my_charset_latin1, table_type, "MRG_MyISAM") ||
 
3289
         !strcmp(table_type,"MRG_ISAM")))
 
3290
      result= IGNORE_DATA;
 
3291
  }
 
3292
  mysql_free_result(res);
 
3293
  return(result);
 
3294
}
 
3295
 
 
3296
 
 
3297
/*
 
3298
  Get string of comma-separated primary key field names
 
3299
 
 
3300
  SYNOPSIS
 
3301
    char *primary_key_fields(const char *table_name)
 
3302
    RETURNS     pointer to allocated buffer (must be freed by caller)
 
3303
    table_name  quoted table name
 
3304
 
 
3305
  DESCRIPTION
 
3306
    Use SHOW KEYS FROM table_name, allocate a buffer to hold the
 
3307
    field names, and then build that string and return the pointer
 
3308
    to that buffer.
 
3309
 
 
3310
    Returns NULL if there is no PRIMARY or UNIQUE key on the table,
 
3311
    or if there is some failure.  It is better to continue to dump
 
3312
    the table unsorted, rather than exit without dumping the data.
 
3313
*/
 
3314
 
 
3315
static char *primary_key_fields(const char *table_name)
 
3316
{
 
3317
  MYSQL_RES  *res= NULL;
 
3318
  MYSQL_ROW  row;
 
3319
  /* SHOW KEYS FROM + table name * 2 (escaped) + 2 quotes + \0 */
 
3320
  char show_keys_buff[15 + NAME_LEN * 2 + 3];
 
3321
  uint result_length= 0;
 
3322
  char *result= 0;
 
3323
  char buff[NAME_LEN * 2 + 3];
 
3324
  char *quoted_field;
 
3325
 
 
3326
  snprintf(show_keys_buff, sizeof(show_keys_buff),
 
3327
           "SHOW KEYS FROM %s", table_name);
 
3328
  if (mysql_query(mysql, show_keys_buff) ||
 
3329
      !(res= mysql_store_result(mysql)))
 
3330
  {
 
3331
    fprintf(stderr, "Warning: Couldn't read keys from table %s;"
 
3332
            " records are NOT sorted (%s)\n",
 
3333
            table_name, mysql_error(mysql));
 
3334
    /* Don't exit, because it's better to print out unsorted records */
 
3335
    goto cleanup;
 
3336
  }
 
3337
 
 
3338
  /*
 
3339
   * Figure out the length of the ORDER BY clause result.
 
3340
   * Note that SHOW KEYS is ordered:  a PRIMARY key is always the first
 
3341
   * row, and UNIQUE keys come before others.  So we only need to check
 
3342
   * the first key, not all keys.
 
3343
   */
 
3344
  if ((row= mysql_fetch_row(res)) && atoi(row[1]) == 0)
 
3345
  {
 
3346
    /* Key is unique */
 
3347
    do
 
3348
    {
 
3349
      quoted_field= quote_name(row[4], buff, 0);
 
3350
      result_length+= strlen(quoted_field) + 1; /* + 1 for ',' or \0 */
 
3351
    } while ((row= mysql_fetch_row(res)) && atoi(row[3]) > 1);
 
3352
  }
 
3353
 
 
3354
  /* Build the ORDER BY clause result */
 
3355
  if (result_length)
 
3356
  {
 
3357
    char *end;
 
3358
    /* result (terminating \0 is already in result_length) */
 
3359
    result= my_malloc(result_length + 10, MYF(MY_WME));
 
3360
    if (!result)
 
3361
    {
 
3362
      fprintf(stderr, "Error: Not enough memory to store ORDER BY clause\n");
 
3363
      goto cleanup;
 
3364
    }
 
3365
    mysql_data_seek(res, 0);
 
3366
    row= mysql_fetch_row(res);
 
3367
    quoted_field= quote_name(row[4], buff, 0);
 
3368
    end= strmov(result, quoted_field);
 
3369
    while ((row= mysql_fetch_row(res)) && atoi(row[3]) > 1)
 
3370
    {
 
3371
      quoted_field= quote_name(row[4], buff, 0);
 
3372
      end= strxmov(end, ",", quoted_field, NullS);
 
3373
    }
 
3374
  }
 
3375
 
 
3376
cleanup:
 
3377
  if (res)
 
3378
    mysql_free_result(res);
 
3379
 
 
3380
  return result;
 
3381
}
 
3382
 
 
3383
/*
 
3384
  The following functions are wrappers for the dynamic string functions
 
3385
  and if they fail, the wrappers will terminate the current process.
 
3386
*/
 
3387
 
 
3388
#define DYNAMIC_STR_ERROR_MSG "Couldn't perform DYNAMIC_STRING operation"
 
3389
 
 
3390
static void init_dynamic_string_checked(DYNAMIC_STRING *str, const char *init_str,
 
3391
                            uint init_alloc, uint alloc_increment)
 
3392
{
 
3393
  if (init_dynamic_string(str, init_str, init_alloc, alloc_increment))
 
3394
    die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG);
 
3395
}
 
3396
 
 
3397
static void dynstr_append_checked(DYNAMIC_STRING* dest, const char* src)
 
3398
{
 
3399
  if (dynstr_append(dest, src))
 
3400
    die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG);
 
3401
}
 
3402
 
 
3403
static void dynstr_set_checked(DYNAMIC_STRING *str, const char *init_str)
 
3404
{
 
3405
  if (dynstr_set(str, init_str))
 
3406
    die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG);
 
3407
}
 
3408
 
 
3409
static void dynstr_append_mem_checked(DYNAMIC_STRING *str, const char *append,
 
3410
                          uint length)
 
3411
{
 
3412
  if (dynstr_append_mem(str, append, length))
 
3413
    die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG);
 
3414
}
 
3415
 
 
3416
static void dynstr_realloc_checked(DYNAMIC_STRING *str, ulong additional_size)
 
3417
{
 
3418
  if (dynstr_realloc(str, additional_size))
 
3419
    die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG);
 
3420
}
 
3421
 
445
3422
 
446
3423
int main(int argc, char **argv)
447
3424
{
448
 
try
449
 
{
 
3425
  char bin_log_name[FN_REFLEN];
450
3426
  int exit_code;
451
 
 
452
 
#if defined(ENABLE_NLS)
453
 
# if defined(HAVE_LOCALE_H)
454
 
  setlocale(LC_ALL, "");
455
 
# endif
456
 
  bindtextdomain("drizzle7", LOCALEDIR);
457
 
  textdomain("drizzle7");
458
 
#endif
459
 
 
460
 
  po::options_description commandline_options(_("Options used only in command line"));
461
 
  commandline_options.add_options()
462
 
  ("all-databases,A", po::value<bool>(&opt_alldbs)->default_value(false)->zero_tokens(),
463
 
  _("Dump all the databases. This will be same as --databases with all databases selected."))
464
 
  ("flush-logs,F", po::value<bool>(&flush_logs)->default_value(false)->zero_tokens(),
465
 
  _("Flush logs file in server before starting dump. Note that if you dump many databases at once (using the option --databases= or --all-databases), the logs will be flushed for each database dumped. The exception is when using --lock-all-tables in this case the logs will be flushed only once, corresponding to the moment all tables are locked. So if you want your dump and the log flush to happen at the same exact moment you should use --lock-all-tables or --flush-logs"))
466
 
  ("force,f", po::value<bool>(&ignore_errors)->default_value(false)->zero_tokens(),
467
 
  _("Continue even if we get an sql-error."))
468
 
  ("help,?", _("Display this help message and exit."))
469
 
  ("lock-all-tables,x", po::value<bool>(&opt_lock_all_tables)->default_value(false)->zero_tokens(),
470
 
  _("Locks all tables across all databases. This is achieved by taking a global read lock for the duration of the whole dump. Automatically turns --single-transaction off."))
471
 
  ("single-transaction", po::value<bool>(&opt_single_transaction)->default_value(false)->zero_tokens(),
472
 
  _("Creates a consistent snapshot by dumping all tables in a single transaction. Works ONLY for tables stored in storage engines which support multiversioning (currently only InnoDB does); the dump is NOT guaranteed to be consistent for other storage engines. While a --single-transaction dump is in process, to ensure a valid dump file (correct table contents), no other connection should use the following statements: ALTER TABLE, DROP TABLE, RENAME TABLE, TRUNCATE TABLE, as consistent snapshot is not isolated from them."))
473
 
  ("skip-opt", 
474
 
  _("Disable --opt. Disables --add-drop-table, --add-locks, --create-options, ---extended-insert and --disable-keys."))    
475
 
  ("tables", _("Overrides option --databases (-B)."))
476
 
  ("show-progress-size", po::value<uint32_t>(&show_progress_size)->default_value(10000),
477
 
  _("Number of rows before each output progress report (requires --verbose)."))
478
 
  ("verbose,v", po::value<bool>(&verbose)->default_value(false)->zero_tokens(),
479
 
  _("Print info about the various stages."))
480
 
  ("version,V", _("Output version information and exit."))
481
 
  ("skip-comments", _("Turn off Comments"))
482
 
  ("skip-create", _("Turn off create-options"))
483
 
  ("skip-extended-insert", _("Turn off extended-insert"))
484
 
  ("skip-dump-date", _( "Turn off dump date at the end of the output"))
485
 
  ("no-defaults", _("Do not read from the configuration files"))
486
 
  ;
487
 
 
488
 
  po::options_description dump_options(_("Options specific to the drizzle client"));
489
 
  dump_options.add_options()
490
 
  ("add-drop-database", po::value<bool>(&opt_drop_database)->default_value(false)->zero_tokens(),
491
 
  _("Add a 'DROP DATABASE' before each create."))
492
 
  ("skip-drop-table", _("Do not add a 'drop table' before each create."))
493
 
  ("compact", po::value<bool>(&opt_compact)->default_value(false)->zero_tokens(),
494
 
  _("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"))
495
 
  ("databases,B", po::value<bool>(&opt_databases)->default_value(false)->zero_tokens(),
496
 
  _("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."))
497
 
  ("skip-disable-keys,K",
498
 
  _("'ALTER TABLE tb_name DISABLE KEYS;' and 'ALTER TABLE tb_name ENABLE KEYS;' will not be put in the output."))
499
 
  ("ignore-table", po::value<string>(),
500
 
  _("Do not dump the specified table. To specify more than one table to ignore, use the directive multiple times, once for each table.  Each table must be specified with both database and table names, e.g. --ignore-table=database.table"))
501
 
  ("insert-ignore", po::value<bool>(&opt_ignore)->default_value(false)->zero_tokens(),
502
 
  _("Insert rows with INSERT IGNORE."))
503
 
  ("no-autocommit", po::value<bool>(&opt_autocommit)->default_value(false)->zero_tokens(),
504
 
  _("Wrap a table's data in START TRANSACTION/COMMIT statements."))
505
 
  ("no-create-db,n", po::value<bool>(&opt_create_db)->default_value(false)->zero_tokens(),
506
 
  _("'CREATE DATABASE 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."))
507
 
  ("no-data,d", po::value<bool>(&opt_no_data)->default_value(false)->zero_tokens(),
508
 
  _("No row information."))
509
 
  ("replace", po::value<bool>(&opt_replace_into)->default_value(false)->zero_tokens(),
510
 
  _("Use REPLACE INTO instead of INSERT INTO."))
511
 
  ("destination-type", po::value<string>()->default_value("stdout"),
512
 
  _("Where to send output to (stdout|database"))
513
 
  ("destination-host", po::value<string>(&opt_destination_host)->default_value("localhost"),
514
 
  _("Hostname for destination db server (requires --destination-type=database)"))
515
 
  ("destination-port", po::value<uint16_t>(&opt_destination_port)->default_value(4427),
516
 
  _("Port number for destination db server (requires --destination-type=database)"))
517
 
  ("destination-user", po::value<string>(&opt_destination_user),
518
 
  _("User name for destination db server (resquires --destination-type=database)"))
519
 
  ("destination-password", po::value<string>(&opt_destination_password),
520
 
  _("Password for destination db server (requires --destination-type=database)"))
521
 
  ("destination-database", po::value<string>(&opt_destination_database),
522
 
  _("The database in the destination db server (requires --destination-type=database, not for use with --all-databases)"))
523
 
  ("my-data-is-mangled", po::value<bool>(&opt_data_is_mangled)->default_value(false)->zero_tokens(),
524
 
  _("Do not make a UTF8 connection to MySQL, use if you have UTF8 data in a non-UTF8 table"))
525
 
  ;
526
 
 
527
 
  po::options_description client_options(_("Options specific to the client"));
528
 
  client_options.add_options()
529
 
  ("host,h", po::value<string>(&current_host)->default_value("localhost"),
530
 
  _("Connect to host."))
531
 
  ("password,P", po::value<string>(&password)->default_value(PASSWORD_SENTINEL),
532
 
  _("Password to use when connecting to server. If password is not given it's solicited on the tty."))
533
 
  ("port,p", po::value<uint32_t>(&opt_drizzle_port)->default_value(0),
534
 
  _("Port number to use for connection."))
535
 
  ("user,u", po::value<string>(&current_user)->default_value(""),
536
 
  _("User for login if not current user."))
537
 
  ("protocol",po::value<string>(&opt_protocol)->default_value("mysql"),
538
 
  _("The protocol of connection (mysql or drizzle)."))
539
 
  ;
540
 
 
541
 
  po::options_description hidden_options(_("Hidden Options"));
542
 
  hidden_options.add_options()
543
 
  ("database-used", po::value<vector<string> >(), _("Used to select the database"))
544
 
  ("Table-used", po::value<vector<string> >(), _("Used to select the tables"))
545
 
  ;
546
 
 
547
 
  po::options_description all_options(_("Allowed Options + Hidden Options"));
548
 
  all_options.add(commandline_options).add(dump_options).add(client_options).add(hidden_options);
549
 
 
550
 
  po::options_description long_options(_("Allowed Options"));
551
 
  long_options.add(commandline_options).add(dump_options).add(client_options);
552
 
 
553
 
  std::string system_config_dir_dump(SYSCONFDIR); 
554
 
  system_config_dir_dump.append("/drizzle/drizzledump.cnf");
555
 
 
556
 
  std::string system_config_dir_client(SYSCONFDIR); 
557
 
  system_config_dir_client.append("/drizzle/client.cnf");
558
 
 
559
 
  std::string user_config_dir((getenv("XDG_CONFIG_HOME")? getenv("XDG_CONFIG_HOME"):"~/.config"));
560
 
 
561
 
  if (user_config_dir.compare(0, 2, "~/") == 0)
562
 
  {
563
 
    char *homedir;
564
 
    homedir= getenv("HOME");
565
 
    if (homedir != NULL)
566
 
      user_config_dir.replace(0, 1, homedir);
567
 
  }
568
 
 
569
 
  po::positional_options_description p;
570
 
  p.add("database-used", 1);
571
 
  p.add("Table-used",-1);
572
 
 
573
 
  md_result_file= stdout;
574
 
 
575
 
  po::variables_map vm;
576
 
 
577
 
  // Disable allow_guessing
578
 
  int style = po::command_line_style::default_style & ~po::command_line_style::allow_guessing;
579
 
 
580
 
  po::store(po::command_line_parser(argc, argv).style(style).
581
 
            options(all_options).positional(p).
582
 
            extra_parser(parse_password_arg).run(), vm);
583
 
 
584
 
  if (! vm.count("no-defaults"))
585
 
  {
586
 
    std::string user_config_dir_dump(user_config_dir);
587
 
    user_config_dir_dump.append("/drizzle/drizzledump.cnf"); 
588
 
 
589
 
    std::string user_config_dir_client(user_config_dir);
590
 
    user_config_dir_client.append("/drizzle/client.cnf");
591
 
 
592
 
    ifstream user_dump_ifs(user_config_dir_dump.c_str());
593
 
    po::store(parse_config_file(user_dump_ifs, dump_options), vm);
594
 
 
595
 
    ifstream user_client_ifs(user_config_dir_client.c_str());
596
 
    po::store(parse_config_file(user_client_ifs, client_options), vm);
597
 
 
598
 
    ifstream system_dump_ifs(system_config_dir_dump.c_str());
599
 
    po::store(parse_config_file(system_dump_ifs, dump_options), vm);
600
 
 
601
 
    ifstream system_client_ifs(system_config_dir_client.c_str());
602
 
    po::store(parse_config_file(system_client_ifs, client_options), vm);
603
 
  }
604
 
 
605
 
  po::notify(vm);  
606
 
  
607
 
  if ((not vm.count("database-used") && not vm.count("Table-used") 
608
 
    && not opt_alldbs && path.empty())
609
 
    || (vm.count("help")) || vm.count("version"))
610
 
  {
611
 
    printf(_("Drizzledump %s build %s, for %s-%s (%s)\n"),
612
 
      drizzle_version(), VERSION, HOST_VENDOR, HOST_OS, HOST_CPU);
613
 
    if (vm.count("version"))
614
 
      exit(0);
615
 
    puts("");
616
 
    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"));
617
 
    puts(_("Dumps definitions and data from a Drizzle database server"));
618
 
    printf(_("Usage: %s [OPTIONS] database [tables]\n"), progname.c_str());
619
 
    printf(_("OR     %s [OPTIONS] --databases [OPTIONS] DB1 [DB2 DB3...]\n"),
620
 
          progname.c_str());
621
 
    printf(_("OR     %s [OPTIONS] --all-databases [OPTIONS]\n"), progname.c_str());
622
 
    cout << long_options;
623
 
    if (vm.count("help"))
624
 
      exit(0);
625
 
    else
626
 
      exit(1);
627
 
  }
628
 
 
629
 
  /* Inverted Booleans */
630
 
 
631
 
  opt_drop= (vm.count("skip-drop-table")) ? false : true;
632
 
  opt_comments= (vm.count("skip-comments")) ? false : true;
633
 
  extended_insert= (vm.count("skip-extended-insert")) ? false : true;
634
 
  opt_dump_date= (vm.count("skip-dump-date")) ? false : true;
635
 
  opt_disable_keys= (vm.count("skip-disable-keys")) ? false : true;
636
 
  opt_quoted= (vm.count("skip-quote-names")) ? false : true;
637
 
 
638
 
  if (vm.count("protocol"))
639
 
  {
640
 
    std::transform(opt_protocol.begin(), opt_protocol.end(),
641
 
      opt_protocol.begin(), ::tolower);
642
 
 
643
 
    if (not opt_protocol.compare("mysql"))
644
 
      use_drizzle_protocol=false;
645
 
    else if (not opt_protocol.compare("drizzle"))
646
 
      use_drizzle_protocol=true;
647
 
    else
648
 
    {
649
 
      cout << _("Error: Unknown protocol") << " '" << opt_protocol << "'" << endl;
650
 
      exit(-1);
651
 
    }
652
 
  }
653
 
 
654
 
  if (vm.count("port"))
655
 
  {
656
 
    /* If the port number is > 65535 it is not a valid port
657
 
     *        This also helps with potential data loss casting unsigned long to a
658
 
     *               uint32_t. 
659
 
     */
660
 
    if (opt_drizzle_port > 65535)
661
 
    {
662
 
      fprintf(stderr, _("Value supplied for port is not valid.\n"));
663
 
      exit(-1);
664
 
    }
665
 
  }
666
 
 
667
 
  if(vm.count("password"))
668
 
  {
669
 
    if (!opt_password.empty())
670
 
      opt_password.erase();
671
 
    if (password == PASSWORD_SENTINEL)
672
 
    {
673
 
      opt_password= "";
674
 
    }
675
 
    else
676
 
    {
677
 
      opt_password= password;
678
 
      tty_password= false;
679
 
    }
680
 
  }
681
 
  else
682
 
  {
683
 
      tty_password= true;
684
 
  }
685
 
 
686
 
  if (! path.empty())
687
 
  { 
688
 
    opt_disable_keys= 0;
689
 
  }
690
 
 
691
 
  if (vm.count("skip-opt"))
692
 
  {
693
 
    extended_insert= opt_drop= create_options= 0;
694
 
    opt_disable_keys= 0;
695
 
  }
696
 
 
697
 
  if (opt_compact)
698
 
  { 
699
 
    opt_comments= opt_drop= opt_disable_keys= 0;
700
 
  }
701
 
 
702
 
  if (vm.count("opt"))
703
 
  {
704
 
    extended_insert= opt_drop= create_options= 1;
705
 
    opt_disable_keys= 1;
706
 
  }
707
 
 
708
 
  if (vm.count("tables"))
709
 
  { 
710
 
    opt_databases= false;
711
 
  }
712
 
 
713
 
  if (vm.count("ignore-table"))
714
 
  {
715
 
    if (!strchr(vm["ignore-table"].as<string>().c_str(), '.'))
716
 
    {
717
 
      fprintf(stderr, _("Illegal use of option --ignore-table=<database>.<table>\n"));
718
 
      exit(EXIT_ARGUMENT_INVALID);
719
 
    }
720
 
    string tmpptr(vm["ignore-table"].as<string>());
721
 
    ignore_table.insert(tmpptr); 
722
 
  }
723
 
 
724
 
  if (vm.count("skip-create"))
725
 
  {
726
 
    opt_create_db= opt_no_create_info= create_options= false;
727
 
  }
728
 
 
729
 
  exit_code= get_options();
 
3427
  MY_INIT("mysqldump");
 
3428
 
 
3429
  compatible_mode_normal_str[0]= 0;
 
3430
  default_charset= (char *)mysql_universal_client_charset;
 
3431
  bzero((char*) &ignore_table, sizeof(ignore_table));
 
3432
 
 
3433
  exit_code= get_options(&argc, &argv);
730
3434
  if (exit_code)
731
3435
  {
732
3436
    free_resources();
733
3437
    exit(exit_code);
734
3438
  }
735
 
  try
736
 
  {
737
 
    db_connection = new DrizzleDumpConnection(current_host, opt_drizzle_port,
738
 
      current_user, opt_password, use_drizzle_protocol);
739
 
  }
740
 
  catch (std::exception&)
741
 
  {
742
 
    maybe_exit(EX_DRIZZLEERR);
743
 
  }
744
 
 
745
 
  if ((db_connection->getServerType() == ServerDetect::SERVER_MYSQL_FOUND) and (not opt_data_is_mangled))
746
 
    db_connection->queryNoResult("SET NAMES 'utf8'");
747
 
 
748
 
  if (vm.count("destination-type"))
749
 
  {
750
 
    string tmp_destination(vm["destination-type"].as<string>());
751
 
    if (tmp_destination.compare("database") == 0)
752
 
      opt_destination= DESTINATION_DB;
753
 
    else if (tmp_destination.compare("stdout") == 0)
754
 
      opt_destination= DESTINATION_STDOUT;
755
 
    else
756
 
      exit(EXIT_ARGUMENT_INVALID);
757
 
  }
758
 
 
759
 
 
760
 
  if (path.empty() && vm.count("database-used"))
761
 
  {
762
 
    string database_used= *vm["database-used"].as< vector<string> >().begin();
763
 
    write_header((char *)database_used.c_str());
764
 
  }
765
 
 
766
 
  if ((opt_lock_all_tables) && do_flush_tables_read_lock())
767
 
    goto err;
768
 
  if (opt_single_transaction && start_transaction())
769
 
    goto err;
770
 
  if (opt_lock_all_tables)
771
 
    db_connection->queryNoResult("FLUSH LOGS");
772
 
  if (opt_single_transaction && do_unlock_tables()) /* unlock but no commit! */
 
3439
 
 
3440
  if (log_error_file)
 
3441
  {
 
3442
    if(!(stderror_file= freopen(log_error_file, "a+", stderr)))
 
3443
    {
 
3444
      free_resources();
 
3445
      exit(EX_MYSQLERR);
 
3446
    }
 
3447
  }
 
3448
 
 
3449
  if (connect_to_db(current_host, current_user, opt_password))
 
3450
  {
 
3451
    free_resources();
 
3452
    exit(EX_MYSQLERR);
 
3453
  }
 
3454
  if (!path)
 
3455
    write_header(md_result_file, *argv);
 
3456
 
 
3457
  if (opt_slave_data && do_stop_slave_sql(mysql))
 
3458
    goto err;
 
3459
 
 
3460
  if ((opt_lock_all_tables || opt_master_data) &&
 
3461
      do_flush_tables_read_lock(mysql))
 
3462
    goto err;
 
3463
  if (opt_single_transaction && start_transaction(mysql))
 
3464
      goto err;
 
3465
  if (opt_delete_master_logs)
 
3466
  {
 
3467
    if (mysql_refresh(mysql, REFRESH_LOG) ||
 
3468
        get_bin_log_name(mysql, bin_log_name, sizeof(bin_log_name)))
 
3469
      goto err;
 
3470
    flush_logs= 0;
 
3471
  }
 
3472
  if (opt_lock_all_tables || opt_master_data)
 
3473
  {
 
3474
    if (flush_logs && mysql_refresh(mysql, REFRESH_LOG))
 
3475
      goto err;
 
3476
    flush_logs= 0; /* not anymore; that would not be sensible */
 
3477
  }
 
3478
  /* Add 'STOP SLAVE to beginning of dump */
 
3479
  if (opt_slave_apply && add_stop_slave())
 
3480
    goto err;
 
3481
  if (opt_master_data && do_show_master_status(mysql))
 
3482
    goto err;
 
3483
  if (opt_slave_data && do_show_slave_status(mysql))
 
3484
    goto err;
 
3485
  if (opt_single_transaction && do_unlock_tables(mysql)) /* unlock but no commit! */
773
3486
    goto err;
774
3487
 
775
3488
  if (opt_alldbs)
776
3489
  {
777
3490
    dump_all_databases();
778
 
    dump_all_tables();
779
3491
  }
780
 
  if (vm.count("database-used") && vm.count("Table-used") && ! opt_databases)
 
3492
  else if (argc > 1 && !opt_databases)
781
3493
  {
782
 
    string database_used= *vm["database-used"].as< vector<string> >().begin();
783
3494
    /* Only one database and selected table(s) */
784
 
    dump_selected_tables(database_used, vm["Table-used"].as< vector<string> >());
785
 
  }
786
 
 
787
 
  if (vm.count("Table-used") and opt_databases)
788
 
  {
789
 
    vector<string> database_used= vm["database-used"].as< vector<string> >();
790
 
    vector<string> table_used= vm["Table-used"].as< vector<string> >();
791
 
 
792
 
    for (vector<string>::iterator it= table_used.begin();
793
 
       it != table_used.end();
794
 
       ++it)
795
 
    {
796
 
      database_used.insert(database_used.end(), *it);
797
 
    }
798
 
 
799
 
    dump_databases(database_used);
800
 
    dump_all_tables();
801
 
  }
802
 
 
803
 
  if (vm.count("database-used") && ! vm.count("Table-used"))
804
 
  {
805
 
    dump_databases(vm["database-used"].as< vector<string> >());
806
 
    dump_all_tables();
807
 
  }
808
 
 
809
 
  if (opt_destination == DESTINATION_STDOUT)
810
 
    generate_dump();
 
3495
    dump_selected_tables(*argv, (argv + 1), (argc - 1));
 
3496
  }
811
3497
  else
812
 
    generate_dump_db();
 
3498
  {
 
3499
    dump_databases(argv);
 
3500
  }
 
3501
 
 
3502
  /* if --dump-slave , start the slave sql thread */
 
3503
  if (opt_slave_data && do_start_slave_sql(mysql))
 
3504
    goto err;
 
3505
 
 
3506
  /* add 'START SLAVE' to end of dump */
 
3507
  if (opt_slave_apply && add_slave_statements())
 
3508
    goto err;
813
3509
 
814
3510
  /* ensure dumped data flushed */
815
3511
  if (md_result_file && fflush(md_result_file))
816
3512
  {
817
3513
    if (!first_error)
818
 
      first_error= EX_DRIZZLEERR;
 
3514
      first_error= EX_MYSQLERR;
819
3515
    goto err;
820
3516
  }
 
3517
  /* everything successful, purge the old logs files */
 
3518
  if (opt_delete_master_logs && purge_bin_logs_to(mysql, bin_log_name))
 
3519
    goto err;
821
3520
 
822
3521
  /*
823
3522
    No reason to explicitely COMMIT the transaction, neither to explicitely
826
3525
    server.
827
3526
  */
828
3527
err:
829
 
  delete db_connection;
830
 
  delete destination_connection;
831
 
  if (path.empty())
 
3528
  dbDisconnect(current_host);
 
3529
  if (!path)
832
3530
    write_footer(md_result_file);
833
3531
  free_resources();
834
3532
 
835
3533
  if (stderror_file)
836
3534
    fclose(stderror_file);
837
 
}
838
3535
 
839
 
  catch(exception &err)
840
 
  {
841
 
    cerr << err.what() << endl;
842
 
  }
843
 
  
844
3536
  return(first_error);
845
3537
} /* main */