mysqldump.c 132 KB
Newer Older
unknown's avatar
unknown committed
1
/* Copyright (C) 2000 MySQL AB
unknown's avatar
unknown committed
2

unknown's avatar
unknown 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
unknown's avatar
unknown committed
5
   the Free Software Foundation; version 2 of the License.
unknown's avatar
unknown committed
6

unknown's avatar
unknown 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.
unknown's avatar
unknown committed
11

unknown's avatar
unknown 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 :-
**
unknown's avatar
unknown committed
20 21 22
** AUTHOR: Igor Romanenko (igor@frog.kiev.ua)
** DATE:   December 3, 1994
** WARRANTY: None, expressed, impressed, implied
23
**          or other
unknown's avatar
unknown committed
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>
unknown's avatar
unknown committed
32
** Tõnu Samuel  <tonu@please.do.not.remove.this.spam.ee>
unknown's avatar
unknown committed
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
unknown's avatar
unknown committed
36
** 10 Jun 2003: SET NAMES and --no-set-names by Alexander Barkov
unknown's avatar
unknown committed
37
*/
unknown's avatar
unknown committed
38

unknown's avatar
unknown committed
39
#define DUMP_VERSION "10.12"
unknown's avatar
unknown committed
40

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

49
#include "client_priv.h"
unknown's avatar
unknown committed
50 51 52
#include "mysql.h"
#include "mysql_version.h"
#include "mysqld_error.h"
53
#include "../sql/ha_ndbcluster_tables.h"
unknown's avatar
unknown 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 */
unknown's avatar
patch  
unknown committed
62
#define EX_ILLEGAL_TABLE 6
unknown's avatar
unknown 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

unknown's avatar
unknown 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);
unknown's avatar
unknown 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,
unknown's avatar
unknown 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;
unknown's avatar
unknown committed
104
static MYSQL mysql_connection,*mysql=0;
unknown's avatar
unknown committed
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,
unknown's avatar
unknown 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
             *err_ptr= 0;
unknown's avatar
unknown committed
113
static char **defaults_argv= 0;
114
static char compatible_mode_normal_str[255];
115
static ulong opt_compatible_mode= 0;
116 117
#define MYSQL_OPT_MASTER_DATA_EFFECTIVE_SQL 1
#define MYSQL_OPT_MASTER_DATA_COMMENTED_SQL 2
118
static uint     opt_mysql_port= 0, opt_master_data;
unknown's avatar
unknown committed
119 120 121
static my_string opt_mysql_unix_port=0;
static int   first_error=0;
static DYNAMIC_STRING extended_row;
122
#include <sslopt-vars.h>
unknown's avatar
unknown committed
123
FILE  *md_result_file= 0;
124 125 126
#ifdef HAVE_SMEM
static char *shared_memory_base_name=0;
#endif
127
static uint opt_protocol= 0;
128 129 130 131 132 133 134 135 136 137 138 139 140

/*
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);
141
/*
unknown's avatar
unknown committed
142 143 144
  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().
145
*/
unknown's avatar
unknown committed
146
static const char *mysql_universal_client_charset=
147 148
  MYSQL_UNIVERSAL_CLIENT_CHARSET;
static char *default_charset;
149
static CHARSET_INFO *charset_info= &my_charset_latin1;
unknown's avatar
unknown committed
150
const char *default_dbug_option="d:t:o,/tmp/mysqldump.trace";
151 152
/* have we seen any VIEWs during table scanning? */
my_bool seen_views= 0;
153 154 155
const char *compatible_mode_names[]=
{
  "MYSQL323", "MYSQL40", "POSTGRESQL", "ORACLE", "MSSQL", "DB2",
156 157
  "MAXDB", "NO_KEY_OPTIONS", "NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS",
  "ANSI",
158 159
  NullS
};
160 161 162 163 164 165 166 167 168
#define MASK_ANSI_QUOTES \
(\
 (1<<2)  | /* POSTGRESQL */\
 (1<<3)  | /* ORACLE     */\
 (1<<4)  | /* MSSQL      */\
 (1<<5)  | /* DB2        */\
 (1<<6)  | /* MAXDB      */\
 (1<<10)   /* ANSI       */\
)
169
TYPELIB compatible_mode_typelib= {array_elements(compatible_mode_names) - 1,
170
                                  "", compatible_mode_names, NULL};
171

172
HASH ignore_table;
unknown's avatar
unknown committed
173

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

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

452 453 454
static void maybe_exit(int error);
static void die(int error, const char* reason, ...);
static void maybe_die(int error, const char* reason, ...);
455
static void write_header(FILE *sql_file, char *db_name);
unknown's avatar
unknown committed
456
static void print_value(FILE *file, MYSQL_RES  *result, MYSQL_ROW row,
457 458
                        const char *prefix,const char *name,
                        int string_value);
unknown's avatar
unknown committed
459 460
static int dump_selected_tables(char *db, char **table_names, int tables);
static int dump_all_tables_in_db(char *db);
461 462 463
static int init_dumping_views(char *);
static int init_dumping_tables(char *);
static int init_dumping(char *, int init_func(char*));
unknown's avatar
unknown committed
464 465
static int dump_databases(char **);
static int dump_all_databases();
unknown's avatar
unknown committed
466
static char *quote_name(const char *name, char *buff, my_bool force);
unknown's avatar
unknown committed
467
char check_if_ignore_table(const char *table_name, char *table_type);
468
static char *primary_key_fields(const char *table_name);
469
static my_bool get_view_structure(char *table, char* db);
470
static my_bool dump_all_views_in_db(char *database);
471 472 473 474
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);
475

unknown's avatar
unknown committed
476
#include <help_start.h>
unknown's avatar
unknown committed
477

unknown's avatar
unknown committed
478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
/*
  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;
}

502 503
/*
  exit with message if ferror(file)
504

505 506
  SYNOPSIS
    check_io()
507
    file        - checked file
508 509 510 511 512
*/

void check_io(FILE *file)
{
  if (ferror(file))
513
    die(EX_EOF, "Got errno %d on write", errno);
514 515
}

unknown's avatar
unknown committed
516 517 518
static void print_version(void)
{
  printf("%s  Ver %s Distrib %s, for %s (%s)\n",my_progname,DUMP_VERSION,
unknown's avatar
unknown committed
519 520
         MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
  NETWARE_SET_SCREEN_MODE(1);
unknown's avatar
unknown committed
521 522 523
} /* print_version */


524 525 526 527
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",
528
         my_progname);
529
  printf("OR     %s [OPTIONS] --all-databases [OPTIONS]\n", my_progname);
unknown's avatar
unknown committed
530
  NETWARE_SET_SCREEN_MODE(1);
531 532
}

unknown's avatar
unknown committed
533

unknown's avatar
unknown committed
534 535 536 537 538 539
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");
540
  short_usage_sub();
unknown's avatar
unknown committed
541
  print_defaults("my",load_default_groups);
542 543
  my_print_help(my_long_options);
  my_print_variables(my_long_options);
unknown's avatar
unknown committed
544 545 546
} /* usage */


547 548 549 550 551 552
static void short_usage(void)
{
  short_usage_sub();
  printf("For more options, use %s --help\n", my_progname);
}

unknown's avatar
unknown committed
553 554
#include <help_end.h>

555

556
static void write_header(FILE *sql_file, char *db_name)
unknown's avatar
unknown committed
557
{
unknown's avatar
unknown committed
558
  if (opt_xml)
unknown's avatar
unknown committed
559
  {
560
    fputs("<?xml version=\"1.0\"?>\n", sql_file);
unknown's avatar
unknown committed
561 562 563 564
    /*
      Schema reference.  Allows use of xsi:nil for NULL values and 
      xsi:type to define an element's data type.
    */
565 566 567 568
    fputs("<mysqldump ", sql_file);
    fputs("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"",
          sql_file);
    fputs(">\n", sql_file);
569
    check_io(sql_file);
unknown's avatar
unknown committed
570
  }
unknown's avatar
unknown committed
571
  else if (!opt_compact)
unknown's avatar
unknown committed
572
  {
unknown's avatar
unknown committed
573 574 575 576
    if (opt_comments)
    {
      fprintf(sql_file, "-- MySQL dump %s\n--\n", DUMP_VERSION);
      fprintf(sql_file, "-- Host: %s    Database: %s\n",
577 578
              current_host ? current_host : "localhost", db_name ? db_name :
              "");
unknown's avatar
unknown committed
579
      fputs("-- ------------------------------------------------------\n",
580
            sql_file);
unknown's avatar
unknown committed
581
      fprintf(sql_file, "-- Server version\t%s\n",
582
              mysql_get_server_info(&mysql_connection));
unknown's avatar
unknown committed
583
    }
584
    if (opt_set_charset)
unknown's avatar
unknown committed
585 586 587 588 589
      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);
unknown's avatar
unknown committed
590 591 592 593 594 595 596

    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");
    }

597 598 599
    if (!path)
    {
      fprintf(md_result_file,"\
600 601 602
/*!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\
");
603 604
    }
    fprintf(sql_file,
605 606 607 608
            "/*!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);
609
    check_io(sql_file);
unknown's avatar
unknown committed
610
  }
611
} /* write_header */
unknown's avatar
unknown committed
612

613

unknown's avatar
unknown committed
614 615 616
static void write_footer(FILE *sql_file)
{
  if (opt_xml)
617
  {
unknown's avatar
unknown committed
618
    fputs("</mysqldump>\n", sql_file);
619 620
    check_io(sql_file);
  }
unknown's avatar
unknown committed
621
  else if (!opt_compact)
622
  {
unknown's avatar
unknown committed
623 624 625
    if (opt_tz_utc)
      fprintf(sql_file,"/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;\n");

626 627 628 629
    fprintf(sql_file,"\n/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;\n");
    if (!path)
    {
      fprintf(md_result_file,"\
630
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;\n\
unknown's avatar
unknown committed
631
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;\n");
632
    }
633
    if (opt_set_charset)
634
      fprintf(sql_file,
unknown's avatar
unknown committed
635 636 637
"/*!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");
638
    fprintf(sql_file,
639
            "/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;\n");
unknown's avatar
unknown committed
640
    fputs("\n", sql_file);
641 642 643 644 645 646 647
    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);
    }
648
    check_io(sql_file);
649
  }
unknown's avatar
unknown committed
650
} /* write_footer */
unknown's avatar
unknown committed
651

unknown's avatar
unknown committed
652 653 654 655 656 657
static void free_table_ent(char *key)

{
  my_free((gptr) key, MYF(0));
}

658

unknown's avatar
patch  
unknown committed
659
byte* get_table_key(const char *entry, uint *length,
660
                                my_bool not_used __attribute__((unused)))
661
{
unknown's avatar
patch  
unknown committed
662 663
  *length= strlen(entry);
  return (byte*) entry;
664 665 666
}


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

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

static int get_options(int *argc, char ***argv)
{
  int ho_error;
819 820 821 822
  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;
823 824 825

  md_result_file= stdout;
  load_defaults("my",load_default_groups,argc,argv);
unknown's avatar
unknown committed
826
  defaults_argv= *argv;
827

unknown's avatar
unknown committed
828 829 830 831
  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);
832
  /* Don't copy internal log tables */
unknown's avatar
unknown committed
833 834 835
  if (my_hash_insert(&ignore_table,
                     (byte*) my_strdup("mysql.apply_status", MYF(MY_WME))) ||
      my_hash_insert(&ignore_table,
836 837 838 839 840
                     (byte*) my_strdup("mysql.schema", MYF(MY_WME))) ||
      my_hash_insert(&ignore_table,
                     (byte*) my_strdup("mysql.general_log", MYF(MY_WME))) ||
      my_hash_insert(&ignore_table,
                     (byte*) my_strdup("mysql.slow_log", MYF(MY_WME))))
unknown's avatar
unknown committed
841
    return(EX_EOM);
842

unknown's avatar
unknown committed
843 844
  if ((ho_error= handle_options(argc, argv, my_long_options, get_one_option)))
    return(ho_error);
845

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

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

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


/*
900
** DB_error -- prints mysql error message and exits the program.
unknown's avatar
unknown committed
901
*/
902
static void DB_error(MYSQL *mysql_arg, const char *when)
unknown's avatar
unknown committed
903
{
904
  DBUG_ENTER("DB_error");
905
  maybe_die(EX_MYSQLERR, "Got error: %d: %s %s",
906
          mysql_errno(mysql_arg), mysql_error(mysql_arg), when);
unknown's avatar
unknown committed
907
  DBUG_VOID_RETURN;
908 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
}



/*
  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);
}

unknown's avatar
unknown committed
973 974


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

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

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

991 992 993 994 995 996
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))))
  {
997 998
    maybe_die(EX_MYSQLERR, "Couldn't execute '%s': %s (%d)",
            query, mysql_error(mysql_con), mysql_errno(mysql_con));
999 1000 1001 1002 1003
    return 1;
  }
  return 0;
}

1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020
/*
  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),
1021
                O_WRONLY, MYF(MY_WME));
1022 1023 1024
  return res;
}

1025

unknown's avatar
unknown committed
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
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);
}


1043
static void maybe_exit(int error)
unknown's avatar
unknown committed
1044 1045 1046 1047 1048
{
  if (!first_error)
    first_error= error;
  if (ignore_errors)
    return;
unknown's avatar
unknown committed
1049 1050
  if (mysql)
    mysql_close(mysql);
unknown's avatar
unknown committed
1051
  free_resources();
unknown's avatar
unknown committed
1052 1053 1054 1055 1056
  exit(error);
}


/*
unknown's avatar
unknown committed
1057
  db_connect -- connects to the host and selects DB.
unknown's avatar
unknown committed
1058
*/
unknown's avatar
unknown committed
1059 1060

static int connect_to_db(char *host, char *user,char *passwd)
unknown's avatar
unknown committed
1061
{
1062
  char buff[20+FN_REFLEN];
unknown's avatar
unknown committed
1063
  DBUG_ENTER("connect_to_db");
unknown's avatar
unknown committed
1064 1065

  verbose_msg("-- Connecting to %s...\n", host ? host : "localhost");
unknown's avatar
unknown committed
1066 1067 1068 1069 1070 1071
  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,
1072
                  opt_ssl_capath, opt_ssl_cipher);
1073 1074
  mysql_options(&mysql_connection,MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
                (char*)&opt_ssl_verify_server_cert);
1075 1076 1077 1078 1079 1080
#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);
unknown's avatar
unknown committed
1081
#endif
1082
  mysql_options(&mysql_connection, MYSQL_SET_CHARSET_NAME, default_charset);
unknown's avatar
unknown committed
1083
  if (!(mysql= mysql_real_connect(&mysql_connection,host,user,passwd,
unknown's avatar
unknown committed
1084 1085
                                  NULL,opt_mysql_port,opt_mysql_unix_port,
                                  0)))
unknown's avatar
unknown committed
1086
  {
1087
    DB_error(&mysql_connection, "when trying to connect");
unknown's avatar
unknown committed
1088
    DBUG_RETURN(1);
unknown's avatar
unknown committed
1089
  }
unknown's avatar
unknown committed
1090 1091 1092 1093 1094
  /*
    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;
1095 1096 1097 1098
  /*
    As we're going to set SQL_MODE, it would be lost on reconnect, so we
    cannot reconnect.
  */
unknown's avatar
unknown committed
1099
  mysql->reconnect= 0;
1100
  my_snprintf(buff, sizeof(buff), "/*!40100 SET @@SQL_MODE='%s' */",
1101
              compatible_mode_normal_str);
unknown's avatar
unknown committed
1102
  if (mysql_query_with_error_report(mysql, 0, buff))
unknown's avatar
unknown committed
1103
    DBUG_RETURN(1);
unknown's avatar
unknown committed
1104
  /*
1105
    set time_zone to UTC to allow dumping date types between servers with
unknown's avatar
unknown committed
1106 1107 1108 1109 1110
    different time zone settings
  */
  if (opt_tz_utc)
  {
    my_snprintf(buff, sizeof(buff), "/*!40103 SET TIME_ZONE='+00:00' */");
unknown's avatar
unknown committed
1111
    if (mysql_query_with_error_report(mysql, 0, buff))
unknown's avatar
unknown committed
1112
      DBUG_RETURN(1);
unknown's avatar
unknown committed
1113
  }
unknown's avatar
unknown committed
1114 1115
  DBUG_RETURN(0);
} /* connect_to_db */
unknown's avatar
unknown committed
1116 1117 1118 1119 1120 1121 1122


