mysqldump.c 144 KB
Newer Older
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1
/* Copyright (C) 2000 MySQL AB
2

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3 4
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
5
   the Free Software Foundation; version 2 of the License.
6

bk@work.mysql.com's avatar
bk@work.mysql.com committed
7 8 9 10
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
11

bk@work.mysql.com's avatar
bk@work.mysql.com committed
12 13 14 15 16 17 18 19
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

/* mysqldump.c  - Dump a tables contents and format to an ASCII file
**
** The author's original notes follow :-
**
20 21 22
** AUTHOR: Igor Romanenko (igor@frog.kiev.ua)
** DATE:   December 3, 1994
** WARRANTY: None, expressed, impressed, implied
23
**          or other
24 25 26 27 28 29 30 31
** STATUS: Public domain
** Adapted and optimized for MySQL by
** Michael Widenius, Sinisa Milivojevic, Jani Tolonen
** -w --where added 9/10/98 by Jim Faucette
** slave code by David Saez Padros <david@ols.es>
** master/autocommit code by Brian Aker <brian@tangent.org>
** SSL by
** Andrei Errapart <andreie@no.spam.ee>
monty@mysql.com's avatar
monty@mysql.com committed
32
** Tõnu Samuel  <tonu@please.do.not.remove.this.spam.ee>
33 34
** XML by Gary Huntress <ghuntress@mediaone.net> 10/10/01, cleaned up
** and adapted to mysqldump 05/11/01 by Jani Tolonen
35
** Added --single-transaction option 06/06/2002 by Peter Zaitsev
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
36
** 10 Jun 2003: SET NAMES and --no-set-names by Alexander Barkov
37
*/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
38

39
#define DUMP_VERSION "10.12"
bk@work.mysql.com's avatar
bk@work.mysql.com committed
40

41
#include <my_global.h>
bk@work.mysql.com's avatar
bk@work.mysql.com committed
42
#include <my_sys.h>
43
#include <my_user.h>
bk@work.mysql.com's avatar
bk@work.mysql.com committed
44 45
#include <m_string.h>
#include <m_ctype.h>
46
#include <hash.h>
47
#include <stdarg.h>
bk@work.mysql.com's avatar
bk@work.mysql.com committed
48

49
#include "client_priv.h"
bk@work.mysql.com's avatar
bk@work.mysql.com committed
50 51 52
#include "mysql.h"
#include "mysql_version.h"
#include "mysqld_error.h"
53
#include "../sql/ha_ndbcluster_tables.h"
bk@work.mysql.com's avatar
bk@work.mysql.com committed
54 55 56 57 58 59 60

/* Exit codes */

#define EX_USAGE 1
#define EX_MYSQLERR 2
#define EX_CONSCHECK 3
#define EX_EOM 4
61
#define EX_EOF 5 /* ferror for output file was got */
msvensson@neptunus.(none)[msvensson]'s avatar
patch  
msvensson@neptunus.(none)[msvensson] committed
62
#define EX_ILLEGAL_TABLE 6
bk@work.mysql.com's avatar
bk@work.mysql.com committed
63 64 65 66 67 68 69 70 71

/* index into 'show fields from table' */

#define SHOW_FIELDNAME  0
#define SHOW_TYPE  1
#define SHOW_NULL  2
#define SHOW_DEFAULT  4
#define SHOW_EXTRA  5

72 73 74
/* Size of buffer for dump's select query */
#define QUERY_LENGTH 1536

patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
75 76 77 78 79
/* ignore table flags */
#define IGNORE_NONE 0x00 /* no ignore */
#define IGNORE_DATA 0x01 /* don't dump data for this table */
#define IGNORE_INSERT_DELAYED 0x02 /* table doesn't support INSERT DELAYED */

80 81
static void add_load_option(DYNAMIC_STRING *str, const char *option,
                             const char *option_value);
82
static ulong find_set(TYPELIB *lib, const char *x, uint length,
83
                      char **err_pos, uint *err_len);
84
static char *alloc_query_str(ulong size);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
85

86
static void field_escape(DYNAMIC_STRING* in, const char *from);
87 88
static my_bool  verbose= 0, opt_no_create_info= 0, opt_no_data= 0,
                quick= 1, extended_insert= 1,
89
                lock_tables=1,ignore_errors=0,flush_logs=0,flush_privileges=0,
90
                opt_drop=1,opt_keywords=0,opt_lock=1,opt_compress=0,
91
                opt_delayed=0,create_options=1,opt_quoted=0,opt_databases=0,
jimw@mysql.com's avatar
jimw@mysql.com committed
92 93
                opt_alldbs=0,opt_create_db=0,opt_lock_all_tables=0,
                opt_set_charset=0,
94 95 96 97
                opt_autocommit=0,opt_disable_keys=1,opt_xml=0,
                opt_delete_master_logs=0, tty_password=0,
                opt_single_transaction=0, opt_comments= 0, opt_compact= 0,
                opt_hex_blob=0, opt_order_by_primary=0, opt_ignore=0,
98
                opt_complete_insert= 0, opt_drop_database= 0,
99
                opt_replace_into= 0,
100
                opt_dump_triggers= 0, opt_routines=0, opt_tz_utc=1,
101
                opt_events= 0,
102
                opt_alltspcs=0, opt_notspcs= 0;
103
static ulong opt_max_allowed_packet, opt_net_buffer_length;
104
static MYSQL mysql_connection,*mysql=0;
105
static my_bool insert_pat_inited= 0, info_flag;
106 107
static DYNAMIC_STRING insert_pat;
static char  *opt_password=0,*current_user=0,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
108 109
             *current_host=0,*path=0,*fields_terminated=0,
             *lines_terminated=0, *enclosed=0, *opt_enclosed=0, *escaped=0,
110
             *where=0, *order_by=0,
111
             *opt_compatible_mode_str= 0,
112 113
             *err_ptr= 0,
             *log_error_file= NULL;
114
static char **defaults_argv= 0;
115
static char compatible_mode_normal_str[255];
116
static ulong opt_compatible_mode= 0;
117 118
#define MYSQL_OPT_MASTER_DATA_EFFECTIVE_SQL 1
#define MYSQL_OPT_MASTER_DATA_COMMENTED_SQL 2
119
static uint     opt_mysql_port= 0, opt_master_data;
120
static char * opt_mysql_unix_port=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
121 122
static int   first_error=0;
static DYNAMIC_STRING extended_row;
123
#include <sslopt-vars.h>
124 125 126
FILE *md_result_file= 0;
FILE *stderror_file=0;

127 128 129
#ifdef HAVE_SMEM
static char *shared_memory_base_name=0;
#endif
130
static uint opt_protocol= 0;
131 132 133 134 135 136 137 138 139 140 141 142 143

/*
Dynamic_string wrapper functions. In this file use these
wrappers, they will terminate the process if there is
an allocation failure.
*/
static void init_dynamic_string_checked(DYNAMIC_STRING *str, const char *init_str,
			    uint init_alloc, uint alloc_increment);
static void dynstr_append_checked(DYNAMIC_STRING* dest, const char* src);
static void dynstr_set_checked(DYNAMIC_STRING *str, const char *init_str);
static void dynstr_append_mem_checked(DYNAMIC_STRING *str, const char *append,
			  uint length);
static void dynstr_realloc_checked(DYNAMIC_STRING *str, ulong additional_size);
144
/*
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
145 146 147
  Constant for detection of default value of default_charset.
  If default_charset is equal to mysql_universal_client_charset, then
  it is the default value which assigned at the very beginning of main().
148
*/
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
149
static const char *mysql_universal_client_charset=
150 151
  MYSQL_UNIVERSAL_CLIENT_CHARSET;
static char *default_charset;
152
static CHARSET_INFO *charset_info= &my_charset_latin1;
153
const char *default_dbug_option="d:t:o,/tmp/mysqldump.trace";
154 155
/* have we seen any VIEWs during table scanning? */
my_bool seen_views= 0;
156 157 158
const char *compatible_mode_names[]=
{
  "MYSQL323", "MYSQL40", "POSTGRESQL", "ORACLE", "MSSQL", "DB2",
159 160
  "MAXDB", "NO_KEY_OPTIONS", "NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS",
  "ANSI",
161 162
  NullS
};
163 164 165 166 167 168 169 170 171
#define MASK_ANSI_QUOTES \
(\
 (1<<2)  | /* POSTGRESQL */\
 (1<<3)  | /* ORACLE     */\
 (1<<4)  | /* MSSQL      */\
 (1<<5)  | /* DB2        */\
 (1<<6)  | /* MAXDB      */\
 (1<<10)   /* ANSI       */\
)
172
TYPELIB compatible_mode_typelib= {array_elements(compatible_mode_names) - 1,
173
                                  "", compatible_mode_names, NULL};
174

175
HASH ignore_table;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
176