/*
** dbDisconnect -- disconnects from the host.
*/
static void dbDisconnect(char *host)
{
unknown's avatar
unknown committed
1123
  verbose_msg("-- Disconnecting from %s...\n", host ? host : "localhost");
unknown's avatar
unknown committed
1124
  mysql_close(mysql);
unknown's avatar
unknown committed
1125 1126 1127 1128 1129 1130 1131 1132
} /* 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))))
1133 1134
    die(EX_MYSQLERR, "Couldn't allocate memory");

unknown's avatar
unknown committed
1135
  mysql_real_escape_string(&mysql_connection, tmp, pos, length);
unknown's avatar
unknown committed
1136 1137 1138
  fputc('\'', file);
  fputs(tmp, file);
  fputc('\'', file);
1139
  check_io(file);
unknown's avatar
unknown committed
1140 1141 1142 1143 1144 1145 1146 1147 1148
  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++)
1149
    if (!my_isvar(charset_info,*str) && *str != '$')
unknown's avatar
unknown committed
1150 1151 1152 1153 1154
      return 1;
#endif
  return 0;
} /* test_if_special_chars */

unknown's avatar
unknown committed
1155

unknown's avatar
unknown committed
1156

unknown's avatar
unknown committed
1157 1158 1159
/*
  quote_name(name, buff, force)

1160
  Quotes char string, taking into account compatible mode
unknown's avatar
unknown committed
1161 1162 1163 1164 1165

  Args

  name                 Unquoted string containing that which will be quoted
  buff                 The buffer that contains the quoted value, also returned
1166
  force                Flag to make it ignore 'test_if_special_chars'
unknown's avatar
unknown committed
1167 1168 1169 1170 1171 1172

  Returns

  buff                 quoted string

*/
unknown's avatar
unknown committed
1173
static char *quote_name(const char *name, char *buff, my_bool force)
unknown's avatar
unknown committed
1174
{
unknown's avatar
unknown committed
1175
  char *to= buff;
1176 1177
  char qtype= (opt_compatible_mode & MASK_ANSI_QUOTES) ? '\"' : '`';

unknown's avatar
unknown committed
1178 1179
  if (!force && !opt_quoted && !test_if_special_chars(name))
    return (char*) name;
1180
  *to++= qtype;
unknown's avatar
unknown committed
1181 1182
  while (*name)
  {
1183 1184
    if (*name == qtype)
      *to++= qtype;
unknown's avatar
unknown committed
1185 1186
    *to++= *name++;
  }
1187 1188
  to[0]= qtype;
  to[1]= 0;
unknown's avatar
unknown committed
1189 1190 1191
  return buff;
} /* quote_name */

unknown's avatar
unknown committed
1192

unknown's avatar
patch  
unknown committed
1193 1194
/*
  Quote a table name so it can be used in "SHOW TABLES LIKE <tabname>"
unknown's avatar
unknown committed
1195

unknown's avatar
patch  
unknown committed
1196
  SYNOPSIS
unknown's avatar
unknown committed
1197 1198 1199
    quote_for_like()
    name     name of the table
    buff     quoted name of the table
unknown's avatar
patch  
unknown committed
1200 1201 1202

  DESCRIPTION
    Quote \, _, ' and % characters
unknown's avatar
unknown committed
1203

unknown's avatar
patch  
unknown committed
1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214
    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"

*/
1215 1216 1217 1218 1219 1220
static char *quote_for_like(const char *name, char *buff)
{
  char *to= buff;
  *to++= '\'';
  while (*name)
  {
unknown's avatar
patch  
unknown committed
1221 1222 1223 1224 1225 1226 1227
    if (*name == '\\')
    {
      *to++='\\';
      *to++='\\';
      *to++='\\';
    }
    else if (*name == '\'' || *name == '_'  || *name == '%')
1228 1229 1230 1231 1232 1233 1234 1235 1236
      *to++= '\\';
    *to++= *name++;
  }
  to[0]= '\'';
  to[1]= 0;
  return buff;
}


1237 1238
/*
  Quote and print a string.
1239

1240 1241
  SYNOPSIS
    print_quoted_xml()
1242
    xml_file    - output file
1243 1244 1245
    str         - string to print
    len         - its length

1246
  DESCRIPTION
1247
    Quote '<' '>' '&' '\"' chars and print a string to the xml_file.
1248 1249 1250 1251 1252
*/

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

1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273
  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;
    }
  }
1274
  check_io(xml_file);
1275 1276 1277 1278
}


/*
1279
  Print xml tag. Optionally add attribute(s).
1280

1281
  SYNOPSIS
1282 1283 1284 1285
    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
1286
    line_end              - line ending
1287 1288 1289 1290 1291
    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
1292

1293
  DESCRIPTION
1294 1295 1296 1297 1298
    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
1299
  NOTE
1300 1301 1302 1303
    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.
1304 1305
*/

1306 1307
static void print_xml_tag(FILE * xml_file, const char* sbeg,
                          const char* line_end, 
1308 1309
                          const char* tag_name, 
                          const char* first_attribute_name, ...)
1310
{
1311
  va_list arg_list;
1312
  const char *attribute_name, *attribute_value;
1313

1314
  fputs(sbeg, xml_file);
1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336
  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);
1337
  fputs(line_end, xml_file);
1338
  check_io(xml_file);
1339 1340 1341
}


1342 1343 1344 1345 1346
/*
  Print xml tag with for a field that is null

  SYNOPSIS
    print_xml_null_tag()
1347 1348 1349 1350
    xml_file    - output file
    sbeg        - line beginning
    stag_atr    - tag and attribute
    sval        - value of attribute
1351
    line_end        - line ending
1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362

  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,
1363
                               const char* line_end)
1364 1365 1366 1367 1368 1369 1370
{
  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);
1371
  fputs(line_end, xml_file);
1372 1373 1374 1375
  check_io(xml_file);
}


1376 1377 1378 1379 1380
/*
  Print xml tag with many attributes.

  SYNOPSIS
    print_xml_row()
1381 1382 1383 1384 1385
    xml_file    - output file
    row_name    - xml tag name
    tableRes    - query result
    row         - result row

1386 1387 1388 1389 1390 1391 1392 1393
  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,
1394
                          MYSQL_RES *tableRes, MYSQL_ROW *row)
1395 1396 1397 1398
{
  uint i;
  MYSQL_FIELD *field;
  ulong *lengths= mysql_fetch_lengths(tableRes);
1399

1400
  fprintf(xml_file, "\t\t<%s", row_name);
1401
  check_io(xml_file);
1402 1403 1404
  mysql_field_seek(tableRes, 0);
  for (i= 0; (field= mysql_fetch_field(tableRes)); i++)
  {
1405
    if ((*row)[i])
1406
    {
unknown's avatar
unknown committed
1407
      fputc(' ', xml_file);
1408
      print_quoted_xml(xml_file, field->name, field->name_length);
1409 1410
      fputs("=\"", xml_file);
      print_quoted_xml(xml_file, (*row)[i], lengths[i]);
unknown's avatar
unknown committed
1411
      fputc('"', xml_file);
1412
      check_io(xml_file);
1413 1414 1415
    }
  }
  fputs(" />\n", xml_file);
1416
  check_io(xml_file);
1417 1418
}

1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478

/*
 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;
  char       delimiter[QUERY_LENGTH], *delimit_test;
  FILE       *sql_file= md_result_file;
  MYSQL_RES  *event_res, *event_list_res;
  MYSQL_ROW  row, event_list_row;
  DBUG_ENTER("dump_events_for_db");
  DBUG_PRINT("enter", ("db: '%s'", db));

1479
  mysql_real_escape_string(mysql, db_name_buff, db, strlen(db));
1480 1481 1482 1483 1484 1485 1486 1487 1488 1489

  /* 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)
1490
    mysql_query(mysql, "LOCK TABLES mysql.event READ");
1491

1492
  if (mysql_query_with_error_report(mysql, &event_list_res, "show events"))
1493 1494 1495 1496 1497
    DBUG_RETURN(0);

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

1500 1501 1502 1503 1504 1505 1506
    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);

1507
      if (mysql_query_with_error_report(mysql, &event_res, query_buff))
1508 1509 1510 1511 1512 1513 1514 1515
        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!
        */
1516
        if (strlen(row[3]) != 0)
1517 1518 1519 1520 1521
        {
          if (opt_drop)
            fprintf(sql_file, "/*!50106 DROP EVENT IF EXISTS %s */%s\n", 
                event_name, delimiter);

1522
          delimit_test= create_delimiter(row[3], delimiter, sizeof(delimiter)); 
1523 1524 1525 1526 1527 1528 1529
          if (delimit_test == NULL) {
            fprintf(stderr, "%s: Warning: Can't dump event '%s'\n", 
                event_name, my_progname);
            DBUG_RETURN(1);
          }

          fprintf(sql_file, "DELIMITER %s\n", delimiter);
1530 1531 1532
          fprintf(sql_file, "/*!50106 SET TIME_ZONE= '%s' */ %s\n",
                  row[2], delimiter);
          fprintf(sql_file, "/*!50106 %s */ %s\n", row[3], delimiter);
1533 1534
        }
      } /* end of event printing */
unknown's avatar
unknown committed
1535 1536
      mysql_free_result(event_res);

1537 1538
    } /* end of list of events */
    fprintf(sql_file, "DELIMITER ;\n");
1539
    fprintf(sql_file, "/*!50106 SET TIME_ZONE= @save_time_zone */ ;\n");
1540 1541 1542 1543
  }
  mysql_free_result(event_list_res);

  if (lock_tables)
1544
    VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES"));
1545 1546 1547 1548
  DBUG_RETURN(0);
}


1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564
/*
  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. */
1565
    const char *ptr= str, *end= ptr + len;
1566 1567 1568 1569 1570
    for (; ptr < end ; ptr++)
      fprintf(output_file, "%02X", *((uchar *)ptr));
    check_io(output_file);
}

1571 1572
/*
  dump_routines_for_db
1573
  -- retrieves list of routines for a given db, and prints out
1574 1575 1576 1577 1578
  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

1579 1580 1581
  RETURN
    0  Success
    1  Error
1582 1583
*/

1584
static uint dump_routines_for_db(char *db)
1585
{
1586
  char       query_buff[QUERY_LENGTH];
1587 1588 1589
  const char *routine_type[]= {"FUNCTION", "PROCEDURE"};
  char       db_name_buff[NAME_LEN*2+3], name_buff[NAME_LEN*2+3];
  char       *routine_name;
1590
  int        i;
1591
  FILE       *sql_file= md_result_file;
1592
  MYSQL_RES  *routine_res, *routine_list_res;
1593
  MYSQL_ROW  row, routine_list_row;
1594
  DBUG_ENTER("dump_routines_for_db");
1595
  DBUG_PRINT("enter", ("db: '%s'", db));
1596

unknown's avatar
unknown committed
1597
  mysql_real_escape_string(mysql, db_name_buff, db, strlen(db));
1598 1599 1600 1601

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

  /*
1604 1605
    not using "mysql_query_with_error_report" because we may have not
    enough privileges to lock mysql.proc.
1606
  */
1607
  if (lock_tables)
unknown's avatar
unknown committed
1608
    mysql_query(mysql, "LOCK TABLES mysql.proc READ");
1609

1610
  fprintf(sql_file, "DELIMITER ;;\n");
1611 1612

  /* 0, retrieve and dump functions, 1, procedures */
1613
  for (i= 0; i <= 1; i++)
1614 1615 1616
  {
    my_snprintf(query_buff, sizeof(query_buff),
                "SHOW %s STATUS WHERE Db = '%s'",
1617
                routine_type[i], db_name_buff);
1618

unknown's avatar
unknown committed
1619
    if (mysql_query_with_error_report(mysql, &routine_list_res, query_buff))
1620 1621 1622 1623 1624
      DBUG_RETURN(1);

    if (mysql_num_rows(routine_list_res))
    {

1625
      while ((routine_list_row= mysql_fetch_row(routine_list_res)))
1626
      {
1627
        routine_name= quote_name(routine_list_row[1], name_buff, 0);
1628 1629
        DBUG_PRINT("info", ("retrieving CREATE %s for %s", routine_type[i],
                            name_buff));
1630
        my_snprintf(query_buff, sizeof(query_buff), "SHOW CREATE %s %s",
1631
                    routine_type[i], routine_name);
1632

unknown's avatar
unknown committed
1633
        if (mysql_query_with_error_report(mysql, &routine_res, query_buff))
1634 1635
          DBUG_RETURN(1);

1636
        while ((row= mysql_fetch_row(routine_res)))
1637 1638
        {
          /*
1639 1640
            if the user has EXECUTE privilege he see routine names, but NOT the
            routine body of other routines that are not the creator of!
1641
          */
unknown's avatar
unknown committed
1642 1643
          DBUG_PRINT("info",("length of body for %s row[2] '%s' is %ld",
                             routine_name, row[2], (long) strlen(row[2])));
1644 1645
          if (strlen(row[2]))
          {
1646 1647 1648
            char *query_str= NULL;
            char *definer_begin;

1649
            if (opt_drop)
1650
              fprintf(sql_file, "/*!50003 DROP %s IF EXISTS %s */;;\n",
1651
                      routine_type[i], routine_name);
1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662

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

              TODO: this is definitely a BAD IDEA to parse SHOW CREATE output.
              We should user INFORMATION_SCHEMA instead. The only problem is
              that now INFORMATION_SCHEMA does not provide information about
              routine parameters.
            */

            definer_begin= strstr(row[2], " DEFINER");
1663

1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682
            if (definer_begin)
            {
              char *definer_end= strstr(definer_begin, " PROCEDURE");

              if (!definer_end)
                definer_end= strstr(definer_begin, " FUNCTION");

              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]);
1683
                query_str_tail= strmov(query_str_tail, "*/ /*!50020");
1684 1685 1686 1687 1688 1689 1690
                query_str_tail= strnmov(query_str_tail, definer_begin,
                                        definer_end - definer_begin);
                query_str_tail= strxmov(query_str_tail, "*/ /*!50003",
                                        definer_end, NullS);
              }
            }

1691
            /*
1692 1693
              we need to change sql_mode only for the CREATE
              PROCEDURE/FUNCTION otherwise we may need to re-quote routine_name
1694
            */;
1695
            fprintf(sql_file, "/*!50003 SET SESSION SQL_MODE=\"%s\"*/;;\n",
1696
                    row[1] /* sql_mode */);
1697 1698
            fprintf(sql_file, "/*!50003 %s */;;\n",
                    (query_str != NULL ? query_str : row[2]));
1699 1700 1701
            fprintf(sql_file,
                    "/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE*/"
                    ";;\n");
1702 1703

            my_free(query_str, MYF(MY_ALLOW_ZERO_PTR));
1704 1705
          }
        } /* end of routine printing */
unknown's avatar
unknown committed
1706 1707
        mysql_free_result(routine_res);

1708 1709 1710 1711
      } /* end of list of routines */
    }
    mysql_free_result(routine_list_res);
  } /* end of for i (0 .. 1)  */
1712 1713
  /* set the delimiter back to ';' */
  fprintf(sql_file, "DELIMITER ;\n");
1714

1715
  if (lock_tables)
unknown's avatar
unknown committed
1716
    VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES"));
1717 1718
  DBUG_RETURN(0);
}
1719

unknown's avatar
unknown committed
1720
/*
unknown's avatar
unknown committed
1721 1722 1723 1724 1725 1726 1727
  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
1728
    table_type  - table type, e.g. "MyISAM" or "InnoDB", but also "VIEW"
unknown's avatar
unknown committed
1729
    ignore_flag - what we must particularly ignore - see IGNORE_ defines above
unknown's avatar
unknown committed
1730 1731 1732

  RETURN
    number of fields in table, 0 if error
unknown's avatar
unknown committed
1733
*/
unknown's avatar
unknown committed
1734

unknown's avatar
unknown committed
1735 1736
static uint get_table_structure(char *table, char *db, char *table_type,
                                char *ignore_flag)
unknown's avatar
unknown committed
1737
{
unknown's avatar
unknown committed
1738
  my_bool    init=0, delayed, write_data, complete_insert;
1739
  my_ulonglong num_fields;
1740
  char       *result_table, *opt_quoted_table;
unknown's avatar
unknown committed
1741
  const char *insert_option;
unknown's avatar
unknown committed
1742
  char	     name_buff[NAME_LEN+3],table_buff[NAME_LEN*2+3];
1743
  char       table_buff2[NAME_LEN*2+3], query_buff[QUERY_LENGTH];
unknown's avatar
unknown committed
1744
  FILE       *sql_file= md_result_file;
1745
  int        len;
1746 1747 1748
  MYSQL_RES  *result;
  MYSQL_ROW  row;

1749
  DBUG_ENTER("get_table_structure");
unknown's avatar
unknown committed
1750
  DBUG_PRINT("enter", ("db: %s  table: %s", db, table));
unknown's avatar
unknown committed
1751

unknown's avatar
unknown committed
1752 1753
  *ignore_flag= check_if_ignore_table(table, table_type);

unknown's avatar
unknown committed
1754 1755 1756 1757
  delayed= opt_delayed;
  if (delayed && (*ignore_flag & IGNORE_INSERT_DELAYED))
  {
    delayed= 0;
unknown's avatar
unknown committed
1758 1759
    verbose_msg("-- Warning: Unable to use delayed inserts for table '%s' "
                "because it's of type %s\n", table, table_type);
unknown's avatar
unknown committed
1760
  }
unknown's avatar
unknown committed
1761

unknown's avatar
unknown committed
1762 1763
  complete_insert= 0;
  if ((write_data= !(*ignore_flag & IGNORE_DATA)))
1764
  {
unknown's avatar
unknown committed
1765
    complete_insert= opt_complete_insert;
unknown's avatar
unknown committed
1766
    if (!insert_pat_inited)
unknown's avatar
unknown committed
1767 1768
    {
      insert_pat_inited= 1;
1769
      init_dynamic_string_checked(&insert_pat, "", 1024, 1024);
unknown's avatar
unknown committed
1770
    }
unknown's avatar
unknown committed
1771
    else
1772
      dynstr_set_checked(&insert_pat, "");
1773 1774
  }

unknown's avatar
unknown committed
1775 1776
  insert_option= ((delayed && opt_ignore) ? " DELAYED IGNORE " :
                  delayed ? " DELAYED " : opt_ignore ? " IGNORE " : "");
unknown's avatar
unknown committed
1777

unknown's avatar
unknown committed
1778
  verbose_msg("-- Retrieving table structure for table %s...\n", table);
unknown's avatar
unknown committed
1779

1780 1781 1782
  len= my_snprintf(query_buff, sizeof(query_buff),
                   "SET OPTION SQL_QUOTE_SHOW_CREATE=%d",
                   (opt_quoted || opt_keywords));
unknown's avatar
unknown committed
1783
  if (!create_options)
unknown's avatar
unknown committed
1784 1785
    strmov(query_buff+len,
           "/*!40102 ,SQL_MODE=concat(@@sql_mode, _utf8 ',NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS') */");
unknown's avatar
unknown committed
1786

unknown's avatar
unknown committed
1787 1788
  result_table=     quote_name(table, table_buff, 1);
  opt_quoted_table= quote_name(table, table_buff2, 0);
1789 1790

  if (opt_order_by_primary)
unknown's avatar
unknown committed
1791
    order_by= primary_key_fields(result_table);
1792

unknown's avatar
unknown committed
1793
  if (!opt_xml && !mysql_query_with_error_report(mysql, 0, query_buff))
unknown's avatar
unknown committed
1794
  {
1795
    /* using SHOW CREATE statement */
1796
    if (!opt_no_create_info)
unknown's avatar
unknown committed
1797
    {
1798 1799
      /* Make an sql-file, if path was given iow. option -T was given */
      char buff[20+FN_REFLEN];
1800
      MYSQL_FIELD *field;
1801

1802
      my_snprintf(buff, sizeof(buff), "show create table %s", result_table);
unknown's avatar
unknown committed
1803
      if (mysql_query_with_error_report(mysql, 0, buff))
1804
        DBUG_RETURN(0);
unknown's avatar
unknown committed
1805

1806 1807
      if (path)
      {
1808
        if (!(sql_file= open_sql_file_for_table(table)))
1809
          DBUG_RETURN(0);
1810

1811
        write_header(sql_file, db);
1812
      }
1813
      if (!opt_xml && opt_comments)
1814
      {
1815 1816 1817 1818
      if (strcmp (table_type, "VIEW") == 0)         /* view */
        fprintf(sql_file, "\n--\n-- Temporary table structure for view %s\n--\n\n",
                result_table);
      else
unknown's avatar
unknown committed
1819
        fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n",
1820 1821
                result_table);
        check_io(sql_file);
1822
      }
1823
      if (opt_drop)
1824
      {
1825 1826 1827 1828 1829 1830 1831
      /*
        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);
1832
      }
1833

unknown's avatar
unknown committed
1834
      result= mysql_store_result(mysql);
1835
      field= mysql_fetch_field_direct(result, 0);
1836 1837
      if (strcmp(field->name, "View") == 0)
      {
unknown's avatar
unknown committed
1838
        char *scv_buff= NULL;
1839

unknown's avatar
unknown committed
1840
        verbose_msg("-- It's a view, create dummy table for view\n");
1841

1842 1843 1844 1845
        /* save "show create" statement for later */
        if ((row= mysql_fetch_row(result)) && (scv_buff=row[1]))
          scv_buff= my_strdup(scv_buff, MYF(0));

1846 1847 1848
        mysql_free_result(result);

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

1853 1854
          The properties of each column, aside from the data type, are not
          preserved in this temporary table, because they are not necessary.
1855

1856 1857 1858
          This will not be necessary once we can determine dependencies
          between views and can simply dump them in the appropriate order.
        */
1859
        my_snprintf(query_buff, sizeof(query_buff),
1860
                    "SHOW FIELDS FROM %s", result_table);
unknown's avatar
unknown committed
1861
        if (mysql_query_with_error_report(mysql, 0, query_buff))
1862
        {
1863 1864 1865 1866 1867 1868
          /*
            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)
          */

unknown's avatar
unknown committed
1869
          if (mysql_errno(mysql) == ER_VIEW_INVALID)
1870 1871 1872 1873
            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));

unknown's avatar
unknown committed
1874
          DBUG_RETURN(0);
1875
        }
1876 1877
        else
          my_free(scv_buff, MYF(MY_ALLOW_ZERO_PTR));
1878

unknown's avatar
unknown committed
1879
        if ((result= mysql_store_result(mysql)))
1880
        {
1881 1882 1883 1884
          if (mysql_num_rows(result))
          {
            if (opt_drop)
            {
1885 1886 1887 1888 1889
            /*
              We have already dropped any table of the same name
              above, so here we just drop the view.
             */

1890 1891 1892 1893
              fprintf(sql_file, "/*!50001 DROP VIEW IF EXISTS %s*/;\n",
                      opt_quoted_table);
              check_io(sql_file);
            }
1894

1895 1896 1897 1898 1899 1900 1901 1902
            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);

1903 1904
            fprintf(sql_file, "  %s %s", quote_name(row[0], name_buff, 0),
                    row[1]);
1905 1906 1907 1908 1909 1910 1911 1912 1913 1914

            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);
          }
1915
        }
1916 1917
        mysql_free_result(result);

1918 1919 1920
        if (path)
          my_fclose(sql_file, MYF(MY_WME));

1921
        seen_views= 1;
1922 1923
        DBUG_RETURN(0);
      }
1924 1925

      row= mysql_fetch_row(result);
1926
      fprintf(sql_file, "%s;\n", row[1]);
1927
      check_io(sql_file);
1928
      mysql_free_result(result);
1929
    }
1930
    my_snprintf(query_buff, sizeof(query_buff), "show fields from %s",
1931
                result_table);
unknown's avatar
unknown committed
1932
    if (mysql_query_with_error_report(mysql, &result, query_buff))
unknown's avatar
unknown committed
1933
    {
1934
      if (path)
1935
        my_fclose(sql_file, MYF(MY_WME));
1936
      DBUG_RETURN(0);
unknown's avatar
unknown committed
1937
    }
1938

unknown's avatar
unknown committed
1939
    /*
unknown's avatar
unknown committed
1940 1941 1942 1943
      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.
unknown's avatar
unknown committed
1944
    */
unknown's avatar
unknown committed
1945
    if (write_data)
unknown's avatar
unknown committed
1946
    {
1947
      if (opt_replace_into)
1948
        dynstr_append_checked(&insert_pat, "REPLACE ");
1949
      else
1950
        dynstr_append_checked(&insert_pat, "INSERT ");
1951 1952 1953
      dynstr_append_checked(&insert_pat, insert_option);
      dynstr_append_checked(&insert_pat, "INTO ");
      dynstr_append_checked(&insert_pat, opt_quoted_table);
unknown's avatar
unknown committed
1954
      if (complete_insert)
unknown's avatar
unknown committed
1955
      {
1956
        dynstr_append_checked(&insert_pat, " (");
unknown's avatar
unknown committed
1957 1958 1959
      }
      else
      {
1960
        dynstr_append_checked(&insert_pat, " VALUES ");
unknown's avatar
unknown committed
1961
        if (!extended_insert)
1962
          dynstr_append_checked(&insert_pat, "(");
unknown's avatar
unknown committed
1963
      }
1964 1965
    }

1966
    while ((row= mysql_fetch_row(result)))
1967
    {
unknown's avatar
unknown committed
1968
      if (complete_insert)
unknown's avatar
unknown committed
1969
      {
unknown's avatar
unknown committed
1970 1971
        if (init)
        {
1972
          dynstr_append_checked(&insert_pat, ", ");
unknown's avatar
unknown committed
1973 1974
        }
        init=1;
1975
        dynstr_append_checked(&insert_pat,
1976
                      quote_name(row[SHOW_FIELDNAME], name_buff, 0));
unknown's avatar
unknown committed
1977
      }
unknown's avatar
unknown committed
1978
    }
1979 1980
    num_fields= mysql_num_rows(result);
    mysql_free_result(result);
unknown's avatar
unknown committed
1981
  }
1982
  else
unknown's avatar
unknown committed
1983
  {
unknown's avatar
unknown committed
1984
    verbose_msg("%s: Warning: Can't set SQL_QUOTE_SHOW_CREATE option (%s)\n",
unknown's avatar
unknown committed
1985
                my_progname, mysql_error(mysql));
1986

1987
    my_snprintf(query_buff, sizeof(query_buff), "show fields from %s",
1988
                result_table);
unknown's avatar
unknown committed
1989
    if (mysql_query_with_error_report(mysql, &result, query_buff))
unknown's avatar
unknown committed
1990 1991
      DBUG_RETURN(0);

1992
    /* Make an sql-file, if path was given iow. option -T was given */
1993
    if (!opt_no_create_info)
unknown's avatar
unknown committed
1994
    {
1995
      if (path)
unknown's avatar
unknown committed
1996
      {
1997
        if (!(sql_file= open_sql_file_for_table(table)))
1998
          DBUG_RETURN(0);
1999
        write_header(sql_file, db);
unknown's avatar
unknown committed
2000
      }
2001
      if (!opt_xml && opt_comments)
2002 2003
        fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n",
                result_table);
2004
      if (opt_drop)
unknown's avatar
unknown committed
2005
        fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", result_table);
2006
      if (!opt_xml)
2007
        fprintf(sql_file, "CREATE TABLE %s (\n", result_table);
2008
      else
2009 2010
        print_xml_tag(sql_file, "\t", "\n", "table_structure", "name=", table, 
                NullS);
2011
      check_io(sql_file);
2012
    }
2013

unknown's avatar
unknown committed
2014
    if (write_data)
2015
    {
2016
      if (opt_replace_into)
2017
        dynstr_append_checked(&insert_pat, "REPLACE ");
2018
      else
2019
        dynstr_append_checked(&insert_pat, "INSERT ");
2020 2021 2022
      dynstr_append_checked(&insert_pat, insert_option);
      dynstr_append_checked(&insert_pat, "INTO ");
      dynstr_append_checked(&insert_pat, result_table);
2023
      if (complete_insert)
2024
        dynstr_append_checked(&insert_pat, " (");
unknown's avatar
unknown committed
2025 2026
      else
      {
2027
        dynstr_append_checked(&insert_pat, " VALUES ");
unknown's avatar
unknown committed
2028
        if (!extended_insert)
2029
          dynstr_append_checked(&insert_pat, "(");
unknown's avatar
unknown committed
2030
      }
unknown's avatar
unknown committed
2031
    }