177
static struct my_option my_long_options[] =
bk@work.mysql.com's avatar
bk@work.mysql.com committed
178
{
179
  {"all", 'a', "Deprecated. Use --create-options instead.",
180
   (uchar**) &create_options, (uchar**) &create_options, 0, GET_BOOL, NO_ARG, 1,
181
   0, 0, 0, 0, 0},
182 183
  {"all-databases", 'A',
   "Dump all the databases. This will be same as --databases with all databases selected.",
184
   (uchar**) &opt_alldbs, (uchar**) &opt_alldbs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
185
   0, 0},
186 187
  {"all-tablespaces", 'Y',
   "Dump all the tablespaces.",
188
   (uchar**) &opt_alltspcs, (uchar**) &opt_alltspcs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
189
   0, 0},
190 191
  {"no-tablespaces", 'y',
   "Do not dump any tablespace information.",
192
   (uchar**) &opt_notspcs, (uchar**) &opt_notspcs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
193
   0, 0},
194
  {"add-drop-database", OPT_DROP_DATABASE, "Add a 'DROP DATABASE' before each create.",
195
   (uchar**) &opt_drop_database, (uchar**) &opt_drop_database, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
196
   0},
197
  {"add-drop-table", OPT_DROP, "Add a 'drop table' before each create.",
198
   (uchar**) &opt_drop, (uchar**) &opt_drop, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0,
199 200
   0},
  {"add-locks", OPT_LOCKS, "Add locks around insert statements.",
201
   (uchar**) &opt_lock, (uchar**) &opt_lock, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0,
202 203
   0},
  {"allow-keywords", OPT_KEYWORDS,
204 205
   "Allow creation of column names that are keywords.", (uchar**) &opt_keywords,
   (uchar**) &opt_keywords, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
206
#ifdef __NETWARE__
207
  {"autoclose", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.",
208 209
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
#endif
210
  {"character-sets-dir", OPT_CHARSETS_DIR,
211 212
   "Directory where character sets are.", (uchar**) &charsets_dir,
   (uchar**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
paul@kite-hub.kitebird.com's avatar
paul@kite-hub.kitebird.com committed
213
  {"comments", 'i', "Write additional information.",
214
   (uchar**) &opt_comments, (uchar**) &opt_comments, 0, GET_BOOL, NO_ARG,
paul@kite-hub.kitebird.com's avatar
paul@kite-hub.kitebird.com committed
215
   1, 0, 0, 0, 0, 0},
216
  {"compatible", OPT_COMPATIBLE,
monty@mishka.local's avatar
monty@mishka.local committed
217
   "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.",
218
   (uchar**) &opt_compatible_mode_str, (uchar**) &opt_compatible_mode_str, 0,
219
   GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
220
  {"compact", OPT_COMPACT,
serg@serg.mylan's avatar
serg@serg.mylan committed
221
   "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",
222
   (uchar**) &opt_compact, (uchar**) &opt_compact, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
223
   0, 0},
224
  {"complete-insert", 'c', "Use complete insert statements.",
225
   (uchar**) &opt_complete_insert, (uchar**) &opt_complete_insert, 0, GET_BOOL,
226
   NO_ARG, 0, 0, 0, 0, 0, 0},
227
  {"compress", 'C', "Use compression in server/client protocol.",
228
   (uchar**) &opt_compress, (uchar**) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
229
   0, 0, 0},
monty@mishka.local's avatar
monty@mishka.local committed
230 231
  {"create-options", OPT_CREATE_OPTIONS,
   "Include all MySQL specific create options.",
232
   (uchar**) &create_options, (uchar**) &create_options, 0, GET_BOOL, NO_ARG, 1,
monty@mishka.local's avatar
monty@mishka.local committed
233
   0, 0, 0, 0, 0},
234 235
  {"databases", 'B',
   "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.",
236
   (uchar**) &opt_databases, (uchar**) &opt_databases, 0, GET_BOOL, NO_ARG, 0, 0,
237
   0, 0, 0, 0},
238 239 240 241
#ifdef DBUG_OFF
  {"debug", '#', "This is a non-debug version. Catch this and exit",
   0,0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
#else
242 243
  {"debug", '#', "Output debug log", (uchar**) &default_dbug_option,
   (uchar**) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
244
#endif
245 246
  {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.", (uchar**) &info_flag,
   (uchar**) &info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
247
  {"default-character-set", OPT_DEFAULT_CHARSET,
248 249
   "Set the default character set.", (uchar**) &default_charset,
   (uchar**) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
250
  {"delayed-insert", OPT_DELAYED, "Insert rows with INSERT DELAYED; ",
251
   (uchar**) &opt_delayed, (uchar**) &opt_delayed, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
252
   0, 0},
253
  {"delete-master-logs", OPT_DELETE_MASTER_LOGS,
254
   "Delete logs on master after backup. This automatically enables --master-data.",
255
   (uchar**) &opt_delete_master_logs, (uchar**) &opt_delete_master_logs, 0,
256
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
257
  {"disable-keys", 'K',
258 259
   "'/*!40000 ALTER TABLE tb_name DISABLE KEYS */; and '/*!40000 ALTER TABLE tb_name ENABLE KEYS */; will be put in the output.", (uchar**) &opt_disable_keys,
   (uchar**) &opt_disable_keys, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
260
  {"events", 'E', "Dump events.",
261
     (uchar**) &opt_events, (uchar**) &opt_events, 0, GET_BOOL,
262
     NO_ARG, 0, 0, 0, 0, 0, 0},
263 264
  {"extended-insert", 'e',
   "Allows utilization of the new, much faster INSERT syntax.",
265
   (uchar**) &extended_insert, (uchar**) &extended_insert, 0, GET_BOOL, NO_ARG,
266
   1, 0, 0, 0, 0, 0},
267
  {"fields-terminated-by", OPT_FTB,
268 269
   "Fields in the textfile are terminated by ...", (uchar**) &fields_terminated,
   (uchar**) &fields_terminated, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
270
  {"fields-enclosed-by", OPT_ENC,
271 272
   "Fields in the importfile are enclosed by ...", (uchar**) &enclosed,
   (uchar**) &enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0 ,0, 0},
273
  {"fields-optionally-enclosed-by", OPT_O_ENC,
274 275
   "Fields in the i.file are opt. enclosed by ...", (uchar**) &opt_enclosed,
   (uchar**) &opt_enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0 ,0, 0},
276
  {"fields-escaped-by", OPT_ESC, "Fields in the i.file are escaped by ...",
277
   (uchar**) &escaped, (uchar**) &escaped, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
278
  {"first-slave", 'x', "Deprecated, renamed to --lock-all-tables.",
279
   (uchar**) &opt_lock_all_tables, (uchar**) &opt_lock_all_tables, 0, GET_BOOL, NO_ARG,
280
   0, 0, 0, 0, 0, 0},
serg@serg.mylan's avatar
serg@serg.mylan committed
281
  {"flush-logs", 'F', "Flush logs file in server before starting dump. "
282 283 284 285 286 287 288 289
   "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 "
   "or --master-data: "
   "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 --master-data with --flush-logs",
290
   (uchar**) &flush_logs, (uchar**) &flush_logs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
291
   0, 0},
292 293 294 295
  {"flush-privileges", OPT_ESC, "Emit a FLUSH PRIVILEGES statement "
   "after dumping the mysql database.  This option should be used any "
   "time the dump contains the mysql database and any other database "
   "that depends on the data in the mysql database for proper restore. ",
296
   (uchar**) &flush_privileges, (uchar**) &flush_privileges, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
297
   0, 0},
298
  {"force", 'f', "Continue even if we get an sql-error.",
299
   (uchar**) &ignore_errors, (uchar**) &ignore_errors, 0, GET_BOOL, NO_ARG,
300 301 302
   0, 0, 0, 0, 0, 0},
  {"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG,
   NO_ARG, 0, 0, 0, 0, 0, 0},
paul@kite-hub.kitebird.com's avatar
paul@kite-hub.kitebird.com committed
303 304
  {"hex-blob", OPT_HEXBLOB, "Dump binary strings (BINARY, "
    "VARBINARY, BLOB) in hexadecimal format.",
305 306 307
   (uchar**) &opt_hex_blob, (uchar**) &opt_hex_blob, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
  {"host", 'h', "Connect to host.", (uchar**) &current_host,
   (uchar**) &current_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
308 309 310 311 312
  {"ignore-table", OPT_IGNORE_TABLE,
   "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",
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
313
  {"insert-ignore", OPT_INSERT_IGNORE, "Insert rows with INSERT IGNORE.",
314
   (uchar**) &opt_ignore, (uchar**) &opt_ignore, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
315
   0, 0},
316
  {"lines-terminated-by", OPT_LTB, "Lines in the i.file are terminated by ...",
317
   (uchar**) &lines_terminated, (uchar**) &lines_terminated, 0, GET_STR,
318
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
319
  {"lock-all-tables", 'x', "Locks all tables across all databases. This "
320 321
   "is achieved by taking a global read lock for the duration of the whole "
   "dump. Automatically turns --single-transaction and --lock-tables off.",
322
   (uchar**) &opt_lock_all_tables, (uchar**) &opt_lock_all_tables, 0, GET_BOOL, NO_ARG,
323
   0, 0, 0, 0, 0, 0},
324 325
  {"lock-tables", 'l', "Lock all tables for read.", (uchar**) &lock_tables,
   (uchar**) &lock_tables, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
326
  {"log-error", OPT_ERROR_LOG_FILE, "Append warnings and errors to given file.",
327
   (uchar**) &log_error_file, (uchar**) &log_error_file, 0, GET_STR,
328
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
329
  {"master-data", OPT_MASTER_DATA,
330 331 332 333 334 335 336 337 338
   "This causes the binary log position and filename to be appended to the "
   "output. If equal to 1, will print it as a CHANGE MASTER command; if equal"
   " to 2, that command will be prefixed with a comment symbol. "
   "This option will turn --lock-all-tables on, unless "
   "--single-transaction is specified too (in which case a "
   "global read lock is only taken a short time at the beginning of the dump "
   "- don't forget to read about --single-transaction below). In all cases "
   "any action on logs will happen at the exact moment of the dump."
   "Option automatically turns --lock-tables off.",
339
   (uchar**) &opt_master_data, (uchar**) &opt_master_data, 0,
340
   GET_UINT, OPT_ARG, 0, 0, MYSQL_OPT_MASTER_DATA_COMMENTED_SQL, 0, 0, 0},
monty@mysql.com's avatar
monty@mysql.com committed
341
  {"max_allowed_packet", OPT_MAX_ALLOWED_PACKET, "",
342
    (uchar**) &opt_max_allowed_packet, (uchar**) &opt_max_allowed_packet, 0,
343
    GET_ULONG, REQUIRED_ARG, 24*1024*1024, 4096,
monty@mysql.com's avatar
monty@mysql.com committed
344 345
   (longlong) 2L*1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0},
  {"net_buffer_length", OPT_NET_BUFFER_LENGTH, "",
346
    (uchar**) &opt_net_buffer_length, (uchar**) &opt_net_buffer_length, 0,
monty@mysql.com's avatar
monty@mysql.com committed
347 348
    GET_ULONG, REQUIRED_ARG, 1024*1024L-1025, 4096, 16*1024L*1024L,
   MALLOC_OVERHEAD-1024, 1024, 0},
349 350
  {"no-autocommit", OPT_AUTOCOMMIT,
   "Wrap tables with autocommit/commit statements.",
351
   (uchar**) &opt_autocommit, (uchar**) &opt_autocommit, 0, GET_BOOL, NO_ARG,
352 353
   0, 0, 0, 0, 0, 0},
  {"no-create-db", 'n',
354
   "'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.}.",
355
   (uchar**) &opt_create_db, (uchar**) &opt_create_db, 0, GET_BOOL, NO_ARG, 0, 0,
356 357
   0, 0, 0, 0},
  {"no-create-info", 't', "Don't write table creation info.",
358
   (uchar**) &opt_no_create_info, (uchar**) &opt_no_create_info, 0, GET_BOOL,
359
   NO_ARG, 0, 0, 0, 0, 0, 0},
360 361
  {"no-data", 'd', "No row information.", (uchar**) &opt_no_data,
   (uchar**) &opt_no_data, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
362
  {"no-set-names", 'N',
363
   "Deprecated. Use --skip-set-charset instead.",
364
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
365
  {"opt", OPT_OPTIMIZE,
366
   "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.",
367
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
paul@kite-hub.kitebird.com's avatar
paul@kite-hub.kitebird.com committed
368 369
  {"order-by-primary", OPT_ORDER_BY_PRIMARY,
   "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.",
370
   (uchar**) &opt_order_by_primary, (uchar**) &opt_order_by_primary, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
371 372 373
  {"password", 'p',
   "Password to use when connecting to server. If password is not given it's solicited on the tty.",
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
bk@work.mysql.com's avatar
bk@work.mysql.com committed
374
#ifdef __WIN__
375
  {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG,
376
   NO_ARG, 0, 0, 0, 0, 0, 0},
bk@work.mysql.com's avatar
bk@work.mysql.com committed
377
#endif
378 379
  {"port", 'P', "Port number to use for connection.", (uchar**) &opt_mysql_port,
   (uchar**) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0,
380
   0},
381
  {"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).",
382
   0, 0, 0, GET_STR,  REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
383
  {"quick", 'q', "Don't buffer query, dump directly to stdout.",
384
   (uchar**) &quick, (uchar**) &quick, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
385
  {"quote-names",'Q', "Quote table and column names with backticks (`).",
386
   (uchar**) &opt_quoted, (uchar**) &opt_quoted, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0,
387
   0, 0},
388
  {"replace", OPT_MYSQL_REPLACE_INTO, "Use REPLACE INTO instead of INSERT INTO.",
389
   (uchar**) &opt_replace_into, (uchar**) &opt_replace_into, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
390
   0, 0},
391
  {"result-file", 'r',
serg@sergbook.mysql.com's avatar
serg@sergbook.mysql.com committed
392
   "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).",
393
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
paul@frost.snake.net's avatar
paul@frost.snake.net committed
394
  {"routines", 'R', "Dump stored routines (functions and procedures).",
395
     (uchar**) &opt_routines, (uchar**) &opt_routines, 0, GET_BOOL,
396
     NO_ARG, 0, 0, 0, 0, 0, 0},
monty@mysql.com's avatar
monty@mysql.com committed
397 398
  {"set-charset", OPT_SET_CHARSET,
   "Add 'SET NAMES default_character_set' to the output. Enabled by default; suppress with --skip-set-charset.",
399
   (uchar**) &opt_set_charset, (uchar**) &opt_set_charset, 0, GET_BOOL, NO_ARG, 1,
monty@mysql.com's avatar
monty@mysql.com committed
400
   0, 0, 0, 0, 0},
401 402 403
  {"set-variable", 'O',
   "Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.",
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
404
#ifdef HAVE_SMEM
405
  {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
406
   "Base name of shared memory.", (uchar**) &shared_memory_base_name, (uchar**) &shared_memory_base_name,
407 408
   0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#endif
monty@mysql.com's avatar
monty@mysql.com committed
409 410 411 412 413
  /*
    Note that the combination --single-transaction --master-data
    will give bullet-proof binlog position only if server >=4.1.3. That's the
    old "FLUSH TABLES WITH READ LOCK does not block commit" fixed bug.
  */
414
  {"single-transaction", OPT_TRANSACTION,
monty@mysql.com's avatar
monty@mysql.com committed
415 416 417 418 419
   "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. Option "
   "automatically turns off --lock-tables.",
420
   (uchar**) &opt_single_transaction, (uchar**) &opt_single_transaction, 0,
monty@mysql.com's avatar
monty@mysql.com committed
421
   GET_BOOL, NO_ARG,  0, 0, 0, 0, 0, 0},
422
  {"skip-opt", OPT_SKIP_OPTIMIZATION,
423
   "Disable --opt. Disables --add-drop-table, --add-locks, --create-options, --quick, --extended-insert, --lock-tables, --set-charset, and --disable-keys.",
424
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
425
  {"socket", 'S', "Socket file to use for connection.",
426
   (uchar**) &opt_mysql_unix_port, (uchar**) &opt_mysql_unix_port, 0, GET_STR,
427
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
428
#include <sslopt-longopts.h>
429 430
  {"tab",'T',
   "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.",
431
   (uchar**) &path, (uchar**) &path, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
432 433
  {"tables", OPT_TABLES, "Overrides option --databases (-B).",
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
434
   {"triggers", OPT_TRIGGERS, "Dump triggers for each dumped table",
435
     (uchar**) &opt_dump_triggers, (uchar**) &opt_dump_triggers, 0, GET_BOOL,
436
     NO_ARG, 1, 0, 0, 0, 0, 0},
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
437
  {"tz-utc", OPT_TZ_UTC,
438
    "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.",
439
    (uchar**) &opt_tz_utc, (uchar**) &opt_tz_utc, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
bk@work.mysql.com's avatar
bk@work.mysql.com committed
440
#ifndef DONT_ALLOW_USER_CHANGE
441
  {"user", 'u', "User for login if not current user.",
442
   (uchar**) &current_user, (uchar**) &current_user, 0, GET_STR, REQUIRED_ARG,
443
   0, 0, 0, 0, 0, 0},
bk@work.mysql.com's avatar
bk@work.mysql.com committed
444
#endif
445
  {"verbose", 'v', "Print info about the various stages.",
446
   (uchar**) &verbose, (uchar**) &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
447 448 449
  {"version",'V', "Output version information and exit.", 0, 0, 0,
   GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
  {"where", 'w', "Dump only selected records; QUOTES mandatory!",
450
   (uchar**) &where, (uchar**) &where, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
451 452
  {"xml", 'X', "Dump a database as well formed XML.", 0, 0, 0, GET_NO_ARG,
   NO_ARG, 0, 0, 0, 0, 0, 0},
453
  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
454 455 456 457
};

static const char *load_default_groups[]= { "mysqldump","client",0 };

458 459 460
static void maybe_exit(int error);
static void die(int error, const char* reason, ...);
static void maybe_die(int error, const char* reason, ...);
461
static void write_header(FILE *sql_file, char *db_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
462
static void print_value(FILE *file, MYSQL_RES  *result, MYSQL_ROW row,
463 464
                        const char *prefix,const char *name,
                        int string_value);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
465 466
static int dump_selected_tables(char *db, char **table_names, int tables);
static int dump_all_tables_in_db(char *db);
467 468 469
static int init_dumping_views(char *);
static int init_dumping_tables(char *);
static int init_dumping(char *, int init_func(char*));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
470 471
static int dump_databases(char **);
static int dump_all_databases();
472
static char *quote_name(const char *name, char *buff, my_bool force);
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
473
char check_if_ignore_table(const char *table_name, char *table_type);
474
static char *primary_key_fields(const char *table_name);
475
static my_bool get_view_structure(char *table, char* db);
476
static my_bool dump_all_views_in_db(char *database);
477 478 479 480
static int dump_all_tablespaces();
static int dump_tablespaces_for_tables(char *db, char **table_names, int tables);
static int dump_tablespaces_for_databases(char** databases);
static int dump_tablespaces(char* ts_where);
481

monty@mysql.com's avatar
monty@mysql.com committed
482
#include <help_start.h>
bk@work.mysql.com's avatar
bk@work.mysql.com committed
483

484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507
/*
  Print the supplied message if in verbose mode

  SYNOPSIS
    verbose_msg()
    fmt   format specifier
    ...   variable number of parameters
*/

static void verbose_msg(const char *fmt, ...)
{
  va_list args;
  DBUG_ENTER("verbose_msg");

  if (!verbose)
    DBUG_VOID_RETURN;

  va_start(args, fmt);
  vfprintf(stderr, fmt, args);
  va_end(args);

  DBUG_VOID_RETURN;
}

508 509
/*
  exit with message if ferror(file)
510

511 512
  SYNOPSIS
    check_io()
513
    file        - checked file
514 515 516 517 518
*/

void check_io(FILE *file)
{
  if (ferror(file))
519
    die(EX_EOF, "Got errno %d on write", errno);
520 521
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
522 523 524
static void print_version(void)
{
  printf("%s  Ver %s Distrib %s, for %s (%s)\n",my_progname,DUMP_VERSION,
monty@mysql.com's avatar
monty@mysql.com committed
525 526
         MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
  NETWARE_SET_SCREEN_MODE(1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
527 528 529
} /* print_version */


530 531 532 533
static void short_usage_sub(void)
{
  printf("Usage: %s [OPTIONS] database [tables]\n", my_progname);
  printf("OR     %s [OPTIONS] --databases [OPTIONS] DB1 [DB2 DB3...]\n",
534
         my_progname);
535
  printf("OR     %s [OPTIONS] --all-databases [OPTIONS]\n", my_progname);
monty@mysql.com's avatar
monty@mysql.com committed
536
  NETWARE_SET_SCREEN_MODE(1);
537 538
}

monty@mysql.com's avatar
monty@mysql.com committed
539

bk@work.mysql.com's avatar
bk@work.mysql.com committed
540 541 542 543 544 545
static void usage(void)
{
  print_version();
  puts("By Igor Romanenko, Monty, Jani & Sinisa");
  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");
  puts("Dumping definition and data mysql database or table");
546
  short_usage_sub();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
547
  print_defaults("my",load_default_groups);
548 549
  my_print_help(my_long_options);
  my_print_variables(my_long_options);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
550 551 552
} /* usage */


553 554 555 556 557 558
static void short_usage(void)
{
  short_usage_sub();
  printf("For more options, use %s --help\n", my_progname);
}

monty@mysql.com's avatar
monty@mysql.com committed
559 560
#include <help_end.h>

561

562
static void write_header(FILE *sql_file, char *db_name)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
563
{
564
  if (opt_xml)
565
  {
566
    fputs("<?xml version=\"1.0\"?>\n", sql_file);
567 568 569 570
    /*
      Schema reference.  Allows use of xsi:nil for NULL values and 
      xsi:type to define an element's data type.
    */
571 572 573 574
    fputs("<mysqldump ", sql_file);
    fputs("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"",
          sql_file);
    fputs(">\n", sql_file);
575
    check_io(sql_file);
576
  }
577
  else if (!opt_compact)
578
  {
579 580 581 582
    if (opt_comments)
    {
      fprintf(sql_file, "-- MySQL dump %s\n--\n", DUMP_VERSION);
      fprintf(sql_file, "-- Host: %s    Database: %s\n",
583 584
              current_host ? current_host : "localhost", db_name ? db_name :
              "");
585
      fputs("-- ------------------------------------------------------\n",
586
            sql_file);
587
      fprintf(sql_file, "-- Server version\t%s\n",
588
              mysql_get_server_info(&mysql_connection));
589
    }
590
    if (opt_set_charset)
bar@bar.intranet.mysql.r18.ru's avatar
bar@bar.intranet.mysql.r18.ru committed
591 592 593 594 595
      fprintf(sql_file,
"\n/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;"
"\n/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;"
"\n/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;"
"\n/*!40101 SET NAMES %s */;\n",default_charset);
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
596 597 598 599 600 601 602

    if (opt_tz_utc)
    {
      fprintf(sql_file, "/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;\n");
      fprintf(sql_file, "/*!40103 SET TIME_ZONE='+00:00' */;\n");
    }

603 604 605
    if (!path)
    {
      fprintf(md_result_file,"\
606 607 608
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;\n\
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;\n\
");
609 610
    }
    fprintf(sql_file,
611 612 613 614
            "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='%s%s%s' */;\n"
            "/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;\n",
            path?"":"NO_AUTO_VALUE_ON_ZERO",compatible_mode_normal_str[0]==0?"":",",
            compatible_mode_normal_str);
615
    check_io(sql_file);
616
  }
617
} /* write_header */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
618

619

620 621 622
static void write_footer(FILE *sql_file)
{
  if (opt_xml)
623
  {
624
    fputs("</mysqldump>\n", sql_file);
625 626
    check_io(sql_file);
  }
627
  else if (!opt_compact)
628
  {
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
629 630 631
    if (opt_tz_utc)
      fprintf(sql_file,"/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;\n");

632 633 634 635
    fprintf(sql_file,"\n/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;\n");
    if (!path)
    {
      fprintf(md_result_file,"\
636
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;\n\
637
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;\n");
638
    }
639
    if (opt_set_charset)
640
      fprintf(sql_file,
bar@bar.intranet.mysql.r18.ru's avatar
bar@bar.intranet.mysql.r18.ru committed
641 642 643
"/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;\n"
"/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;\n"
"/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;\n");
644
    fprintf(sql_file,
645
            "/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;\n");
646
    fputs("\n", sql_file);
647 648 649 650 651 652 653
    if (opt_comments)
    {
      char time_str[20];
      get_date(time_str, GETDATE_DATE_TIME, 0);
      fprintf(sql_file, "-- Dump completed on %s\n",
              time_str);
    }
654
    check_io(sql_file);
655
  }
656
} /* write_footer */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
657

monty@mishka.local's avatar
monty@mishka.local committed
658

659
static void free_table_ent(char *key)
monty@mishka.local's avatar
monty@mishka.local committed
660
{
661
  my_free(key, MYF(0));
monty@mishka.local's avatar
monty@mishka.local committed
662 663
}

664

665 666
uchar* get_table_key(const char *entry, size_t *length,
                     my_bool not_used __attribute__((unused)))
667
{
msvensson@neptunus.(none)[msvensson]'s avatar
patch  
msvensson@neptunus.(none)[msvensson] committed
668
  *length= strlen(entry);
669
  return (uchar*) entry;
670 671 672
}


673 674
static my_bool
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
675
               char *argument)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
676
{
677
  switch (optid) {
678 679 680 681 682
#ifdef __NETWARE__
  case OPT_AUTO_CLOSE:
    setscreenmode(SCR_AUTOCLOSE_ON_EXIT);
    break;
#endif
683 684 685 686 687 688
  case 'p':
    if (argument)
    {
      char *start=argument;
      my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
      opt_password=my_strdup(argument,MYF(MY_FAE));
689
      while (*argument) *argument++= 'x';               /* Destroy argument */
690
      if (*start)
691
        start[1]=0;                             /* Cut length of argument */
692
      tty_password= 0;
693 694 695 696 697
    }
    else
      tty_password=1;
    break;
  case 'r':
grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
698
    if (!(md_result_file= my_fopen(argument, O_WRONLY | FILE_BINARY,
699
                                    MYF(MY_WME))))
700 701 702
      exit(1);
    break;
  case 'W':
bk@work.mysql.com's avatar
bk@work.mysql.com committed
703
#ifdef __WIN__
grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
704
    opt_protocol= MYSQL_PROTOCOL_PIPE;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
705
#endif
706
    break;
707 708 709
  case 'N':
    opt_set_charset= 0;
    break;
710 711 712 713
  case 'T':
    opt_disable_keys=0;
    break;
  case '#':
714
    DBUG_PUSH(argument ? argument : default_dbug_option);
715
    info_flag= 1;
716
    break;
717
#include <sslopt-case.h>
718 719
  case 'V': print_version(); exit(0);
  case 'X':
grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
720
    opt_xml= 1;
721
    extended_insert= opt_drop= opt_lock=
722
      opt_disable_keys= opt_autocommit= opt_create_db= 0;
723 724 725 726 727
    break;
  case 'I':
  case '?':
    usage();
    exit(0);
728 729 730 731
  case (int) OPT_MASTER_DATA:
    if (!argument) /* work like in old versions */
      opt_master_data= MYSQL_OPT_MASTER_DATA_EFFECTIVE_SQL;
    break;
732
  case (int) OPT_OPTIMIZE:
733
    extended_insert= opt_drop= opt_lock= quick= create_options=
734
      opt_disable_keys= lock_tables= opt_set_charset= 1;
735
    break;
736 737
  case (int) OPT_SKIP_OPTIMIZATION:
    extended_insert= opt_drop= opt_lock= quick= create_options=
monty@mishka.local's avatar
monty@mishka.local committed
738
      opt_disable_keys= lock_tables= opt_set_charset= 0;
739
    break;
740 741 742 743
  case (int) OPT_COMPACT:
  if (opt_compact)
  {
    opt_comments= opt_drop= opt_disable_keys= opt_lock= 0;
744
    opt_set_charset= 0;
745
  }
746 747 748
  case (int) OPT_TABLES:
    opt_databases=0;
    break;
749 750
  case (int) OPT_IGNORE_TABLE:
  {
serg@serg.mylan's avatar
serg@serg.mylan committed
751
    if (!strchr(argument, '.'))
752
    {
serg@serg.mylan's avatar
serg@serg.mylan committed
753
      fprintf(stderr, "Illegal use of option --ignore-table=<database>.<table>\n");
754 755
      exit(1);
    }
756
    if (my_hash_insert(&ignore_table, (uchar*)my_strdup(argument, MYF(0))))
serg@serg.mylan's avatar
serg@serg.mylan committed
757
      exit(EX_EOM);
758 759
    break;
  }
760
  case (int) OPT_COMPATIBLE:
serg@serg.mylan's avatar
serg@serg.mylan committed
761
    {
762
      char buff[255];
763 764 765
      char *end= compatible_mode_normal_str;
      int i;
      ulong mode;
766
      uint err_len;
767 768

      opt_quoted= 1;
769
      opt_set_charset= 0;
770 771
      opt_compatible_mode_str= argument;
      opt_compatible_mode= find_set(&compatible_mode_typelib,
772 773
                                    argument, strlen(argument),
                                    &err_ptr, &err_len);
774 775
      if (err_len)
      {
776 777 778
        strmake(buff, err_ptr, min(sizeof(buff), err_len));
        fprintf(stderr, "Invalid mode to --compatible: %s\n", buff);
        exit(1);
779
      }
780 781
#if !defined(DBUG_OFF)
      {
782 783 784 785 786 787
        uint size_for_sql_mode= 0;
        const char **ptr;
        for (ptr= compatible_mode_names; *ptr; ptr++)
          size_for_sql_mode+= strlen(*ptr);
        size_for_sql_mode+= sizeof(compatible_mode_names)-1;
        DBUG_ASSERT(sizeof(compatible_mode_normal_str)>=size_for_sql_mode);
788 789 790 791 792
      }
#endif
      mode= opt_compatible_mode;
      for (i= 0, mode= opt_compatible_mode; mode; mode>>= 1, i++)
      {
793 794 795 796 797
        if (mode & 1)
        {
          end= strmov(end, compatible_mode_names[i]);
          end= strmov(end, ",");
        }
798 799
      }
      if (end!=compatible_mode_normal_str)
800 801
        end[-1]= 0;
      /*
802 803 804
        Set charset to the default compiled value if it hasn't
        been reset yet by --default-character-set=xxx.
      */
805
      if (default_charset == mysql_universal_client_charset)
806
        default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME;
807 808 809
      break;
    }
  case (int) OPT_MYSQL_PROTOCOL:
810 811 812
    opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib,
                                    opt->name);
    break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
813
  }
814 815 816 817 818 819
  return 0;
}

static int get_options(int *argc, char ***argv)
{
  int ho_error;
820 821 822 823
  MYSQL_PARAMETERS *mysql_params= mysql_get_parameters();

  opt_max_allowed_packet= *mysql_params->p_max_allowed_packet;
  opt_net_buffer_length= *mysql_params->p_net_buffer_length;
824 825 826

  md_result_file= stdout;
  load_defaults("my",load_default_groups,argc,argv);
827
  defaults_argv= *argv;
828

829 830 831 832
  if (hash_init(&ignore_table, charset_info, 16, 0, 0,
                (hash_get_key) get_table_key,
                (hash_free_key) free_table_ent, 0))
    return(EX_EOM);
833
  /* Don't copy internal log tables */
834
  if (my_hash_insert(&ignore_table,
835
                     (uchar*) my_strdup("mysql.apply_status", MYF(MY_WME))) ||
836
      my_hash_insert(&ignore_table,
837
                     (uchar*) my_strdup("mysql.schema", MYF(MY_WME))) ||
838
      my_hash_insert(&ignore_table,
839
                     (uchar*) my_strdup("mysql.general_log", MYF(MY_WME))) ||
840
      my_hash_insert(&ignore_table,
841
                     (uchar*) my_strdup("mysql.slow_log", MYF(MY_WME))))
842
    return(EX_EOM);
843

844 845
  if ((ho_error= handle_options(argc, argv, my_long_options, get_one_option)))
    return(ho_error);
846

847 848 849
  *mysql_params->p_max_allowed_packet= opt_max_allowed_packet;
  *mysql_params->p_net_buffer_length= opt_net_buffer_length;

bk@work.mysql.com's avatar
bk@work.mysql.com committed
850
  if (opt_delayed)
851
    opt_lock=0;                         /* Can't have lock with delayed */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
852
  if (!path && (enclosed || opt_enclosed || escaped || lines_terminated ||
853
                fields_terminated))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
854
  {
855
    fprintf(stderr,
856
            "%s: You must use option --tab with --fields-...\n", my_progname);
857
    return(EX_USAGE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
858
  }
859 860 861 862 863 864 865 866

  /* Ensure consistency of the set of binlog & locking options */
  if (opt_delete_master_logs && !opt_master_data)
    opt_master_data= MYSQL_OPT_MASTER_DATA_COMMENTED_SQL;
  if (opt_single_transaction && opt_lock_all_tables)
  {
    fprintf(stderr, "%s: You can't use --single-transaction and "
            "--lock-all-tables at the same time.\n", my_progname);
867
    return(EX_USAGE);
868
  }
869 870 871
  if (opt_master_data)
    opt_lock_all_tables= !opt_single_transaction;
  if (opt_single_transaction || opt_lock_all_tables)
872
    lock_tables= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
873 874 875
  if (enclosed && opt_enclosed)
  {
    fprintf(stderr, "%s: You can't use ..enclosed.. and ..optionally-enclosed.. at the same time.\n", my_progname);
876
    return(EX_USAGE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
877 878 879 880
  }
  if ((opt_databases || opt_alldbs) && path)
  {
    fprintf(stderr,
881 882
            "%s: --databases or --all-databases can't be used with --tab.\n",
            my_progname);
883
    return(EX_USAGE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
884
  }
885
  if (strcmp(default_charset, charset_info->csname) &&
886 887
      !(charset_info= get_charset_by_csname(default_charset,
                                            MY_CS_PRIMARY, MYF(MY_WME))))
888
    exit(1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
889 890
  if ((*argc < 1 && !opt_alldbs) || (*argc > 0 && opt_alldbs))
  {
891
    short_usage();
892
    return EX_USAGE;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
893 894
  }
  if (tty_password)
895
    opt_password=get_tty_password(NullS);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
896 897 898 899 900
  return(0);
} /* get_options */


/*
901
** DB_error -- prints mysql error message and exits the program.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
902
*/
903
static void DB_error(MYSQL *mysql_arg, const char *when)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
904
{
905
  DBUG_ENTER("DB_error");
906
  maybe_die(EX_MYSQLERR, "Got error: %d: %s %s",
907
          mysql_errno(mysql_arg), mysql_error(mysql_arg), when);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
908
  DBUG_VOID_RETURN;
909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973
}



/*
  Prints out an error message and kills the process.

  SYNOPSIS
    die()
    error_num   - process return value
    fmt_reason  - a format string for use by my_vsnprintf.
    ...         - variable arguments for above fmt_reason string
  
  DESCRIPTION
    This call prints out the formatted error message to stderr and then
    terminates the process.
*/
static void die(int error_num, const char* fmt_reason, ...)
{
  char buffer[1000];
  va_list args;
  va_start(args,fmt_reason);
  my_vsnprintf(buffer, sizeof(buffer), fmt_reason, args);
  va_end(args);

  fprintf(stderr, "%s: %s\n", my_progname, buffer);
  fflush(stderr);

  ignore_errors= 0; /* force the exit */
  maybe_exit(error_num);
}


/*
  Prints out an error message and maybe kills the process.

  SYNOPSIS
    maybe_die()
    error_num   - process return value
    fmt_reason  - a format string for use by my_vsnprintf.
    ...         - variable arguments for above fmt_reason string
  
  DESCRIPTION
    This call prints out the formatted error message to stderr and then
    terminates the process, unless the --force command line option is used.
    
    This call should be used for non-fatal errors (such as database
    errors) that the code may still be able to continue to the next unit
    of work.
    
*/
static void maybe_die(int error_num, const char* fmt_reason, ...)
{
  char buffer[1000];
  va_list args;
  va_start(args,fmt_reason);
  my_vsnprintf(buffer, sizeof(buffer), fmt_reason, args);
  va_end(args);

  fprintf(stderr, "%s: %s\n", my_progname, buffer);
  fflush(stderr);

  maybe_exit(error_num);
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
974 975


976 977 978 979 980 981 982
/*
  Sends a query to server, optionally reads result, prints error message if
  some.

  SYNOPSIS
    mysql_query_with_error_report()
    mysql_con       connection to use
monty@mysql.com's avatar
monty@mysql.com committed
983
    res             if non zero, result will be put there with
984
                    mysql_store_result()
985 986 987 988 989 990
    query           query to send to server

  RETURN VALUES
    0               query sending and (if res!=0) result reading went ok
    1               error
*/
991

992 993 994 995 996 997
static int mysql_query_with_error_report(MYSQL *mysql_con, MYSQL_RES **res,
                                         const char *query)
{
  if (mysql_query(mysql_con, query) ||
      (res && !((*res)= mysql_store_result(mysql_con))))
  {
998 999
    maybe_die(EX_MYSQLERR, "Couldn't execute '%s': %s (%d)",
            query, mysql_error(mysql_con), mysql_errno(mysql_con));
1000 1001 1002 1003 1004
    return 1;
  }
  return 0;
}

1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190

static int fetch_db_collation(const char *db_name,
                              char *db_cl_name,
                              int db_cl_size)
{
  bool err_status= FALSE;
  char query[QUERY_LENGTH];
  MYSQL_RES *db_cl_res;
  MYSQL_ROW db_cl_row;

  my_snprintf(query, sizeof (query), "use %s", db_name);

  if (mysql_query_with_error_report(mysql, NULL, query))
    return 1;

  if (mysql_query_with_error_report(mysql, &db_cl_res,
                                    "select @@collation_database"))
    return 1;

  do
  {
    if (mysql_num_rows(db_cl_res) != 1)
    {
      err_status= TRUE;
      break;
    }

    if (!(db_cl_row= mysql_fetch_row(db_cl_res)))
    {
      err_status= TRUE;
      break;
    }

    strncpy(db_cl_name, db_cl_row[0], db_cl_size);
    db_cl_name[db_cl_size - 1]= 0; /* just in case. */

  } while (FALSE);

  mysql_free_result(db_cl_res);

  return err_status ? 1 : 0;
}


static char *my_case_str(const char *str,
                         uint str_len,
                         const char *token,
                         uint token_len)
{
  my_match_t match;

  uint status= my_charset_latin1.coll->instr(&my_charset_latin1,
                                             str, str_len,
                                             token, token_len,
                                             &match, 1);

  return status ? (char *) str + match.end : NULL;
}


static int switch_db_collation(FILE *sql_file,
                               const char *db_name,
                               const char *delimiter,
                               const char *current_db_cl_name,
                               const char *required_db_cl_name)
{
  if (strcmp(current_db_cl_name, required_db_cl_name) != 0)
  {
    CHARSET_INFO *db_cl= get_charset_by_name(required_db_cl_name, MYF(0));

    fprintf(sql_file,
            "ALTER DATABASE %s CHARACTER SET %s COLLATE %s %s\n",
            (const char *) db_name,
            (const char *) db_cl->csname,
            (const char *) db_cl->name,
            (const char *) delimiter);

    return 1;
  }

  return 0;
}


static void restore_db_collation(FILE *sql_file,
                                 const char *db_name,
                                 const char *delimiter,
                                 const char *db_cl_name)
{
  CHARSET_INFO *db_cl= get_charset_by_name(db_cl_name, MYF(0));

  fprintf(sql_file,
          "ALTER DATABASE %s CHARACTER SET %s COLLATE %s %s\n",
          (const char *) db_name,
          (const char *) db_cl->csname,
          (const char *) db_cl->name,
          (const char *) delimiter);
}


static void switch_cs_variables(FILE *sql_file,
                                const char *delimiter,
                                const char *character_set_client,
                                const char *character_set_results,
                                const char *collation_connection)
{
  fprintf(sql_file,
          "/*!50003 SET @saved_cs_client      = @@character_set_client */ %s\n"
          "/*!50003 SET @saved_cs_results     = @@character_set_results */ %s\n"
          "/*!50003 SET @saved_col_connection = @@collation_connection */ %s\n"
          "/*!50003 SET character_set_client  = %s */ %s\n"
          "/*!50003 SET character_set_results = %s */ %s\n"
          "/*!50003 SET collation_connection  = %s */ %s\n",
          (const char *) delimiter,
          (const char *) delimiter,
          (const char *) delimiter,

          (const char *) character_set_client,
          (const char *) delimiter,

          (const char *) character_set_results,
          (const char *) delimiter,

          (const char *) collation_connection,
          (const char *) delimiter);
}


static void restore_cs_variables(FILE *sql_file,
                                 const char *delimiter)
{
  fprintf(sql_file,
          "/*!50003 SET character_set_client  = @saved_cs_client */ %s\n"
          "/*!50003 SET character_set_results = @saved_cs_results */ %s\n"
          "/*!50003 SET collation_connection  = @saved_col_connection */ %s\n",
          (const char *) delimiter,
          (const char *) delimiter,
          (const char *) delimiter);
}


static void switch_sql_mode(FILE *sql_file,
                            const char *delimiter,
                            const char *sql_mode)
{
  fprintf(sql_file,
          "/*!50003 SET @saved_sql_mode       = @@sql_mode */ %s\n"
          "/*!50003 SET sql_mode              = '%s' */ %s\n",
          (const char *) delimiter,

          (const char *) sql_mode,
          (const char *) delimiter);
}


static void restore_sql_mode(FILE *sql_file,
                             const char *delimiter)
{
  fprintf(sql_file,
          "/*!50003 SET sql_mode              = @saved_sql_mode */ %s\n",
          (const char *) delimiter);
}


static void switch_time_zone(FILE *sql_file,
                             const char *delimiter,
                             const char *time_zone)
{
  fprintf(sql_file,
          "/*!50003 SET @saved_time_zone      = @@time_zone */ %s\n"
          "/*!50003 SET time_zone             = '%s' */ %s\n",
          (const char *) delimiter,

          (const char *) time_zone,
          (const char *) delimiter);
}


static void restore_time_zone(FILE *sql_file,
                              const char *delimiter)
{
  fprintf(sql_file,
          "/*!50003 SET time_zone             = @saved_time_zone */ %s\n",
          (const char *) delimiter);
}

1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207
/*
  Open a new .sql file to dump the table or view into

  SYNOPSIS
    open_sql_file_for_table
    name      name of the table or view

  RETURN VALUES
    0        Failed to open file
    > 0      Handle of the open file
*/
static FILE* open_sql_file_for_table(const char* table)
{
  FILE* res;
  char filename[FN_REFLEN], tmp_path[FN_REFLEN];
  convert_dirname(tmp_path,path,NullS);
  res= my_fopen(fn_format(filename, table, tmp_path, ".sql", 4),
1208
                O_WRONLY, MYF(MY_WME));
1209 1210 1211
  return res;
}

1212

1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229
static void free_resources()
{
  if (md_result_file && md_result_file != stdout)
    my_fclose(md_result_file, MYF(0));
  my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR));
  if (hash_inited(&ignore_table))
    hash_free(&ignore_table);
  if (extended_insert)
    dynstr_free(&extended_row);
  if (insert_pat_inited)
    dynstr_free(&insert_pat);
  if (defaults_argv)
    free_defaults(defaults_argv);
  my_end(info_flag ? MY_CHECK_ERROR : 0);
}


1230
static void maybe_exit(int error)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1231 1232 1233 1234 1235
{
  if (!first_error)
    first_error= error;
  if (ignore_errors)
    return;
1236 1237
  if (mysql)
    mysql_close(mysql);
1238
  free_resources();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1239 1240 1241 1242 1243
  exit(error);
}


/*
1244
  db_connect -- connects to the host and selects DB.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1245
*/
1246 1247

static int connect_to_db(char *host, char *user,char *passwd)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1248
{
1249
  char buff[20+FN_REFLEN];
1250
  DBUG_ENTER("connect_to_db");
1251 1252

  verbose_msg("-- Connecting to %s...\n", host ? host : "localhost");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1253 1254 1255 1256 1257 1258
  mysql_init(&mysql_connection);
  if (opt_compress)
    mysql_options(&mysql_connection,MYSQL_OPT_COMPRESS,NullS);
#ifdef HAVE_OPENSSL
  if (opt_use_ssl)
    mysql_ssl_set(&mysql_connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
1259
                  opt_ssl_capath, opt_ssl_cipher);
1260 1261
  mysql_options(&mysql_connection,MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
                (char*)&opt_ssl_verify_server_cert);
1262 1263 1264 1265 1266 1267
#endif
  if (opt_protocol)
    mysql_options(&mysql_connection,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
#ifdef HAVE_SMEM
  if (shared_memory_base_name)
    mysql_options(&mysql_connection,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1268
#endif
1269
  mysql_options(&mysql_connection, MYSQL_SET_CHARSET_NAME, default_charset);
1270
  if (!(mysql= mysql_real_connect(&mysql_connection,host,user,passwd,
1271 1272
                                  NULL,opt_mysql_port,opt_mysql_unix_port,
                                  0)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1273
  {
1274
    DB_error(&mysql_connection, "when trying to connect");
1275
    DBUG_RETURN(1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1276
  }
bar@mysql.com's avatar
bar@mysql.com committed
1277 1278 1279 1280 1281
  /*
    Don't dump SET NAMES with a pre-4.1 server (bug#7997).
  */
  if (mysql_get_server_version(&mysql_connection) < 40100)
    opt_set_charset= 0;
1282 1283 1284 1285
  /*
    As we're going to set SQL_MODE, it would be lost on reconnect, so we
    cannot reconnect.
  */
1286
  mysql->reconnect= 0;
1287
  my_snprintf(buff, sizeof(buff), "/*!40100 SET @@SQL_MODE='%s' */",
1288
              compatible_mode_normal_str);
1289
  if (mysql_query_with_error_report(mysql, 0, buff))
1290
    DBUG_RETURN(1);
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
1291
  /*
1292
    set time_zone to UTC to allow dumping date types between servers with
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
1293 1294 1295 1296 1297
    different time zone settings
  */
  if (opt_tz_utc)
  {
    my_snprintf(buff, sizeof(buff), "/*!40103 SET TIME_ZONE='+00:00' */");
1298
    if (mysql_query_with_error_report(mysql, 0, buff))
1299
      DBUG_RETURN(1);
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
1300
  }
1301 1302
  DBUG_RETURN(0);
} /* connect_to_db */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1303 1304 1305 1306 1307 1308 1309


/*
** dbDisconnect -- disconnects from the host.
*/
static void dbDisconnect(char *host)
{
1310
  verbose_msg("-- Disconnecting from %s...\n", host ? host : "localhost");
1311
  mysql_close(mysql);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1312 1313 1314 1315 1316 1317 1318 1319
} /* dbDisconnect */


static void unescape(FILE *file,char *pos,uint length)
{
  char *tmp;
  DBUG_ENTER("unescape");
  if (!(tmp=(char*) my_malloc(length*2+1, MYF(MY_WME))))
1320 1321
    die(EX_MYSQLERR, "Couldn't allocate memory");

1322
  mysql_real_escape_string(&mysql_connection, tmp, pos, length);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1323 1324 1325
  fputc('\'', file);
  fputs(tmp, file);
  fputc('\'', file);
1326
  check_io(file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1327 1328 1329 1330 1331 1332 1333 1334 1335
  my_free(tmp, MYF(MY_WME));
  DBUG_VOID_RETURN;
} /* unescape */


static my_bool test_if_special_chars(const char *str)
{
#if MYSQL_VERSION_ID >= 32300
  for ( ; *str ; str++)
1336
    if (!my_isvar(charset_info,*str) && *str != '$')
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1337 1338 1339 1340 1341
      return 1;
#endif
  return 0;
} /* test_if_special_chars */

1342

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1343

patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
1344 1345 1346
/*
  quote_name(name, buff, force)

1347
  Quotes char string, taking into account compatible mode
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
1348 1349 1350 1351 1352

  Args

  name                 Unquoted string containing that which will be quoted
  buff                 The buffer that contains the quoted value, also returned
1353
  force                Flag to make it ignore 'test_if_special_chars'
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
1354 1355 1356 1357 1358 1359

  Returns

  buff                 quoted string

*/
1360
static char *quote_name(const char *name, char *buff, my_bool force)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1361
{
1362
  char *to= buff;
1363 1364
  char qtype= (opt_compatible_mode & MASK_ANSI_QUOTES) ? '\"' : '`';

1365 1366
  if (!force && !opt_quoted && !test_if_special_chars(name))
    return (char*) name;
1367
  *to++= qtype;
1368 1369
  while (*name)
  {
1370 1371
    if (*name == qtype)
      *to++= qtype;
1372 1373
    *to++= *name++;
  }
1374 1375
  to[0]= qtype;
  to[1]= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1376 1377 1378
  return buff;
} /* quote_name */

monty@mishka.local's avatar
monty@mishka.local committed
1379

msvensson@neptunus.(none)[msvensson]'s avatar
patch  
msvensson@neptunus.(none)[msvensson] committed
1380 1381
/*
  Quote a table name so it can be used in "SHOW TABLES LIKE <tabname>"
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1382

msvensson@neptunus.(none)[msvensson]'s avatar
patch  
msvensson@neptunus.(none)[msvensson] committed
1383
  SYNOPSIS
monty@mishka.local's avatar
monty@mishka.local committed
1384 1385 1386
    quote_for_like()
    name     name of the table
    buff     quoted name of the table
msvensson@neptunus.(none)[msvensson]'s avatar
patch  
msvensson@neptunus.(none)[msvensson] committed
1387 1388 1389

  DESCRIPTION
    Quote \, _, ' and % characters
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1390

msvensson@neptunus.(none)[msvensson]'s avatar
patch  
msvensson@neptunus.(none)[msvensson] committed
1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401
    Note: Because MySQL uses the C escape syntax in strings
    (for example, '\n' to represent newline), you must double
    any '\' that you use in your LIKE  strings. For example, to
    search for '\n', specify it as '\\n'. To search for '\', specify
    it as '\\\\' (the backslashes are stripped once by the parser
    and another time when the pattern match is done, leaving a
    single backslash to be matched).

    Example: "t\1" => "t\\\\1"

*/
1402 1403 1404 1405 1406 1407
static char *quote_for_like(const char *name, char *buff)
{
  char *to= buff;
  *to++= '\'';
  while (*name)
  {
msvensson@neptunus.(none)[msvensson]'s avatar
patch  
msvensson@neptunus.(none)[msvensson] committed
1408 1409 1410 1411 1412 1413 1414
    if (*name == '\\')
    {
      *to++='\\';
      *to++='\\';
      *to++='\\';
    }
    else if (*name == '\'' || *name == '_'  || *name == '%')
1415 1416 1417 1418 1419 1420 1421 1422 1423
      *to++= '\\';
    *to++= *name++;
  }
  to[0]= '\'';
  to[1]= 0;
  return buff;
}


1424 1425
/*
  Quote and print a string.
1426

1427 1428
  SYNOPSIS
    print_quoted_xml()
1429
    xml_file    - output file
1430 1431 1432
    str         - string to print
    len         - its length

1433
  DESCRIPTION
1434
    Quote '<' '>' '&' '\"' chars and print a string to the xml_file.
1435 1436 1437 1438 1439
*/

static void print_quoted_xml(FILE *xml_file, const char *str, ulong len)
{
  const char *end;
1440

1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460
  for (end= str + len; str != end; str++)
  {
    switch (*str) {
    case '<':
      fputs("&lt;", xml_file);
      break;
    case '>':
      fputs("&gt;", xml_file);
      break;
    case '&':
      fputs("&amp;", xml_file);
      break;
    case '\"':
      fputs("&quot;", xml_file);
      break;
    default:
      fputc(*str, xml_file);
      break;
    }
  }
1461
  check_io(xml_file);
1462 1463 1464 1465
}


/*
1466
  Print xml tag. Optionally add attribute(s).
1467

1468
  SYNOPSIS
1469 1470 1471 1472
    print_xml_tag(xml_file, sbeg, send, tag_name, first_attribute_name, 
                    ..., attribute_name_n, attribute_value_n, NullS)
    xml_file              - output file
    sbeg                  - line beginning
1473
    line_end              - line ending
1474 1475 1476 1477 1478
    tag_name              - XML tag name.
    first_attribute_name  - tag and first attribute
    first_attribute_value - (Implied) value of first attribute
    attribute_name_n      - attribute n
    attribute_value_n     - value of attribute n
1479

1480
  DESCRIPTION
1481 1482 1483 1484 1485
    Print XML tag with any number of attribute="value" pairs to the xml_file.

    Format is:
      sbeg<tag_name first_attribute_name="first_attribute_value" ... 
      attribute_name_n="attribute_value_n">send
1486
  NOTE
1487 1488 1489 1490
    Additional arguments must be present in attribute/value pairs.
    The last argument should be the null character pointer.
    All attribute_value arguments MUST be NULL terminated strings.
    All attribute_value arguments will be quoted before output.
1491 1492
*/

1493 1494
static void print_xml_tag(FILE * xml_file, const char* sbeg,
                          const char* line_end, 
1495 1496
                          const char* tag_name, 
                          const char* first_attribute_name, ...)
1497
{
1498
  va_list arg_list;
1499
  const char *attribute_name, *attribute_value;
1500

1501
  fputs(sbeg, xml_file);
1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523
  fputc('<', xml_file);
  fputs(tag_name, xml_file);  

  va_start(arg_list, first_attribute_name);
  attribute_name= first_attribute_name;
  while (attribute_name != NullS)
  {
    attribute_value= va_arg(arg_list, char *);
    DBUG_ASSERT(attribute_value != NullS);

    fputc(' ', xml_file);
    fputs(attribute_name, xml_file);    
    fputc('\"', xml_file);
    
    print_quoted_xml(xml_file, attribute_value, strlen(attribute_value));
    fputc('\"', xml_file);

    attribute_name= va_arg(arg_list, char *);
  }
  va_end(arg_list);

  fputc('>', xml_file);
1524
  fputs(line_end, xml_file);
1525
  check_io(xml_file);
1526 1527 1528
}


1529 1530 1531 1532 1533
/*
  Print xml tag with for a field that is null

  SYNOPSIS
    print_xml_null_tag()
1534 1535 1536 1537
    xml_file    - output file
    sbeg        - line beginning
    stag_atr    - tag and attribute
    sval        - value of attribute
1538
    line_end        - line ending
1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549

  DESCRIPTION
    Print tag with one attribute to the xml_file. Format is:
      <stag_atr="sval" xsi:nil="true"/>
  NOTE
    sval MUST be a NULL terminated string.
    sval string will be qouted before output.
*/

static void print_xml_null_tag(FILE * xml_file, const char* sbeg,
                               const char* stag_atr, const char* sval,
1550
                               const char* line_end)
1551 1552 1553 1554 1555 1556 1557
{
  fputs(sbeg, xml_file);
  fputs("<", xml_file);
  fputs(stag_atr, xml_file);
  fputs("\"", xml_file);
  print_quoted_xml(xml_file, sval, strlen(sval));
  fputs("\" xsi:nil=\"true\" />", xml_file);
1558
  fputs(line_end, xml_file);
1559 1560 1561 1562
  check_io(xml_file);
}


1563 1564 1565 1566 1567
/*
  Print xml tag with many attributes.

  SYNOPSIS
    print_xml_row()
1568 1569 1570 1571 1572
    xml_file    - output file
    row_name    - xml tag name
    tableRes    - query result
    row         - result row

1573 1574 1575 1576 1577 1578 1579 1580
  DESCRIPTION
    Print tag with many attribute to the xml_file. Format is:
      \t\t<row_name Atr1="Val1" Atr2="Val2"... />
  NOTE
    All atributes and values will be quoted before output.
*/

static void print_xml_row(FILE *xml_file, const char *row_name,
1581
                          MYSQL_RES *tableRes, MYSQL_ROW *row)
1582 1583 1584 1585
{
  uint i;
  MYSQL_FIELD *field;
  ulong *lengths= mysql_fetch_lengths(tableRes);
1586

1587
  fprintf(xml_file, "\t\t<%s", row_name);
1588
  check_io(xml_file);
1589 1590 1591
  mysql_field_seek(tableRes, 0);
  for (i= 0; (field= mysql_fetch_field(tableRes)); i++)
  {
1592
    if ((*row)[i])
1593
    {
monty@mishka.local's avatar
monty@mishka.local committed
1594
      fputc(' ', xml_file);
1595
      print_quoted_xml(xml_file, field->name, field->name_length);
1596 1597
      fputs("=\"", xml_file);
      print_quoted_xml(xml_file, (*row)[i], lengths[i]);
monty@mishka.local's avatar
monty@mishka.local committed
1598
      fputc('"', xml_file);
1599
      check_io(xml_file);
1600 1601 1602
    }
  }
  fputs(" />\n", xml_file);
1603
  check_io(xml_file);
1604 1605
}

1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658

/*
 create_delimiter
 Generate a new (null-terminated) string that does not exist in  query 
 and is therefore suitable for use as a query delimiter.  Store this
 delimiter in  delimiter_buff .
 
 This is quite simple in that it doesn't even try to parse statements as an
 interpreter would.  It merely returns a string that is not in the query, which
 is much more than adequate for constructing a delimiter.

 RETURN
   ptr to the delimiter  on Success
   NULL                  on Failure
*/
static char *create_delimiter(char *query, char *delimiter_buff, 
                              int delimiter_max_size) 
{
  int proposed_length;
  char *presence;

  delimiter_buff[0]= ';';  /* start with one semicolon, and */

  for (proposed_length= 2; proposed_length < delimiter_max_size; 
      delimiter_max_size++) {

    delimiter_buff[proposed_length-1]= ';';  /* add semicolons, until */
    delimiter_buff[proposed_length]= '\0';

    presence = strstr(query, delimiter_buff);
    if (presence == NULL) { /* the proposed delimiter is not in the query. */
       return delimiter_buff;
    }

  }
  return NULL;  /* but if we run out of space, return nothing at all. */
}


/*
  dump_events_for_db
  -- retrieves list of events for a given db, and prints out
  the CREATE EVENT statement into the output (the dump).

  RETURN
    0  Success
    1  Error
*/
static uint dump_events_for_db(char *db)
{
  char       query_buff[QUERY_LENGTH];
  char       db_name_buff[NAME_LEN*2+3], name_buff[NAME_LEN*2+3];
  char       *event_name;
1659
  char       delimiter[QUERY_LENGTH];
1660 1661 1662
  FILE       *sql_file= md_result_file;
  MYSQL_RES  *event_res, *event_list_res;
  MYSQL_ROW  row, event_list_row;
1663 1664 1665 1666

  char       db_cl_name[MY_CS_NAME_SIZE];
  int        db_cl_altered;

1667 1668 1669
  DBUG_ENTER("dump_events_for_db");
  DBUG_PRINT("enter", ("db: '%s'", db));

1670
  mysql_real_escape_string(mysql, db_name_buff, db, strlen(db));
1671 1672 1673 1674 1675 1676 1677 1678 1679 1680

  /* nice comments */
  if (opt_comments)
    fprintf(sql_file, "\n--\n-- Dumping events for database '%s'\n--\n", db);

  /*
    not using "mysql_query_with_error_report" because we may have not
    enough privileges to lock mysql.events.
  */
  if (lock_tables)
1681
    mysql_query(mysql, "LOCK TABLES mysql.event READ");
1682

1683
  if (mysql_query_with_error_report(mysql, &event_list_res, "show events"))
1684 1685 1686 1687 1688
    DBUG_RETURN(0);

  strcpy(delimiter, ";");
  if (mysql_num_rows(event_list_res) > 0)
  {
1689 1690
    fprintf(sql_file, "/*!50106 SET @save_time_zone= @@TIME_ZONE */ ;\n");

1691 1692 1693 1694 1695
    /* Get database collation. */

    if (fetch_db_collation(db_name_buff, db_cl_name, sizeof (db_cl_name)))
      DBUG_RETURN(1);

1696 1697 1698 1699 1700 1701 1702
    while ((event_list_row= mysql_fetch_row(event_list_res)) != NULL)
    {
      event_name= quote_name(event_list_row[1], name_buff, 0);
      DBUG_PRINT("info", ("retrieving CREATE EVENT for %s", name_buff));
      my_snprintf(query_buff, sizeof(query_buff), "SHOW CREATE EVENT %s", 
          event_name);

1703
      if (mysql_query_with_error_report(mysql, &event_res, query_buff))
1704 1705 1706 1707 1708 1709 1710 1711
        DBUG_RETURN(1);

      while ((row= mysql_fetch_row(event_res)) != NULL)
      {
        /*
          if the user has EXECUTE privilege he can see event names, but not the
          event body!
        */
1712
        if (strlen(row[3]) != 0)
1713 1714 1715 1716 1717
        {
          if (opt_drop)
            fprintf(sql_file, "/*!50106 DROP EVENT IF EXISTS %s */%s\n", 
                event_name, delimiter);

1718 1719 1720 1721
          if (create_delimiter(row[3], delimiter, sizeof(delimiter)) == NULL)
          {
            fprintf(stderr, "%s: Warning: Can't create delimiter for event '%s'\n",
                    event_name, my_progname);
1722 1723 1724 1725
            DBUG_RETURN(1);
          }

          fprintf(sql_file, "DELIMITER %s\n", delimiter);
1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752

          db_cl_altered= switch_db_collation(sql_file,
                                             db_name_buff,
                                             delimiter,
                                             db_cl_name,
                                             row[6]);

          switch_cs_variables(sql_file, delimiter,
                              row[4],   /* character_set_client */
                              row[4],   /* character_set_results */
                              row[5]);  /* collation_connection */

          switch_sql_mode(sql_file, delimiter, row[1]);

          switch_time_zone(sql_file, delimiter, row[2]);

          fprintf(sql_file,
                  "/*!50106 %s */ %s\n",
                  (const char *) row[3],
                  (const char *) delimiter);

          restore_time_zone(sql_file, delimiter);
          restore_sql_mode(sql_file, delimiter);
          restore_cs_variables(sql_file, delimiter);

          if (db_cl_altered)
            restore_db_collation(sql_file, db_name_buff, delimiter, db_cl_name);
1753 1754
        }
      } /* end of event printing */
dkatz/Damien@damiendev's avatar
dkatz/Damien@damiendev committed
1755 1756
      mysql_free_result(event_res);

1757 1758
    } /* end of list of events */
    fprintf(sql_file, "DELIMITER ;\n");
1759
    fprintf(sql_file, "/*!50106 SET TIME_ZONE= @save_time_zone */ ;\n");
1760 1761 1762 1763
  }
  mysql_free_result(event_list_res);

  if (lock_tables)
1764
    VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES"));
1765 1766 1767 1768
  DBUG_RETURN(0);
}


1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784
/*
  Print hex value for blob data.

  SYNOPSIS
    print_blob_as_hex()
    output_file         - output file
    str                 - string to print
    len                 - its length

  DESCRIPTION
    Print hex value for blob data.
*/

static void print_blob_as_hex(FILE *output_file, const char *str, ulong len)
{
    /* sakaik got the idea to to provide blob's in hex notation. */
1785
    const char *ptr= str, *end= ptr + len;
1786 1787 1788 1789 1790
    for (; ptr < end ; ptr++)
      fprintf(output_file, "%02X", *((uchar *)ptr));
    check_io(output_file);
}

1791 1792
/*
  dump_routines_for_db
1793
  -- retrieves list of routines for a given db, and prints out
1794 1795 1796 1797 1798
  the CREATE PROCEDURE definition into the output (the dump).

  This function has logic to print the appropriate syntax depending on whether
  this is a procedure or functions

1799 1800 1801
  RETURN
    0  Success
    1  Error
1802 1803
*/

1804
static uint dump_routines_for_db(char *db)
1805
{
1806
  char       query_buff[QUERY_LENGTH];
1807 1808 1809
  const char *routine_type[]= {"FUNCTION", "PROCEDURE"};
  char       db_name_buff[NAME_LEN*2+3], name_buff[NAME_LEN*2+3];
  char       *routine_name;
1810
  int        i;
1811
  FILE       *sql_file= md_result_file;
1812
  MYSQL_RES  *routine_res, *routine_list_res;
1813
  MYSQL_ROW  row, routine_list_row;
1814 1815 1816 1817

  char       db_cl_name[MY_CS_NAME_SIZE];
  int        db_cl_altered;

1818
  DBUG_ENTER("dump_routines_for_db");
1819
  DBUG_PRINT("enter", ("db: '%s'", db));
1820

1821
  mysql_real_escape_string(mysql, db_name_buff, db, strlen(db));
1822 1823 1824 1825

  /* nice comments */
  if (opt_comments)
    fprintf(sql_file, "\n--\n-- Dumping routines for database '%s'\n--\n", db);
1826 1827

  /*
1828 1829
    not using "mysql_query_with_error_report" because we may have not
    enough privileges to lock mysql.proc.
1830
  */
1831
  if (lock_tables)
1832
    mysql_query(mysql, "LOCK TABLES mysql.proc READ");
1833

1834
  /* Get database collation. */
1835

1836 1837
  if (fetch_db_collation(db_name_buff, db_cl_name, sizeof (db_cl_name)))
    DBUG_RETURN(1);
1838 1839

  /* 0, retrieve and dump functions, 1, procedures */
1840
  for (i= 0; i <= 1; i++)
1841 1842 1843
  {
    my_snprintf(query_buff, sizeof(query_buff),
                "SHOW %s STATUS WHERE Db = '%s'",
1844
                routine_type[i], db_name_buff);
1845

1846
    if (mysql_query_with_error_report(mysql, &routine_list_res, query_buff))
1847 1848 1849 1850 1851
      DBUG_RETURN(1);

    if (mysql_num_rows(routine_list_res))
    {

1852
      while ((routine_list_row= mysql_fetch_row(routine_list_res)))
1853
      {
1854
        routine_name= quote_name(routine_list_row[1], name_buff, 0);
1855 1856
        DBUG_PRINT("info", ("retrieving CREATE %s for %s", routine_type[i],
                            name_buff));
1857
        my_snprintf(query_buff, sizeof(query_buff), "SHOW CREATE %s %s",
1858
                    routine_type[i], routine_name);
1859

1860
        if (mysql_query_with_error_report(mysql, &routine_res, query_buff))
1861 1862
          DBUG_RETURN(1);

1863
        while ((row= mysql_fetch_row(routine_res)))
1864 1865
        {
          /*
1866 1867
            if the user has EXECUTE privilege he see routine names, but NOT the
            routine body of other routines that are not the creator of!
1868
          */
1869 1870 1871 1872 1873 1874 1875 1876 1877 1878
          DBUG_PRINT("info",("length of body for %s row[2] '%s' is %d",
                             routine_name, row[2] ? row[2] : "(null)",
                             row[2] ? (int) strlen(row[2]) : 0));
          if (row[2] == NULL)
          {
            fprintf(sql_file, "\n-- insufficient privileges to %s\n", query_buff);
            fprintf(sql_file, "-- does %s have permissions on mysql.proc?\n\n", current_user);
            maybe_die(EX_MYSQLERR,"%s has insufficent privileges to %s!", current_user, query_buff);
          }
          else if (strlen(row[2]))
1879
          {
1880 1881 1882
            char *query_str= NULL;
            char *definer_begin;

1883
            if (opt_drop)
1884
              fprintf(sql_file, "/*!50003 DROP %s IF EXISTS %s */;\n",
1885
                      routine_type[i], routine_name);
1886 1887 1888 1889 1890

            /*
              Cover DEFINER-clause in version-specific comments.

              TODO: this is definitely a BAD IDEA to parse SHOW CREATE output.
1891 1892 1893 1894 1895
              However, we can not use INFORMATION_SCHEMA instead:
                1. INFORMATION_SCHEMA provides data in UTF8, but here we
                   need data in the original character set;
                2. INFORMATION_SCHEMA does not provide information about
                   routine parameters now.
1896 1897
            */

1898 1899
            definer_begin= my_case_str(row[2], strlen(row[2]),
                                       C_STRING_WITH_LEN(" DEFINER"));
1900

1901 1902
            if (definer_begin)
            {
1903 1904 1905
              char *definer_end= my_case_str(definer_begin,
                                             strlen(definer_begin),
                                             C_STRING_WITH_LEN(" PROCEDURE"));
1906 1907

              if (!definer_end)
1908 1909 1910 1911
              {
                definer_end= my_case_str(definer_begin, strlen(definer_begin),
                                         C_STRING_WITH_LEN(" FUNCTION"));
              }
1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924

              if (definer_end)
              {
                char *query_str_tail;

                /*
                  Allocate memory for new query string: original string
                  from SHOW statement and version-specific comments.
                */
                query_str= alloc_query_str(strlen(row[2]) + 23);

                query_str_tail= strnmov(query_str, row[2],
                                        definer_begin - row[2]);
1925
                query_str_tail= strmov(query_str_tail, "*/ /*!50020");
1926 1927 1928 1929 1930 1931 1932
                query_str_tail= strnmov(query_str_tail, definer_begin,
                                        definer_end - definer_begin);
                query_str_tail= strxmov(query_str_tail, "*/ /*!50003",
                                        definer_end, NullS);
              }
            }

1933
            /*
1934 1935
              we need to change sql_mode only for the CREATE
              PROCEDURE/FUNCTION otherwise we may need to re-quote routine_name
1936
            */
1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947

            db_cl_altered= switch_db_collation(sql_file, db_name_buff, ";",
                                               db_cl_name, row[5]);

            switch_cs_variables(sql_file, ";",
                                row[3],   /* character_set_client */
                                row[3],   /* character_set_results */
                                row[4]);  /* collation_connection */

            switch_sql_mode(sql_file, ";", row[1]);

1948
            fprintf(sql_file,
1949 1950 1951 1952 1953 1954 1955 1956 1957 1958
                    "DELIMITER ;;\n"
                    "/*!50003 %s */;;\n"
                    "DELIMITER ;\n",
                    (const char *) (query_str != NULL ? query_str : row[2]));

            restore_sql_mode(sql_file, ";");
            restore_cs_variables(sql_file, ";");

            if (db_cl_altered)
              restore_db_collation(sql_file, db_name_buff, ";", db_cl_name);
1959 1960

            my_free(query_str, MYF(MY_ALLOW_ZERO_PTR));
1961 1962
          }
        } /* end of routine printing */
dkatz/Damien@damiendev's avatar
dkatz/Damien@damiendev committed
1963 1964
        mysql_free_result(routine_res);

1965 1966 1967 1968 1969
      } /* end of list of routines */
    }
    mysql_free_result(routine_list_res);
  } /* end of for i (0 .. 1)  */

1970
  if (lock_tables)
1971
    VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES"));
1972 1973
  DBUG_RETURN(0);
}
1974

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1975
/*
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
1976 1977 1978 1979 1980 1981 1982
  get_table_structure -- retrievs database structure, prints out corresponding
  CREATE statement and fills out insert_pat if the table is the type we will
  be dumping.

  ARGS
    table       - table name
    db          - db name
1983
    table_type  - table type, e.g. "MyISAM" or "InnoDB", but also "VIEW"
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
1984
    ignore_flag - what we must particularly ignore - see IGNORE_ defines above
1985 1986 1987

  RETURN
    number of fields in table, 0 if error
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1988
*/
1989

patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
1990 1991
static uint get_table_structure(char *table, char *db, char *table_type,
                                char *ignore_flag)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1992
{
monty@mysql.com's avatar
monty@mysql.com committed
1993
  my_bool    init=0, delayed, write_data, complete_insert;
1994
  my_ulonglong num_fields;
1995
  char       *result_table, *opt_quoted_table;
1996
  const char *insert_option;
1997
  char	     name_buff[NAME_LEN+3],table_buff[NAME_LEN*2+3];
1998
  char       table_buff2[NAME_LEN*2+3], query_buff[QUERY_LENGTH];
grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
1999
  FILE       *sql_file= md_result_file;
2000
  int        len;
2001 2002 2003
  MYSQL_RES  *result;
  MYSQL_ROW  row;

2004
  DBUG_ENTER("get_table_structure");
monty@mysql.com's avatar
monty@mysql.com committed
2005
  DBUG_PRINT("enter", ("db: %s  table: %s", db, table));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2006

patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2007 2008
  *ignore_flag= check_if_ignore_table(table, table_type);

monty@mysql.com's avatar
monty@mysql.com committed
2009 2010 2011 2012
  delayed= opt_delayed;
  if (delayed && (*ignore_flag & IGNORE_INSERT_DELAYED))
  {
    delayed= 0;
2013 2014
    verbose_msg("-- Warning: Unable to use delayed inserts for table '%s' "
                "because it's of type %s\n", table, table_type);
monty@mysql.com's avatar
monty@mysql.com committed
2015
  }
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2016

monty@mysql.com's avatar
monty@mysql.com committed
2017 2018
  complete_insert= 0;
  if ((write_data= !(*ignore_flag & IGNORE_DATA)))
2019
  {
monty@mysql.com's avatar
monty@mysql.com committed
2020
    complete_insert= opt_complete_insert;
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2021
    if (!insert_pat_inited)
2022 2023
    {
      insert_pat_inited= 1;
2024
      init_dynamic_string_checked(&insert_pat, "", 1024, 1024);
2025
    }
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2026
    else
2027
      dynstr_set_checked(&insert_pat, "");
2028 2029
  }

monty@mysql.com's avatar
monty@mysql.com committed
2030 2031
  insert_option= ((delayed && opt_ignore) ? " DELAYED IGNORE " :
                  delayed ? " DELAYED " : opt_ignore ? " IGNORE " : "");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2032

2033
  verbose_msg("-- Retrieving table structure for table %s...\n", table);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2034

2035 2036 2037
  len= my_snprintf(query_buff, sizeof(query_buff),
                   "SET OPTION SQL_QUOTE_SHOW_CREATE=%d",
                   (opt_quoted || opt_keywords));
monty@mishka.local's avatar
monty@mishka.local committed
2038
  if (!create_options)
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2039 2040
    strmov(query_buff+len,
           "/*!40102 ,SQL_MODE=concat(@@sql_mode, _utf8 ',NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS') */");
monty@mishka.local's avatar
monty@mishka.local committed
2041

2042 2043
  result_table=     quote_name(table, table_buff, 1);
  opt_quoted_table= quote_name(table, table_buff2, 0);
2044 2045

  if (opt_order_by_primary)
grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
2046
    order_by= primary_key_fields(result_table);
2047

2048
  if (!opt_xml && !mysql_query_with_error_report(mysql, 0, query_buff))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2049
  {
2050
    /* using SHOW CREATE statement */
2051
    if (!opt_no_create_info)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2052
    {
2053 2054
      /* Make an sql-file, if path was given iow. option -T was given */
      char buff[20+FN_REFLEN];
2055
      MYSQL_FIELD *field;
2056

2057
      my_snprintf(buff, sizeof(buff), "show create table %s", result_table);
2058
      if (mysql_query_with_error_report(mysql, 0, buff))
2059
        DBUG_RETURN(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2060

2061 2062
      if (path)
      {
2063
        if (!(sql_file= open_sql_file_for_table(table)))
2064
          DBUG_RETURN(0);
2065

2066
        write_header(sql_file, db);
2067
      }
2068
      if (!opt_xml && opt_comments)
2069
      {
2070 2071 2072 2073
      if (strcmp (table_type, "VIEW") == 0)         /* view */
        fprintf(sql_file, "\n--\n-- Temporary table structure for view %s\n--\n\n",
                result_table);
      else
monty@mysql.com's avatar
monty@mysql.com committed
2074
        fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n",
2075 2076
                result_table);
        check_io(sql_file);
2077
      }
2078
      if (opt_drop)
2079
      {
2080 2081 2082 2083 2084 2085 2086
      /*
        Even if the "table" is a view, we do a DROP TABLE here.  The
        view-specific code below fills in the DROP VIEW.
       */
        fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n",
                opt_quoted_table);
        check_io(sql_file);
2087
      }
2088

2089
      result= mysql_store_result(mysql);
2090
      field= mysql_fetch_field_direct(result, 0);
2091 2092
      if (strcmp(field->name, "View") == 0)
      {
grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
2093
        char *scv_buff= NULL;
2094

2095
        verbose_msg("-- It's a view, create dummy table for view\n");
2096

2097 2098 2099 2100
        /* save "show create" statement for later */
        if ((row= mysql_fetch_row(result)) && (scv_buff=row[1]))
          scv_buff= my_strdup(scv_buff, MYF(0));

2101 2102 2103
        mysql_free_result(result);

        /*
2104
          Create a table with the same name as the view and with columns of
2105 2106
          the same name in order to satisfy views that depend on this view.
          The table will be removed when the actual view is created.
2107

2108 2109
          The properties of each column, aside from the data type, are not
          preserved in this temporary table, because they are not necessary.
2110

2111 2112 2113
          This will not be necessary once we can determine dependencies
          between views and can simply dump them in the appropriate order.
        */
2114
        my_snprintf(query_buff, sizeof(query_buff),
2115
                    "SHOW FIELDS FROM %s", result_table);
2116
        if (mysql_query_with_error_report(mysql, 0, query_buff))
2117
        {
2118 2119 2120 2121 2122 2123
          /*
            View references invalid or privileged table/col/fun (err 1356),
            so we cannot create a stand-in table.  Be defensive and dump
            a comment with the view's 'show create' statement. (Bug #17371)
          */

2124
          if (mysql_errno(mysql) == ER_VIEW_INVALID)
2125 2126 2127 2128
            fprintf(sql_file, "\n-- failed on view %s: %s\n\n", result_table, scv_buff ? scv_buff : "");

          my_free(scv_buff, MYF(MY_ALLOW_ZERO_PTR));

grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
2129
          DBUG_RETURN(0);
2130
        }
2131 2132
        else
          my_free(scv_buff, MYF(MY_ALLOW_ZERO_PTR));
2133

2134
        if ((result= mysql_store_result(mysql)))
2135
        {
2136 2137 2138 2139
          if (mysql_num_rows(result))
          {
            if (opt_drop)
            {
2140 2141 2142 2143 2144
            /*
              We have already dropped any table of the same name
              above, so here we just drop the view.
             */

2145 2146 2147 2148
              fprintf(sql_file, "/*!50001 DROP VIEW IF EXISTS %s*/;\n",
                      opt_quoted_table);
              check_io(sql_file);
            }
2149

2150 2151 2152 2153 2154 2155 2156 2157
            fprintf(sql_file, "/*!50001 CREATE TABLE %s (\n", result_table);
            /*
               Get first row, following loop will prepend comma - keeps
               from having to know if the row being printed is last to
               determine if there should be a _trailing_ comma.
            */
            row= mysql_fetch_row(result);

2158 2159
            fprintf(sql_file, "  %s %s", quote_name(row[0], name_buff, 0),
                    row[1]);
2160 2161 2162 2163 2164 2165 2166 2167 2168 2169

            while((row= mysql_fetch_row(result)))
            {
              /* col name, col type */
              fprintf(sql_file, ",\n  %s %s",
                      quote_name(row[0], name_buff, 0), row[1]);
            }
            fprintf(sql_file, "\n) */;\n");
            check_io(sql_file);
          }
2170
        }
2171 2172
        mysql_free_result(result);

2173 2174 2175
        if (path)
          my_fclose(sql_file, MYF(MY_WME));

2176
        seen_views= 1;
2177 2178
        DBUG_RETURN(0);
      }
2179 2180

      row= mysql_fetch_row(result);
2181
      fprintf(sql_file, "%s;\n", row[1]);
2182
      check_io(sql_file);
2183
      mysql_free_result(result);
2184
    }
2185
    my_snprintf(query_buff, sizeof(query_buff), "show fields from %s",
2186
                result_table);
2187
    if (mysql_query_with_error_report(mysql, &result, query_buff))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2188
    {
2189
      if (path)
2190
        my_fclose(sql_file, MYF(MY_WME));
2191
      DBUG_RETURN(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2192
    }
2193

patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2194
    /*
monty@mysql.com's avatar
monty@mysql.com committed
2195 2196 2197 2198
      If write_data is true, then we build up insert statements for
      the table's data. Note: in subsequent lines of code, this test
      will have to be performed each time we are appending to
      insert_pat.
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2199
    */
monty@mysql.com's avatar
monty@mysql.com committed
2200
    if (write_data)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2201
    {
2202
      if (opt_replace_into)
2203
        dynstr_append_checked(&insert_pat, "REPLACE ");
2204
      else
2205
        dynstr_append_checked(&insert_pat, "INSERT ");
2206 2207 2208
      dynstr_append_checked(&insert_pat, insert_option);
      dynstr_append_checked(&insert_pat, "INTO ");
      dynstr_append_checked(&insert_pat, opt_quoted_table);
monty@mysql.com's avatar
monty@mysql.com committed
2209
      if (complete_insert)
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2210
      {
2211
        dynstr_append_checked(&insert_pat, " (");
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2212 2213 2214
      }
      else
      {
2215
        dynstr_append_checked(&insert_pat, " VALUES ");
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2216
        if (!extended_insert)
2217
          dynstr_append_checked(&insert_pat, "(");
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2218
      }
2219 2220
    }

2221
    while ((row= mysql_fetch_row(result)))
2222
    {
monty@mysql.com's avatar
monty@mysql.com committed
2223
      if (complete_insert)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2224
      {
monty@mysql.com's avatar
monty@mysql.com committed
2225 2226
        if (init)
        {
2227
          dynstr_append_checked(&insert_pat, ", ");
monty@mysql.com's avatar
monty@mysql.com committed
2228 2229
        }
        init=1;
2230
        dynstr_append_checked(&insert_pat,
2231
                      quote_name(row[SHOW_FIELDNAME], name_buff, 0));
monty@mysql.com's avatar
monty@mysql.com committed
2232
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2233
    }
2234 2235
    num_fields= mysql_num_rows(result);
    mysql_free_result(result);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2236
  }
2237
  else
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2238
  {
2239
    verbose_msg("%s: Warning: Can't set SQL_QUOTE_SHOW_CREATE option (%s)\n",
2240
                my_progname, mysql_error(mysql));
2241

2242
    my_snprintf(query_buff, sizeof(query_buff), "show fields from %s",
2243
                result_table);
2244
    if (mysql_query_with_error_report(mysql, &result, query_buff))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2245 2246
      DBUG_RETURN(0);

2247
    /* Make an sql-file, if path was given iow. option -T was given */
2248
    if (!opt_no_create_info)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2249
    {
2250
      if (path)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2251
      {
2252
        if (!(sql_file= open_sql_file_for_table(table)))
2253
          DBUG_RETURN(0);
2254
        write_header(sql_file, db);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2255
      }
2256
      if (!opt_xml && opt_comments)
2257 2258
        fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n",
                result_table);
2259
      if (opt_drop)
monty@mishka.local's avatar
monty@mishka.local committed
2260
        fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", result_table);
2261
      if (!opt_xml)
2262
        fprintf(sql_file, "CREATE TABLE %s (\n", result_table);
2263
      else
2264 2265
        print_xml_tag(sql_file, "\t", "\n", "table_structure", "name=", table, 
                NullS);
2266
      check_io(sql_file);
2267
    }
2268

monty@mysql.com's avatar
monty@mysql.com committed
2269
    if (write_data)
2270
    {
2271
      if (opt_replace_into)
2272
        dynstr_append_checked(&insert_pat, "REPLACE ");
2273
      else
2274
        dynstr_append_checked(&insert_pat, "INSERT ");
2275 2276 2277
      dynstr_append_checked(&insert_pat, insert_option);
      dynstr_append_checked(&insert_pat, "INTO ");
      dynstr_append_checked(&insert_pat, result_table);
2278
      if (complete_insert)
2279
        dynstr_append_checked(&insert_pat, " (");
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2280 2281
      else
      {
2282
        dynstr_append_checked(&insert_pat, " VALUES ");
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2283
        if (!extended_insert)
2284
          dynstr_append_checked(&insert_pat, "(");
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2285
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2286
    }
2287

2288
    while ((row= mysql_fetch_row(result)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2289
    {
2290
      ulong *lengths= mysql_fetch_lengths(result);
2291
      if (init)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2292
      {
2293
        if (!opt_xml && !opt_no_create_info)
2294 2295 2296 2297
        {
          fputs(",\n",sql_file);
          check_io(sql_file);
        }
monty@mysql.com's avatar
monty@mysql.com committed
2298
        if (complete_insert)
2299
          dynstr_append_checked(&insert_pat, ", ");
2300 2301
      }
      init=1;
2302
      if (complete_insert)
2303
        dynstr_append_checked(&insert_pat,
2304
                      quote_name(row[SHOW_FIELDNAME], name_buff, 0));
2305
      if (!opt_no_create_info)
2306
      {
2307 2308 2309 2310 2311
        if (opt_xml)
        {
          print_xml_row(sql_file, "field", result, &row);
          continue;
        }
2312

2313
        if (opt_keywords)
2314 2315 2316
          fprintf(sql_file, "  %s.%s %s", result_table,
                  quote_name(row[SHOW_FIELDNAME],name_buff, 0),
                  row[SHOW_TYPE]);
2317
        else
2318 2319 2320
          fprintf(sql_file, "  %s %s", quote_name(row[SHOW_FIELDNAME],
                                                  name_buff, 0),
                  row[SHOW_TYPE]);
2321 2322
        if (row[SHOW_DEFAULT])
        {
2323 2324
          fputs(" DEFAULT ", sql_file);
          unescape(sql_file, row[SHOW_DEFAULT], lengths[SHOW_DEFAULT]);
2325 2326
        }
        if (!row[SHOW_NULL][0])
2327
          fputs(" NOT NULL", sql_file);
2328
        if (row[SHOW_EXTRA][0])
2329 2330
          fprintf(sql_file, " %s",row[SHOW_EXTRA]);
        check_io(sql_file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2331 2332
      }
    }
2333 2334
    num_fields= mysql_num_rows(result);
    mysql_free_result(result);
2335
    if (!opt_no_create_info)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2336
    {
2337 2338 2339
      /* Make an sql-file, if path was given iow. option -T was given */
      char buff[20+FN_REFLEN];
      uint keynr,primary_key;
2340
      my_snprintf(buff, sizeof(buff), "show keys from %s", result_table);
2341
      if (mysql_query_with_error_report(mysql, &result, buff))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2342
      {
2343
        if (mysql_errno(mysql) == ER_WRONG_OBJECT)
2344 2345 2346 2347 2348 2349
        {
          /* it is VIEW */
          fputs("\t\t<options Comment=\"view\" />\n", sql_file);
          goto continue_xml;
        }
        fprintf(stderr, "%s: Can't get keys for table %s (%s)\n",
2350
                my_progname, result_table, mysql_error(mysql));
2351
        if (path)
2352
          my_fclose(sql_file, MYF(MY_WME));
2353
        DBUG_RETURN(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2354
      }
2355 2356 2357 2358

      /* Find first which key is primary key */
      keynr=0;
      primary_key=INT_MAX;
2359
      while ((row= mysql_fetch_row(result)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2360
      {
2361 2362
        if (atoi(row[3]) == 1)
        {
2363
          keynr++;
2364
#ifdef FORCE_PRIMARY_KEY
2365 2366
          if (atoi(row[1]) == 0 && primary_key == INT_MAX)
            primary_key=keynr;
2367
#endif
2368 2369 2370 2371 2372
          if (!strcmp(row[2],"PRIMARY"))
          {
            primary_key=keynr;
            break;
          }
2373
        }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2374
      }
2375
      mysql_data_seek(result,0);
2376
      keynr=0;
2377
      while ((row= mysql_fetch_row(result)))
2378
      {
2379 2380 2381 2382 2383
        if (opt_xml)
        {
          print_xml_row(sql_file, "key", result, &row);
          continue;
        }
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2384

2385 2386
        if (atoi(row[3]) == 1)
        {
2387 2388 2389 2390 2391 2392 2393 2394 2395 2396
          if (keynr++)
            putc(')', sql_file);
          if (atoi(row[1]))       /* Test if duplicate key */
            /* Duplicate allowed */
            fprintf(sql_file, ",\n  KEY %s (",quote_name(row[2],name_buff,0));
          else if (keynr == primary_key)
            fputs(",\n  PRIMARY KEY (",sql_file); /* First UNIQUE is primary */
          else
            fprintf(sql_file, ",\n  UNIQUE %s (",quote_name(row[2],name_buff,
                                                            0));
2397 2398
        }
        else
2399
          putc(',', sql_file);
2400
        fputs(quote_name(row[4], name_buff, 0), sql_file);
2401
        if (row[7])
2402 2403
          fprintf(sql_file, " (%s)",row[7]);      /* Sub key */
        check_io(sql_file);
2404
      }
2405 2406
      if (!opt_xml)
      {
2407 2408 2409 2410
        if (keynr)
          putc(')', sql_file);
        fputs("\n)",sql_file);
        check_io(sql_file);
2411
      }
2412 2413 2414

      /* Get MySQL specific create options */
      if (create_options)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2415
      {
2416
        char show_name_buff[NAME_LEN*2+2+24];
2417

2418
        /* Check memory for quote_for_like() */
2419
        my_snprintf(buff, sizeof(buff), "show table status like %s",
2420
                    quote_for_like(table, show_name_buff));
2421

2422
        if (mysql_query_with_error_report(mysql, &result, buff))
2423
        {
2424
          if (mysql_errno(mysql) != ER_PARSE_ERROR)
2425
          {                                     /* If old MySQL version */
2426
            verbose_msg("-- Warning: Couldn't get status information for " \
2427
                        "table %s (%s)\n", result_table,mysql_error(mysql));
2428
          }
2429
        }
2430
        else if (!(row= mysql_fetch_row(result)))
2431
        {
2432 2433
          fprintf(stderr,
                  "Error: Couldn't read status information for table %s (%s)\n",
2434
                  result_table,mysql_error(mysql));
2435 2436 2437
        }
        else
        {
2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448
          if (opt_xml)
            print_xml_row(sql_file, "options", result, &row);
          else
          {
            fputs("/*!",sql_file);
            print_value(sql_file,result,row,"engine=","Engine",0);
            print_value(sql_file,result,row,"","Create_options",0);
            print_value(sql_file,result,row,"comment=","Comment",1);
            fputs(" */",sql_file);
            check_io(sql_file);
          }
2449
        }
2450
        mysql_free_result(result);              /* Is always safe to free */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2451
      }
2452
continue_xml:
2453
      if (!opt_xml)
2454
        fputs(";\n", sql_file);
2455
      else
2456
        fputs("\t</table_structure>\n", sql_file);
2457
      check_io(sql_file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2458 2459
    }
  }
2460
  if (complete_insert)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2461
  {
2462
    dynstr_append_checked(&insert_pat, ") VALUES ");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2463
    if (!extended_insert)
2464
      dynstr_append_checked(&insert_pat, "(");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2465
  }
2466
  if (sql_file != md_result_file)
2467 2468 2469
  {
    fputs("\n", sql_file);
    write_footer(sql_file);
2470
    my_fclose(sql_file, MYF(MY_WME));
2471
  }
2472
  DBUG_RETURN((uint) num_fields);
2473
} /* get_table_structure */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2474 2475


2476 2477 2478 2479 2480 2481 2482 2483 2484 2485
/*

  dump_triggers_for_table

  Dumps the triggers given a table/db name. This should be called after
  the tables have been dumped in case a trigger depends on the existence
  of a table

*/

2486
static void dump_triggers_for_table(char *table, char *db_name)
2487
{
2488 2489
  char       *result_table;
  char       name_buff[NAME_LEN*4+3], table_buff[NAME_LEN*2+3];
2490
  char       query_buff[QUERY_LENGTH];
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2491
  uint old_opt_compatible_mode=opt_compatible_mode;
grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
2492
  FILE       *sql_file= md_result_file;
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2493 2494
  MYSQL_RES  *result;
  MYSQL_ROW  row;
2495 2496 2497 2498

  char       db_cl_name[MY_CS_NAME_SIZE];
  int        db_cl_altered;

2499
  DBUG_ENTER("dump_triggers_for_table");
2500
  DBUG_PRINT("enter", ("db: %s, table: %s", db_name, table));
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2501 2502 2503

  /* Do not use ANSI_QUOTES on triggers in dump */
  opt_compatible_mode&= ~MASK_ANSI_QUOTES;
2504 2505 2506 2507 2508 2509
  result_table=     quote_name(table, table_buff, 1);

  my_snprintf(query_buff, sizeof(query_buff),
              "SHOW TRIGGERS LIKE %s",
              quote_for_like(table, name_buff));

2510
  if (mysql_query_with_error_report(mysql, &result, query_buff))
2511 2512 2513 2514 2515
  {
    if (path)
      my_fclose(sql_file, MYF(MY_WME));
    DBUG_VOID_RETURN;
  }
2516 2517 2518 2519 2520 2521 2522 2523

  /* Get database collation. */

  if (fetch_db_collation(db_name, db_cl_name, sizeof (db_cl_name)))
    DBUG_VOID_RETURN;

  /* Dump triggers. */

2524
  while ((row= mysql_fetch_row(result)))
2525
  {
2526 2527 2528 2529 2530
    MYSQL_RES *res2;

    my_snprintf(query_buff, sizeof (query_buff),
                "SHOW CREATE TRIGGER %s",
                quote_name(row[0], name_buff, TRUE));
2531

2532
    if (mysql_query_with_error_report(mysql, &res2, query_buff))
2533
    {
2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544
      if (path)
        my_fclose(sql_file, MYF(MY_WME));
      maybe_exit(EX_MYSQLERR);
      DBUG_VOID_RETURN;
    }

    while ((row= mysql_fetch_row(res2)))
    {
      char *query_str= NULL;
      char *definer_begin;

2545
      /*
2546 2547 2548 2549 2550 2551 2552 2553
        Cover DEFINER-clause in version-specific comments.

        TODO: this is definitely a BAD IDEA to parse SHOW CREATE output.
        However, we can not use INFORMATION_SCHEMA instead:
          1. INFORMATION_SCHEMA provides data in UTF8, but here we
             need data in the original character set;
          2. INFORMATION_SCHEMA does not provide information about
             routine parameters now.
2554 2555
      */

2556 2557
      definer_begin= my_case_str(row[2], strlen(row[2]),
                                 C_STRING_WITH_LEN(" DEFINER"));
2558

2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592
      if (definer_begin)
      {
        char *definer_end= my_case_str(definer_begin, strlen(definer_begin),
                                       C_STRING_WITH_LEN(" TRIGGER"));

        if (definer_end)
        {
          char *query_str_tail;

          /*
             Allocate memory for new query string: original string
             from SHOW statement and version-specific comments.
           */
          query_str= alloc_query_str(strlen(row[2]) + 23);

          query_str_tail= strnmov(query_str, row[2],
            definer_begin - row[2]);
          query_str_tail= strmov(query_str_tail, "*/ /*!50017");
          query_str_tail= strnmov(query_str_tail, definer_begin,
            definer_end - definer_begin);
          query_str_tail= strxmov(query_str_tail, "*/ /*!50003",
            definer_end, NullS);
        }
      }

      db_cl_altered= switch_db_collation(sql_file, db_name, ";",
                                         db_cl_name, row[5]);

      switch_cs_variables(sql_file, ";",
                          row[3],   /* character_set_client */
                          row[3],   /* character_set_results */
                          row[4]);  /* collation_connection */

      switch_sql_mode(sql_file, ";", row[1]);
2593 2594

      fprintf(sql_file,
2595 2596 2597 2598
              "DELIMITER ;;\n"
              "/*!50003 %s */;;\n"
              "DELIMITER ;\n",
              (const char *) (query_str != NULL ? query_str : row[2]));
2599

2600 2601 2602 2603 2604 2605 2606 2607 2608
      restore_sql_mode(sql_file, ";");
      restore_cs_variables(sql_file, ";");

      if (db_cl_altered)
        restore_db_collation(sql_file, db_name, ";", db_cl_name);

      my_free(query_str, MYF(MY_ALLOW_ZERO_PTR));
    }
    mysql_free_result(res2);
2609
  }
2610

2611
  mysql_free_result(result);
2612

patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2613
  /*
2614
    make sure to set back opt_compatible mode to
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2615 2616 2617
    original value
  */
  opt_compatible_mode=old_opt_compatible_mode;
2618

2619 2620 2621
  DBUG_VOID_RETURN;
}

2622 2623
static void add_load_option(DYNAMIC_STRING *str, const char *option,
                             const char *option_value)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2624
{
2625
  if (!option_value)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2626
  {
2627 2628
    /* Null value means we don't add this option. */
    return;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2629
  }
2630 2631 2632 2633 2634 2635 2636

  dynstr_append_checked(str, option);
  
  if (strncmp(option_value, "0x", sizeof("0x")-1) == 0)
  {
    /* It's a hex constant, don't escape */
    dynstr_append_checked(str, option_value);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2637
  }
2638 2639 2640 2641 2642 2643
  else
  {
    /* char constant; escape */
    field_escape(str, option_value);
  }
}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2644 2645 2646


/*
2647 2648 2649 2650
  Allow the user to specify field terminator strings like:
  "'", "\", "\\" (escaped backslash), "\t" (tab), "\n" (newline)
  This is done by doubling ' and add a end -\ if needed to avoid
  syntax errors from the SQL parser.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2651 2652
*/

2653
static void field_escape(DYNAMIC_STRING* in, const char *from)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2654
{
2655
  uint end_backslashes= 0; 
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2656

2657
  dynstr_append_checked(in, "'");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2658

2659
  while (*from)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2660
  {
2661 2662
    dynstr_append_mem_checked(in, from, 1);

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2663 2664 2665 2666 2667
    if (*from == '\\')
      end_backslashes^=1;    /* find odd number of backslashes */
    else
    {
      if (*from == '\'' && !end_backslashes)
2668 2669 2670 2671
      {
        /* We want a duplicate of "'" for MySQL */
        dynstr_append_checked(in, "\'");
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2672 2673
      end_backslashes=0;
    }
2674
    from++;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2675 2676 2677
  }
  /* Add missing backslashes if user has specified odd number of backs.*/
  if (end_backslashes)
2678 2679 2680 2681 2682
    dynstr_append_checked(in, "\\");
  
  dynstr_append_checked(in, "'");
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2683 2684


2685 2686 2687 2688 2689
static char *alloc_query_str(ulong size)
{
  char *query;

  if (!(query= (char*) my_malloc(size, MYF(MY_WME))))
2690 2691
    die(EX_MYSQLERR, "Couldn't allocate a query string.");

2692 2693 2694
  return query;
}

2695

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2696
/*
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708

 SYNOPSIS
  dump_table()

  dump_table saves database contents as a series of INSERT statements.

  ARGS
   table - table name
   db    - db name

   RETURNS
    void
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2709
*/
2710

2711

patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2712
static void dump_table(char *table, char *db)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2713
{
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2714
  char ignore_flag;
2715 2716
  char buf[200], table_buff[NAME_LEN+3];
  DYNAMIC_STRING query_string;
monty@mysql.com's avatar
monty@mysql.com committed
2717
  char table_type[NAME_LEN];
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
2718
  char *result_table, table_buff2[NAME_LEN*2+3], *opt_quoted_table;
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2719
  int error= 0;
2720
  ulong         rownr, row_break, total_length, init_length;
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2721
  uint num_fields;
2722 2723 2724
  MYSQL_RES     *res;
  MYSQL_FIELD   *field;
  MYSQL_ROW     row;
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2725 2726 2727 2728 2729 2730
  DBUG_ENTER("dump_table");

  /*
    Make sure you get the create table info before the following check for
    --no-data flag below. Otherwise, the create table info won't be printed.
  */
monty@mysql.com's avatar
monty@mysql.com committed
2731
  num_fields= get_table_structure(table, db, table_type, &ignore_flag);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2732

2733 2734 2735 2736
  /*
    The "table" could be a view.  If so, we don't do anything here.
  */
  if (strcmp (table_type, "VIEW") == 0)
2737
    DBUG_VOID_RETURN;
2738

2739
  /* Check --no-data flag */
2740
  if (opt_no_data)
2741
  {
2742 2743
    verbose_msg("-- Skipping dump data for table '%s', --no-data was used\n",
                table);
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2744
    DBUG_VOID_RETURN;
2745 2746
  }

monty@mysql.com's avatar
monty@mysql.com committed
2747 2748 2749
  DBUG_PRINT("info",
             ("ignore_flag: %x  num_fields: %d", (int) ignore_flag,
              num_fields));
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2750 2751 2752 2753 2754 2755
  /*
    If the table type is a merge table or any type that has to be
     _completely_ ignored and no data dumped
  */
  if (ignore_flag & IGNORE_DATA)
  {
2756 2757
    verbose_msg("-- Warning: Skipping data for table '%s' because " \
                "it's of type %s\n", table, table_type);
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2758 2759
    DBUG_VOID_RETURN;
  }
2760
  /* Check that there are any fields in the table */
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2761
  if (num_fields == 0)
2762
  {
2763 2764
    verbose_msg("-- Skipping dump data for table '%s', it has no fields\n",
                table);
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2765
    DBUG_VOID_RETURN;
2766 2767
  }

2768 2769
  result_table= quote_name(table,table_buff, 1);
  opt_quoted_table= quote_name(table, table_buff2, 0);
2770

2771
  verbose_msg("-- Sending SELECT query...\n");
2772 2773 2774

  init_dynamic_string_checked(&query_string, "", 1024, 1024);

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2775 2776 2777
  if (path)
  {
    char filename[FN_REFLEN], tmp_path[FN_REFLEN];
2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794

    if (strlen(path) >= FN_REFLEN)
    {
      /*
        This check is made because the some the file functions below
        have FN_REFLEN sized stack allocated buffers and will cause
        a crash even if the input destination buffer is large enough
        to hold the output.
      */
      die(EX_USAGE, "Input filename or options too long: %s", path);
    }

    /*
      Convert the path to native os format
      and resolve to the full filepath.
    */
    convert_dirname(tmp_path,path,NullS);    
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2795
    my_load_path(tmp_path, tmp_path, NULL);
2796 2797 2798 2799 2800 2801
    fn_format(filename, table, tmp_path, ".txt", MYF(MY_UNPACK_FILENAME));

    /* Must delete the file that 'INTO OUTFILE' will write to */
    my_delete(filename, MYF(0));

    /* convert to a unix path name to stick into the query */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2802
    to_unix_path(filename);
2803 2804 2805 2806 2807 2808

    /* now build the query string */

    dynstr_append_checked(&query_string, "SELECT /*!40001 SQL_NO_CACHE */ * INTO OUTFILE '");
    dynstr_append_checked(&query_string, filename);
    dynstr_append_checked(&query_string, "'");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2809 2810

    if (fields_terminated || enclosed || opt_enclosed || escaped)
2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822
      dynstr_append_checked(&query_string, " FIELDS");
    
    add_load_option(&query_string, " TERMINATED BY ", fields_terminated);
    add_load_option(&query_string, " ENCLOSED BY ", enclosed);
    add_load_option(&query_string, " OPTIONALLY ENCLOSED BY ", opt_enclosed);
    add_load_option(&query_string, " ESCAPED BY ", escaped);
    add_load_option(&query_string, " LINES TERMINATED BY ", lines_terminated);

    dynstr_append_checked(&query_string, " FROM ");
    dynstr_append_checked(&query_string, result_table);

    if (where)
2823
    {
2824 2825
      dynstr_append_checked(&query_string, " WHERE ");
      dynstr_append_checked(&query_string, where);
2826
    }
2827 2828 2829 2830 2831 2832 2833 2834

    if (order_by)
    {
      dynstr_append_checked(&query_string, " ORDER BY ");
      dynstr_append_checked(&query_string, order_by);
    }

    if (mysql_real_query(mysql, query_string.str, query_string.length))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2835
    {
2836
      DB_error(mysql, "when executing 'SELECT INTO OUTFILE'");
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2837
      DBUG_VOID_RETURN;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2838 2839 2840 2841
    }
  }
  else
  {
2842
    if (!opt_xml && opt_comments)
2843
    {
2844
      fprintf(md_result_file,"\n--\n-- Dumping data for table %s\n--\n",
2845
              result_table);
2846 2847
      check_io(md_result_file);
    }
2848 2849 2850
    
    dynstr_append_checked(&query_string, "SELECT /*!40001 SQL_NO_CACHE */ * FROM ");
    dynstr_append_checked(&query_string, result_table);
2851

2852 2853 2854
    if (where)
    {
      if (!opt_xml && opt_comments)
2855
      {
2856 2857
        fprintf(md_result_file, "-- WHERE:  %s\n", where);
        check_io(md_result_file);
2858
      }
2859 2860 2861 2862 2863 2864 2865
      
      dynstr_append_checked(&query_string, " WHERE ");
      dynstr_append_checked(&query_string, where);
    }
    if (order_by)
    {
      if (!opt_xml && opt_comments)
2866
      {
2867 2868
        fprintf(md_result_file, "-- ORDER BY:  %s\n", order_by);
        check_io(md_result_file);
2869
      }
2870 2871
      dynstr_append_checked(&query_string, " ORDER BY ");
      dynstr_append_checked(&query_string, order_by);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2872
    }
2873

2874
    if (!opt_xml && !opt_compact)
2875
    {
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
2876
      fputs("\n", md_result_file);
2877 2878
      check_io(md_result_file);
    }
2879
    if (mysql_query_with_error_report(mysql, 0, query_string.str))
2880
    {
2881
      DB_error(mysql, "when retrieving data from server");
2882 2883
      goto err;
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2884
    if (quick)
2885
      res=mysql_use_result(mysql);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2886
    else
2887
      res=mysql_store_result(mysql);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2888
    if (!res)
2889
    {
2890
      DB_error(mysql, "when retrieving data from server");
2891 2892
      goto err;
    }
2893 2894

    verbose_msg("-- Retrieving rows...\n");
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
2895
    if (mysql_num_fields(res) != num_fields)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2896
    {
2897
      fprintf(stderr,"%s: Error in field count for table: %s !  Aborting.\n",
2898
              my_progname, result_table);
2899 2900
      error= EX_CONSCHECK;
      goto err;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2901 2902
    }

2903
    if (opt_lock)
2904
    {
2905
      fprintf(md_result_file,"LOCK TABLES %s WRITE;\n", opt_quoted_table);
2906 2907
      check_io(md_result_file);
    }
2908 2909
    /* Moved disable keys to after lock per bug 15977 */
    if (opt_disable_keys)
2910
    {
2911 2912
      fprintf(md_result_file, "/*!40000 ALTER TABLE %s DISABLE KEYS */;\n",
	      opt_quoted_table);
2913 2914
      check_io(md_result_file);
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2915

2916
    total_length= opt_net_buffer_length;                /* Force row break */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2917 2918
    row_break=0;
    rownr=0;
2919
    init_length=(uint) insert_pat.length+4;
2920
    if (opt_xml)
2921 2922
      print_xml_tag(md_result_file, "\t", "\n", "table_data", "name=", table,
              NullS);
2923
    if (opt_autocommit)
2924
    {
2925
      fprintf(md_result_file, "set autocommit=0;\n");
2926 2927
      check_io(md_result_file);
    }
2928

2929
    while ((row= mysql_fetch_row(res)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2930 2931
    {
      uint i;
2932
      ulong *lengths= mysql_fetch_lengths(res);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2933
      rownr++;
2934
      if (!extended_insert && !opt_xml)
2935
      {
2936 2937
        fputs(insert_pat.str,md_result_file);
        check_io(md_result_file);
2938
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2939 2940
      mysql_field_seek(res,0);

jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
2941
      if (opt_xml)
2942
      {
2943
        fputs("\t<row>\n", md_result_file);
2944
        check_io(md_result_file);
2945
      }
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
2946

grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
2947
      for (i= 0; i < mysql_num_fields(res); i++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2948
      {
2949
        int is_blob;
2950 2951
        ulong length= lengths[i];

grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
2952
        if (!(field= mysql_fetch_field(res)))
2953 2954 2955
          die(EX_CONSCHECK,
                      "Not enough fields from table %s! Aborting.\n",
                      result_table);
2956 2957 2958 2959 2960 2961

        /*
           63 is my_charset_bin. If charsetnr is not 63,
           we have not a BLOB but a TEXT column.
           we'll dump in hex only BLOB columns.
        */
2962
        is_blob= (opt_hex_blob && field->charsetnr == 63 &&
2963 2964
                  (field->type == MYSQL_TYPE_BIT ||
                   field->type == MYSQL_TYPE_STRING ||
2965 2966 2967 2968 2969 2970
                   field->type == MYSQL_TYPE_VAR_STRING ||
                   field->type == MYSQL_TYPE_VARCHAR ||
                   field->type == MYSQL_TYPE_BLOB ||
                   field->type == MYSQL_TYPE_LONG_BLOB ||
                   field->type == MYSQL_TYPE_MEDIUM_BLOB ||
                   field->type == MYSQL_TYPE_TINY_BLOB)) ? 1 : 0;
2971
        if (extended_insert && !opt_xml)
2972 2973
        {
          if (i == 0)
2974
            dynstr_set_checked(&extended_row,"(");
2975
          else
2976
            dynstr_append_checked(&extended_row,",");
2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989

          if (row[i])
          {
            if (length)
            {
              if (!IS_NUM_FIELD(field))
              {
                /*
                  "length * 2 + 2" is OK for both HEX and non-HEX modes:
                  - In HEX mode we need exactly 2 bytes per character
                  plus 2 bytes for '0x' prefix.
                  - In non-HEX mode we need up to 2 bytes per character,
                  plus 2 bytes for leading and trailing '\'' characters.
gshchepa/uchum@gleb.loc's avatar
gshchepa/uchum@gleb.loc committed
2990
                  Also we need to reserve 1 byte for terminating '\0'.
2991
                */
gshchepa/uchum@gleb.loc's avatar
gshchepa/uchum@gleb.loc committed
2992
                dynstr_realloc_checked(&extended_row,length * 2 + 2 + 1);
2993 2994
                if (opt_hex_blob && is_blob)
                {
2995
                  dynstr_append_checked(&extended_row, "0x");
2996
                  extended_row.length+= mysql_hex_string(extended_row.str +
bar@mysql.com's avatar
bar@mysql.com committed
2997 2998
                                                         extended_row.length,
                                                         row[i], length);
gshchepa/uchum@gleb.loc's avatar
gshchepa/uchum@gleb.loc committed
2999 3000 3001
                  DBUG_ASSERT(extended_row.length+1 <= extended_row.max_length);
                  /* mysql_hex_string() already terminated string by '\0' */
                  DBUG_ASSERT(extended_row.str[extended_row.length] == '\0');
3002 3003 3004
                }
                else
                {
3005
                  dynstr_append_checked(&extended_row,"'");
3006 3007 3008 3009 3010
                  extended_row.length +=
                  mysql_real_escape_string(&mysql_connection,
                                           &extended_row.str[extended_row.length],
                                           row[i],length);
                  extended_row.str[extended_row.length]='\0';
3011
                  dynstr_append_checked(&extended_row,"'");
3012
                }
3013 3014 3015 3016
              }
              else
              {
                /* change any strings ("inf", "-inf", "nan") into NULL */
grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
3017
                char *ptr= row[i];
3018 3019
                if (my_isalpha(charset_info, *ptr) || (*ptr == '-' &&
                    my_isalpha(charset_info, ptr[1])))
3020
                  dynstr_append_checked(&extended_row, "NULL");
3021 3022
                else
                {
3023
                  if (field->type == MYSQL_TYPE_DECIMAL)
3024 3025
                  {
                    /* add " signs around */
3026 3027 3028
                    dynstr_append_checked(&extended_row, "'");
                    dynstr_append_checked(&extended_row, ptr);
                    dynstr_append_checked(&extended_row, "'");
3029 3030
                  }
                  else
3031
                    dynstr_append_checked(&extended_row, ptr);
3032 3033 3034 3035
                }
              }
            }
            else
3036
              dynstr_append_checked(&extended_row,"''");
3037
          }
3038 3039
          else
            dynstr_append_checked(&extended_row,"NULL");
3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053
        }
        else
        {
          if (i && !opt_xml)
          {
            fputc(',', md_result_file);
            check_io(md_result_file);
          }
          if (row[i])
          {
            if (!IS_NUM_FIELD(field))
            {
              if (opt_xml)
              {
3054 3055
                if (opt_hex_blob && is_blob && length)
                {
3056 3057 3058 3059
                  /* Define xsi:type="xs:hexBinary" for hex encoded data */
                  print_xml_tag(md_result_file, "\t\t", "", "field", "name=",
                                field->name, "xsi:type=", "xs:hexBinary", NullS);
                  print_blob_as_hex(md_result_file, row[i], length);
3060 3061 3062
                }
                else
                {
3063 3064 3065
                  print_xml_tag(md_result_file, "\t\t", "", "field", "name=", 
                                field->name, NullS);
                  print_quoted_xml(md_result_file, row[i], length);
3066
                }
3067 3068 3069
                fputs("</field>\n", md_result_file);
              }
              else if (opt_hex_blob && is_blob && length)
monty@mysql.com's avatar
monty@mysql.com committed
3070
              {
3071
                fputs("0x", md_result_file);
3072
                print_blob_as_hex(md_result_file, row[i], length);
3073 3074
              }
              else
3075
                unescape(md_result_file, row[i], length);
3076 3077 3078 3079
            }
            else
            {
              /* change any strings ("inf", "-inf", "nan") into NULL */
grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
3080
              char *ptr= row[i];
3081 3082
              if (opt_xml)
              {
3083 3084
                print_xml_tag(md_result_file, "\t\t", "", "field", "name=",
                        field->name, NullS);
3085 3086 3087 3088 3089 3090 3091
                fputs(!my_isalpha(charset_info, *ptr) ? ptr: "NULL",
                      md_result_file);
                fputs("</field>\n", md_result_file);
              }
              else if (my_isalpha(charset_info, *ptr) ||
                       (*ptr == '-' && my_isalpha(charset_info, ptr[1])))
                fputs("NULL", md_result_file);
3092
              else if (field->type == MYSQL_TYPE_DECIMAL)
3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103
              {
                /* add " signs around */
                fputc('\'', md_result_file);
                fputs(ptr, md_result_file);
                fputc('\'', md_result_file);
              }
              else
                fputs(ptr, md_result_file);
            }
          }
          else
3104 3105 3106 3107 3108 3109 3110 3111
          {
            /* The field value is NULL */
            if (!opt_xml)
              fputs("NULL", md_result_file);
            else
              print_xml_null_tag(md_result_file, "\t\t", "field name=",
                                 field->name, "\n");
          }
vva@eagle.mysql.r18.ru's avatar
Merge  
vva@eagle.mysql.r18.ru committed
3112
          check_io(md_result_file);
3113
        }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3114 3115
      }

jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
3116
      if (opt_xml)
3117
      {
3118
        fputs("\t</row>\n", md_result_file);
3119
        check_io(md_result_file);
3120
      }
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
3121

3122
      if (extended_insert)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3123
      {
3124
        ulong row_length;
3125
        dynstr_append_checked(&extended_row,")");
grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
3126
        row_length= 2 + extended_row.length;
3127
        if (total_length + row_length < opt_net_buffer_length)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3128
        {
grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
3129
          total_length+= row_length;
3130 3131 3132
          fputc(',',md_result_file);            /* Always row break */
          fputs(extended_row.str,md_result_file);
        }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3133 3134
        else
        {
3135 3136 3137
          if (row_break)
            fputs(";\n", md_result_file);
          row_break=1;                          /* This is first row */
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3138

3139
          fputs(insert_pat.str,md_result_file);
3140
          fputs(extended_row.str,md_result_file);
grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
3141
          total_length= row_length+init_length;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3142
        }
3143
        check_io(md_result_file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3144
      }
3145
      else if (!opt_xml)
3146
      {
3147 3148
        fputs(");\n", md_result_file);
        check_io(md_result_file);
3149
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3150
    }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3151

3152
    /* XML - close table tag and supress regular output */
3153
    if (opt_xml)
3154
        fputs("\t</table_data>\n", md_result_file);
3155
    else if (extended_insert && row_break)
3156
      fputs(";\n", md_result_file);             /* If not empty table */
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3157
    fflush(md_result_file);
3158
    check_io(md_result_file);
3159
    if (mysql_errno(mysql))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3160
    {
3161
      my_snprintf(buf, sizeof(buf),
3162 3163
                  "%s: Error %d: %s when dumping table %s at row: %ld\n",
                  my_progname,
3164 3165
                  mysql_errno(mysql),
                  mysql_error(mysql),
3166 3167
                  result_table,
                  rownr);
3168
      fputs(buf,stderr);
3169 3170
      error= EX_CONSCHECK;
      goto err;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3171
    }
3172 3173

    /* Moved enable keys to before unlock per bug 15977 */
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
3174
    if (opt_disable_keys)
3175
    {
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
3176
      fprintf(md_result_file,"/*!40000 ALTER TABLE %s ENABLE KEYS */;\n",
3177
              opt_quoted_table);
3178 3179
      check_io(md_result_file);
    }
3180 3181 3182 3183 3184
    if (opt_lock)
    {
      fputs("UNLOCK TABLES;\n", md_result_file);
      check_io(md_result_file);
    }
3185
    if (opt_autocommit)
3186
    {
3187
      fprintf(md_result_file, "commit;\n");
3188 3189
      check_io(md_result_file);
    }
3190
    mysql_free_result(res);
3191
    dynstr_free(&query_string);
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
3192 3193
  }
  DBUG_VOID_RETURN;
3194 3195

err:
3196 3197
  dynstr_free(&query_string);
  maybe_exit(error);
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
3198
  DBUG_VOID_RETURN;
3199
} /* dump_table */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3200 3201 3202 3203


static char *getTableName(int reset)
{
grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
3204
  static MYSQL_RES *res= NULL;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3205 3206 3207 3208
  MYSQL_ROW    row;

  if (!res)
  {
3209
    if (!(res= mysql_list_tables(mysql,NullS)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3210 3211
      return(NULL);
  }
grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
3212
  if ((row= mysql_fetch_row(res)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3213
    return((char*) row[0]);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
3214

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3215 3216 3217 3218 3219
  if (reset)
    mysql_data_seek(res,0);      /* We want to read again */
  else
  {
    mysql_free_result(res);
grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
3220
    res= NULL;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3221 3222 3223 3224 3225
  }
  return(NULL);
} /* getTableName */


3226 3227 3228 3229 3230
/*
  dump all logfile groups and tablespaces
*/

static int dump_all_tablespaces()
3231 3232 3233 3234 3235 3236
{
  return dump_tablespaces(NULL);
}

static int dump_tablespaces_for_tables(char *db, char **table_names, int tables)
{
3237
  DYNAMIC_STRING where;
3238 3239 3240
  int r;
  int i;
  char name_buff[NAME_LEN*2+3];
3241

3242 3243
  mysql_real_escape_string(mysql, name_buff, db, strlen(db));

3244
  init_dynamic_string_checked(&where, " AND TABLESPACE_NAME IN ("
3245 3246 3247 3248
                      "SELECT DISTINCT TABLESPACE_NAME FROM"
                      " INFORMATION_SCHEMA.PARTITIONS"
                      " WHERE"
                      " TABLE_SCHEMA='", 256, 1024);
3249 3250
  dynstr_append_checked(&where, name_buff);
  dynstr_append_checked(&where, "' AND TABLE_NAME IN (");
3251 3252 3253 3254 3255

  for (i=0 ; i<tables ; i++)
  {
    mysql_real_escape_string(mysql, name_buff,
                             table_names[i], strlen(table_names[i]));
3256

3257 3258 3259
    dynstr_append_checked(&where, "'");
    dynstr_append_checked(&where, name_buff);
    dynstr_append_checked(&where, "',");
3260
  }
3261
  dynstr_trunc(&where, 1);
3262
  dynstr_append_checked(&where,"))");
3263

3264
  DBUG_PRINT("info",("Dump TS for Tables where: %s",where.str));
3265 3266
  r= dump_tablespaces(where.str);
  dynstr_free(&where);
3267 3268 3269 3270 3271
  return r;
}

static int dump_tablespaces_for_databases(char** databases)
{
3272
  DYNAMIC_STRING where;
3273 3274 3275
  int r;
  int i;

3276
  init_dynamic_string_checked(&where, " AND TABLESPACE_NAME IN ("
3277 3278 3279 3280
                      "SELECT DISTINCT TABLESPACE_NAME FROM"
                      " INFORMATION_SCHEMA.PARTITIONS"
                      " WHERE"
                      " TABLE_SCHEMA IN (", 256, 1024);
3281 3282 3283 3284 3285 3286

  for (i=0 ; databases[i]!=NULL ; i++)
  {
    char db_name_buff[NAME_LEN*2+3];
    mysql_real_escape_string(mysql, db_name_buff,
                             databases[i], strlen(databases[i]));
3287 3288 3289
    dynstr_append_checked(&where, "'");
    dynstr_append_checked(&where, db_name_buff);
    dynstr_append_checked(&where, "',");
3290
  }
3291
  dynstr_trunc(&where, 1);
3292
  dynstr_append_checked(&where,"))");
3293

3294
  DBUG_PRINT("info",("Dump TS for DBs where: %s",where.str));
3295 3296
  r= dump_tablespaces(where.str);
  dynstr_free(&where);
3297 3298 3299 3300
  return r;
}

static int dump_tablespaces(char* ts_where)
3301 3302 3303 3304
{
  MYSQL_ROW row;
  MYSQL_RES *tableres;
  char buf[FN_REFLEN];
3305
  DYNAMIC_STRING sqlbuf;
3306
  int first= 0;
3307 3308 3309 3310 3311 3312
  /*
    The following are used for parsing the EXTRA field
  */
  char extra_format[]= "UNDO_BUFFER_SIZE=";
  char *ubs;
  char *endsemi;
3313

3314
  init_dynamic_string_checked(&sqlbuf,
3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326
                      "SELECT LOGFILE_GROUP_NAME,"
                      " FILE_NAME,"
                      " TOTAL_EXTENTS,"
                      " INITIAL_SIZE,"
                      " ENGINE,"
                      " EXTRA"
                      " FROM INFORMATION_SCHEMA.FILES"
                      " WHERE FILE_TYPE = 'UNDO LOG'"
                      " AND FILE_NAME IS NOT NULL",
                      256, 1024);
  if(ts_where)
  {
3327
    dynstr_append_checked(&sqlbuf,
3328 3329 3330 3331 3332
                  " AND LOGFILE_GROUP_NAME IN ("
                  "SELECT DISTINCT LOGFILE_GROUP_NAME"
                  " FROM INFORMATION_SCHEMA.FILES"
                  " WHERE FILE_TYPE = 'DATAFILE'"
                  );
3333 3334
    dynstr_append_checked(&sqlbuf, ts_where);
    dynstr_append_checked(&sqlbuf, ")");
3335
  }
3336
  dynstr_append_checked(&sqlbuf,
3337 3338 3339 3340 3341
                " GROUP BY LOGFILE_GROUP_NAME, FILE_NAME"
                ", ENGINE"
                " ORDER BY LOGFILE_GROUP_NAME");

  if (mysql_query(mysql, sqlbuf.str) ||
3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356
      !(tableres = mysql_store_result(mysql)))
  {
    if (mysql_errno(mysql) == ER_BAD_TABLE_ERROR ||
        mysql_errno(mysql) == ER_BAD_DB_ERROR ||
        mysql_errno(mysql) == ER_UNKNOWN_TABLE)
    {
      fprintf(md_result_file,
              "\n--\n-- Not dumping tablespaces as no INFORMATION_SCHEMA.FILES"
              " table on this server\n--\n");
      check_io(md_result_file);
      return 0;
    }

    my_printf_error(0, "Error: Couldn't dump tablespaces %s",
                    MYF(0), mysql_error(mysql));
3357
    return 1;
3358
  }
3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379

  buf[0]= 0;
  while ((row= mysql_fetch_row(tableres)))
  {
    if (strcmp(buf, row[0]) != 0)
      first= 1;
    if (first)
    {
      if (!opt_xml && opt_comments)
      {
	fprintf(md_result_file,"\n--\n-- Logfile group: %s\n--\n", row[0]);
	check_io(md_result_file);
      }
      fprintf(md_result_file, "\nCREATE");
    }
    else
    {
      fprintf(md_result_file, "\nALTER");
    }
    fprintf(md_result_file,
            " LOGFILE GROUP %s\n"
3380 3381 3382 3383 3384
            "  ADD UNDOFILE '%s'\n",
            row[0],
            row[1]);
    if (first)
    {
3385 3386 3387 3388 3389 3390 3391
      ubs= strstr(row[5],extra_format);
      if(!ubs)
        break;
      ubs+= strlen(extra_format);
      endsemi= strstr(ubs,";");
      if(endsemi)
        endsemi[0]= '\0';
3392 3393
      fprintf(md_result_file,
              "  UNDO_BUFFER_SIZE %s\n",
3394
              ubs);
3395 3396
    }
    fprintf(md_result_file,
3397 3398
            "  INITIAL_SIZE %s\n"
            "  ENGINE=%s;\n",
3399 3400
            row[3],
            row[4]);
3401
    check_io(md_result_file);
3402 3403 3404 3405 3406
    if (first)
    {
      first= 0;
      strxmov(buf, row[0], NullS);
    }
3407
  }
3408
  dynstr_free(&sqlbuf);
3409
  init_dynamic_string_checked(&sqlbuf,
3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420
                      "SELECT DISTINCT TABLESPACE_NAME,"
                      " FILE_NAME,"
                      " LOGFILE_GROUP_NAME,"
                      " EXTENT_SIZE,"
                      " INITIAL_SIZE,"
                      " ENGINE"
                      " FROM INFORMATION_SCHEMA.FILES"
                      " WHERE FILE_TYPE = 'DATAFILE'",
                      256, 1024);

  if(ts_where)
3421
    dynstr_append_checked(&sqlbuf, ts_where);
3422

3423
  dynstr_append_checked(&sqlbuf, " ORDER BY TABLESPACE_NAME, LOGFILE_GROUP_NAME");
3424 3425

  if (mysql_query_with_error_report(mysql, &tableres, sqlbuf.str))
3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449
    return 1;

  buf[0]= 0;
  while ((row= mysql_fetch_row(tableres)))
  {
    if (strcmp(buf, row[0]) != 0)
      first= 1;
    if (first)
    {
      if (!opt_xml && opt_comments)
      {
	fprintf(md_result_file,"\n--\n-- Tablespace: %s\n--\n", row[0]);
	check_io(md_result_file);
      }
      fprintf(md_result_file, "\nCREATE");
    }
    else
    {
      fprintf(md_result_file, "\nALTER");
    }
    fprintf(md_result_file,
            " TABLESPACE %s\n"
            "  ADD DATAFILE '%s'\n",
            row[0],
3450
            row[1]);
3451 3452 3453
    if (first)
    {
      fprintf(md_result_file,
3454 3455 3456 3457
              "  USE LOGFILE GROUP %s\n"
              "  EXTENT_SIZE %s\n",
              row[2],
              row[3]);
3458 3459 3460 3461
    }
    fprintf(md_result_file,
            "  INITIAL_SIZE %s\n"
            "  ENGINE=%s;\n",
3462 3463
            row[4],
            row[5]);
3464
    check_io(md_result_file);
3465 3466 3467 3468 3469
    if (first)
    {
      first= 0;
      strxmov(buf, row[0], NullS);
    }
3470
  }
3471 3472

  dynstr_free(&sqlbuf);
3473 3474 3475
  return 0;
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3476 3477 3478 3479 3480 3481
static int dump_all_databases()
{
  MYSQL_ROW row;
  MYSQL_RES *tableres;
  int result=0;

3482
  if (mysql_query_with_error_report(mysql, &tableres, "SHOW DATABASES"))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3483
    return 1;
grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
3484
  while ((row= mysql_fetch_row(tableres)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3485 3486 3487 3488
  {
    if (dump_all_tables_in_db(row[0]))
      result=1;
  }
3489
  if (seen_views)
3490
  {
3491
    if (mysql_query(mysql, "SHOW DATABASES") ||
3492
        !(tableres= mysql_store_result(mysql)))
3493 3494
    {
      my_printf_error(0, "Error: Couldn't execute 'SHOW DATABASES': %s",
3495
                      MYF(0), mysql_error(mysql));
3496 3497
      return 1;
    }
grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
3498
    while ((row= mysql_fetch_row(tableres)))
3499 3500 3501 3502 3503
    {
      if (dump_all_views_in_db(row[0]))
        result=1;
    }
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3504 3505 3506 3507 3508 3509 3510 3511
  return result;
}
/* dump_all_databases */


static int dump_databases(char **db_names)
{
  int result=0;
3512
  char **db;
3513 3514
  DBUG_ENTER("dump_databases");

3515
  for (db= db_names ; *db ; db++)
3516
  {
3517
    if (dump_all_tables_in_db(*db))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3518 3519
      result=1;
  }
3520
  if (!result && seen_views)
3521 3522 3523 3524 3525 3526 3527
  {
    for (db= db_names ; *db ; db++)
    {
      if (dump_all_views_in_db(*db))
        result=1;
    }
  }
3528
  DBUG_RETURN(result);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3529 3530 3531
} /* dump_databases */


3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542
/*
View Specific database initalization.

SYNOPSIS
  init_dumping_views
  qdatabase      quoted name of the database

RETURN VALUES
  0        Success.
  1        Failure.
*/
3543
int init_dumping_views(char *qdatabase __attribute__((unused)))
3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601
{
    return 0;
} /* init_dumping_views */


/*
Table Specific database initalization.

SYNOPSIS
  init_dumping_tables
  qdatabase      quoted name of the database

RETURN VALUES
  0        Success.
  1        Failure.
*/
int init_dumping_tables(char *qdatabase)
{
  if (!opt_create_db)
  {
    char qbuf[256];
    MYSQL_ROW row;
    MYSQL_RES *dbinfo;

    my_snprintf(qbuf, sizeof(qbuf),
                "SHOW CREATE DATABASE IF NOT EXISTS %s",
                qdatabase);

    if (mysql_query(mysql, qbuf) || !(dbinfo = mysql_store_result(mysql)))
    {
      /* Old server version, dump generic CREATE DATABASE */
      if (opt_drop_database)
        fprintf(md_result_file,
                "\n/*!40000 DROP DATABASE IF EXISTS %s;*/\n",
                qdatabase);
      fprintf(md_result_file,
              "\nCREATE DATABASE /*!32312 IF NOT EXISTS*/ %s;\n",
              qdatabase);
    }
    else
    {
      if (opt_drop_database)
        fprintf(md_result_file,
                "\n/*!40000 DROP DATABASE IF EXISTS %s*/;\n",
                qdatabase);
      row = mysql_fetch_row(dbinfo);
      if (row[1])
      {
        fprintf(md_result_file,"\n%s;\n",row[1]);
      }
    }
  }

  return 0;
} /* init_dumping_tables */


static int init_dumping(char *database, int init_func(char*))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3602
{
3603
  if (mysql_get_server_version(mysql) >= 50003 &&
3604
      !my_strcasecmp(&my_charset_latin1, database, "information_schema"))
3605
    return 1;
3606

3607
  if (mysql_select_db(mysql, database))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3608
  {
3609
    DB_error(mysql, "when selecting the database");
3610
    return 1;                   /* If --force */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3611
  }
3612
  if (!path && !opt_xml)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3613 3614 3615
  {
    if (opt_databases || opt_alldbs)
    {
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3616
      /*
3617
        length of table name * 2 (if name contains quotes), 2 quotes and 0
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3618
      */
3619
      char quoted_database_buf[NAME_LEN*2+3];
3620
      char *qdatabase= quote_name(database,quoted_database_buf,opt_quoted);
3621
      if (opt_comments)
3622
      {
3623 3624
        fprintf(md_result_file,"\n--\n-- Current Database: %s\n--\n", qdatabase);
        check_io(md_result_file);
3625
      }
3626

3627 3628
      /* Call the view or table specific function */
      init_func(qdatabase);
3629

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3630
      fprintf(md_result_file,"\nUSE %s;\n", qdatabase);
3631
      check_io(md_result_file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3632 3633
    }
  }
3634 3635
  if (extended_insert)
    init_dynamic_string_checked(&extended_row, "", 1024, 1024);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3636 3637 3638 3639
  return 0;
} /* init_dumping */


3640 3641
/* Return 1 if we should copy the table */

3642
my_bool include_table(uchar* hash_key, uint len)
3643
{
3644
  return !hash_search(&ignore_table, (uchar*) hash_key, len);
3645 3646
}

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3647

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3648 3649 3650 3651
static int dump_all_tables_in_db(char *database)
{
  char *table;
  uint numrows;
3652
  char table_buff[NAME_LEN*2+3];
3653 3654
  char hash_key[2*NAME_LEN+2];  /* "db.tablename" */
  char *afterdot;
3655
  int using_mysql_db= my_strcasecmp(&my_charset_latin1, database, "mysql");
3656
  DBUG_ENTER("dump_all_tables_in_db");
3657 3658 3659 3660

  afterdot= strmov(hash_key, database);
  *afterdot++= '.';

3661
  if (init_dumping(database, init_dumping_tables))
3662
    DBUG_RETURN(1);
3663
  if (opt_xml)
3664
    print_xml_tag(md_result_file, "", "\n", "database", "name=", database, NullS);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3665 3666 3667
  if (lock_tables)
  {
    DYNAMIC_STRING query;
3668
    init_dynamic_string_checked(&query, "LOCK TABLES ", 256, 1024);
3669
    for (numrows= 0 ; (table= getTableName(1)) ; numrows++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3670
    {
3671 3672 3673
      char *end= strmov(afterdot, table);
      if (include_table(hash_key,end - hash_key))
      {
3674 3675
        dynstr_append_checked(&query, quote_name(table, table_buff, 1));
        dynstr_append_checked(&query, " READ /*!32311 LOCAL */,");
3676
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3677
    }
3678 3679
    if (numrows && mysql_real_query(mysql, query.str, query.length-1))
      DB_error(mysql, "when using LOCK TABLES");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3680 3681 3682 3683 3684
            /* We shall continue here, if --force was given */
    dynstr_free(&query);
  }
  if (flush_logs)
  {
3685 3686
    if (mysql_refresh(mysql, REFRESH_LOG))
      DB_error(mysql, "when doing refresh");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3687 3688
           /* We shall continue here, if --force was given */
  }
3689
  while ((table= getTableName(0)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3690
  {
3691 3692 3693
    char *end= strmov(afterdot, table);
    if (include_table(hash_key, end - hash_key))
    {
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
3694
      dump_table(table,database);
3695 3696
      my_free(order_by, MYF(MY_ALLOW_ZERO_PTR));
      order_by= 0;
3697
      if (opt_dump_triggers && ! opt_xml &&
3698
          mysql_get_server_version(mysql) >= 50009)
3699
        dump_triggers_for_table(table, database);
3700
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3701
  }
3702
  if (opt_events && !opt_xml &&
3703
      mysql_get_server_version(mysql) >= 50106)
3704 3705 3706 3707
  {
    DBUG_PRINT("info", ("Dumping events for database %s", database));
    dump_events_for_db(database);
  }
3708
  if (opt_routines && !opt_xml &&
3709
      mysql_get_server_version(mysql) >= 50009)
3710 3711 3712 3713
  {
    DBUG_PRINT("info", ("Dumping routines for database %s", database));
    dump_routines_for_db(database);
  }
3714
  if (opt_xml)
3715
  {
3716
    fputs("</database>\n", md_result_file);
3717 3718
    check_io(md_result_file);
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3719
  if (lock_tables)
3720
    VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES"));
3721 3722 3723 3724 3725
  if (flush_privileges && using_mysql_db == 0)
  {
    fprintf(md_result_file,"\n--\n-- Flush Grant Tables \n--\n");
    fprintf(md_result_file,"\n/*! FLUSH PRIVILEGES */;\n");
  }
3726
  DBUG_RETURN(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3727 3728 3729
} /* dump_all_tables_in_db */


3730 3731 3732 3733 3734 3735
/*
   dump structure of views of database

   SYNOPSIS
     dump_all_views_in_db()
     database  database name
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3736

3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747
  RETURN
    0 OK
    1 ERROR
*/

static my_bool dump_all_views_in_db(char *database)
{
  char *table;
  uint numrows;
  char table_buff[NAME_LEN*2+3];

3748
  if (init_dumping(database, init_dumping_views))
3749
    return 1;
3750
  if (opt_xml)
3751
    print_xml_tag(md_result_file, "", "\n", "database", "name=", database, NullS);
3752 3753 3754
  if (lock_tables)
  {
    DYNAMIC_STRING query;
3755
    init_dynamic_string_checked(&query, "LOCK TABLES ", 256, 1024);
3756 3757
    for (numrows= 0 ; (table= getTableName(1)); numrows++)
    {
3758 3759
      dynstr_append_checked(&query, quote_name(table, table_buff, 1));
      dynstr_append_checked(&query, " READ /*!32311 LOCAL */,");
3760
    }
3761 3762
    if (numrows && mysql_real_query(mysql, query.str, query.length-1))
      DB_error(mysql, "when using LOCK TABLES");
3763 3764 3765 3766 3767
            /* We shall continue here, if --force was given */
    dynstr_free(&query);
  }
  if (flush_logs)
  {
3768 3769
    if (mysql_refresh(mysql, REFRESH_LOG))
      DB_error(mysql, "when doing refresh");
3770 3771 3772
           /* We shall continue here, if --force was given */
  }
  while ((table= getTableName(0)))
3773
     get_view_structure(table, database);
3774 3775 3776 3777 3778 3779
  if (opt_xml)
  {
    fputs("</database>\n", md_result_file);
    check_io(md_result_file);
  }
  if (lock_tables)
3780
    VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES"));
3781 3782
  return 0;
} /* dump_all_tables_in_db */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3783

gluh@gluh.mysql.r18.ru's avatar
gluh@gluh.mysql.r18.ru committed
3784

3785
/*
3786 3787 3788
  get_actual_table_name -- executes a SHOW TABLES LIKE '%s' to get the actual
  table name from the server for the table name given on the command line.
  we do this because the table name given on the command line may be a
3789
  different case (e.g.  T1 vs t1)
3790

3791
  RETURN
ramil@mysql.com's avatar
ramil@mysql.com committed
3792 3793
    pointer to the table name
    0 if error
3794 3795
*/

ramil@mysql.com's avatar
ramil@mysql.com committed
3796
static char *get_actual_table_name(const char *old_table_name, MEM_ROOT *root)
3797
{
ramil@mysql.com's avatar
ramil@mysql.com committed
3798
  char *name= 0;
3799
  MYSQL_RES  *table_res;
3800
  MYSQL_ROW  row;
3801
  char query[50 + 2*NAME_LEN];
3802
  char show_name_buff[FN_REFLEN];
3803
  DBUG_ENTER("get_actual_table_name");
3804

3805 3806
  /* Check memory for quote_for_like() */
  DBUG_ASSERT(2*sizeof(old_table_name) < sizeof(show_name_buff));
3807
  my_snprintf(query, sizeof(query), "SHOW TABLES LIKE %s",
3808
              quote_for_like(old_table_name, show_name_buff));
3809

3810
  if (mysql_query_with_error_report(mysql, 0, query))
3811
    return NullS;
3812

3813
  if ((table_res= mysql_store_result(mysql)))
3814
  {
3815 3816 3817
    my_ulonglong num_rows= mysql_num_rows(table_res);
    if (num_rows > 0)
    {
ramil@mysql.com's avatar
ramil@mysql.com committed
3818
      ulong *lengths;
3819 3820 3821 3822 3823
      /*
        Return first row
        TODO: Return all matching rows
      */
      row= mysql_fetch_row(table_res);
ramil@mysql.com's avatar
ramil@mysql.com committed
3824
      lengths= mysql_fetch_lengths(table_res);
ramil@mysql.com's avatar
ramil@mysql.com committed
3825
      name= strmake_root(root, row[0], lengths[0]);
3826 3827
    }
    mysql_free_result(table_res);
3828
  }
ramil@mysql.com's avatar
ramil@mysql.com committed
3829 3830
  DBUG_PRINT("exit", ("new_table_name: %s", name));
  DBUG_RETURN(name);
3831
}
3832

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3833 3834 3835

static int dump_selected_tables(char *db, char **table_names, int tables)
{
3836
  char table_buff[NAME_LEN*2+3];
msvensson@neptunus.(none)[msvensson]'s avatar
patch  
msvensson@neptunus.(none)[msvensson] committed
3837
  DYNAMIC_STRING lock_tables_query;
ramil@mysql.com's avatar
ramil@mysql.com committed
3838 3839
  MEM_ROOT root;
  char **dump_tables, **pos, **end;
msvensson@neptunus.(none)[msvensson]'s avatar
patch  
msvensson@neptunus.(none)[msvensson] committed
3840
  DBUG_ENTER("dump_selected_tables");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3841

3842
  if (init_dumping(db, init_dumping_tables))
serg@serg.mylan's avatar
serg@serg.mylan committed
3843
    DBUG_RETURN(1);
msvensson@neptunus.(none)[msvensson]'s avatar
patch  
msvensson@neptunus.(none)[msvensson] committed
3844

ramil@mysql.com's avatar
ramil@mysql.com committed
3845 3846
  init_alloc_root(&root, 8192, 0);
  if (!(dump_tables= pos= (char**) alloc_root(&root, tables * sizeof(char *))))
3847
     die(EX_EOM, "alloc_root failure.");
msvensson@neptunus.(none)[msvensson]'s avatar
patch  
msvensson@neptunus.(none)[msvensson] committed
3848

3849
  init_dynamic_string_checked(&lock_tables_query, "LOCK TABLES ", 256, 1024);
msvensson@neptunus.(none)[msvensson]'s avatar
patch  
msvensson@neptunus.(none)[msvensson] committed
3850
  for (; tables > 0 ; tables-- , table_names++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3851
  {
msvensson@neptunus.(none)[msvensson]'s avatar
patch  
msvensson@neptunus.(none)[msvensson] committed
3852
    /* the table name passed on commandline may be wrong case */
ramil@mysql.com's avatar
ramil@mysql.com committed
3853
    if ((*pos= get_actual_table_name(*table_names, &root)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3854
    {
msvensson@neptunus.(none)[msvensson]'s avatar
patch  
msvensson@neptunus.(none)[msvensson] committed
3855 3856 3857
      /* Add found table name to lock_tables_query */
      if (lock_tables)
      {
3858 3859
        dynstr_append_checked(&lock_tables_query, quote_name(*pos, table_buff, 1));
        dynstr_append_checked(&lock_tables_query, " READ /*!32311 LOCAL */,");
msvensson@neptunus.(none)[msvensson]'s avatar
patch  
msvensson@neptunus.(none)[msvensson] committed
3860
      }
ramil@mysql.com's avatar
ramil@mysql.com committed
3861
      pos++;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3862
    }
msvensson@neptunus.(none)[msvensson]'s avatar
patch  
msvensson@neptunus.(none)[msvensson] committed
3863
    else
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3864
    {
3865
       maybe_die(EX_ILLEGAL_TABLE, "Couldn't find table: \"%s\"", *table_names);
msvensson@neptunus.(none)[msvensson]'s avatar
patch  
msvensson@neptunus.(none)[msvensson] committed
3866
       /* We shall countinue here, if --force was given */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3867
    }
msvensson@neptunus.(none)[msvensson]'s avatar
patch  
msvensson@neptunus.(none)[msvensson] committed
3868
  }
ramil@mysql.com's avatar
ramil@mysql.com committed
3869
  end= pos;
msvensson@neptunus.(none)[msvensson]'s avatar
patch  
msvensson@neptunus.(none)[msvensson] committed
3870 3871 3872

  if (lock_tables)
  {
3873
    if (mysql_real_query(mysql, lock_tables_query.str,
msvensson@neptunus.(none)[msvensson]'s avatar
patch  
msvensson@neptunus.(none)[msvensson] committed
3874
                         lock_tables_query.length-1))
3875
      DB_error(mysql, "when doing LOCK TABLES");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3876 3877
       /* We shall countinue here, if --force was given */
  }
msvensson@neptunus.(none)[msvensson]'s avatar
patch  
msvensson@neptunus.(none)[msvensson] committed
3878
  dynstr_free(&lock_tables_query);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3879 3880
  if (flush_logs)
  {
3881 3882
    if (mysql_refresh(mysql, REFRESH_LOG))
      DB_error(mysql, "when doing refresh");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3883 3884
     /* We shall countinue here, if --force was given */
  }
3885
  if (opt_xml)
3886
    print_xml_tag(md_result_file, "", "\n", "database", "name=", db, NullS);
3887

msvensson@neptunus.(none)[msvensson]'s avatar
patch  
msvensson@neptunus.(none)[msvensson] committed
3888
  /* Dump each selected table */
ramil@mysql.com's avatar
ramil@mysql.com committed
3889
  for (pos= dump_tables; pos < end; pos++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3890
  {
ramil@mysql.com's avatar
ramil@mysql.com committed
3891 3892
    DBUG_PRINT("info",("Dumping table %s", *pos));
    dump_table(*pos, db);
3893
    if (opt_dump_triggers &&
3894
        mysql_get_server_version(mysql) >= 50009)
ramil@mysql.com's avatar
ramil@mysql.com committed
3895
      dump_triggers_for_table(*pos, db);
3896
  }
3897 3898

  /* Dump each selected view */
3899
  if (seen_views)
3900
  {
ramil@mysql.com's avatar
ramil@mysql.com committed
3901 3902
    for (pos= dump_tables; pos < end; pos++)
      get_view_structure(*pos, db);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3903
  }
3904
  if (opt_events && !opt_xml &&
3905
      mysql_get_server_version(mysql) >= 50106)
3906 3907 3908 3909
  {
    DBUG_PRINT("info", ("Dumping events for database %s", db));
    dump_events_for_db(db);
  }
3910 3911
  /* obtain dump of routines (procs/functions) */
  if (opt_routines  && !opt_xml &&
3912
      mysql_get_server_version(mysql) >= 50009)
3913 3914 3915 3916
  {
    DBUG_PRINT("info", ("Dumping routines for database %s", db));
    dump_routines_for_db(db);
  }
ramil@mysql.com's avatar
ramil@mysql.com committed
3917
  free_root(&root, MYF(0));
msvensson@neptunus.(none)[msvensson]'s avatar
patch  
msvensson@neptunus.(none)[msvensson] committed
3918 3919
  my_free(order_by, MYF(MY_ALLOW_ZERO_PTR));
  order_by= 0;
3920
  if (opt_xml)
3921
  {
3922
    fputs("</database>\n", md_result_file);
3923 3924
    check_io(md_result_file);
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3925
  if (lock_tables)
3926
    VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES"));
msvensson@neptunus.(none)[msvensson]'s avatar
patch  
msvensson@neptunus.(none)[msvensson] committed
3927
  DBUG_RETURN(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3928 3929 3930
} /* dump_selected_tables */


3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942
static int do_show_master_status(MYSQL *mysql_con)
{
  MYSQL_ROW row;
  MYSQL_RES *master;
  const char *comment_prefix=
    (opt_master_data == MYSQL_OPT_MASTER_DATA_COMMENTED_SQL) ? "-- " : "";
  if (mysql_query_with_error_report(mysql_con, &master, "SHOW MASTER STATUS"))
  {
    return 1;
  }
  else
  {
grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
3943
    row= mysql_fetch_row(master);
3944 3945
    if (row && row[0] && row[1])
    {
3946
      /* SHOW MASTER STATUS reports file and position */
3947 3948 3949 3950 3951 3952
      if (opt_comments)
        fprintf(md_result_file,
                "\n--\n-- Position to start replication or point-in-time "
                "recovery from\n--\n\n");
      fprintf(md_result_file,
              "%sCHANGE MASTER TO MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n",
3953
              comment_prefix, row[0], row[1]);
3954 3955
      check_io(md_result_file);
    }
3956 3957 3958
    else if (!ignore_errors)
    {
      /* SHOW MASTER STATUS reports nothing and --force is not enabled */
3959 3960
      my_printf_error(0, "Error: Binlogging on server not active",
                      MYF(0));
3961 3962 3963
      mysql_free_result(master);
      return 1;
    }
3964 3965 3966 3967 3968 3969 3970 3971
    mysql_free_result(master);
  }
  return 0;
}


static int do_flush_tables_read_lock(MYSQL *mysql_con)
{
3972 3973 3974 3975 3976 3977 3978 3979
  /*
    We do first a FLUSH TABLES. If a long update is running, the FLUSH TABLES
    will wait but will not stall the whole mysqld, and when the long update is
    done the FLUSH TABLES WITH READ LOCK will start and succeed quickly. So,
    FLUSH TABLES is to lower the probability of a stage where both mysqldump
    and most client connections are stalled. Of course, if a second long
    update starts between the two FLUSHes, we have that bad stall.
  */
3980
  return
3981 3982 3983
    ( mysql_query_with_error_report(mysql_con, 0, "FLUSH TABLES") ||
      mysql_query_with_error_report(mysql_con, 0,
                                    "FLUSH TABLES WITH READ LOCK") );
3984 3985 3986 3987 3988 3989 3990 3991
}


static int do_unlock_tables(MYSQL *mysql_con)
{
  return mysql_query_with_error_report(mysql_con, 0, "UNLOCK TABLES");
}

tsmith@quadxeon.mysql.com's avatar
tsmith@quadxeon.mysql.com committed
3992 3993
static int get_bin_log_name(MYSQL *mysql_con,
                            char* buff_log_name, uint buff_len)
3994 3995 3996 3997
{
  MYSQL_RES *res;
  MYSQL_ROW row;

tsmith@quadxeon.mysql.com's avatar
tsmith@quadxeon.mysql.com committed
3998
  if (mysql_query(mysql_con, "SHOW MASTER STATUS") ||
3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011
      !(res= mysql_store_result(mysql)))
    return 1;

  if (!(row= mysql_fetch_row(res)))
  {
    mysql_free_result(res);
    return 1;
  }
  /*
    Only one row is returned, and the first column is the name of the
    active log.
  */
  strmake(buff_log_name, row[0], buff_len - 1);
4012

4013 4014 4015 4016 4017
  mysql_free_result(res);
  return 0;
}

static int purge_bin_logs_to(MYSQL *mysql_con, char* log_name)
4018
{
4019 4020 4021 4022 4023 4024 4025 4026
  DYNAMIC_STRING str;
  int err;
  init_dynamic_string_checked(&str, "PURGE BINARY LOGS TO '", 1024, 1024);
  dynstr_append_checked(&str, log_name);
  dynstr_append_checked(&str, "'");
  err = mysql_query_with_error_report(mysql_con, 0, str.str);
  dynstr_free(&str);
  return err;
4027 4028 4029
}


4030
static int start_transaction(MYSQL *mysql_con)
4031 4032 4033 4034 4035
{
  /*
    We use BEGIN for old servers. --single-transaction --master-data will fail
    on old servers, but that's ok as it was already silently broken (it didn't
    do a consistent read, so better tell people frankly, with the error).
4036 4037 4038 4039

    We want the first consistent read to be used for all tables to dump so we
    need the REPEATABLE READ level (not anything lower, for example READ
    COMMITTED would give one new consistent read per dumped table).
4040 4041
  */
  return (mysql_query_with_error_report(mysql_con, 0,
4042 4043 4044
                                        "SET SESSION TRANSACTION ISOLATION "
                                        "LEVEL REPEATABLE READ") ||
          mysql_query_with_error_report(mysql_con, 0,
4045
                                        "START TRANSACTION "
4046
                                        "/*!40100 WITH CONSISTENT SNAPSHOT */"));
4047 4048
}

4049 4050

static ulong find_set(TYPELIB *lib, const char *x, uint length,
4051
                      char **err_pos, uint *err_len)
4052 4053 4054 4055 4056 4057
{
  const char *end= x + length;
  ulong found= 0;
  uint find;
  char buff[255];

4058
  *err_pos= 0;                  /* No error yet */
4059
  while (end > x && my_isspace(charset_info, end[-1]))
4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090
    end--;

  *err_len= 0;
  if (x != end)
  {
    const char *start= x;
    for (;;)
    {
      const char *pos= start;
      uint var_len;

      for (; pos != end && *pos != ','; pos++) ;
      var_len= (uint) (pos - start);
      strmake(buff, start, min(sizeof(buff), var_len));
      find= find_type(buff, lib, var_len);
      if (!find)
      {
        *err_pos= (char*) start;
        *err_len= var_len;
      }
      else
        found|= ((longlong) 1 << (find - 1));
      if (pos == end)
        break;
      start= pos + 1;
    }
  }
  return found;
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
4091 4092
/* Print a value with a prefix on file */
static void print_value(FILE *file, MYSQL_RES  *result, MYSQL_ROW row,
4093 4094
                        const char *prefix, const char *name,
                        int string_value)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4095
{
4096
  MYSQL_FIELD   *field;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4097 4098
  mysql_field_seek(result, 0);

grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
4099
  for ( ; (field= mysql_fetch_field(result)) ; row++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4100 4101 4102 4103 4104
  {
    if (!strcmp(field->name,name))
    {
      if (row[0] && row[0][0] && strcmp(row[0],"0")) /* Skip default */
      {
4105 4106 4107 4108 4109 4110 4111 4112
        fputc(' ',file);
        fputs(prefix, file);
        if (string_value)
          unescape(file,row[0],(uint) strlen(row[0]));
        else
          fputs(row[0], file);
        check_io(file);
        return;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4113 4114 4115
      }
    }
  }
4116
  return;                                       /* This shouldn't happen */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4117 4118 4119
} /* print_value */


4120 4121
/*
  SYNOPSIS
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
4122 4123 4124 4125

  Check if we the table is one of the table types that should be ignored:
  MRG_ISAM, MRG_MYISAM, if opt_delayed, if that table supports delayed inserts.
  If the table should be altogether ignored, it returns a TRUE, FALSE if it
4126 4127
  should not be ignored. If the user has selected to use INSERT DELAYED, it
  sets the value of the bool pointer supports_delayed_inserts to 0 if not
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
4128 4129 4130 4131
  supported, 1 if it is supported.

  ARGS

4132
    check_if_ignore_table()
4133
    table_name                  Table name to check
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
4134
    table_type                  Type of table
4135 4136

  GLOBAL VARIABLES
4137
    mysql                       MySQL connection
4138
    verbose                     Write warning messages
4139 4140

  RETURN
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
4141
    char (bit value)            See IGNORE_ values at top
4142 4143
*/

patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
4144
char check_if_ignore_table(const char *table_name, char *table_type)
4145
{
4146
  char result= IGNORE_NONE;
4147
  char buff[FN_REFLEN+80], show_name_buff[FN_REFLEN];
dkatz/Damien@damiendev's avatar
dkatz/Damien@damiendev committed
4148
  MYSQL_RES *res= NULL;
4149
  MYSQL_ROW row;
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
4150
  DBUG_ENTER("check_if_ignore_table");
4151

4152 4153 4154
  /* Check memory for quote_for_like() */
  DBUG_ASSERT(2*sizeof(table_name) < sizeof(show_name_buff));
  my_snprintf(buff, sizeof(buff), "show table status like %s",
4155
              quote_for_like(table_name, show_name_buff));
4156
  if (mysql_query_with_error_report(mysql, &res, buff))
4157
  {
4158
    if (mysql_errno(mysql) != ER_PARSE_ERROR)
4159
    {                                   /* If old MySQL version */
4160 4161
      verbose_msg("-- Warning: Couldn't get status information for "
                  "table %s (%s)\n", table_name, mysql_error(mysql));
4162
      DBUG_RETURN(result);                       /* assume table is ok */
4163 4164
    }
  }
4165
  if (!(row= mysql_fetch_row(res)))
4166 4167
  {
    fprintf(stderr,
4168
            "Error: Couldn't read status information for table %s (%s)\n",
4169
            table_name, mysql_error(mysql));
4170
    mysql_free_result(res);
4171
    DBUG_RETURN(result);                         /* assume table is ok */
4172
  }
4173
  if (!(row[1]))
monty@mysql.com's avatar
monty@mysql.com committed
4174
    strmake(table_type, "VIEW", NAME_LEN-1);
4175 4176
  else
  {
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
4177 4178 4179 4180 4181 4182
    /*
      If the table type matches any of these, we do support delayed inserts.
      Note: we do not want to skip dumping this table if if is not one of
      these types, but we do want to use delayed inserts in the dump if
      the table type is _NOT_ one of these types
    */
4183
    strmake(table_type, row[1], NAME_LEN-1);
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196
    if (opt_delayed)
    {
      if (strcmp(table_type,"MyISAM") &&
          strcmp(table_type,"ISAM") &&
          strcmp(table_type,"ARCHIVE") &&
          strcmp(table_type,"HEAP") &&
          strcmp(table_type,"MEMORY"))
        result= IGNORE_INSERT_DELAYED;
    }

    /*
      If these two types, we do want to skip dumping the table
    */
4197
    if (!opt_no_data &&
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
4198 4199
        (!strcmp(table_type,"MRG_MyISAM") || !strcmp(table_type,"MRG_ISAM")))
      result= IGNORE_DATA;
4200
  }
4201
  mysql_free_result(res);
patg@krsna.patg.net's avatar
patg@krsna.patg.net committed
4202
  DBUG_RETURN(result);
4203 4204
}

4205

4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222
/*
  Get string of comma-separated primary key field names

  SYNOPSIS
    char *primary_key_fields(const char *table_name)
    RETURNS     pointer to allocated buffer (must be freed by caller)
    table_name  quoted table name

  DESCRIPTION
    Use SHOW KEYS FROM table_name, allocate a buffer to hold the
    field names, and then build that string and return the pointer
    to that buffer.

    Returns NULL if there is no PRIMARY or UNIQUE key on the table,
    or if there is some failure.  It is better to continue to dump
    the table unsorted, rather than exit without dumping the data.
*/
monty@mishka.local's avatar
monty@mishka.local committed
4223

4224 4225
static char *primary_key_fields(const char *table_name)
{
grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
4226
  MYSQL_RES  *res= NULL;
4227 4228
  MYSQL_ROW  row;
  /* SHOW KEYS FROM + table name * 2 (escaped) + 2 quotes + \0 */
4229
  char show_keys_buff[15 + NAME_LEN * 2 + 3];
grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
4230 4231
  uint result_length= 0;
  char *result= 0;
4232 4233
  char buff[NAME_LEN * 2 + 3];
  char *quoted_field;
4234

4235 4236
  my_snprintf(show_keys_buff, sizeof(show_keys_buff),
              "SHOW KEYS FROM %s", table_name);
4237
  if (mysql_query(mysql, show_keys_buff) ||
4238
      !(res= mysql_store_result(mysql)))
4239 4240 4241
  {
    fprintf(stderr, "Warning: Couldn't read keys from table %s;"
            " records are NOT sorted (%s)\n",
4242
            table_name, mysql_error(mysql));
4243 4244 4245 4246
    /* Don't exit, because it's better to print out unsorted records */
    goto cleanup;
  }

tsmith@build.mysql.com's avatar
tsmith@build.mysql.com committed
4247 4248 4249 4250 4251 4252
  /*
   * Figure out the length of the ORDER BY clause result.
   * Note that SHOW KEYS is ordered:  a PRIMARY key is always the first
   * row, and UNIQUE keys come before others.  So we only need to check
   * the first key, not all keys.
   */
grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
4253
  if ((row= mysql_fetch_row(res)) && atoi(row[1]) == 0)
4254
  {
tsmith@build.mysql.com's avatar
tsmith@build.mysql.com committed
4255 4256
    /* Key is unique */
    do
4257 4258 4259 4260
    {
      quoted_field= quote_name(row[4], buff, 0);
      result_length+= strlen(quoted_field) + 1; /* + 1 for ',' or \0 */
    } while ((row= mysql_fetch_row(res)) && atoi(row[3]) > 1);
4261 4262 4263
  }

  /* Build the ORDER BY clause result */
monty@mishka.local's avatar
monty@mishka.local committed
4264 4265
  if (result_length)
  {
4266 4267
    char *end;
    /* result (terminating \0 is already in result_length) */
grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
4268
    result= my_malloc(result_length + 10, MYF(MY_WME));
monty@mishka.local's avatar
monty@mishka.local committed
4269 4270
    if (!result)
    {
4271 4272 4273
      fprintf(stderr, "Error: Not enough memory to store ORDER BY clause\n");
      goto cleanup;
    }
tsmith@build.mysql.com's avatar
tsmith@build.mysql.com committed
4274
    mysql_data_seek(res, 0);
grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
4275
    row= mysql_fetch_row(res);
4276 4277
    quoted_field= quote_name(row[4], buff, 0);
    end= strmov(result, quoted_field);
grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
4278
    while ((row= mysql_fetch_row(res)) && atoi(row[3]) > 1)
4279 4280 4281 4282
    {
      quoted_field= quote_name(row[4], buff, 0);
      end= strxmov(end, ",", quoted_field, NullS);
    }
4283 4284 4285 4286 4287 4288 4289 4290 4291
  }

cleanup:
  if (res)
    mysql_free_result(res);

  return result;
}

4292

4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312
/*
  Replace a substring

  SYNOPSIS
    replace
    ds_str      The string to search and perform the replace in
    search_str  The string to search for
    search_len  Length of the string to search for
    replace_str The string to replace with
    replace_len Length of the string to replace with

  RETURN
    0 String replaced
    1 Could not find search_str in str
*/

static int replace(DYNAMIC_STRING *ds_str,
                   const char *search_str, ulong search_len,
                   const char *replace_str, ulong replace_len)
{
msvensson@neptunus.(none)'s avatar
msvensson@neptunus.(none) committed
4313
  DYNAMIC_STRING ds_tmp;
4314 4315 4316
  const char *start= strstr(ds_str->str, search_str);
  if (!start)
    return 1;
4317
  init_dynamic_string_checked(&ds_tmp, "",
4318
                      ds_str->length + replace_len, 256);
4319 4320 4321 4322
  dynstr_append_mem_checked(&ds_tmp, ds_str->str, start - ds_str->str);
  dynstr_append_mem_checked(&ds_tmp, replace_str, replace_len);
  dynstr_append_checked(&ds_tmp, start + search_len);
  dynstr_set_checked(ds_str, ds_tmp.str);
4323 4324 4325 4326 4327
  dynstr_free(&ds_tmp);
  return 0;
}


4328 4329 4330 4331
/*
  Getting VIEW structure

  SYNOPSIS
4332
    get_view_structure()
4333 4334 4335 4336 4337 4338 4339 4340
    table   view name
    db      db name

  RETURN
    0 OK
    1 ERROR
*/

4341
static my_bool get_view_structure(char *table, char* db)
4342
{
4343
  MYSQL_RES  *table_res;
4344 4345
  MYSQL_ROW  row;
  MYSQL_FIELD *field;
4346 4347 4348
  char       *result_table, *opt_quoted_table;
  char       table_buff[NAME_LEN*2+3];
  char       table_buff2[NAME_LEN*2+3];
4349
  char       query[QUERY_LENGTH];
grog@eucla.lemis.com's avatar
grog@eucla.lemis.com committed
4350
  FILE       *sql_file= md_result_file;
4351
  DBUG_ENTER("get_view_structure");
4352

4353
  if (opt_no_create_info) /* Don't write table creation info */
4354 4355
    DBUG_RETURN(0);

4356
  verbose_msg("-- Retrieving view structure for table %s...\n", table);
4357

jimw@mysql.com's avatar
jimw@mysql.com committed
4358
#ifdef NOT_REALLY_USED_YET
4359
  sprintf(insert_pat,"SET OPTION SQL_QUOTE_SHOW_CREATE=%d",
4360
          (opt_quoted || opt_keywords));
jimw@mysql.com's avatar
jimw@mysql.com committed
4361 4362
#endif

4363 4364 4365
  result_table=     quote_name(table, table_buff, 1);
  opt_quoted_table= quote_name(table, table_buff2, 0);

4366
  my_snprintf(query, sizeof(query), "SHOW CREATE TABLE %s", result_table);
4367
  if (mysql_query_with_error_report(mysql, &table_res, query))
4368 4369
    DBUG_RETURN(0);

4370 4371 4372 4373
  /* Check if this is a view */
  field= mysql_fetch_field_direct(table_res, 0);
  if (strcmp(field->name, "View") != 0)
  {
4374
    verbose_msg("-- It's base table, skipped\n");
4375 4376 4377 4378
    DBUG_RETURN(0);
  }

  /* If requested, open separate .sql file for this view */
4379 4380
  if (path)
  {
4381
    if (!(sql_file= open_sql_file_for_table(table)))
4382
      DBUG_RETURN(1);
4383

4384 4385 4386 4387 4388
    write_header(sql_file, db);
  }

  if (!opt_xml && opt_comments)
  {
4389
    fprintf(sql_file, "\n--\n-- Final view structure for view %s\n--\n\n",
4390 4391 4392 4393 4394
            result_table);
    check_io(sql_file);
  }
  if (opt_drop)
  {
4395 4396 4397 4398
    fprintf(sql_file, "/*!50001 DROP TABLE IF EXISTS %s*/;\n",
            opt_quoted_table);
    fprintf(sql_file, "/*!50001 DROP VIEW IF EXISTS %s*/;\n",
            opt_quoted_table);
4399 4400 4401 4402
    check_io(sql_file);
  }


4403
  my_snprintf(query, sizeof(query),
4404 4405 4406
              "SELECT CHECK_OPTION, DEFINER, SECURITY_TYPE, "
              "       CHARACTER_SET_CLIENT, COLLATION_CONNECTION "
              "FROM information_schema.views "
4407
              "WHERE table_name=\"%s\" AND table_schema=\"%s\"", table, db);
4408

4409
  if (mysql_query(mysql, query))
4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430
  {
    /*
      Use the raw output from SHOW CREATE TABLE if
       information_schema query fails.
     */
    row= mysql_fetch_row(table_res);
    fprintf(sql_file, "/*!50001 %s */;\n", row[1]);
    check_io(sql_file);
    mysql_free_result(table_res);
  }
  else
  {
    char *ptr;
    ulong *lengths;
    char search_buf[256], replace_buf[256];
    ulong search_len, replace_len;
    DYNAMIC_STRING ds_view;

    /* Save the result of SHOW CREATE TABLE in ds_view */
    row= mysql_fetch_row(table_res);
    lengths= mysql_fetch_lengths(table_res);
4431
    init_dynamic_string_checked(&ds_view, row[1], lengths[1] + 1, 1024);
4432 4433 4434
    mysql_free_result(table_res);

    /* Get the result from "select ... information_schema" */
4435
    if (!(table_res= mysql_store_result(mysql)) ||
4436
        !(row= mysql_fetch_row(table_res)))
4437
    {
4438
      DB_error(mysql, "when trying to save the result of SHOW CREATE TABLE in ds_view.");
4439 4440
      DBUG_RETURN(1);
    }
4441

4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464
    lengths= mysql_fetch_lengths(table_res);

    /*
      "WITH %s CHECK OPTION" is available from 5.0.2
      Surround it with !50002 comments
    */
    if (strcmp(row[0], "NONE"))
    {

      ptr= search_buf;
      search_len= (ulong)(strxmov(ptr, "WITH ", row[0],
                                  " CHECK OPTION", NullS) - ptr);
      ptr= replace_buf;
      replace_len=(ulong)(strxmov(ptr, "*/\n/*!50002 WITH ", row[0],
                                  " CHECK OPTION", NullS) - ptr);
      replace(&ds_view, search_buf, search_len, replace_buf, replace_len);
    }

    /*
      "DEFINER=%s SQL SECURITY %s" is available from 5.0.13
      Surround it with !50013 comments
    */
    {
4465
      size_t     user_name_len;
4466 4467
      char       user_name_str[USERNAME_LENGTH + 1];
      char       quoted_user_name_str[USERNAME_LENGTH * 2 + 3];
4468
      size_t     host_name_len;
4469 4470 4471 4472
      char       host_name_str[HOSTNAME_LENGTH + 1];
      char       quoted_host_name_str[HOSTNAME_LENGTH * 2 + 3];

      parse_user(row[1], lengths[1], user_name_str, &user_name_len,
4473
                 host_name_str, &host_name_len);
4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493

      ptr= search_buf;
      search_len=
        (ulong)(strxmov(ptr, "DEFINER=",
                        quote_name(user_name_str, quoted_user_name_str, FALSE),
                        "@",
                        quote_name(host_name_str, quoted_host_name_str, FALSE),
                        " SQL SECURITY ", row[2], NullS) - ptr);
      ptr= replace_buf;
      replace_len=
        (ulong)(strxmov(ptr, "*/\n/*!50013 DEFINER=",
                        quote_name(user_name_str, quoted_user_name_str, FALSE),
                        "@",
                        quote_name(host_name_str, quoted_host_name_str, FALSE),
                        " SQL SECURITY ", row[2],
                        " */\n/*!50001", NullS) - ptr);
      replace(&ds_view, search_buf, search_len, replace_buf, replace_len);
    }

    /* Dump view structure to file */
4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510

    fprintf(sql_file,
            "/*!50001 SET @saved_cs_client          = @@character_set_client */;\n"
            "/*!50001 SET @saved_cs_results         = @@character_set_results */;\n"
            "/*!50001 SET @saved_col_connection     = @@collation_connection */;\n"
            "/*!50001 SET character_set_client      = %s */;\n"
            "/*!50001 SET character_set_results     = %s */;\n"
            "/*!50001 SET collation_connection      = %s */;\n"
            "/*!50001 %s */;\n"
            "/*!50001 SET character_set_client      = @saved_cs_client */;\n"
            "/*!50001 SET character_set_results     = @saved_cs_results */;\n"
            "/*!50001 SET collation_connection      = @saved_col_connection */;\n",
            (const char *) row[3],
            (const char *) row[3],
            (const char *) row[4],
            (const char *) ds_view.str);

4511 4512 4513 4514 4515 4516
    check_io(sql_file);
    mysql_free_result(table_res);
    dynstr_free(&ds_view);
  }

  /* If a separate .sql file was opened, close it now */
4517 4518 4519 4520 4521 4522 4523 4524 4525
  if (sql_file != md_result_file)
  {
    fputs("\n", sql_file);
    write_footer(sql_file);
    my_fclose(sql_file, MYF(MY_WME));
  }
  DBUG_RETURN(0);
}

4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564
/*
  The following functions are wrappers for the dynamic string functions
  and if they fail, the wrappers will terminate the current process.
*/

#define DYNAMIC_STR_ERROR_MSG "Couldn't perform DYNAMIC_STRING operation"

static void init_dynamic_string_checked(DYNAMIC_STRING *str, const char *init_str,
			    uint init_alloc, uint alloc_increment)
{
  if (init_dynamic_string(str, init_str, init_alloc, alloc_increment))
    die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG);
}

static void dynstr_append_checked(DYNAMIC_STRING* dest, const char* src)
{
  if (dynstr_append(dest, src))
    die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG);
}

static void dynstr_set_checked(DYNAMIC_STRING *str, const char *init_str)
{
  if (dynstr_set(str, init_str))
    die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG);
}

static void dynstr_append_mem_checked(DYNAMIC_STRING *str, const char *append,
			  uint length)
{
  if (dynstr_append_mem(str, append, length))
    die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG);
}

static void dynstr_realloc_checked(DYNAMIC_STRING *str, ulong additional_size)
{
  if (dynstr_realloc(str, additional_size))
    die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG);
}

4565

bk@work.mysql.com's avatar
bk@work.mysql.com committed
4566 4567
int main(int argc, char **argv)
{
4568
  char bin_log_name[FN_REFLEN];
4569
  int exit_code;
4570 4571
  MY_INIT("mysqldump");

4572
  compatible_mode_normal_str[0]= 0;
4573
  default_charset= (char *)mysql_universal_client_charset;
monty@mishka.local's avatar
monty@mishka.local committed
4574
  bzero((char*) &ignore_table, sizeof(ignore_table));
4575

4576 4577
  exit_code= get_options(&argc, &argv);
  if (exit_code)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4578
  {
4579 4580
    free_resources(0);
    exit(exit_code);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4581
  }
4582 4583 4584 4585 4586 4587 4588 4589 4590 4591

  if (log_error_file)
  {
    if(!(stderror_file= freopen(log_error_file, "a+", stderr)))
    {
      free_resources(0);
      exit(EX_MYSQLERR);
    }
  }

4592 4593 4594
  if (connect_to_db(current_host, current_user, opt_password))
  {
    free_resources(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4595
    exit(EX_MYSQLERR);
4596
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4597
  if (!path)
4598 4599
    write_header(md_result_file, *argv);

4600
  if ((opt_lock_all_tables || opt_master_data) &&
4601
      do_flush_tables_read_lock(mysql))
4602
    goto err;
4603
  if (opt_single_transaction && start_transaction(mysql))
4604
      goto err;
4605 4606 4607 4608 4609 4610 4611
  if (opt_delete_master_logs)
  {
    if (mysql_refresh(mysql, REFRESH_LOG) ||
        get_bin_log_name(mysql, bin_log_name, sizeof(bin_log_name)))
      goto err;
    flush_logs= 0;
  }
4612
  if (opt_lock_all_tables || opt_master_data)
4613
  {
4614
    if (flush_logs && mysql_refresh(mysql, REFRESH_LOG))
4615 4616
      goto err;
    flush_logs= 0; /* not anymore; that would not be sensible */
4617
  }
4618
  if (opt_master_data && do_show_master_status(mysql))
4619
    goto err;
4620
  if (opt_single_transaction && do_unlock_tables(mysql)) /* unlock but no commit! */
4621 4622
    goto err;

4623 4624 4625
  if (opt_alltspcs)
    dump_all_tablespaces();

bk@work.mysql.com's avatar
bk@work.mysql.com committed
4626
  if (opt_alldbs)
4627 4628 4629
  {
    if (!opt_alltspcs && !opt_notspcs)
      dump_all_tablespaces();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4630
    dump_all_databases();
4631
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4632
  else if (argc > 1 && !opt_databases)
4633 4634
  {
    /* Only one database and selected table(s) */
4635 4636
    if (!opt_alltspcs && !opt_notspcs)
      dump_tablespaces_for_tables(*argv, (argv + 1), (argc -1));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4637
    dump_selected_tables(*argv, (argv + 1), (argc - 1));
4638
  }
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
4639
  else
4640 4641
  {
    /* One or more databases, all tables */
4642 4643
    if (!opt_alltspcs && !opt_notspcs)
      dump_tablespaces_for_databases(argv);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4644
    dump_databases(argv);
4645
  }
4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657

  /* ensure dumped data flushed */
  if (md_result_file && fflush(md_result_file))
  {
    if (!first_error)
      first_error= EX_MYSQLERR;
    goto err;
  }
  /* everything successful, purge the old logs files */
  if (opt_delete_master_logs && purge_bin_logs_to(mysql, bin_log_name))
    goto err;

4658 4659 4660
#ifdef HAVE_SMEM
  my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR));
#endif
4661 4662 4663 4664 4665 4666 4667
  /*
    No reason to explicitely COMMIT the transaction, neither to explicitely
    UNLOCK TABLES: these will be automatically be done by the server when we
    disconnect now. Saves some code here, some network trips, adds nothing to
    server.
  */
err:
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4668
  dbDisconnect(current_host);
4669 4670
  if (!path)
    write_footer(md_result_file);
4671
  free_resources();
4672 4673 4674 4675

  if (stderror_file)
    fclose(stderror_file);

bk@work.mysql.com's avatar
bk@work.mysql.com committed
4676 4677
  return(first_error);
} /* main */