2032

2033
    while ((row= mysql_fetch_row(result)))
unknown's avatar
unknown committed
2034
    {
2035
      ulong *lengths= mysql_fetch_lengths(result);
2036
      if (init)
unknown's avatar
unknown committed
2037
      {
2038
        if (!opt_xml && !opt_no_create_info)
2039 2040 2041 2042
        {
          fputs(",\n",sql_file);
          check_io(sql_file);
        }
unknown's avatar
unknown committed
2043
        if (complete_insert)
2044
          dynstr_append_checked(&insert_pat, ", ");
2045 2046
      }
      init=1;
2047
      if (complete_insert)
2048
        dynstr_append_checked(&insert_pat,
2049
                      quote_name(row[SHOW_FIELDNAME], name_buff, 0));
2050
      if (!opt_no_create_info)
2051
      {
2052 2053 2054 2055 2056
        if (opt_xml)
        {
          print_xml_row(sql_file, "field", result, &row);
          continue;
        }
2057

2058
        if (opt_keywords)
2059 2060 2061
          fprintf(sql_file, "  %s.%s %s", result_table,
                  quote_name(row[SHOW_FIELDNAME],name_buff, 0),
                  row[SHOW_TYPE]);
2062
        else
2063 2064 2065
          fprintf(sql_file, "  %s %s", quote_name(row[SHOW_FIELDNAME],
                                                  name_buff, 0),
                  row[SHOW_TYPE]);
2066 2067
        if (row[SHOW_DEFAULT])
        {
2068 2069
          fputs(" DEFAULT ", sql_file);
          unescape(sql_file, row[SHOW_DEFAULT], lengths[SHOW_DEFAULT]);
2070 2071
        }
        if (!row[SHOW_NULL][0])
2072
          fputs(" NOT NULL", sql_file);
2073
        if (row[SHOW_EXTRA][0])
2074 2075
          fprintf(sql_file, " %s",row[SHOW_EXTRA]);
        check_io(sql_file);
unknown's avatar
unknown committed
2076 2077
      }
    }
2078 2079
    num_fields= mysql_num_rows(result);
    mysql_free_result(result);
2080
    if (!opt_no_create_info)
unknown's avatar
unknown committed
2081
    {
2082 2083 2084
      /* Make an sql-file, if path was given iow. option -T was given */
      char buff[20+FN_REFLEN];
      uint keynr,primary_key;
2085
      my_snprintf(buff, sizeof(buff), "show keys from %s", result_table);
unknown's avatar
unknown committed
2086
      if (mysql_query_with_error_report(mysql, &result, buff))
unknown's avatar
unknown committed
2087
      {
unknown's avatar
unknown committed
2088
        if (mysql_errno(mysql) == ER_WRONG_OBJECT)
2089 2090 2091 2092 2093 2094
        {
          /* 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",
unknown's avatar
unknown committed
2095
                my_progname, result_table, mysql_error(mysql));
2096
        if (path)
2097
          my_fclose(sql_file, MYF(MY_WME));
2098
        DBUG_RETURN(0);
unknown's avatar
unknown committed
2099
      }
2100 2101 2102 2103

      /* Find first which key is primary key */
      keynr=0;
      primary_key=INT_MAX;
2104
      while ((row= mysql_fetch_row(result)))
unknown's avatar
unknown committed
2105
      {
2106 2107
        if (atoi(row[3]) == 1)
        {
2108
          keynr++;
unknown's avatar
unknown committed
2109
#ifdef FORCE_PRIMARY_KEY
2110 2111
          if (atoi(row[1]) == 0 && primary_key == INT_MAX)
            primary_key=keynr;
unknown's avatar
unknown committed
2112
#endif
2113 2114 2115 2116 2117
          if (!strcmp(row[2],"PRIMARY"))
          {
            primary_key=keynr;
            break;
          }
2118
        }
unknown's avatar
unknown committed
2119
      }
2120
      mysql_data_seek(result,0);
2121
      keynr=0;
2122
      while ((row= mysql_fetch_row(result)))
2123
      {
2124 2125 2126 2127 2128
        if (opt_xml)
        {
          print_xml_row(sql_file, "key", result, &row);
          continue;
        }
unknown's avatar
unknown committed
2129

2130 2131
        if (atoi(row[3]) == 1)
        {
2132 2133 2134 2135 2136 2137 2138 2139 2140 2141
          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));
2142 2143
        }
        else
2144
          putc(',', sql_file);
unknown's avatar
unknown committed
2145
        fputs(quote_name(row[4], name_buff, 0), sql_file);
2146
        if (row[7])
2147 2148
          fprintf(sql_file, " (%s)",row[7]);      /* Sub key */
        check_io(sql_file);
2149
      }
2150 2151
      if (!opt_xml)
      {
2152 2153 2154 2155
        if (keynr)
          putc(')', sql_file);
        fputs("\n)",sql_file);
        check_io(sql_file);
2156
      }
2157 2158 2159

      /* Get MySQL specific create options */
      if (create_options)
unknown's avatar
unknown committed
2160
      {
2161
        char show_name_buff[NAME_LEN*2+2+24];
2162

2163
        /* Check memory for quote_for_like() */
2164
        my_snprintf(buff, sizeof(buff), "show table status like %s",
2165
                    quote_for_like(table, show_name_buff));
2166

unknown's avatar
unknown committed
2167
        if (mysql_query_with_error_report(mysql, &result, buff))
2168
        {
unknown's avatar
unknown committed
2169
          if (mysql_errno(mysql) != ER_PARSE_ERROR)
2170
          {                                     /* If old MySQL version */
unknown's avatar
unknown committed
2171
            verbose_msg("-- Warning: Couldn't get status information for " \
unknown's avatar
unknown committed
2172
                        "table %s (%s)\n", result_table,mysql_error(mysql));
2173
          }
2174
        }
2175
        else if (!(row= mysql_fetch_row(result)))
2176
        {
2177 2178
          fprintf(stderr,
                  "Error: Couldn't read status information for table %s (%s)\n",
unknown's avatar
unknown committed
2179
                  result_table,mysql_error(mysql));
2180 2181 2182
        }
        else
        {
2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193
          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);
          }
2194
        }
2195
        mysql_free_result(result);              /* Is always safe to free */
unknown's avatar
unknown committed
2196
      }
2197
continue_xml:
2198
      if (!opt_xml)
2199
        fputs(";\n", sql_file);
2200
      else
2201
        fputs("\t</table_structure>\n", sql_file);
2202
      check_io(sql_file);
unknown's avatar
unknown committed
2203 2204
    }
  }
2205
  if (complete_insert)
unknown's avatar
unknown committed
2206
  {
2207
    dynstr_append_checked(&insert_pat, ") VALUES ");
unknown's avatar
unknown committed
2208
    if (!extended_insert)
2209
      dynstr_append_checked(&insert_pat, "(");
unknown's avatar
unknown committed
2210
  }
2211
  if (sql_file != md_result_file)
2212 2213 2214
  {
    fputs("\n", sql_file);
    write_footer(sql_file);
2215
    my_fclose(sql_file, MYF(MY_WME));
2216
  }
2217
  DBUG_RETURN((uint) num_fields);
2218
} /* get_table_structure */
unknown's avatar
unknown committed
2219 2220


2221 2222 2223 2224 2225 2226 2227 2228 2229 2230
/*

  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

*/

unknown's avatar
unknown committed
2231 2232
static void dump_triggers_for_table(char *table,
                                    char *db __attribute__((unused)))
2233
{
2234 2235
  char       *result_table;
  char       name_buff[NAME_LEN*4+3], table_buff[NAME_LEN*2+3];
2236
  char       query_buff[QUERY_LENGTH];
unknown's avatar
unknown committed
2237
  uint old_opt_compatible_mode=opt_compatible_mode;
unknown's avatar
unknown committed
2238
  FILE       *sql_file= md_result_file;
unknown's avatar
unknown committed
2239 2240
  MYSQL_RES  *result;
  MYSQL_ROW  row;
2241 2242
  DBUG_ENTER("dump_triggers_for_table");
  DBUG_PRINT("enter", ("db: %s, table: %s", db, table));
unknown's avatar
unknown committed
2243 2244 2245

  /* Do not use ANSI_QUOTES on triggers in dump */
  opt_compatible_mode&= ~MASK_ANSI_QUOTES;
2246 2247 2248 2249 2250 2251
  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));

unknown's avatar
unknown committed
2252
  if (mysql_query_with_error_report(mysql, &result, query_buff))
2253 2254 2255 2256 2257 2258 2259
  {
    if (path)
      my_fclose(sql_file, MYF(MY_WME));
    DBUG_VOID_RETURN;
  }
  if (mysql_num_rows(result))
    fprintf(sql_file, "\n/*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/;\n\
2260
DELIMITER ;;\n");
2261
  while ((row= mysql_fetch_row(result)))
2262
  {
2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281
    fprintf(sql_file,
            "/*!50003 SET SESSION SQL_MODE=\"%s\" */;;\n"
            "/*!50003 CREATE */ ",
            row[6] /* sql_mode */);

    if (mysql_num_fields(result) > 7)
    {
      /*
        mysqldump can be run against the server, that does not support definer
        in triggers (there is no DEFINER column in SHOW TRIGGERS output). So,
        we should check if we have this column before accessing it.
      */

      uint       user_name_len;
      char       user_name_str[USERNAME_LENGTH + 1];
      char       quoted_user_name_str[USERNAME_LENGTH * 2 + 3];
      uint       host_name_len;
      char       host_name_str[HOSTNAME_LENGTH + 1];
      char       quoted_host_name_str[HOSTNAME_LENGTH * 2 + 3];
2282

2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293
      parse_user(row[7], strlen(row[7]), user_name_str, &user_name_len,
                 host_name_str, &host_name_len);

      fprintf(sql_file,
              "/*!50017 DEFINER=%s@%s */ ",
              quote_name(user_name_str, quoted_user_name_str, FALSE),
              quote_name(host_name_str, quoted_host_name_str, FALSE));
    }

    fprintf(sql_file,
            "/*!50003 TRIGGER %s %s %s ON %s FOR EACH ROW%s%s */;;\n\n",
2294 2295 2296 2297
            quote_name(row[0], name_buff, 0), /* Trigger */
            row[4], /* Timing */
            row[1], /* Event */
            result_table,
2298
            (strchr(" \t\n\r", *(row[3]))) ? "" : " ",
2299 2300 2301 2302
            row[3] /* Statement */);
  }
  if (mysql_num_rows(result))
    fprintf(sql_file,
2303 2304
            "DELIMITER ;\n"
            "/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE */;\n");
2305
  mysql_free_result(result);
unknown's avatar
unknown committed
2306
  /*
2307
    make sure to set back opt_compatible mode to
unknown's avatar
unknown committed
2308 2309 2310
    original value
  */
  opt_compatible_mode=old_opt_compatible_mode;
2311 2312 2313
  DBUG_VOID_RETURN;
}

2314 2315
static void add_load_option(DYNAMIC_STRING *str, const char *option,
                             const char *option_value)
unknown's avatar
unknown committed
2316
{
2317
  if (!option_value)
unknown's avatar
unknown committed
2318
  {
2319 2320
    /* Null value means we don't add this option. */
    return;
unknown's avatar
unknown committed
2321
  }
2322 2323 2324 2325 2326 2327 2328

  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);
unknown's avatar
unknown committed
2329
  }
2330 2331 2332 2333 2334 2335
  else
  {
    /* char constant; escape */
    field_escape(str, option_value);
  }
}
unknown's avatar
unknown committed
2336 2337 2338


/*
2339 2340 2341 2342
  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.
unknown's avatar
unknown committed
2343 2344
*/

2345
static void field_escape(DYNAMIC_STRING* in, const char *from)
unknown's avatar
unknown committed
2346
{
2347
  uint end_backslashes= 0; 
unknown's avatar
unknown committed
2348

2349
  dynstr_append_checked(in, "'");
unknown's avatar
unknown committed
2350

2351
  while (*from)
unknown's avatar
unknown committed
2352
  {
2353 2354
    dynstr_append_mem_checked(in, from, 1);

unknown's avatar
unknown committed
2355 2356 2357 2358 2359
    if (*from == '\\')
      end_backslashes^=1;    /* find odd number of backslashes */
    else
    {
      if (*from == '\'' && !end_backslashes)
2360 2361 2362 2363
      {
        /* We want a duplicate of "'" for MySQL */
        dynstr_append_checked(in, "\'");
      }
unknown's avatar
unknown committed
2364 2365
      end_backslashes=0;
    }
2366
    from++;
unknown's avatar
unknown committed
2367 2368 2369
  }
  /* Add missing backslashes if user has specified odd number of backs.*/
  if (end_backslashes)
2370 2371 2372 2373 2374
    dynstr_append_checked(in, "\\");
  
  dynstr_append_checked(in, "'");
}

unknown's avatar
unknown committed
2375 2376


2377 2378 2379 2380 2381
static char *alloc_query_str(ulong size)
{
  char *query;

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

2384 2385 2386
  return query;
}

2387

unknown's avatar
unknown committed
2388
/*
unknown's avatar
unknown committed
2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400

 SYNOPSIS
  dump_table()

  dump_table saves database contents as a series of INSERT statements.

  ARGS
   table - table name
   db    - db name

   RETURNS
    void
unknown's avatar
unknown committed
2401
*/
2402

2403

unknown's avatar
unknown committed
2404
static void dump_table(char *table, char *db)
unknown's avatar
unknown committed
2405
{
unknown's avatar
unknown committed
2406
  char ignore_flag;
2407 2408
  char buf[200], table_buff[NAME_LEN+3];
  DYNAMIC_STRING query_string;
unknown's avatar
unknown committed
2409
  char table_type[NAME_LEN];
unknown's avatar
unknown committed
2410
  char *result_table, table_buff2[NAME_LEN*2+3], *opt_quoted_table;
unknown's avatar
unknown committed
2411
  int error= 0;
2412
  ulong         rownr, row_break, total_length, init_length;
unknown's avatar
unknown committed
2413
  uint num_fields;
2414 2415 2416
  MYSQL_RES     *res;
  MYSQL_FIELD   *field;
  MYSQL_ROW     row;
unknown's avatar
unknown committed
2417 2418 2419 2420 2421 2422
  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.
  */
unknown's avatar
unknown committed
2423
  num_fields= get_table_structure(table, db, table_type, &ignore_flag);
unknown's avatar
unknown committed
2424

2425 2426 2427 2428
  /*
    The "table" could be a view.  If so, we don't do anything here.
  */
  if (strcmp (table_type, "VIEW") == 0)
unknown's avatar
unknown committed
2429
    DBUG_VOID_RETURN;
2430

2431
  /* Check --no-data flag */
2432
  if (opt_no_data)
2433
  {
unknown's avatar
unknown committed
2434 2435
    verbose_msg("-- Skipping dump data for table '%s', --no-data was used\n",
                table);
unknown's avatar
unknown committed
2436
    DBUG_VOID_RETURN;
2437 2438
  }

unknown's avatar
unknown committed
2439 2440 2441
  DBUG_PRINT("info",
             ("ignore_flag: %x  num_fields: %d", (int) ignore_flag,
              num_fields));
unknown's avatar
unknown committed
2442 2443 2444 2445 2446 2447
  /*
    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)
  {
unknown's avatar
unknown committed
2448 2449
    verbose_msg("-- Warning: Skipping data for table '%s' because " \
                "it's of type %s\n", table, table_type);
unknown's avatar
unknown committed
2450 2451
    DBUG_VOID_RETURN;
  }
2452
  /* Check that there are any fields in the table */
unknown's avatar
unknown committed
2453
  if (num_fields == 0)
2454
  {
unknown's avatar
unknown committed
2455 2456
    verbose_msg("-- Skipping dump data for table '%s', it has no fields\n",
                table);
unknown's avatar
unknown committed
2457
    DBUG_VOID_RETURN;
2458 2459
  }

unknown's avatar
unknown committed
2460 2461
  result_table= quote_name(table,table_buff, 1);
  opt_quoted_table= quote_name(table, table_buff2, 0);
2462

unknown's avatar
unknown committed
2463
  verbose_msg("-- Sending SELECT query...\n");
2464 2465 2466

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

unknown's avatar
unknown committed
2467 2468 2469
  if (path)
  {
    char filename[FN_REFLEN], tmp_path[FN_REFLEN];
2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486

    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);    
unknown's avatar
unknown committed
2487
    my_load_path(tmp_path, tmp_path, NULL);
2488 2489 2490 2491 2492 2493
    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 */
unknown's avatar
unknown committed
2494
    to_unix_path(filename);
2495 2496 2497 2498 2499 2500

    /* 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, "'");
unknown's avatar
unknown committed
2501 2502

    if (fields_terminated || enclosed || opt_enclosed || escaped)
2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514
      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)
2515
    {
2516 2517
      dynstr_append_checked(&query_string, " WHERE ");
      dynstr_append_checked(&query_string, where);
2518
    }
2519 2520 2521 2522 2523 2524 2525 2526

    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))
unknown's avatar
unknown committed
2527
    {
unknown's avatar
unknown committed
2528
      DB_error(mysql, "when executing 'SELECT INTO OUTFILE'");
unknown's avatar
unknown committed
2529
      DBUG_VOID_RETURN;
unknown's avatar
unknown committed
2530 2531 2532 2533
    }
  }
  else
  {
2534
    if (!opt_xml && opt_comments)
2535
    {
unknown's avatar
unknown committed
2536
      fprintf(md_result_file,"\n--\n-- Dumping data for table %s\n--\n",
2537
              result_table);
2538 2539
      check_io(md_result_file);
    }
2540 2541 2542
    
    dynstr_append_checked(&query_string, "SELECT /*!40001 SQL_NO_CACHE */ * FROM ");
    dynstr_append_checked(&query_string, result_table);
2543

2544 2545 2546
    if (where)
    {
      if (!opt_xml && opt_comments)
2547
      {
2548 2549
        fprintf(md_result_file, "-- WHERE:  %s\n", where);
        check_io(md_result_file);
2550
      }
2551 2552 2553 2554 2555 2556 2557
      
      dynstr_append_checked(&query_string, " WHERE ");
      dynstr_append_checked(&query_string, where);
    }
    if (order_by)
    {
      if (!opt_xml && opt_comments)
2558
      {
2559 2560
        fprintf(md_result_file, "-- ORDER BY:  %s\n", order_by);
        check_io(md_result_file);
2561
      }
2562 2563
      dynstr_append_checked(&query_string, " ORDER BY ");
      dynstr_append_checked(&query_string, order_by);
unknown's avatar
unknown committed
2564
    }
2565

unknown's avatar
unknown committed
2566
    if (!opt_xml && !opt_compact)
2567
    {
unknown's avatar
merge  
unknown committed
2568
      fputs("\n", md_result_file);
2569 2570
      check_io(md_result_file);
    }
2571
    if (mysql_query_with_error_report(mysql, 0, query_string.str))
2572
    {
unknown's avatar
unknown committed
2573
      DB_error(mysql, "when retrieving data from server");
2574 2575
      goto err;
    }
unknown's avatar
unknown committed
2576
    if (quick)
unknown's avatar
unknown committed
2577
      res=mysql_use_result(mysql);
unknown's avatar
unknown committed
2578
    else
unknown's avatar
unknown committed
2579
      res=mysql_store_result(mysql);
unknown's avatar
unknown committed
2580
    if (!res)
2581
    {
unknown's avatar
unknown committed
2582
      DB_error(mysql, "when retrieving data from server");
2583 2584
      goto err;
    }
unknown's avatar
unknown committed
2585 2586

    verbose_msg("-- Retrieving rows...\n");
unknown's avatar
unknown committed
2587
    if (mysql_num_fields(res) != num_fields)
unknown's avatar
unknown committed
2588
    {
unknown's avatar
unknown committed
2589
      fprintf(stderr,"%s: Error in field count for table: %s !  Aborting.\n",
2590
              my_progname, result_table);
2591 2592
      error= EX_CONSCHECK;
      goto err;
unknown's avatar
unknown committed
2593 2594
    }

2595
    if (opt_lock)
2596
    {
2597
      fprintf(md_result_file,"LOCK TABLES %s WRITE;\n", opt_quoted_table);
2598 2599
      check_io(md_result_file);
    }
2600 2601
    /* Moved disable keys to after lock per bug 15977 */
    if (opt_disable_keys)
2602
    {
2603 2604
      fprintf(md_result_file, "/*!40000 ALTER TABLE %s DISABLE KEYS */;\n",
	      opt_quoted_table);
2605 2606
      check_io(md_result_file);
    }
unknown's avatar
unknown committed
2607

2608
    total_length= opt_net_buffer_length;                /* Force row break */
unknown's avatar
unknown committed
2609 2610
    row_break=0;
    rownr=0;
2611
    init_length=(uint) insert_pat.length+4;
unknown's avatar
unknown committed
2612
    if (opt_xml)
2613 2614
      print_xml_tag(md_result_file, "\t", "\n", "table_data", "name=", table,
              NullS);
unknown's avatar
unknown committed
2615
    if (opt_autocommit)
2616
    {
unknown's avatar
unknown committed
2617
      fprintf(md_result_file, "set autocommit=0;\n");
2618 2619
      check_io(md_result_file);
    }
unknown's avatar
unknown committed
2620

2621
    while ((row= mysql_fetch_row(res)))
unknown's avatar
unknown committed
2622 2623
    {
      uint i;
2624
      ulong *lengths= mysql_fetch_lengths(res);
unknown's avatar
unknown committed
2625
      rownr++;
unknown's avatar
unknown committed
2626
      if (!extended_insert && !opt_xml)
2627
      {
2628 2629
        fputs(insert_pat.str,md_result_file);
        check_io(md_result_file);
2630
      }
unknown's avatar
unknown committed
2631 2632
      mysql_field_seek(res,0);

unknown's avatar
merge  
unknown committed
2633
      if (opt_xml)
2634
      {
2635
        fputs("\t<row>\n", md_result_file);
2636
        check_io(md_result_file);
2637
      }
unknown's avatar
merge  
unknown committed
2638

unknown's avatar
unknown committed
2639
      for (i= 0; i < mysql_num_fields(res); i++)
unknown's avatar
unknown committed
2640
      {
2641
        int is_blob;
2642 2643
        ulong length= lengths[i];

unknown's avatar
unknown committed
2644
        if (!(field= mysql_fetch_field(res)))
2645 2646 2647
          die(EX_CONSCHECK,
                      "Not enough fields from table %s! Aborting.\n",
                      result_table);
2648 2649 2650 2651 2652 2653

        /*
           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.
        */
2654
        is_blob= (opt_hex_blob && field->charsetnr == 63 &&
2655 2656
                  (field->type == MYSQL_TYPE_BIT ||
                   field->type == MYSQL_TYPE_STRING ||
2657 2658 2659 2660 2661 2662
                   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;
2663
        if (extended_insert && !opt_xml)
2664 2665
        {
          if (i == 0)
2666
            dynstr_set_checked(&extended_row,"(");
2667
          else
2668
            dynstr_append_checked(&extended_row,",");
2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682

          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.
                */
2683
                dynstr_realloc_checked(&extended_row,length * 2+2);
2684 2685
                if (opt_hex_blob && is_blob)
                {
2686
                  dynstr_append_checked(&extended_row, "0x");
2687
                  extended_row.length+= mysql_hex_string(extended_row.str +
unknown's avatar
unknown committed
2688 2689 2690
                                                         extended_row.length,
                                                         row[i], length);
                  extended_row.str[extended_row.length]= '\0';
2691 2692 2693
                }
                else
                {
2694
                  dynstr_append_checked(&extended_row,"'");
2695 2696 2697 2698 2699
                  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';
2700
                  dynstr_append_checked(&extended_row,"'");
2701
                }
2702 2703 2704 2705
              }
              else
              {
                /* change any strings ("inf", "-inf", "nan") into NULL */
unknown's avatar
unknown committed
2706
                char *ptr= row[i];
2707 2708
                if (my_isalpha(charset_info, *ptr) || (*ptr == '-' &&
                    my_isalpha(charset_info, ptr[1])))
2709
                  dynstr_append_checked(&extended_row, "NULL");
2710 2711
                else
                {
2712
                  if (field->type == MYSQL_TYPE_DECIMAL)
2713 2714
                  {
                    /* add " signs around */
2715 2716 2717
                    dynstr_append_checked(&extended_row, "'");
                    dynstr_append_checked(&extended_row, ptr);
                    dynstr_append_checked(&extended_row, "'");
2718 2719
                  }
                  else
2720
                    dynstr_append_checked(&extended_row, ptr);
2721 2722 2723 2724
                }
              }
            }
            else
2725
              dynstr_append_checked(&extended_row,"''");
2726
          }
2727 2728
          else
            dynstr_append_checked(&extended_row,"NULL");
2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742
        }
        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)
              {
2743 2744
                if (opt_hex_blob && is_blob && length)
                {
unknown's avatar
unknown committed
2745 2746 2747 2748
                  /* 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);
2749 2750 2751
                }
                else
                {
unknown's avatar
unknown committed
2752 2753 2754
                  print_xml_tag(md_result_file, "\t\t", "", "field", "name=", 
                                field->name, NullS);
                  print_quoted_xml(md_result_file, row[i], length);
2755
                }
2756 2757 2758
                fputs("</field>\n", md_result_file);
              }
              else if (opt_hex_blob && is_blob && length)
unknown's avatar
unknown committed
2759
              {
2760
                fputs("0x", md_result_file);
2761
                print_blob_as_hex(md_result_file, row[i], length);
2762 2763
              }
              else
2764
                unescape(md_result_file, row[i], length);
2765 2766 2767 2768
            }
            else
            {
              /* change any strings ("inf", "-inf", "nan") into NULL */
unknown's avatar
unknown committed
2769
              char *ptr= row[i];
2770 2771
              if (opt_xml)
              {
2772 2773
                print_xml_tag(md_result_file, "\t\t", "", "field", "name=",
                        field->name, NullS);
2774 2775 2776 2777 2778 2779 2780
                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);
2781
              else if (field->type == MYSQL_TYPE_DECIMAL)
2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792
              {
                /* add " signs around */
                fputc('\'', md_result_file);
                fputs(ptr, md_result_file);
                fputc('\'', md_result_file);
              }
              else
                fputs(ptr, md_result_file);
            }
          }
          else
2793 2794 2795 2796 2797 2798 2799 2800
          {
            /* 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");
          }
unknown's avatar
Merge  
unknown committed
2801
          check_io(md_result_file);
2802
        }
unknown's avatar
unknown committed
2803 2804
      }

unknown's avatar
merge  
unknown committed
2805
      if (opt_xml)
2806
      {
2807
        fputs("\t</row>\n", md_result_file);
2808
        check_io(md_result_file);
2809
      }
unknown's avatar
merge  
unknown committed
2810

2811
      if (extended_insert)
unknown's avatar
unknown committed
2812
      {
2813
        ulong row_length;
2814
        dynstr_append_checked(&extended_row,")");
unknown's avatar
unknown committed
2815
        row_length= 2 + extended_row.length;
2816
        if (total_length + row_length < opt_net_buffer_length)
unknown's avatar
unknown committed
2817
        {
unknown's avatar
unknown committed
2818
          total_length+= row_length;
2819 2820 2821
          fputc(',',md_result_file);            /* Always row break */
          fputs(extended_row.str,md_result_file);
        }
unknown's avatar
unknown committed
2822 2823
        else
        {
2824 2825 2826
          if (row_break)
            fputs(";\n", md_result_file);
          row_break=1;                          /* This is first row */
unknown's avatar
unknown committed
2827

2828
          fputs(insert_pat.str,md_result_file);
2829
          fputs(extended_row.str,md_result_file);
unknown's avatar
unknown committed
2830
          total_length= row_length+init_length;
unknown's avatar
unknown committed
2831
        }
2832
        check_io(md_result_file);
unknown's avatar
unknown committed
2833
      }
unknown's avatar
unknown committed
2834
      else if (!opt_xml)
2835
      {
2836 2837
        fputs(");\n", md_result_file);
        check_io(md_result_file);
2838
      }
unknown's avatar
unknown committed
2839
    }
unknown's avatar
unknown committed
2840

unknown's avatar
unknown committed
2841
    /* XML - close table tag and supress regular output */
unknown's avatar
unknown committed
2842
    if (opt_xml)
2843
        fputs("\t</table_data>\n", md_result_file);
unknown's avatar
unknown committed
2844
    else if (extended_insert && row_break)
2845
      fputs(";\n", md_result_file);             /* If not empty table */
unknown's avatar
unknown committed
2846
    fflush(md_result_file);
2847
    check_io(md_result_file);
unknown's avatar
unknown committed
2848
    if (mysql_errno(mysql))
unknown's avatar
unknown committed
2849
    {
2850
      my_snprintf(buf, sizeof(buf),
2851 2852
                  "%s: Error %d: %s when dumping table %s at row: %ld\n",
                  my_progname,
unknown's avatar
unknown committed
2853 2854
                  mysql_errno(mysql),
                  mysql_error(mysql),
2855 2856
                  result_table,
                  rownr);
2857
      fputs(buf,stderr);
2858 2859
      error= EX_CONSCHECK;
      goto err;
unknown's avatar
unknown committed
2860
    }
2861 2862

    /* Moved enable keys to before unlock per bug 15977 */
unknown's avatar
merge  
unknown committed
2863
    if (opt_disable_keys)
2864
    {
unknown's avatar
merge  
unknown committed
2865
      fprintf(md_result_file,"/*!40000 ALTER TABLE %s ENABLE KEYS */;\n",
2866
              opt_quoted_table);
2867 2868
      check_io(md_result_file);
    }
2869 2870 2871 2872 2873
    if (opt_lock)
    {
      fputs("UNLOCK TABLES;\n", md_result_file);
      check_io(md_result_file);
    }
unknown's avatar
unknown committed
2874
    if (opt_autocommit)
2875
    {
unknown's avatar
unknown committed
2876
      fprintf(md_result_file, "commit;\n");
2877 2878
      check_io(md_result_file);
    }
2879
    mysql_free_result(res);
2880
    dynstr_free(&query_string);
unknown's avatar
unknown committed
2881 2882
  }
  DBUG_VOID_RETURN;
2883 2884

err:
2885 2886
  dynstr_free(&query_string);
  maybe_exit(error);
unknown's avatar
unknown committed
2887
  DBUG_VOID_RETURN;
2888
} /* dump_table */
unknown's avatar
unknown committed
2889 2890 2891 2892


static char *getTableName(int reset)
{
unknown's avatar
unknown committed
2893
  static MYSQL_RES *res= NULL;
unknown's avatar
unknown committed
2894 2895 2896 2897
  MYSQL_ROW    row;

  if (!res)
  {
2898
    if (!(res= mysql_list_tables(mysql,NullS)))
unknown's avatar
unknown committed
2899 2900
      return(NULL);
  }
unknown's avatar
unknown committed
2901
  if ((row= mysql_fetch_row(res)))
unknown's avatar
unknown committed
2902
    return((char*) row[0]);
unknown's avatar
unknown committed
2903

unknown's avatar
unknown committed
2904 2905 2906 2907 2908
  if (reset)
    mysql_data_seek(res,0);      /* We want to read again */
  else
  {
    mysql_free_result(res);
unknown's avatar
unknown committed
2909
    res= NULL;
unknown's avatar
unknown committed
2910 2911 2912 2913 2914
  }
  return(NULL);
} /* getTableName */


2915 2916 2917 2918 2919
/*
  dump all logfile groups and tablespaces
*/

static int dump_all_tablespaces()
2920 2921 2922 2923 2924 2925
{
  return dump_tablespaces(NULL);
}

static int dump_tablespaces_for_tables(char *db, char **table_names, int tables)
{
2926
  DYNAMIC_STRING where;
2927 2928 2929
  int r;
  int i;
  char name_buff[NAME_LEN*2+3];
2930

2931 2932
  mysql_real_escape_string(mysql, name_buff, db, strlen(db));

2933
  init_dynamic_string_checked(&where, " AND TABLESPACE_NAME IN ("
2934 2935 2936 2937
                      "SELECT DISTINCT TABLESPACE_NAME FROM"
                      " INFORMATION_SCHEMA.PARTITIONS"
                      " WHERE"
                      " TABLE_SCHEMA='", 256, 1024);
2938 2939
  dynstr_append_checked(&where, name_buff);
  dynstr_append_checked(&where, "' AND TABLE_NAME IN (");
2940 2941 2942 2943 2944

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

2946 2947 2948
    dynstr_append_checked(&where, "'");
    dynstr_append_checked(&where, name_buff);
    dynstr_append_checked(&where, "',");
2949
  }
2950
  dynstr_trunc(&where, 1);
2951
  dynstr_append_checked(&where,"))");
2952

unknown's avatar
unknown committed
2953
  DBUG_PRINT("info",("Dump TS for Tables where: %s",where.str));
2954 2955
  r= dump_tablespaces(where.str);
  dynstr_free(&where);
2956 2957 2958 2959 2960
  return r;
}

static int dump_tablespaces_for_databases(char** databases)
{
2961
  DYNAMIC_STRING where;
2962 2963 2964
  int r;
  int i;

2965
  init_dynamic_string_checked(&where, " AND TABLESPACE_NAME IN ("
2966 2967 2968 2969
                      "SELECT DISTINCT TABLESPACE_NAME FROM"
                      " INFORMATION_SCHEMA.PARTITIONS"
                      " WHERE"
                      " TABLE_SCHEMA IN (", 256, 1024);
2970 2971 2972 2973 2974 2975

  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]));
2976 2977 2978
    dynstr_append_checked(&where, "'");
    dynstr_append_checked(&where, db_name_buff);
    dynstr_append_checked(&where, "',");
2979
  }
2980
  dynstr_trunc(&where, 1);
2981
  dynstr_append_checked(&where,"))");
2982

unknown's avatar
unknown committed
2983
  DBUG_PRINT("info",("Dump TS for DBs where: %s",where.str));
2984 2985
  r= dump_tablespaces(where.str);
  dynstr_free(&where);
2986 2987 2988 2989
  return r;
}

static int dump_tablespaces(char* ts_where)
2990 2991 2992 2993
{
  MYSQL_ROW row;
  MYSQL_RES *tableres;
  char buf[FN_REFLEN];
2994
  DYNAMIC_STRING sqlbuf;
unknown's avatar
unknown committed
2995
  int first= 0;
2996 2997 2998 2999 3000 3001
  /*
    The following are used for parsing the EXTRA field
  */
  char extra_format[]= "UNDO_BUFFER_SIZE=";
  char *ubs;
  char *endsemi;
3002

3003
  init_dynamic_string_checked(&sqlbuf,
3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015
                      "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)
  {
3016
    dynstr_append_checked(&sqlbuf,
3017 3018 3019 3020 3021
                  " AND LOGFILE_GROUP_NAME IN ("
                  "SELECT DISTINCT LOGFILE_GROUP_NAME"
                  " FROM INFORMATION_SCHEMA.FILES"
                  " WHERE FILE_TYPE = 'DATAFILE'"
                  );
3022 3023
    dynstr_append_checked(&sqlbuf, ts_where);
    dynstr_append_checked(&sqlbuf, ")");
3024
  }
3025
  dynstr_append_checked(&sqlbuf,
3026 3027 3028 3029 3030
                " GROUP BY LOGFILE_GROUP_NAME, FILE_NAME"
                ", ENGINE"
                " ORDER BY LOGFILE_GROUP_NAME");

  if (mysql_query(mysql, sqlbuf.str) ||
3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045
      !(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));
3046
    return 1;
3047
  }
3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068

  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"
3069 3070 3071 3072 3073
            "  ADD UNDOFILE '%s'\n",
            row[0],
            row[1]);
    if (first)
    {
3074 3075 3076 3077 3078 3079 3080
      ubs= strstr(row[5],extra_format);
      if(!ubs)
        break;
      ubs+= strlen(extra_format);
      endsemi= strstr(ubs,";");
      if(endsemi)
        endsemi[0]= '\0';
3081 3082
      fprintf(md_result_file,
              "  UNDO_BUFFER_SIZE %s\n",
3083
              ubs);
3084 3085
    }
    fprintf(md_result_file,
3086 3087
            "  INITIAL_SIZE %s\n"
            "  ENGINE=%s;\n",
3088 3089
            row[3],
            row[4]);
3090
    check_io(md_result_file);
3091 3092 3093 3094 3095
    if (first)
    {
      first= 0;
      strxmov(buf, row[0], NullS);
    }
3096
  }
3097
  dynstr_free(&sqlbuf);
3098
  init_dynamic_string_checked(&sqlbuf,
3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109
                      "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)
3110
    dynstr_append_checked(&sqlbuf, ts_where);
3111

3112
  dynstr_append_checked(&sqlbuf, " ORDER BY TABLESPACE_NAME, LOGFILE_GROUP_NAME");
3113 3114

  if (mysql_query_with_error_report(mysql, &tableres, sqlbuf.str))
3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138
    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],
3139
            row[1]);
3140 3141 3142
    if (first)
    {
      fprintf(md_result_file,
3143 3144 3145 3146
              "  USE LOGFILE GROUP %s\n"
              "  EXTENT_SIZE %s\n",
              row[2],
              row[3]);
3147 3148 3149 3150
    }
    fprintf(md_result_file,
            "  INITIAL_SIZE %s\n"
            "  ENGINE=%s;\n",
3151 3152
            row[4],
            row[5]);
3153
    check_io(md_result_file);
3154 3155 3156 3157 3158
    if (first)
    {
      first= 0;
      strxmov(buf, row[0], NullS);
    }
3159
  }
3160 3161

  dynstr_free(&sqlbuf);
3162 3163 3164
  return 0;
}

unknown's avatar
unknown committed
3165 3166 3167 3168 3169 3170
static int dump_all_databases()
{
  MYSQL_ROW row;
  MYSQL_RES *tableres;
  int result=0;

unknown's avatar
unknown committed
3171
  if (mysql_query_with_error_report(mysql, &tableres, "SHOW DATABASES"))
unknown's avatar
unknown committed
3172
    return 1;
unknown's avatar
unknown committed
3173
  while ((row= mysql_fetch_row(tableres)))
unknown's avatar
unknown committed
3174 3175 3176 3177
  {
    if (dump_all_tables_in_db(row[0]))
      result=1;
  }
3178
  if (seen_views)
3179
  {
unknown's avatar
unknown committed
3180
    if (mysql_query(mysql, "SHOW DATABASES") ||
3181
        !(tableres= mysql_store_result(mysql)))
3182 3183
    {
      my_printf_error(0, "Error: Couldn't execute 'SHOW DATABASES': %s",
unknown's avatar
unknown committed
3184
                      MYF(0), mysql_error(mysql));
3185 3186
      return 1;
    }
unknown's avatar
unknown committed
3187
    while ((row= mysql_fetch_row(tableres)))
3188 3189 3190 3191 3192
    {
      if (dump_all_views_in_db(row[0]))
        result=1;
    }
  }
unknown's avatar
unknown committed
3193 3194 3195 3196 3197 3198 3199 3200
  return result;
}
/* dump_all_databases */


static int dump_databases(char **db_names)
{
  int result=0;
3201
  char **db;
unknown's avatar
unknown committed
3202 3203
  DBUG_ENTER("dump_databases");

3204
  for (db= db_names ; *db ; db++)
3205
  {
3206
    if (dump_all_tables_in_db(*db))
unknown's avatar
unknown committed
3207 3208
      result=1;
  }
3209
  if (!result && seen_views)
3210 3211 3212 3213 3214 3215 3216
  {
    for (db= db_names ; *db ; db++)
    {
      if (dump_all_views_in_db(*db))
        result=1;
    }
  }
unknown's avatar
unknown committed
3217
  DBUG_RETURN(result);
unknown's avatar
unknown committed
3218 3219 3220
} /* dump_databases */


3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231
/*
View Specific database initalization.

SYNOPSIS
  init_dumping_views
  qdatabase      quoted name of the database

RETURN VALUES
  0        Success.
  1        Failure.
*/
unknown's avatar
unknown committed
3232
int init_dumping_views(char *qdatabase __attribute__((unused)))
3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290
{
    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*))
unknown's avatar
unknown committed
3291
{
unknown's avatar
unknown committed
3292
  if (mysql_get_server_version(mysql) >= 50003 &&
unknown's avatar
unknown committed
3293
      !my_strcasecmp(&my_charset_latin1, database, "information_schema"))
3294
    return 1;
3295

unknown's avatar
unknown committed
3296
  if (mysql_select_db(mysql, database))
unknown's avatar
unknown committed
3297
  {
unknown's avatar
unknown committed
3298
    DB_error(mysql, "when selecting the database");
3299
    return 1;                   /* If --force */
unknown's avatar
unknown committed
3300
  }
unknown's avatar
unknown committed
3301
  if (!path && !opt_xml)
unknown's avatar
unknown committed
3302 3303 3304
  {
    if (opt_databases || opt_alldbs)
    {
unknown's avatar
unknown committed
3305
      /*
3306
        length of table name * 2 (if name contains quotes), 2 quotes and 0
unknown's avatar
unknown committed
3307
      */
3308
      char quoted_database_buf[NAME_LEN*2+3];
unknown's avatar
unknown committed
3309
      char *qdatabase= quote_name(database,quoted_database_buf,opt_quoted);
3310
      if (opt_comments)
3311
      {
3312 3313
        fprintf(md_result_file,"\n--\n-- Current Database: %s\n--\n", qdatabase);
        check_io(md_result_file);
3314
      }
3315

3316 3317
      /* Call the view or table specific function */
      init_func(qdatabase);
3318

unknown's avatar
unknown committed
3319
      fprintf(md_result_file,"\nUSE %s;\n", qdatabase);
3320
      check_io(md_result_file);
unknown's avatar
unknown committed
3321 3322
    }
  }
3323 3324
  if (extended_insert)
    init_dynamic_string_checked(&extended_row, "", 1024, 1024);
unknown's avatar
unknown committed
3325 3326 3327 3328
  return 0;
} /* init_dumping */


unknown's avatar
unknown committed
3329 3330
/* Return 1 if we should copy the table */

3331 3332
my_bool include_table(byte* hash_key, uint len)
{
unknown's avatar
unknown committed
3333
  return !hash_search(&ignore_table, (byte*) hash_key, len);
3334 3335
}

unknown's avatar
unknown committed
3336

unknown's avatar
unknown committed
3337 3338 3339 3340
static int dump_all_tables_in_db(char *database)
{
  char *table;
  uint numrows;
unknown's avatar
unknown committed
3341
  char table_buff[NAME_LEN*2+3];
3342 3343
  char hash_key[2*NAME_LEN+2];  /* "db.tablename" */
  char *afterdot;
3344
  int using_mysql_db= my_strcasecmp(&my_charset_latin1, database, "mysql");
unknown's avatar
unknown committed
3345
  DBUG_ENTER("dump_all_tables_in_db");
3346 3347 3348 3349

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

3350
  if (init_dumping(database, init_dumping_tables))
unknown's avatar
unknown committed
3351
    DBUG_RETURN(1);
unknown's avatar
unknown committed
3352
  if (opt_xml)
3353
    print_xml_tag(md_result_file, "", "\n", "database", "name=", database, NullS);
unknown's avatar
unknown committed
3354 3355 3356
  if (lock_tables)
  {
    DYNAMIC_STRING query;
3357
    init_dynamic_string_checked(&query, "LOCK TABLES ", 256, 1024);
3358
    for (numrows= 0 ; (table= getTableName(1)) ; numrows++)
unknown's avatar
unknown committed
3359
    {
3360 3361 3362
      char *end= strmov(afterdot, table);
      if (include_table(hash_key,end - hash_key))
      {
3363 3364
        dynstr_append_checked(&query, quote_name(table, table_buff, 1));
        dynstr_append_checked(&query, " READ /*!32311 LOCAL */,");
3365
      }
unknown's avatar
unknown committed
3366
    }
unknown's avatar
unknown committed
3367 3368
    if (numrows && mysql_real_query(mysql, query.str, query.length-1))
      DB_error(mysql, "when using LOCK TABLES");
unknown's avatar
unknown committed
3369 3370 3371 3372 3373
            /* We shall continue here, if --force was given */
    dynstr_free(&query);
  }
  if (flush_logs)
  {
unknown's avatar
unknown committed
3374 3375
    if (mysql_refresh(mysql, REFRESH_LOG))
      DB_error(mysql, "when doing refresh");
unknown's avatar
unknown committed
3376 3377
           /* We shall continue here, if --force was given */
  }
3378
  while ((table= getTableName(0)))
unknown's avatar
unknown committed
3379
  {
3380 3381 3382
    char *end= strmov(afterdot, table);
    if (include_table(hash_key, end - hash_key))
    {
unknown's avatar
unknown committed
3383
      dump_table(table,database);
3384 3385
      my_free(order_by, MYF(MY_ALLOW_ZERO_PTR));
      order_by= 0;
3386
      if (opt_dump_triggers && ! opt_xml &&
unknown's avatar
unknown committed
3387
          mysql_get_server_version(mysql) >= 50009)
3388
        dump_triggers_for_table(table, database);
3389
    }
unknown's avatar
unknown committed
3390
  }
3391
  if (opt_events && !opt_xml &&
3392
      mysql_get_server_version(mysql) >= 50106)
3393 3394 3395 3396
  {
    DBUG_PRINT("info", ("Dumping events for database %s", database));
    dump_events_for_db(database);
  }
3397
  if (opt_routines && !opt_xml &&
unknown's avatar
unknown committed
3398
      mysql_get_server_version(mysql) >= 50009)
3399 3400 3401 3402
  {
    DBUG_PRINT("info", ("Dumping routines for database %s", database));
    dump_routines_for_db(database);
  }
unknown's avatar
unknown committed
3403
  if (opt_xml)
3404
  {
3405
    fputs("</database>\n", md_result_file);
3406 3407
    check_io(md_result_file);
  }
unknown's avatar
unknown committed
3408
  if (lock_tables)
unknown's avatar
unknown committed
3409
    VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES"));
3410 3411 3412 3413 3414
  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");
  }
unknown's avatar
unknown committed
3415
  DBUG_RETURN(0);
unknown's avatar
unknown committed
3416 3417 3418
} /* dump_all_tables_in_db */


3419 3420 3421 3422 3423 3424
/*
   dump structure of views of database

   SYNOPSIS
     dump_all_views_in_db()
     database  database name
unknown's avatar
unknown committed
3425

3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436
  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];

3437
  if (init_dumping(database, init_dumping_views))
3438
    return 1;
3439
  if (opt_xml)
3440
    print_xml_tag(md_result_file, "", "\n", "database", "name=", database, NullS);
3441 3442 3443
  if (lock_tables)
  {
    DYNAMIC_STRING query;
3444
    init_dynamic_string_checked(&query, "LOCK TABLES ", 256, 1024);
3445 3446
    for (numrows= 0 ; (table= getTableName(1)); numrows++)
    {
3447 3448
      dynstr_append_checked(&query, quote_name(table, table_buff, 1));
      dynstr_append_checked(&query, " READ /*!32311 LOCAL */,");
3449
    }
unknown's avatar
unknown committed
3450 3451
    if (numrows && mysql_real_query(mysql, query.str, query.length-1))
      DB_error(mysql, "when using LOCK TABLES");
3452 3453 3454 3455 3456
            /* We shall continue here, if --force was given */
    dynstr_free(&query);
  }
  if (flush_logs)
  {
unknown's avatar
unknown committed
3457 3458
    if (mysql_refresh(mysql, REFRESH_LOG))
      DB_error(mysql, "when doing refresh");
3459 3460 3461
           /* We shall continue here, if --force was given */
  }
  while ((table= getTableName(0)))
3462
     get_view_structure(table, database);
3463 3464 3465 3466 3467 3468
  if (opt_xml)
  {
    fputs("</database>\n", md_result_file);
    check_io(md_result_file);
  }
  if (lock_tables)
unknown's avatar
unknown committed
3469
    VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES"));
3470 3471
  return 0;
} /* dump_all_tables_in_db */
unknown's avatar
unknown committed
3472

unknown's avatar
unknown committed
3473

3474
/*
3475 3476 3477
  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
3478
  different case (e.g.  T1 vs t1)
3479

3480
  RETURN
unknown's avatar
unknown committed
3481 3482
    pointer to the table name
    0 if error
3483 3484
*/

unknown's avatar
unknown committed
3485
static char *get_actual_table_name(const char *old_table_name, MEM_ROOT *root)
3486
{
unknown's avatar
unknown committed
3487
  char *name= 0;
3488
  MYSQL_RES  *table_res;
3489
  MYSQL_ROW  row;
3490
  char query[50 + 2*NAME_LEN];
3491
  char show_name_buff[FN_REFLEN];
3492
  DBUG_ENTER("get_actual_table_name");
3493

3494 3495
  /* Check memory for quote_for_like() */
  DBUG_ASSERT(2*sizeof(old_table_name) < sizeof(show_name_buff));
3496
  my_snprintf(query, sizeof(query), "SHOW TABLES LIKE %s",
3497
              quote_for_like(old_table_name, show_name_buff));
3498

unknown's avatar
unknown committed
3499
  if (mysql_query_with_error_report(mysql, 0, query))
3500
    return NullS;
3501

unknown's avatar
unknown committed
3502
  if ((table_res= mysql_store_result(mysql)))
3503
  {
3504 3505 3506
    my_ulonglong num_rows= mysql_num_rows(table_res);
    if (num_rows > 0)
    {
unknown's avatar
unknown committed
3507
      ulong *lengths;
3508 3509 3510 3511 3512
      /*
        Return first row
        TODO: Return all matching rows
      */
      row= mysql_fetch_row(table_res);
unknown's avatar
unknown committed
3513
      lengths= mysql_fetch_lengths(table_res);
unknown's avatar
unknown committed
3514
      name= strmake_root(root, row[0], lengths[0]);
3515 3516
    }
    mysql_free_result(table_res);
3517
  }
unknown's avatar
unknown committed
3518 3519
  DBUG_PRINT("exit", ("new_table_name: %s", name));
  DBUG_RETURN(name);
3520
}
3521

unknown's avatar
unknown committed
3522 3523 3524

static int dump_selected_tables(char *db, char **table_names, int tables)
{
unknown's avatar
unknown committed
3525
  char table_buff[NAME_LEN*+3];
unknown's avatar
patch  
unknown committed
3526
  DYNAMIC_STRING lock_tables_query;
unknown's avatar
unknown committed
3527 3528
  MEM_ROOT root;
  char **dump_tables, **pos, **end;
unknown's avatar
patch  
unknown committed
3529
  DBUG_ENTER("dump_selected_tables");
unknown's avatar
unknown committed
3530

3531
  if (init_dumping(db, init_dumping_tables))
unknown's avatar
unknown committed
3532
    DBUG_RETURN(1);
unknown's avatar
patch  
unknown committed
3533

unknown's avatar
unknown committed
3534 3535
  init_alloc_root(&root, 8192, 0);
  if (!(dump_tables= pos= (char**) alloc_root(&root, tables * sizeof(char *))))
3536
     die(EX_EOM, "alloc_root failure.");
unknown's avatar
patch  
unknown committed
3537

3538
  init_dynamic_string_checked(&lock_tables_query, "LOCK TABLES ", 256, 1024);
unknown's avatar
patch  
unknown committed
3539
  for (; tables > 0 ; tables-- , table_names++)
unknown's avatar
unknown committed
3540
  {
unknown's avatar
patch  
unknown committed
3541
    /* the table name passed on commandline may be wrong case */
unknown's avatar
unknown committed
3542
    if ((*pos= get_actual_table_name(*table_names, &root)))
unknown's avatar
unknown committed
3543
    {
unknown's avatar
patch  
unknown committed
3544 3545 3546
      /* Add found table name to lock_tables_query */
      if (lock_tables)
      {
3547 3548
        dynstr_append_checked(&lock_tables_query, quote_name(*pos, table_buff, 1));
        dynstr_append_checked(&lock_tables_query, " READ /*!32311 LOCAL */,");
unknown's avatar
patch  
unknown committed
3549
      }
unknown's avatar
unknown committed
3550
      pos++;
unknown's avatar
unknown committed
3551
    }
unknown's avatar
patch  
unknown committed
3552
    else
unknown's avatar
unknown committed
3553
    {
3554
       maybe_die(EX_ILLEGAL_TABLE, "Couldn't find table: \"%s\"", *table_names);
unknown's avatar
patch  
unknown committed
3555
       /* We shall countinue here, if --force was given */
unknown's avatar
unknown committed
3556
    }
unknown's avatar
patch  
unknown committed
3557
  }
unknown's avatar
unknown committed
3558
  end= pos;
unknown's avatar
patch  
unknown committed
3559 3560 3561

  if (lock_tables)
  {
unknown's avatar
unknown committed
3562
    if (mysql_real_query(mysql, lock_tables_query.str,
unknown's avatar
patch  
unknown committed
3563
                         lock_tables_query.length-1))
unknown's avatar
unknown committed
3564
      DB_error(mysql, "when doing LOCK TABLES");
unknown's avatar
unknown committed
3565 3566
       /* We shall countinue here, if --force was given */
  }
unknown's avatar
patch  
unknown committed
3567
  dynstr_free(&lock_tables_query);
unknown's avatar
unknown committed
3568 3569
  if (flush_logs)
  {
unknown's avatar
unknown committed
3570 3571
    if (mysql_refresh(mysql, REFRESH_LOG))
      DB_error(mysql, "when doing refresh");
unknown's avatar
unknown committed
3572 3573
     /* We shall countinue here, if --force was given */
  }
unknown's avatar
unknown committed
3574
  if (opt_xml)
3575
    print_xml_tag(md_result_file, "", "\n", "database", "name=", db, NullS);
3576

unknown's avatar
patch  
unknown committed
3577
  /* Dump each selected table */
unknown's avatar
unknown committed
3578
  for (pos= dump_tables; pos < end; pos++)
unknown's avatar
unknown committed
3579
  {
unknown's avatar
unknown committed
3580 3581
    DBUG_PRINT("info",("Dumping table %s", *pos));
    dump_table(*pos, db);
3582
    if (opt_dump_triggers &&
unknown's avatar
unknown committed
3583
        mysql_get_server_version(mysql) >= 50009)
unknown's avatar
unknown committed
3584
      dump_triggers_for_table(*pos, db);
3585
  }
3586 3587

  /* Dump each selected view */
3588
  if (seen_views)
3589
  {
unknown's avatar
unknown committed
3590 3591
    for (pos= dump_tables; pos < end; pos++)
      get_view_structure(*pos, db);
unknown's avatar
unknown committed
3592
  }
3593
  if (opt_events && !opt_xml &&
3594
      mysql_get_server_version(mysql) >= 50106)
3595 3596 3597 3598
  {
    DBUG_PRINT("info", ("Dumping events for database %s", db));
    dump_events_for_db(db);
  }
3599 3600
  /* obtain dump of routines (procs/functions) */
  if (opt_routines  && !opt_xml &&
unknown's avatar
unknown committed
3601
      mysql_get_server_version(mysql) >= 50009)
3602 3603 3604 3605
  {
    DBUG_PRINT("info", ("Dumping routines for database %s", db));
    dump_routines_for_db(db);
  }
unknown's avatar
unknown committed
3606
  free_root(&root, MYF(0));
unknown's avatar
patch  
unknown committed
3607 3608
  my_free(order_by, MYF(MY_ALLOW_ZERO_PTR));
  order_by= 0;
unknown's avatar
unknown committed
3609
  if (opt_xml)
3610
  {
3611
    fputs("</database>\n", md_result_file);
3612 3613
    check_io(md_result_file);
  }
unknown's avatar
unknown committed
3614
  if (lock_tables)
unknown's avatar
unknown committed
3615
    VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES"));
unknown's avatar
patch  
unknown committed
3616
  DBUG_RETURN(0);
unknown's avatar
unknown committed
3617 3618 3619
} /* dump_selected_tables */


3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631
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
  {
unknown's avatar
unknown committed
3632
    row= mysql_fetch_row(master);
3633 3634
    if (row && row[0] && row[1])
    {
3635
      /* SHOW MASTER STATUS reports file and position */
3636 3637 3638 3639 3640 3641
      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",
3642
              comment_prefix, row[0], row[1]);
3643 3644
      check_io(md_result_file);
    }
3645 3646 3647
    else if (!ignore_errors)
    {
      /* SHOW MASTER STATUS reports nothing and --force is not enabled */
3648 3649
      my_printf_error(0, "Error: Binlogging on server not active",
                      MYF(0));
3650 3651 3652
      mysql_free_result(master);
      return 1;
    }
3653 3654 3655 3656 3657 3658 3659 3660
    mysql_free_result(master);
  }
  return 0;
}


static int do_flush_tables_read_lock(MYSQL *mysql_con)
{
3661 3662 3663 3664 3665 3666 3667 3668
  /*
    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.
  */
3669
  return
3670 3671 3672
    ( mysql_query_with_error_report(mysql_con, 0, "FLUSH TABLES") ||
      mysql_query_with_error_report(mysql_con, 0,
                                    "FLUSH TABLES WITH READ LOCK") );
3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687
}


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


static int do_reset_master(MYSQL *mysql_con)
{
  return mysql_query_with_error_report(mysql_con, 0, "RESET MASTER");
}


3688
static int start_transaction(MYSQL *mysql_con)
3689 3690 3691 3692 3693
{
  /*
    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).
3694 3695 3696 3697

    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).
3698 3699
  */
  return (mysql_query_with_error_report(mysql_con, 0,
3700 3701 3702
                                        "SET SESSION TRANSACTION ISOLATION "
                                        "LEVEL REPEATABLE READ") ||
          mysql_query_with_error_report(mysql_con, 0,
3703
                                        "START TRANSACTION "
3704
                                        "/*!40100 WITH CONSISTENT SNAPSHOT */"));
3705 3706
}

3707 3708

static ulong find_set(TYPELIB *lib, const char *x, uint length,
3709
                      char **err_pos, uint *err_len)
3710 3711 3712 3713 3714 3715
{
  const char *end= x + length;
  ulong found= 0;
  uint find;
  char buff[255];

3716
  *err_pos= 0;                  /* No error yet */
3717
  while (end > x && my_isspace(charset_info, end[-1]))
3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748
    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;
}


unknown's avatar
unknown committed
3749 3750
/* Print a value with a prefix on file */
static void print_value(FILE *file, MYSQL_RES  *result, MYSQL_ROW row,
3751 3752
                        const char *prefix, const char *name,
                        int string_value)
unknown's avatar
unknown committed
3753
{
3754
  MYSQL_FIELD   *field;
unknown's avatar
unknown committed
3755 3756
  mysql_field_seek(result, 0);

unknown's avatar
unknown committed
3757
  for ( ; (field= mysql_fetch_field(result)) ; row++)
unknown's avatar
unknown committed
3758 3759 3760 3761 3762
  {
    if (!strcmp(field->name,name))
    {
      if (row[0] && row[0][0] && strcmp(row[0],"0")) /* Skip default */
      {
3763 3764 3765 3766 3767 3768 3769 3770
        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;
unknown's avatar
unknown committed
3771 3772 3773
      }
    }
  }
3774
  return;                                       /* This shouldn't happen */
unknown's avatar
unknown committed
3775 3776 3777
} /* print_value */


3778 3779
/*
  SYNOPSIS
unknown's avatar
unknown committed
3780 3781 3782 3783

  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
3784 3785
  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
unknown's avatar
unknown committed
3786 3787 3788 3789
  supported, 1 if it is supported.

  ARGS

3790
    check_if_ignore_table()
3791
    table_name                  Table name to check
unknown's avatar
unknown committed
3792
    table_type                  Type of table
3793 3794

  GLOBAL VARIABLES
unknown's avatar
unknown committed
3795
    mysql                       MySQL connection
3796
    verbose                     Write warning messages
3797 3798

  RETURN
unknown's avatar
unknown committed
3799
    char (bit value)            See IGNORE_ values at top
3800 3801
*/

unknown's avatar
unknown committed
3802
char check_if_ignore_table(const char *table_name, char *table_type)
3803
{
3804
  char result= IGNORE_NONE;
3805
  char buff[FN_REFLEN+80], show_name_buff[FN_REFLEN];
unknown's avatar
unknown committed
3806
  MYSQL_RES *res= NULL;
3807
  MYSQL_ROW row;
unknown's avatar
unknown committed
3808
  DBUG_ENTER("check_if_ignore_table");
3809

3810 3811 3812
  /* 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",
3813
              quote_for_like(table_name, show_name_buff));
unknown's avatar
unknown committed
3814
  if (mysql_query_with_error_report(mysql, &res, buff))
3815
  {
unknown's avatar
unknown committed
3816
    if (mysql_errno(mysql) != ER_PARSE_ERROR)
3817
    {                                   /* If old MySQL version */
unknown's avatar
unknown committed
3818 3819
      verbose_msg("-- Warning: Couldn't get status information for "
                  "table %s (%s)\n", table_name, mysql_error(mysql));
3820
      DBUG_RETURN(result);                       /* assume table is ok */
3821 3822
    }
  }
3823
  if (!(row= mysql_fetch_row(res)))
3824 3825
  {
    fprintf(stderr,
3826
            "Error: Couldn't read status information for table %s (%s)\n",
unknown's avatar
unknown committed
3827
            table_name, mysql_error(mysql));
3828
    mysql_free_result(res);
3829
    DBUG_RETURN(result);                         /* assume table is ok */
3830
  }
3831
  if (!(row[1]))
unknown's avatar
unknown committed
3832
    strmake(table_type, "VIEW", NAME_LEN-1);
3833 3834
  else
  {
unknown's avatar
unknown committed
3835 3836 3837 3838 3839 3840
    /*
      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
    */
3841
    strmake(table_type, row[1], NAME_LEN-1);
unknown's avatar
unknown committed
3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854
    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
    */
3855
    if (!opt_no_data &&
unknown's avatar
unknown committed
3856 3857
        (!strcmp(table_type,"MRG_MyISAM") || !strcmp(table_type,"MRG_ISAM")))
      result= IGNORE_DATA;
3858
  }
3859
  mysql_free_result(res);
unknown's avatar
unknown committed
3860
  DBUG_RETURN(result);
3861 3862
}

unknown's avatar
unknown committed
3863

3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880
/*
  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.
*/
unknown's avatar
unknown committed
3881

3882 3883
static char *primary_key_fields(const char *table_name)
{
unknown's avatar
unknown committed
3884
  MYSQL_RES  *res= NULL;
3885 3886
  MYSQL_ROW  row;
  /* SHOW KEYS FROM + table name * 2 (escaped) + 2 quotes + \0 */
3887
  char show_keys_buff[15 + NAME_LEN * 2 + 3];
unknown's avatar
unknown committed
3888 3889
  uint result_length= 0;
  char *result= 0;
3890 3891
  char buff[NAME_LEN * 2 + 3];
  char *quoted_field;
3892

3893 3894
  my_snprintf(show_keys_buff, sizeof(show_keys_buff),
              "SHOW KEYS FROM %s", table_name);
unknown's avatar
unknown committed
3895
  if (mysql_query(mysql, show_keys_buff) ||
3896
      !(res= mysql_store_result(mysql)))
3897 3898 3899
  {
    fprintf(stderr, "Warning: Couldn't read keys from table %s;"
            " records are NOT sorted (%s)\n",
unknown's avatar
unknown committed
3900
            table_name, mysql_error(mysql));
3901 3902 3903 3904
    /* Don't exit, because it's better to print out unsorted records */
    goto cleanup;
  }

unknown's avatar
unknown committed
3905 3906 3907 3908 3909 3910
  /*
   * 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.
   */
unknown's avatar
unknown committed
3911
  if ((row= mysql_fetch_row(res)) && atoi(row[1]) == 0)
3912
  {
unknown's avatar
unknown committed
3913 3914
    /* Key is unique */
    do
3915 3916 3917 3918
    {
      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);
3919 3920 3921
  }

  /* Build the ORDER BY clause result */
unknown's avatar
unknown committed
3922 3923
  if (result_length)
  {
3924 3925
    char *end;
    /* result (terminating \0 is already in result_length) */
unknown's avatar
unknown committed
3926
    result= my_malloc(result_length + 10, MYF(MY_WME));
unknown's avatar
unknown committed
3927 3928
    if (!result)
    {
3929 3930 3931
      fprintf(stderr, "Error: Not enough memory to store ORDER BY clause\n");
      goto cleanup;
    }
unknown's avatar
unknown committed
3932
    mysql_data_seek(res, 0);
unknown's avatar
unknown committed
3933
    row= mysql_fetch_row(res);
3934 3935
    quoted_field= quote_name(row[4], buff, 0);
    end= strmov(result, quoted_field);
unknown's avatar
unknown committed
3936
    while ((row= mysql_fetch_row(res)) && atoi(row[3]) > 1)
3937 3938 3939 3940
    {
      quoted_field= quote_name(row[4], buff, 0);
      end= strxmov(end, ",", quoted_field, NullS);
    }
3941 3942 3943 3944 3945 3946 3947 3948 3949
  }

cleanup:
  if (res)
    mysql_free_result(res);

  return result;
}

3950

3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970
/*
  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)
{
unknown's avatar
unknown committed
3971
  DYNAMIC_STRING ds_tmp;
3972 3973 3974
  const char *start= strstr(ds_str->str, search_str);
  if (!start)
    return 1;
3975
  init_dynamic_string_checked(&ds_tmp, "",
3976
                      ds_str->length + replace_len, 256);
3977 3978 3979 3980
  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);
3981 3982 3983 3984 3985
  dynstr_free(&ds_tmp);
  return 0;
}


3986 3987 3988 3989
/*
  Getting VIEW structure

  SYNOPSIS
3990
    get_view_structure()
3991 3992 3993 3994 3995 3996 3997 3998
    table   view name
    db      db name

  RETURN
    0 OK
    1 ERROR
*/

3999
static my_bool get_view_structure(char *table, char* db)
4000
{
4001
  MYSQL_RES  *table_res;
4002 4003
  MYSQL_ROW  row;
  MYSQL_FIELD *field;
4004 4005 4006
  char       *result_table, *opt_quoted_table;
  char       table_buff[NAME_LEN*2+3];
  char       table_buff2[NAME_LEN*2+3];
4007
  char       query[QUERY_LENGTH];
unknown's avatar
unknown committed
4008
  FILE       *sql_file= md_result_file;
4009
  DBUG_ENTER("get_view_structure");
4010

4011
  if (opt_no_create_info) /* Don't write table creation info */
4012 4013
    DBUG_RETURN(0);

unknown's avatar
unknown committed
4014
  verbose_msg("-- Retrieving view structure for table %s...\n", table);
4015

unknown's avatar
unknown committed
4016
#ifdef NOT_REALLY_USED_YET
4017
  sprintf(insert_pat,"SET OPTION SQL_QUOTE_SHOW_CREATE=%d",
4018
          (opt_quoted || opt_keywords));
unknown's avatar
unknown committed
4019 4020
#endif

4021 4022 4023
  result_table=     quote_name(table, table_buff, 1);
  opt_quoted_table= quote_name(table, table_buff2, 0);

unknown's avatar
unknown committed
4024
  my_snprintf(query, sizeof(query), "SHOW CREATE TABLE %s", result_table);
unknown's avatar
unknown committed
4025
  if (mysql_query_with_error_report(mysql, &table_res, query))
4026 4027
    DBUG_RETURN(0);

4028 4029 4030 4031
  /* Check if this is a view */
  field= mysql_fetch_field_direct(table_res, 0);
  if (strcmp(field->name, "View") != 0)
  {
unknown's avatar
unknown committed
4032
    verbose_msg("-- It's base table, skipped\n");
4033 4034 4035 4036
    DBUG_RETURN(0);
  }

  /* If requested, open separate .sql file for this view */
4037 4038
  if (path)
  {
4039
    if (!(sql_file= open_sql_file_for_table(table)))
4040
      DBUG_RETURN(1);
4041

4042 4043 4044 4045 4046
    write_header(sql_file, db);
  }

  if (!opt_xml && opt_comments)
  {
4047
    fprintf(sql_file, "\n--\n-- Final view structure for view %s\n--\n\n",
4048 4049 4050 4051 4052
            result_table);
    check_io(sql_file);
  }
  if (opt_drop)
  {
4053 4054 4055 4056
    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);
4057 4058 4059 4060
    check_io(sql_file);
  }


unknown's avatar
unknown committed
4061 4062 4063 4064
  my_snprintf(query, sizeof(query),
              "SELECT CHECK_OPTION, DEFINER, SECURITY_TYPE "            \
              "FROM information_schema.views "                          \
              "WHERE table_name=\"%s\" AND table_schema=\"%s\"", table, db);
unknown's avatar
unknown committed
4065
  if (mysql_query(mysql, query))
4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086
  {
    /*
      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);
4087
    init_dynamic_string_checked(&ds_view, row[1], lengths[1] + 1, 1024);
4088 4089 4090
    mysql_free_result(table_res);

    /* Get the result from "select ... information_schema" */
unknown's avatar
unknown committed
4091
    if (!(table_res= mysql_store_result(mysql)) ||
4092
        !(row= mysql_fetch_row(table_res)))
4093
    {
4094
      DB_error(mysql, "when trying to save the result of SHOW CREATE TABLE in ds_view.");
4095 4096
      DBUG_RETURN(1);
    }
4097

4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128
    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
    */
    {
      uint       user_name_len;
      char       user_name_str[USERNAME_LENGTH + 1];
      char       quoted_user_name_str[USERNAME_LENGTH * 2 + 3];
      uint       host_name_len;
      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,
4129
                 host_name_str, &host_name_len);
4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156

      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 */
    fprintf(sql_file, "/*!50001 %s */;\n", ds_view.str);
    check_io(sql_file);
    mysql_free_result(table_res);
    dynstr_free(&ds_view);
  }

  /* If a separate .sql file was opened, close it now */
4157 4158 4159 4160 4161 4162 4163 4164 4165
  if (sql_file != md_result_file)
  {
    fputs("\n", sql_file);
    write_footer(sql_file);
    my_fclose(sql_file, MYF(MY_WME));
  }
  DBUG_RETURN(0);
}

4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204
/*
  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);
}

4205

unknown's avatar
unknown committed
4206 4207
int main(int argc, char **argv)
{
unknown's avatar
unknown committed
4208
  int exit_code;
4209 4210
  MY_INIT("mysqldump");

4211
  compatible_mode_normal_str[0]= 0;
4212
  default_charset= (char *)mysql_universal_client_charset;
unknown's avatar
unknown committed
4213
  bzero((char*) &ignore_table, sizeof(ignore_table));
unknown's avatar
unknown committed
4214

unknown's avatar
unknown committed
4215 4216
  exit_code= get_options(&argc, &argv);
  if (exit_code)
unknown's avatar
unknown committed
4217
  {
unknown's avatar
unknown committed
4218 4219
    free_resources(0);
    exit(exit_code);
unknown's avatar
unknown committed
4220
  }
unknown's avatar
unknown committed
4221 4222 4223
  if (connect_to_db(current_host, current_user, opt_password))
  {
    free_resources(0);
unknown's avatar
unknown committed
4224
    exit(EX_MYSQLERR);
unknown's avatar
unknown committed
4225
  }
unknown's avatar
unknown committed
4226
  if (!path)
4227 4228
    write_header(md_result_file, *argv);

4229
  if ((opt_lock_all_tables || opt_master_data) &&
unknown's avatar
unknown committed
4230
      do_flush_tables_read_lock(mysql))
4231
    goto err;
4232
  if (opt_single_transaction && start_transaction(mysql))
4233
      goto err;
unknown's avatar
unknown committed
4234
  if (opt_delete_master_logs && do_reset_master(mysql))
4235 4236
    goto err;
  if (opt_lock_all_tables || opt_master_data)
4237
  {
unknown's avatar
unknown committed
4238
    if (flush_logs && mysql_refresh(mysql, REFRESH_LOG))
4239 4240
      goto err;
    flush_logs= 0; /* not anymore; that would not be sensible */
4241
  }
unknown's avatar
unknown committed
4242
  if (opt_master_data && do_show_master_status(mysql))
4243
    goto err;
unknown's avatar
unknown committed
4244
  if (opt_single_transaction && do_unlock_tables(mysql)) /* unlock but no commit! */
4245 4246
    goto err;

4247 4248 4249
  if (opt_alltspcs)
    dump_all_tablespaces();

unknown's avatar
unknown committed
4250
  if (opt_alldbs)
4251 4252 4253
  {
    if (!opt_alltspcs && !opt_notspcs)
      dump_all_tablespaces();
unknown's avatar
unknown committed
4254
    dump_all_databases();
4255
  }
unknown's avatar
unknown committed
4256
  else if (argc > 1 && !opt_databases)
4257 4258
  {
    /* Only one database and selected table(s) */
4259 4260
    if (!opt_alltspcs && !opt_notspcs)
      dump_tablespaces_for_tables(*argv, (argv + 1), (argc -1));
unknown's avatar
unknown committed
4261
    dump_selected_tables(*argv, (argv + 1), (argc - 1));
4262
  }
unknown's avatar
unknown committed
4263
  else
4264 4265
  {
    /* One or more databases, all tables */
4266 4267
    if (!opt_alltspcs && !opt_notspcs)
      dump_tablespaces_for_databases(argv);
unknown's avatar
unknown committed
4268
    dump_databases(argv);
4269
  }
4270 4271 4272
#ifdef HAVE_SMEM
  my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR));
#endif
4273 4274 4275 4276 4277 4278 4279
  /*
    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:
unknown's avatar
unknown committed
4280
  dbDisconnect(current_host);
4281 4282
  if (!path)
    write_footer(md_result_file);
unknown's avatar
unknown committed
4283
  free_resources();
unknown's avatar
unknown committed
4284 4285
  return(first_error);
} /* main */