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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3 4 5 6
   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
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
7

bk@work.mysql.com's avatar
bk@work.mysql.com committed
8 9 10 11
   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.
12

bk@work.mysql.com's avatar
bk@work.mysql.com committed
13 14 15 16 17 18 19 20
   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 :-
**
21 22 23 24 25 26 27 28 29 30 31 32
** AUTHOR: Igor Romanenko (igor@frog.kiev.ua)
** DATE:   December 3, 1994
** WARRANTY: None, expressed, impressed, implied
**	    or other
** 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>
33
** Tõnu Samuel  <tonu@please.do.not.remove.this.spam.ee>
34 35
** XML by Gary Huntress <ghuntress@mediaone.net> 10/10/01, cleaned up
** and adapted to mysqldump 05/11/01 by Jani Tolonen
36
** Added --single-transaction option 06/06/2002 by Peter Zaitsev
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
37
** 10 Jun 2003: SET NAMES and --no-set-names by Alexander Barkov
38
*/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
39

40
#define DUMP_VERSION "10.9"
bk@work.mysql.com's avatar
bk@work.mysql.com committed
41

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

47
#include "client_priv.h"
bk@work.mysql.com's avatar
bk@work.mysql.com committed
48 49 50 51 52 53 54 55 56 57
#include "mysql.h"
#include "mysql_version.h"
#include "mysqld_error.h"

/* Exit codes */

#define EX_USAGE 1
#define EX_MYSQLERR 2
#define EX_CONSCHECK 3
#define EX_EOM 4
58
#define EX_EOF 5 /* ferror for output file was got */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
59 60 61 62 63 64 65 66 67

/* 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

68 69 70
/* Size of buffer for dump's select query */
#define QUERY_LENGTH 1536

bk@work.mysql.com's avatar
bk@work.mysql.com committed
71 72
static char *add_load_option(char *ptr, const char *object,
			     const char *statement);
73 74
static ulong find_set(TYPELIB *lib, const char *x, uint length,
		      char **err_pos, uint *err_len);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
75 76

static char *field_escape(char *to,const char *from,uint length);
77 78 79 80
static my_bool  verbose=0,tFlag=0,cFlag=0,dFlag=0,quick= 1, extended_insert= 1,
		lock_tables=1,ignore_errors=0,flush_logs=0,replace=0,
		ignore=0,opt_drop=1,opt_keywords=0,opt_lock=1,opt_compress=0,
                opt_delayed=0,create_options=1,opt_quoted=0,opt_databases=0,
81 82
                opt_alldbs=0,opt_create_db=0,opt_lock_all_tables=0,opt_set_charset,
		opt_autocommit=0,opt_disable_keys=1,opt_xml=0,
monty@mysql.com's avatar
monty@mysql.com committed
83
		opt_delete_master_logs=0, tty_password=0,
84 85
		opt_single_transaction=0, opt_comments= 0, opt_compact= 0,
		opt_hex_blob=0;
86
static ulong opt_max_allowed_packet, opt_net_buffer_length;
monty@mysql.com's avatar
monty@mysql.com committed
87
static MYSQL mysql_connection,*sock=0;
88
static char  insert_pat[12 * 1024],*opt_password=0,*current_user=0,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
89 90
             *current_host=0,*path=0,*fields_terminated=0,
             *lines_terminated=0, *enclosed=0, *opt_enclosed=0, *escaped=0,
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
91
             *where=0,
92
             *opt_compatible_mode_str= 0,
93
             *err_ptr= 0;
94
static char compatible_mode_normal_str[255];
95
static ulong opt_compatible_mode= 0;
96 97 98
#define MYSQL_OPT_MASTER_DATA_EFFECTIVE_SQL 1
#define MYSQL_OPT_MASTER_DATA_COMMENTED_SQL 2
static uint     opt_mysql_port= 0, err_len= 0, opt_master_data;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
99 100 101
static my_string opt_mysql_unix_port=0;
static int   first_error=0;
static DYNAMIC_STRING extended_row;
102
#include <sslopt-vars.h>
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
103
FILE  *md_result_file;
104 105 106
#ifdef HAVE_SMEM
static char *shared_memory_base_name=0;
#endif
107
static uint opt_protocol= 0;
108
static char *default_charset= (char*) MYSQL_UNIVERSAL_CLIENT_CHARSET;
109
static CHARSET_INFO *charset_info= &my_charset_latin1;
110
const char *default_dbug_option="d:t:o,/tmp/mysqldump.trace";
111 112
/* do we met VIEWs during tables scaning */
my_bool was_views= 0;
113 114 115 116

const char *compatible_mode_names[]=
{
  "MYSQL323", "MYSQL40", "POSTGRESQL", "ORACLE", "MSSQL", "DB2",
117 118
  "MAXDB", "NO_KEY_OPTIONS", "NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS",
  "ANSI",
119 120
  NullS
};
121 122 123 124 125 126 127 128 129
#define MASK_ANSI_QUOTES \
(\
 (1<<2)  | /* POSTGRESQL */\
 (1<<3)  | /* ORACLE     */\
 (1<<4)  | /* MSSQL      */\
 (1<<5)  | /* DB2        */\
 (1<<6)  | /* MAXDB      */\
 (1<<10)   /* ANSI       */\
)
130
TYPELIB compatible_mode_typelib= {array_elements(compatible_mode_names) - 1,
bar@mysql.com's avatar
bar@mysql.com committed
131
				  "", compatible_mode_names, NULL};
132

bk@work.mysql.com's avatar
bk@work.mysql.com committed
133

134
static struct my_option my_long_options[] =
bk@work.mysql.com's avatar
bk@work.mysql.com committed
135
{
136 137 138
  {"all", 'a', "Deprecated. Use --create-options instead.",
   (gptr*) &create_options, (gptr*) &create_options, 0, GET_BOOL, NO_ARG, 1,
   0, 0, 0, 0, 0},
139 140 141 142 143
  {"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},
  {"add-drop-table", OPT_DROP, "Add a 'drop table' before each create.",
144
   (gptr*) &opt_drop, (gptr*) &opt_drop, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0,
145 146
   0},
  {"add-locks", OPT_LOCKS, "Add locks around insert statements.",
147
   (gptr*) &opt_lock, (gptr*) &opt_lock, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0,
148 149 150 151 152
   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},
  {"character-sets-dir", OPT_CHARSETS_DIR,
153
   "Directory where character sets are.", (gptr*) &charsets_dir,
154
   (gptr*) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
155
  {"compatible", OPT_COMPATIBLE,
monty@mishka.local's avatar
monty@mishka.local committed
156
   "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.",
157 158
   (gptr*) &opt_compatible_mode_str, (gptr*) &opt_compatible_mode_str, 0,
   GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
159 160 161 162
  {"compact", OPT_COMPACT,
   "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-lock-tables",
   (gptr*) &opt_compact, (gptr*) &opt_compact, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
   0, 0},
163 164
  {"complete-insert", 'c', "Use complete insert statements.", (gptr*) &cFlag,
   (gptr*) &cFlag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
165 166 167
  {"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},
monty@mishka.local's avatar
monty@mishka.local committed
168 169 170 171
  {"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},
172 173 174 175
  {"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},
176 177 178 179 180 181 182
#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
183 184 185 186 187 188
  {"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},
  {"delayed-insert", OPT_DELAYED, "Insert rows with INSERT DELAYED.",
   (gptr*) &opt_delayed, (gptr*) &opt_delayed, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
   0, 0},
189
  {"delete-master-logs", OPT_DELETE_MASTER_LOGS,
190 191 192
   "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},
193 194
  {"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,
195
   (gptr*) &opt_disable_keys, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
196 197 198
  {"extended-insert", 'e',
   "Allows utilization of the new, much faster INSERT syntax.",
   (gptr*) &extended_insert, (gptr*) &extended_insert, 0, GET_BOOL, NO_ARG,
199
   1, 0, 0, 0, 0, 0},
200 201 202 203 204 205 206 207 208 209
  {"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 ...",
serg@serg.mylan's avatar
serg@serg.mylan committed
210
   (gptr*) &escaped, (gptr*) &escaped, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
211 212
  {"first-slave", 'x', "Deprecated, renamed to --lock-all-tables.",
   (gptr*) &opt_lock_all_tables, (gptr*) &opt_lock_all_tables, 0, GET_BOOL, NO_ARG,
213
   0, 0, 0, 0, 0, 0},
serg@serg.mylan's avatar
serg@serg.mylan committed
214
  {"flush-logs", 'F', "Flush logs file in server before starting dump. "
215 216 217 218 219 220 221 222
   "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",
223 224 225 226 227 228 229 230
   (gptr*) &flush_logs, (gptr*) &flush_logs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
   0, 0},
  {"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},
  {"host", 'h', "Connect to host.", (gptr*) &current_host,
231
   (gptr*) &current_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
232 233 234
  {"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},
235 236 237 238 239
  {"lock-all-tables", 'x', "Locks all tables across all databases. This " 
   "is achieved by taking a global read lock for the duration of the whole "
   "dump. Automatically turns --single-transaction 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},
240
  {"lock-tables", 'l', "Lock all tables for read.", (gptr*) &lock_tables,
241
   (gptr*) &lock_tables, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
242
  {"master-data", OPT_MASTER_DATA,
243 244 245 246 247 248 249 250 251 252 253
   "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,
   GET_UINT, REQUIRED_ARG, 0, 0, MYSQL_OPT_MASTER_DATA_COMMENTED_SQL, 0, 0, 0},
254 255 256 257
  {"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},
258 259 260 261 262
  /*
    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.
  */
263
  {"single-transaction", OPT_TRANSACTION,
264 265 266 267 268
   "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.",
269
   (gptr*) &opt_single_transaction, (gptr*) &opt_single_transaction, 0,
270
   GET_BOOL, NO_ARG,  0, 0, 0, 0, 0, 0},
271
  {"no-create-db", 'n',
272
   "'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.}.",
273 274 275
   (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.",
276 277 278
   (gptr*) &tFlag, (gptr*) &tFlag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
  {"no-data", 'd', "No row information.", (gptr*) &dFlag, (gptr*) &dFlag, 0,
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
279
  {"no-set-names", 'N',
280
   "Deprecated. Use --skip-set-charset instead.",
281 282
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
  {"set-charset", OPT_SET_CHARSET,
paul@kite-hub.kitebird.com's avatar
paul@kite-hub.kitebird.com committed
283
   "Add 'SET NAMES default_character_set' to the output. Enabled by default; suppress with --skip-set-charset.",
284 285
   (gptr*) &opt_set_charset, (gptr*) &opt_set_charset, 0, GET_BOOL, NO_ARG, 1,
   0, 0, 0, 0, 0},
286
  {"set-variable", 'O',
287
   "Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.",
288 289
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  {"opt", OPT_OPTIMIZE,
290
   "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.",
291 292 293 294
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
  {"password", 'p',
   "Password to use when connecting to server. If password is not given it's solicited on the tty.",
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
bk@work.mysql.com's avatar
bk@work.mysql.com committed
295
#ifdef __WIN__
296
  {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG,
297
   NO_ARG, 0, 0, 0, 0, 0, 0},
bk@work.mysql.com's avatar
bk@work.mysql.com committed
298
#endif
299 300 301
  {"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port,
   (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0,
   0},
302
  {"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).",
303
   0, 0, 0, GET_STR,  REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
304
  {"quick", 'q', "Don't buffer query, dump directly to stdout.",
305
   (gptr*) &quick, (gptr*) &quick, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
306
  {"quote-names",'Q', "Quote table and column names with backticks (`).",
307
   (gptr*) &opt_quoted, (gptr*) &opt_quoted, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0,
308 309
   0, 0},
  {"result-file", 'r',
serg@sergbook.mysql.com's avatar
serg@sergbook.mysql.com committed
310
   "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).",
311
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
312
#ifdef HAVE_SMEM
313
  {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
314
   "Base name of shared memory.", (gptr*) &shared_memory_base_name, (gptr*) &shared_memory_base_name,
315 316
   0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#endif
317
  {"skip-opt", OPT_SKIP_OPTIMIZATION,
318
   "Disable --opt. Disables --add-drop-table, --add-locks, --create-options, --quick, --extended-insert, --lock-tables, --set-charset, and --disable-keys.",
319
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
320 321 322
  {"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},
323
#include <sslopt-longopts.h>
324 325 326 327 328
  {"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},
bk@work.mysql.com's avatar
bk@work.mysql.com committed
329
#ifndef DONT_ALLOW_USER_CHANGE
330 331 332
  {"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},
bk@work.mysql.com's avatar
bk@work.mysql.com committed
333
#endif
334 335 336 337 338 339 340 341
  {"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},
342
  {"max_allowed_packet", OPT_MAX_ALLOWED_PACKET, "",
343
    (gptr*) &opt_max_allowed_packet, (gptr*) &opt_max_allowed_packet, 0,
344 345
    GET_ULONG, REQUIRED_ARG, 24*1024*1024, 4096, 
   (longlong) 2L*1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0},
346
  {"net_buffer_length", OPT_NET_BUFFER_LENGTH, "",
347
    (gptr*) &opt_net_buffer_length, (gptr*) &opt_net_buffer_length, 0,
348
    GET_ULONG, REQUIRED_ARG, 1024*1024L-1025, 4096, 16*1024L*1024L,
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
349
    MALLOC_OVERHEAD-1024, 1024, 0},
350 351 352
  {"comments", 'i', "Write additional information.",
   (gptr*) &opt_comments, (gptr*) &opt_comments, 0, GET_BOOL, NO_ARG,
   1, 0, 0, 0, 0, 0},
bar@mysql.com's avatar
bar@mysql.com committed
353
  {"hex-blob", OPT_HEXBLOB, "Dump BLOBs in HEX.",
354
   (gptr*) &opt_hex_blob, (gptr*) &opt_hex_blob, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
355
  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
356 357 358 359 360
};

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

static void safe_exit(int error);
361
static void write_header(FILE *sql_file, char *db_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
362 363 364 365 366 367 368 369
static void print_value(FILE *file, MYSQL_RES  *result, MYSQL_ROW row,
			const char *prefix,const char *name,
			int string_value);
static int dump_selected_tables(char *db, char **table_names, int tables);
static int dump_all_tables_in_db(char *db);
static int init_dumping(char *);
static int dump_databases(char **);
static int dump_all_databases();
370
static char *quote_name(const char *name, char *buff, my_bool force);
371
static const char *check_if_ignore_table(const char *table_name);
372 373
static my_bool getViewStructure(char *table, char* db);
static my_bool dump_all_views_in_db(char *database);
374

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

377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
/*
  exit with message if ferror(file)
  
  SYNOPSIS
    check_io()
    file	- checked file
*/

void check_io(FILE *file)
{
  if (ferror(file))
  {
    fprintf(stderr, "%s: Got errno %d on write\n", my_progname, errno);
    safe_exit(EX_EOF);
  }
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
394 395 396
static void print_version(void)
{
  printf("%s  Ver %s Distrib %s, for %s (%s)\n",my_progname,DUMP_VERSION,
monty@mysql.com's avatar
monty@mysql.com committed
397 398
         MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
  NETWARE_SET_SCREEN_MODE(1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
399 400 401
} /* print_version */


402 403 404 405 406 407
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",
	 my_progname);
  printf("OR     %s [OPTIONS] --all-databases [OPTIONS]\n", my_progname);
monty@mysql.com's avatar
monty@mysql.com committed
408
  NETWARE_SET_SCREEN_MODE(1);
409 410
}

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
412 413 414 415 416 417
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");
418
  short_usage_sub();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
419
  print_defaults("my",load_default_groups);
420 421
  my_print_help(my_long_options);
  my_print_variables(my_long_options);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
422 423 424
} /* usage */


425 426 427 428 429 430
static void short_usage(void)
{
  short_usage_sub();
  printf("For more options, use %s --help\n", my_progname);
}

monty@mysql.com's avatar
monty@mysql.com committed
431 432
#include <help_end.h>

433

434
static void write_header(FILE *sql_file, char *db_name)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
435
{
436
  if (opt_xml)
437
  {
438 439
    fputs("<?xml version=\"1.0\"?>\n", sql_file);
    fputs("<mysqldump>\n", sql_file);
440
    check_io(sql_file);
441
  }
442
  else if (!opt_compact)
443
  {
444 445 446 447 448 449 450 451 452 453 454
    if (opt_comments)
    {
      fprintf(sql_file, "-- MySQL dump %s\n--\n", DUMP_VERSION);
      fprintf(sql_file, "-- Host: %s    Database: %s\n",
	      current_host ? current_host : "localhost", db_name ? db_name :
	      "");
      fputs("-- ------------------------------------------------------\n",
	    sql_file);
      fprintf(sql_file, "-- Server version\t%s\n",
	      mysql_get_server_info(&mysql_connection));
    }
455
    if (opt_set_charset)
bar@bar.intranet.mysql.r18.ru's avatar
bar@bar.intranet.mysql.r18.ru committed
456 457 458 459 460
      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);
461 462 463
    if (!path)
    {
      fprintf(md_result_file,"\
464 465 466
/*!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\
");
467 468
    }
    fprintf(sql_file,
vva@eagle.mysql.r18.ru's avatar
Merge  
vva@eagle.mysql.r18.ru committed
469 470 471
	    "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE=\"%s%s%s\" */;\n",
	    path?"":"NO_AUTO_VALUE_ON_ZERO",compatible_mode_normal_str[0]==0?"":",",
	    compatible_mode_normal_str);
472
    check_io(sql_file);
473
  }
474
} /* write_header */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
475

476

477 478 479
static void write_footer(FILE *sql_file)
{
  if (opt_xml)
480
  {
481
    fputs("</mysqldump>\n", sql_file);
482 483
    check_io(sql_file);
  }
484
  else if (!opt_compact)
485
  {
486 487 488 489
    fprintf(sql_file,"\n/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;\n");
    if (!path)
    {
      fprintf(md_result_file,"\
490
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;\n\
491
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;\n");
492
    }
493
    if (opt_set_charset)
494
      fprintf(sql_file,
bar@bar.intranet.mysql.r18.ru's avatar
bar@bar.intranet.mysql.r18.ru committed
495 496 497
"/*!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");
498
    fputs("\n", sql_file);
499
    check_io(sql_file);
500
  }
501
} /* write_footer */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
502

503

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

505 506 507
static my_bool
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
	       char *argument)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
508
{
509
  switch (optid) {
510 511 512 513 514 515 516 517 518
  case 'p':
    if (argument)
    {
      char *start=argument;
      my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
      opt_password=my_strdup(argument,MYF(MY_FAE));
      while (*argument) *argument++= 'x';		/* Destroy argument */
      if (*start)
	start[1]=0;				/* Cut length of argument */
519
      tty_password= 0;
520 521 522 523 524
    }
    else
      tty_password=1;
    break;
  case 'r':
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
525
    if (!(md_result_file = my_fopen(argument, O_WRONLY | FILE_BINARY,
526 527 528 529
				    MYF(MY_WME))))
      exit(1);
    break;
  case 'W':
bk@work.mysql.com's avatar
bk@work.mysql.com committed
530
#ifdef __WIN__
531
    opt_protocol = MYSQL_PROTOCOL_PIPE;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
532
#endif
533
    break;
534 535 536
  case 'N':
    opt_set_charset= 0;
    break;
537 538 539 540
  case 'T':
    opt_disable_keys=0;
    break;
  case '#':
541
    DBUG_PUSH(argument ? argument : default_dbug_option);
542
    break;
543
#include <sslopt-case.h>
544 545 546
  case 'V': print_version(); exit(0);
  case 'X':
    opt_xml = 1;
547 548
    extended_insert= opt_drop= opt_lock= 
      opt_disable_keys= opt_autocommit= opt_create_db= 0;
549 550 551 552 553 554
    break;
  case 'I':
  case '?':
    usage();
    exit(0);
  case (int) OPT_OPTIMIZE:
555
    extended_insert= opt_drop= opt_lock= quick= create_options=
556
      opt_disable_keys= lock_tables= opt_set_charset= 1;
557
    break;
558 559
  case (int) OPT_SKIP_OPTIMIZATION:
    extended_insert= opt_drop= opt_lock= quick= create_options=
monty@mishka.local's avatar
monty@mishka.local committed
560
      opt_disable_keys= lock_tables= opt_set_charset= 0;
561
    break;
562 563 564 565
  case (int) OPT_COMPACT:
  if (opt_compact)
  {
    opt_comments= opt_drop= opt_disable_keys= opt_lock= 0;
566
    opt_set_charset= 0;
567
  }
568 569 570
  case (int) OPT_TABLES:
    opt_databases=0;
    break;
571 572 573
  case (int) OPT_COMPATIBLE:
    {  
      char buff[255];
574 575 576
      char *end= compatible_mode_normal_str;
      int i;
      ulong mode;
577 578

      opt_quoted= 1;
579
      opt_set_charset= 0;
580 581 582 583 584 585 586 587 588 589
      opt_compatible_mode_str= argument;
      opt_compatible_mode= find_set(&compatible_mode_typelib,
				    argument, strlen(argument),
				    &err_ptr, &err_len);
      if (err_len)
      {
	strmake(buff, err_ptr, min(sizeof(buff), err_len));
	fprintf(stderr, "Invalid mode to --compatible: %s\n", buff);
	exit(1);
      }
590 591
#if !defined(DBUG_OFF)
      {
monty@mysql.com's avatar
monty@mysql.com committed
592
	uint size_for_sql_mode= 0;
593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
	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);
      }
#endif
      mode= opt_compatible_mode;
      for (i= 0, mode= opt_compatible_mode; mode; mode>>= 1, i++)
      {
	if (mode & 1)
	{
	  end= strmov(end, compatible_mode_names[i]);
	  end= strmov(end, ",");
	}
      }
      if (end!=compatible_mode_normal_str)
	end[-1]= 0;
611 612 613
      break;
    }
  case (int) OPT_MYSQL_PROTOCOL:
614
    {
615
      if ((opt_protocol= find_type(argument, &sql_protocol_typelib,0)) <= 0)
616 617 618 619 620
      {
	fprintf(stderr, "Unknown option to protocol: %s\n", argument);
	exit(1);
      }
      break;
621
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
622
  }
623 624 625 626 627 628
  return 0;
}

static int get_options(int *argc, char ***argv)
{
  int ho_error;
629 630 631 632
  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;
633 634 635 636

  md_result_file= stdout;
  load_defaults("my",load_default_groups,argc,argv);

637
  if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
638
    exit(ho_error);
639

640 641 642
  *mysql_params->p_max_allowed_packet= opt_max_allowed_packet;
  *mysql_params->p_net_buffer_length= opt_net_buffer_length;

bk@work.mysql.com's avatar
bk@work.mysql.com committed
643 644 645 646 647
  if (opt_delayed)
    opt_lock=0;				/* Can't have lock with delayed */
  if (!path && (enclosed || opt_enclosed || escaped || lines_terminated ||
		fields_terminated))
  {
648 649
    fprintf(stderr,
	    "%s: You must use option --tab with --fields-...\n", my_progname);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
650 651
    return(1);
  }
652 653 654 655 656 657 658 659 660 661 662 663 664

  /* 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);
    return(1);
  }  
  if (opt_master_data)
    opt_lock_all_tables= !opt_single_transaction;
  if (opt_single_transaction || opt_lock_all_tables)
665
    lock_tables= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682
  if (enclosed && opt_enclosed)
  {
    fprintf(stderr, "%s: You can't use ..enclosed.. and ..optionally-enclosed.. at the same time.\n", my_progname);
    return(1);
  }
  if (replace && ignore)
  {
    fprintf(stderr, "%s: You can't use --ignore (-i) and --replace (-r) at the same time.\n",my_progname);
    return(1);
  }
  if ((opt_databases || opt_alldbs) && path)
  {
    fprintf(stderr,
	    "%s: --databases or --all-databases can't be used with --tab.\n",
	    my_progname);
    return(1);
  }
683 684
  if (strcmp(default_charset, charset_info->csname) &&
      !(charset_info= get_charset_by_csname(default_charset, 
685
  					    MY_CS_PRIMARY, MYF(MY_WME))))
686
    exit(1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
687 688
  if ((*argc < 1 && !opt_alldbs) || (*argc > 0 && opt_alldbs))
  {
689
    short_usage();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
690 691 692
    return 1;
  }
  if (tty_password)
693
    opt_password=get_tty_password(NullS);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
694 695 696 697 698 699 700 701 702 703
  return(0);
} /* get_options */


/*
** DBerror -- prints mysql error message and exits the program.
*/
static void DBerror(MYSQL *mysql, const char *when)
{
  DBUG_ENTER("DBerror");
704
  my_printf_error(0,"Got error: %d: %s %s", MYF(0),
bk@work.mysql.com's avatar
bk@work.mysql.com committed
705 706 707 708 709 710
		  mysql_errno(mysql), mysql_error(mysql), when);
  safe_exit(EX_MYSQLERR);
  DBUG_VOID_RETURN;
} /* DBerror */


711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740
/*
  Sends a query to server, optionally reads result, prints error message if
  some.

  SYNOPSIS
    mysql_query_with_error_report()
    mysql_con       connection to use
    res             if non zero, result will be put there with mysql_store_result
    query           query to send to server

  RETURN VALUES
    0               query sending and (if res!=0) result reading went ok
    1               error
*/
  
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))))
  {
    my_printf_error(0, "%s: Couldn't execute '%s': %s (%d)",
                    MYF(0), my_progname, query,
                    mysql_error(mysql_con), mysql_errno(mysql_con));
    return 1;
  }
  return 0;
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759
static void safe_exit(int error)
{
  if (!first_error)
    first_error= error;
  if (ignore_errors)
    return;
  if (sock)
    mysql_close(sock);
  exit(error);
}
/* safe_exit */


/*
** dbConnect -- connects to the host and selects DB.
**        Also checks whether the tablename is a valid table name.
*/
static int dbConnect(char *host, char *user,char *passwd)
{
760
  char buff[20+FN_REFLEN];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
761 762 763
  DBUG_ENTER("dbConnect");
  if (verbose)
  {
764
    fprintf(stderr, "-- Connecting to %s...\n", host ? host : "localhost");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
765 766 767 768 769 770 771
  }
  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,
772
		  opt_ssl_capath, opt_ssl_cipher);
773 774 775 776 777 778
#endif
  if (opt_protocol)
    mysql_options(&mysql_connection,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
#ifdef HAVE_SMEM
  if (shared_memory_base_name)
    mysql_options(&mysql_connection,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
779
#endif
780
  mysql_options(&mysql_connection, MYSQL_SET_CHARSET_NAME, default_charset);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
781 782 783 784 785 786 787
  if (!(sock= mysql_real_connect(&mysql_connection,host,user,passwd,
         NULL,opt_mysql_port,opt_mysql_unix_port,
         0)))
  {
    DBerror(&mysql_connection, "when trying to connect");
    return 1;
  }
788 789 790 791 792
  /*
    As we're going to set SQL_MODE, it would be lost on reconnect, so we
    cannot reconnect.
  */
  sock->reconnect= 0;
793 794
  sprintf(buff, "/*!40100 SET @@SQL_MODE=\"%s\" */",
	  compatible_mode_normal_str);
795
  if (mysql_query_with_error_report(sock, 0, buff))
796 797 798 799 800
  {
    mysql_close(sock);
    safe_exit(EX_MYSQLERR);
    return 1;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
801 802 803 804 805 806 807 808 809 810
  return 0;
} /* dbConnect */


/*
** dbDisconnect -- disconnects from the host.
*/
static void dbDisconnect(char *host)
{
  if (verbose)
811
    fprintf(stderr, "-- Disconnecting from %s...\n", host ? host : "localhost");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
812 813 814 815 816 817 818 819 820 821 822 823 824
  mysql_close(sock);
} /* 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))))
  {
    ignore_errors=0;				/* Fatal error */
    safe_exit(EX_MYSQLERR);			/* Force exit */
  }
825
  mysql_real_escape_string(&mysql_connection, tmp, pos, length);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
826 827 828
  fputc('\'', file);
  fputs(tmp, file);
  fputc('\'', file);
829
  check_io(file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
830 831 832 833 834 835 836 837 838
  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++)
839
    if (!my_isvar(charset_info,*str) && *str != '$')
bk@work.mysql.com's avatar
bk@work.mysql.com committed
840 841 842 843 844
      return 1;
#endif
  return 0;
} /* test_if_special_chars */

845

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

847
static char *quote_name(const char *name, char *buff, my_bool force)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
848
{
849
  char *to= buff;
850 851
  char qtype= (opt_compatible_mode & MASK_ANSI_QUOTES) ? '\"' : '`';

852 853
  if (!force && !opt_quoted && !test_if_special_chars(name))
    return (char*) name;
854
  *to++= qtype;
855 856
  while (*name)
  {
857 858
    if (*name == qtype)
      *to++= qtype;
859 860
    *to++= *name++;
  }
861 862
  to[0]= qtype;
  to[1]= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
863 864 865 866
  return buff;
} /* quote_name */


867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883

static char *quote_for_like(const char *name, char *buff)
{
  char *to= buff;
  *to++= '\'';
  while (*name)
  {
    if (*name == '\'' || *name == '_' || *name == '\\' || *name == '%')
      *to++= '\\';
    *to++= *name++;
  }
  to[0]= '\'';
  to[1]= 0;
  return buff;
}


884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920
/*
  Quote and print a string.
  
  SYNOPSIS
    print_quoted_xml()
    output	- output file
    str		- string to print
    len		- its length
    
  DESCRIPTION
    Quote '<' '>' '&' '\"' singns and print a string to the xml_file.
*/

static void print_quoted_xml(FILE *xml_file, const char *str, ulong len)
{
  const char *end;
  
  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;
    }
  }
921
  check_io(xml_file);
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
}


/*
  Print xml tag with one attribute.
  
  SYNOPSIS
    print_xml_tag1()
    xml_file	- output file
    sbeg	- line beginning
    stag_atr	- tag and attribute
    sval	- value of attribute
    send	- line ending
    
  DESCRIPTION
    Print tag with one attribute to the xml_file. Format is:
      sbeg<stag_atr="sval">send
  NOTE
    sval MUST be a NULL terminated string.
    sval string will be qouted before output.
*/

static void print_xml_tag1(FILE * xml_file, const char* sbeg,
			   const char* stag_atr, const char* sval,
			   const char* send)
{
  fputs(sbeg, xml_file);
  fputs("<", xml_file);
  fputs(stag_atr, xml_file);
  fputs("\"", xml_file);
  print_quoted_xml(xml_file, sval, strlen(sval));
  fputs("\">", xml_file);
  fputs(send, xml_file);
955
  check_io(xml_file);
956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977
}


/*
  Print xml tag with many attributes.

  SYNOPSIS
    print_xml_row()
    xml_file	- output file
    row_name	- xml tag name
    tableRes	- query result
    row		- result row
    
  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,
			  MYSQL_RES *tableRes, MYSQL_ROW *row)
978 979 980 981 982 983
{
  uint i;
  MYSQL_FIELD *field;
  ulong *lengths= mysql_fetch_lengths(tableRes);
  
  fprintf(xml_file, "\t\t<%s", row_name);
984
  check_io(xml_file);
985 986 987
  mysql_field_seek(tableRes, 0);
  for (i= 0; (field= mysql_fetch_field(tableRes)); i++)
  {
988
    if ((*row)[i])
989
    {
monty@mishka.local's avatar
monty@mishka.local committed
990
      fputc(' ', xml_file);
991
      print_quoted_xml(xml_file, field->name, field->name_length);
992 993
      fputs("=\"", xml_file);
      print_quoted_xml(xml_file, (*row)[i], lengths[i]);
monty@mishka.local's avatar
monty@mishka.local committed
994
      fputc('"', xml_file);
995
      check_io(xml_file);
996 997 998
    }
  }
  fputs(" />\n", xml_file);
999
  check_io(xml_file);
1000 1001
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1002
/*
1003 1004 1005 1006 1007
  getStructure -- retrievs database structure, prints out corresponding
  CREATE statement and fills out insert_pat.

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1010 1011 1012 1013 1014 1015
static uint getTableStructure(char *table, char* db)
{
  MYSQL_RES  *tableRes;
  MYSQL_ROW  row;
  my_bool    init=0;
  uint       numFields;
1016
  char	     *strpos, *result_table, *opt_quoted_table;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1017
  const char *delayed;
1018 1019
  char	     name_buff[NAME_LEN+3],table_buff[NAME_LEN*2+3];
  char	     table_buff2[NAME_LEN*2+3];
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1020
  FILE       *sql_file = md_result_file;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1021 1022 1023 1024 1025
  DBUG_ENTER("getTableStructure");

  delayed= opt_delayed ? " DELAYED " : "";

  if (verbose)
1026
    fprintf(stderr, "-- Retrieving table structure for table %s...\n", table);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1027

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1028 1029
  sprintf(insert_pat,"SET OPTION SQL_QUOTE_SHOW_CREATE=%d",
	  (opt_quoted || opt_keywords));
monty@mishka.local's avatar
monty@mishka.local committed
1030
  if (!create_options)
monty@mysql.com's avatar
monty@mysql.com committed
1031
    strmov(strend(insert_pat), "/*!40102 ,SQL_MODE=concat(@@sql_mode, _utf8 ',NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS') */");
monty@mishka.local's avatar
monty@mishka.local committed
1032

1033 1034
  result_table=     quote_name(table, table_buff, 1);
  opt_quoted_table= quote_name(table, table_buff2, 0);
1035
  if (!opt_xml && !mysql_query_with_error_report(sock, 0, insert_pat))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1036
  {
1037 1038
    /* using SHOW CREATE statement */
    if (!tFlag)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1039
    {
1040 1041
      /* Make an sql-file, if path was given iow. option -T was given */
      char buff[20+FN_REFLEN];
1042
      MYSQL_FIELD *field;
1043

1044
      sprintf(buff,"show create table %s", result_table);
1045
      if (mysql_query_with_error_report(sock, 0, buff))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1046
      {
1047 1048
        safe_exit(EX_MYSQLERR);
        DBUG_RETURN(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1049 1050
      }

1051 1052 1053
      if (path)
      {
        char filename[FN_REFLEN], tmp_path[FN_REFLEN];
1054
        convert_dirname(tmp_path,path,NullS);
1055
        sql_file= my_fopen(fn_format(filename, table, tmp_path, ".sql", 4),
1056
				 O_WRONLY, MYF(MY_WME));
1057 1058
        if (!sql_file)			/* If file couldn't be opened */
        {
1059 1060
	  safe_exit(EX_MYSQLERR);
	  DBUG_RETURN(0);
1061
        }
1062
        write_header(sql_file, db);
1063
      }
1064
      if (!opt_xml && opt_comments)
1065
      {
monty@mysql.com's avatar
monty@mysql.com committed
1066
        fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n",
1067
		result_table);
1068 1069
	check_io(sql_file);
      }
1070
      if (opt_drop)
1071
      {
1072
        fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", opt_quoted_table);
1073 1074
	check_io(sql_file);
      }
1075

1076 1077 1078 1079 1080 1081 1082 1083 1084 1085
      tableRes= mysql_store_result(sock);
      field= mysql_fetch_field_direct(tableRes, 0);
      if (strcmp(field->name, "View") == 0)
      {
        if (verbose)
          fprintf(stderr, "-- It's a view, skipped\n");
        was_views= 1;
        DBUG_RETURN(0);
      }
      row= mysql_fetch_row(tableRes);
1086
      fprintf(sql_file, "%s;\n", row[1]);
1087
      check_io(sql_file);
1088 1089
      mysql_free_result(tableRes);
    }
1090
    sprintf(insert_pat,"show fields from %s", result_table);
1091
    if (mysql_query_with_error_report(sock, &tableRes, insert_pat))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1092
    {
1093 1094
      if (path)
	my_fclose(sql_file, MYF(MY_WME));
1095 1096
      safe_exit(EX_MYSQLERR);
      DBUG_RETURN(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1097
    }
1098

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1099
    if (cFlag)
1100
      sprintf(insert_pat, "INSERT %sINTO %s (", delayed, opt_quoted_table);
1101
    else
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1102
    {
1103 1104
      sprintf(insert_pat, "INSERT %sINTO %s VALUES ", delayed,
	      opt_quoted_table);
1105 1106 1107 1108 1109 1110 1111 1112
      if (!extended_insert)
        strcat(insert_pat,"(");
    }

    strpos=strend(insert_pat);
    while ((row=mysql_fetch_row(tableRes)))
    {
      if (init)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1113
      {
1114
        if (cFlag)
1115
	  strpos=strmov(strpos,", ");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1116
      }
1117 1118
      init=1;
      if (cFlag)
1119
        strpos=strmov(strpos,quote_name(row[SHOW_FIELDNAME], name_buff, 0));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1120
    }
1121 1122
    numFields = (uint) mysql_num_rows(tableRes);
    mysql_free_result(tableRes);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1123
  }
1124
  else
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1125
  {
monty@mishka.local's avatar
monty@mishka.local committed
1126 1127 1128 1129
    if (verbose)
      fprintf(stderr,
              "%s: Warning: Can't set SQL_QUOTE_SHOW_CREATE option (%s)\n",
              my_progname, mysql_error(sock));
1130

1131
    sprintf(insert_pat,"show fields from %s", result_table);
1132
    if (mysql_query_with_error_report(sock, &tableRes, insert_pat))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1133 1134 1135 1136 1137
    {
      safe_exit(EX_MYSQLERR);
      DBUG_RETURN(0);
    }

1138 1139
    /* Make an sql-file, if path was given iow. option -T was given */
    if (!tFlag)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1140
    {
1141
      if (path)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1142
      {
1143
        char filename[FN_REFLEN], tmp_path[FN_REFLEN];
1144
        convert_dirname(tmp_path,path,NullS);
1145 1146 1147 1148
        sql_file= my_fopen(fn_format(filename, table, tmp_path, ".sql", 4),
				 O_WRONLY, MYF(MY_WME));
        if (!sql_file)			/* If file couldn't be opened */
        {
1149 1150
	  safe_exit(EX_MYSQLERR);
	  DBUG_RETURN(0);
1151
        }
1152
        write_header(sql_file, db);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1153
      }
1154
      if (!opt_xml && opt_comments)
1155 1156
	fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n",
		result_table);
1157
      if (opt_drop)
1158
        fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n",result_table);
1159 1160 1161
      if (!opt_xml)
	fprintf(sql_file, "CREATE TABLE %s (\n", result_table);
      else
1162
        print_xml_tag1(sql_file, "\t", "table_structure name=", table, "\n");
1163
      check_io(sql_file);
1164 1165
    }
    if (cFlag)
1166
      sprintf(insert_pat, "INSERT %sINTO %s (", delayed, result_table);
1167 1168
    else
    {
1169
      sprintf(insert_pat, "INSERT %sINTO %s VALUES ", delayed, result_table);
1170 1171
      if (!extended_insert)
        strcat(insert_pat,"(");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1172
    }
1173 1174

    strpos=strend(insert_pat);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1175 1176
    while ((row=mysql_fetch_row(tableRes)))
    {
1177 1178
      ulong *lengths=mysql_fetch_lengths(tableRes);
      if (init)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1179
      {
1180
        if (!opt_xml && !tFlag)
1181
	{
1182
	  fputs(",\n",sql_file);
1183 1184
	  check_io(sql_file);
	}
1185
        if (cFlag)
1186
	  strpos=strmov(strpos,", ");
1187 1188 1189
      }
      init=1;
      if (cFlag)
1190
        strpos=strmov(strpos,quote_name(row[SHOW_FIELDNAME], name_buff, 0));
1191 1192
      if (!tFlag)
      {
1193 1194 1195 1196 1197 1198
	if (opt_xml)
	{
	  print_xml_row(sql_file, "field", tableRes, &row);
	  continue;
	}
	
1199
        if (opt_keywords)
1200
	  fprintf(sql_file, "  %s.%s %s", result_table,
1201 1202
		  quote_name(row[SHOW_FIELDNAME],name_buff, 0),
		  row[SHOW_TYPE]);
1203
        else
1204
	  fprintf(sql_file, "  %s %s", quote_name(row[SHOW_FIELDNAME],
1205 1206
						  name_buff, 0),
		  row[SHOW_TYPE]);
1207 1208
        if (row[SHOW_DEFAULT])
        {
1209
	  fputs(" DEFAULT ", sql_file);
1210
	  unescape(sql_file, row[SHOW_DEFAULT], lengths[SHOW_DEFAULT]);
1211 1212
        }
        if (!row[SHOW_NULL][0])
1213
	  fputs(" NOT NULL", sql_file);
1214
        if (row[SHOW_EXTRA][0])
1215
	  fprintf(sql_file, " %s",row[SHOW_EXTRA]);
1216
	check_io(sql_file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1217 1218
      }
    }
1219 1220 1221
    numFields = (uint) mysql_num_rows(tableRes);
    mysql_free_result(tableRes);
    if (!tFlag)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1222
    {
1223 1224 1225
      /* Make an sql-file, if path was given iow. option -T was given */
      char buff[20+FN_REFLEN];
      uint keynr,primary_key;
1226
      sprintf(buff,"show keys from %s", result_table);
1227
      if (mysql_query_with_error_report(sock, &tableRes, buff))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1228
      {
1229 1230 1231 1232 1233 1234 1235 1236
        if (mysql_errno(sock) == ER_WRONG_OBJECT)
        {
          /* 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",
		my_progname, result_table, mysql_error(sock));
1237
        if (path)
1238
	  my_fclose(sql_file, MYF(MY_WME));
1239 1240
        safe_exit(EX_MYSQLERR);
        DBUG_RETURN(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1241
      }
1242 1243 1244 1245 1246

      /* Find first which key is primary key */
      keynr=0;
      primary_key=INT_MAX;
      while ((row=mysql_fetch_row(tableRes)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1247
      {
1248 1249
        if (atoi(row[3]) == 1)
        {
1250 1251 1252 1253 1254 1255 1256 1257 1258 1259
	  keynr++;
#ifdef FORCE_PRIMARY_KEY
	  if (atoi(row[1]) == 0 && primary_key == INT_MAX)
	    primary_key=keynr;
#endif
	  if (!strcmp(row[2],"PRIMARY"))
	  {
	    primary_key=keynr;
	    break;
	  }
1260
        }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1261
      }
1262 1263 1264 1265
      mysql_data_seek(tableRes,0);
      keynr=0;
      while ((row=mysql_fetch_row(tableRes)))
      {
1266 1267 1268 1269 1270 1271
	if (opt_xml)
	{
	  print_xml_row(sql_file, "key", tableRes, &row);
	  continue;
	}
        
1272 1273
        if (atoi(row[3]) == 1)
        {
1274 1275 1276 1277
	  if (keynr++)
	    putc(')', sql_file);
	  if (atoi(row[1]))       /* Test if duplicate key */
	    /* Duplicate allowed */
1278
	    fprintf(sql_file, ",\n  KEY %s (",quote_name(row[2],name_buff,0));
1279 1280 1281
	  else if (keynr == primary_key)
	    fputs(",\n  PRIMARY KEY (",sql_file); /* First UNIQUE is primary */
	  else
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1282 1283
	    fprintf(sql_file, ",\n  UNIQUE %s (",quote_name(row[2],name_buff,
							    0));
1284 1285
        }
        else
1286
	  putc(',', sql_file);
1287
        fputs(quote_name(row[4], name_buff, 0), sql_file);
1288
        if (row[7])
1289
	  fprintf(sql_file, " (%s)",row[7]);      /* Sub key */
1290
	check_io(sql_file);
1291
      }
1292 1293 1294 1295 1296
      if (!opt_xml)
      {
	if (keynr)
	  putc(')', sql_file);
	fputs("\n)",sql_file);
1297
	check_io(sql_file);
1298
      }
1299 1300 1301

      /* Get MySQL specific create options */
      if (create_options)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1302
      {
1303 1304 1305
	char show_name_buff[FN_REFLEN];
        sprintf(buff,"show table status like %s",
		quote_for_like(table, show_name_buff));
1306
        if (mysql_query_with_error_report(sock, &tableRes, buff))
1307
        {
1308 1309 1310 1311
	  if (mysql_errno(sock) != ER_PARSE_ERROR)
	  {					/* If old MySQL version */
	    if (verbose)
	      fprintf(stderr,
1312 1313
		      "-- Warning: Couldn't get status information for table %s (%s)\n",
		      result_table,mysql_error(sock));
1314
	  }
1315
        }
1316
        else if (!(row=mysql_fetch_row(tableRes)))
1317
        {
1318
	  fprintf(stderr,
1319 1320
		  "Error: Couldn't read status information for table %s (%s)\n",
		  result_table,mysql_error(sock));
1321 1322 1323
        }
        else
        {
1324 1325 1326 1327 1328 1329 1330
	  if (opt_xml)
	  {
	    print_xml_row(sql_file, "options", tableRes, &row);
	  }
	  else
	  {
	    fputs("/*!",sql_file);
monty@mishka.local's avatar
monty@mishka.local committed
1331
	    print_value(sql_file,tableRes,row,"engine=","Engine",0);
1332 1333 1334
	    print_value(sql_file,tableRes,row,"","Create_options",0);
	    print_value(sql_file,tableRes,row,"comment=","Comment",1);
	    fputs(" */",sql_file);
1335
	    check_io(sql_file);
1336
	  }
1337 1338
        }
        mysql_free_result(tableRes);		/* Is always safe to free */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1339
      }
1340
continue_xml:
1341 1342 1343 1344
      if (!opt_xml)
	fputs(";\n", sql_file);
      else
	fputs("\t</table_structure>\n", sql_file);
1345
      check_io(sql_file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1346 1347 1348 1349 1350 1351 1352 1353
    }
  }
  if (cFlag)
  {
    strpos=strmov(strpos,") VALUES ");
    if (!extended_insert)
      strpos=strmov(strpos,"(");
  }
1354
  if (sql_file != md_result_file)
1355 1356 1357
  {
    fputs("\n", sql_file);
    write_footer(sql_file);
1358
    my_fclose(sql_file, MYF(MY_WME));
1359
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1360 1361 1362 1363 1364 1365 1366 1367 1368
  DBUG_RETURN(numFields);
} /* getTableStructure */


static char *add_load_option(char *ptr,const char *object,
			     const char *statement)
{
  if (object)
  {
1369 1370 1371 1372 1373 1374 1375 1376 1377 1378
    /* Don't escape hex constants */
    if (object[0] == '0' && (object[1] == 'x' || object[1] == 'X'))
      ptr= strxmov(ptr," ",statement," ",object,NullS);
    else
    {
      /* char constant; escape */
      ptr= strxmov(ptr," ",statement," '",NullS);
      ptr= field_escape(ptr,object,(uint) strlen(object));
      *ptr++= '\'';
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414
  }
  return ptr;
} /* add_load_option */


/*
** Allow the user to specify field terminator strings like:
** "'", "\", "\\" (escaped backslash), "\t" (tab), "\n" (newline)
** This is done by doubleing ' and add a end -\ if needed to avoid
** syntax errors from the SQL parser.
*/

static char *field_escape(char *to,const char *from,uint length)
{
  const char *end;
  uint end_backslashes=0;

  for (end= from+length; from != end; from++)
  {
    *to++= *from;
    if (*from == '\\')
      end_backslashes^=1;    /* find odd number of backslashes */
    else
    {
      if (*from == '\'' && !end_backslashes)
	*to++= *from;      /* We want a duplicate of "'" for MySQL */
      end_backslashes=0;
    }
  }
  /* Add missing backslashes if user has specified odd number of backs.*/
  if (end_backslashes)
    *to++= '\\';
  return to;
} /* field_escape */


1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426
static char *alloc_query_str(ulong size)
{
  char *query;

  if (!(query= (char*) my_malloc(size, MYF(MY_WME))))
  {
    ignore_errors= 0;   			/* Fatal error */
    safe_exit(EX_MYSQLERR);			/* Force exit */
  }
  return query;
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1427 1428 1429 1430 1431
/*
** dumpTable saves database contents as a series of INSERT statements.
*/
static void dumpTable(uint numFields, char *table)
{
1432
  char query_buf[QUERY_LENGTH], *end, buff[256],table_buff[NAME_LEN+3];
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1433
  char *result_table, table_buff2[NAME_LEN*2+3], *opt_quoted_table;
1434
  char *query= query_buf;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1435
  MYSQL_RES	*res;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1436 1437
  MYSQL_FIELD	*field;
  MYSQL_ROW	row;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1438
  ulong		rownr, row_break, total_length, init_length;
1439
  const char    *table_type;
1440
  int error= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1441

1442 1443
  result_table= quote_name(table,table_buff, 1);
  opt_quoted_table= quote_name(table, table_buff2, 0);
1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456

  /* Check table type */
  if ((table_type= check_if_ignore_table(table)))
  {
    if (verbose)
      fprintf(stderr,
	      "-- Skipping data for table '%s' because it's of type %s\n",
	      table, table_type);
    return;
  }

  if (verbose)
    fprintf(stderr, "-- Sending SELECT query...\n");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1457 1458 1459
  if (path)
  {
    char filename[FN_REFLEN], tmp_path[FN_REFLEN];
1460
    convert_dirname(tmp_path,path,NullS);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1461 1462 1463 1464 1465
    my_load_path(tmp_path, tmp_path, NULL);
    fn_format(filename, table, tmp_path, ".txt", 4);
    my_delete(filename, MYF(0)); /* 'INTO OUTFILE' doesn't work, if
				    filename wasn't deleted */
    to_unix_path(filename);
1466 1467
    sprintf(query, "SELECT /*!40001 SQL_NO_CACHE */ * INTO OUTFILE '%s'",
	    filename);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482
    end= strend(query);
    if (replace)
      end= strmov(end, " REPLACE");
    if (ignore)
      end= strmov(end, " IGNORE");

    if (fields_terminated || enclosed || opt_enclosed || escaped)
      end= strmov(end, " FIELDS");
    end= add_load_option(end, fields_terminated, " TERMINATED BY");
    end= add_load_option(end, enclosed, " ENCLOSED BY");
    end= add_load_option(end, opt_enclosed, " OPTIONALLY ENCLOSED BY");
    end= add_load_option(end, escaped, " ESCAPED BY");
    end= add_load_option(end, lines_terminated, " LINES TERMINATED BY");
    *end= '\0';

1483
    sprintf(buff," FROM %s", result_table);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1484 1485
    end= strmov(end,buff);
    if (where)
1486 1487 1488 1489 1490
    {
      query= alloc_query_str((ulong) (strlen(where) + (end - query) + 10));
      end= strxmov(query, query_buf, " WHERE ", where, NullS);
    }
    if (mysql_real_query(sock, query, (uint) (end - query)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1491 1492 1493 1494 1495 1496 1497
    {
      DBerror(sock, "when executing 'SELECT INTO OUTFILE'");
      return;
    }
  }
  else
  {
1498
    if (!opt_xml && opt_comments)
1499
    {
1500 1501
      fprintf(md_result_file,"\n--\n-- Dumping data for table %s\n--\n",
	      result_table);
1502 1503
      check_io(md_result_file);
    }
1504
    sprintf(query, "SELECT /*!40001 SQL_NO_CACHE */ * FROM %s",
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1505
	    result_table);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1506 1507
    if (where)
    {
1508
      if (!opt_xml && opt_comments)
1509
      {
1510
	fprintf(md_result_file,"-- WHERE:  %s\n",where);
1511 1512
	check_io(md_result_file);
      }
1513 1514
      query= alloc_query_str((ulong) (strlen(where) + strlen(query) + 10));
      strxmov(query, query_buf, " WHERE ", where, NullS);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1515
    }
1516
    if (!opt_xml && !opt_compact)
1517
    {
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
1518
      fputs("\n", md_result_file);
1519 1520
      check_io(md_result_file);
    }
1521
    if (mysql_query_with_error_report(sock, 0, query))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1522 1523 1524 1525 1526 1527 1528 1529
      DBerror(sock, "when retrieving data from server");
    if (quick)
      res=mysql_use_result(sock);
    else
      res=mysql_store_result(sock);
    if (!res)
      DBerror(sock, "when retrieving data from server");
    if (verbose)
1530
      fprintf(stderr, "-- Retrieving rows...\n");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1531 1532
    if (mysql_num_fields(res) != numFields)
    {
1533 1534
      fprintf(stderr,"%s: Error in field count for table: %s !  Aborting.\n",
	      my_progname, result_table);
1535 1536
      error= EX_CONSCHECK;
      goto err;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1537 1538
    }

jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
1539
    if (opt_disable_keys)
1540
    {
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1541
      fprintf(md_result_file, "\n/*!40000 ALTER TABLE %s DISABLE KEYS */;\n",
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1542
	      opt_quoted_table);
1543 1544
      check_io(md_result_file);
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1545
    if (opt_lock)
1546
    {
1547
      fprintf(md_result_file,"LOCK TABLES %s WRITE;\n", opt_quoted_table);
1548 1549
      check_io(md_result_file);
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1550

1551
    total_length= opt_net_buffer_length;		/* Force row break */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1552 1553
    row_break=0;
    rownr=0;
1554
    init_length=(uint) strlen(insert_pat)+4;
1555
    if (opt_xml)
1556
      print_xml_tag1(md_result_file, "\t", "table_data name=", table, "\n");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1557

1558
    if (opt_autocommit)
1559
    {
1560
      fprintf(md_result_file, "set autocommit=0;\n");
1561 1562
      check_io(md_result_file);
    }
1563

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1564 1565 1566 1567 1568
    while ((row=mysql_fetch_row(res)))
    {
      uint i;
      ulong *lengths=mysql_fetch_lengths(res);
      rownr++;
1569
      if (!extended_insert && !opt_xml)
1570
      {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1571
	fputs(insert_pat,md_result_file);
1572 1573
	check_io(md_result_file);
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1574 1575
      mysql_field_seek(res,0);

jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
1576
      if (opt_xml)
1577
      {
1578
        fputs("\t<row>\n", md_result_file);
1579 1580
	check_io(md_result_file);
      }
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
1581

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1582 1583
      for (i = 0; i < mysql_num_fields(res); i++)
      {
1584
        int is_blob;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1585 1586
	if (!(field = mysql_fetch_field(res)))
	{
1587 1588
	  sprintf(query,"%s: Not enough fields from table %s! Aborting.\n",
		  my_progname, result_table);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1589
	  fputs(query,stderr);
1590 1591
	  error= EX_CONSCHECK;
	  goto err;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1592
	}
1593 1594 1595 1596
	
	/*
	   63 is my_charset_bin. If charsetnr is not 63,
	   we have not a BLOB but a TEXT column. 
bar@mysql.com's avatar
bar@mysql.com committed
1597
	   we'll dump in hex only BLOB columns.
1598 1599
	*/
        is_blob= (opt_hex_blob && field->charsetnr == 63 &&
bar@mysql.com's avatar
bar@mysql.com committed
1600
                  (field->type == FIELD_TYPE_STRING ||
bar@mysql.com's avatar
bar@mysql.com committed
1601
                   field->type == FIELD_TYPE_VAR_STRING ||
bar@mysql.com's avatar
bar@mysql.com committed
1602
                   field->type == FIELD_TYPE_BLOB ||
1603 1604 1605
                   field->type == FIELD_TYPE_LONG_BLOB ||
                   field->type == FIELD_TYPE_MEDIUM_BLOB ||
                   field->type == FIELD_TYPE_TINY_BLOB)) ? 1 : 0;
1606
	if (extended_insert)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617
	{
	  ulong length = lengths[i];
	  if (i == 0)
	    dynstr_set(&extended_row,"(");
	  else
	    dynstr_append(&extended_row,",");

	  if (row[i])
	  {
	    if (length)
	    {
1618
	      if (!IS_NUM_FIELD(field))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1619
	      {
bar@mysql.com's avatar
bar@mysql.com committed
1620 1621 1622 1623 1624 1625 1626
	        /*
	          "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.
	        */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1627 1628 1629
		if (dynstr_realloc(&extended_row,length * 2+2))
		{
		  fputs("Aborting dump (out of memory)",stderr);
1630 1631
		  error= EX_EOM;
		  goto err;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1632
		}
1633 1634 1635
                if (opt_hex_blob && is_blob)
                {
                  dynstr_append(&extended_row, "0x");
bar@mysql.com's avatar
bar@mysql.com committed
1636 1637 1638 1639
                  extended_row.length+= mysql_hex_string(extended_row.str + 
                                                         extended_row.length,
                                                         row[i], length);
                  extended_row.str[extended_row.length]= '\0';
1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650
                }
                else
                {
                  dynstr_append(&extended_row,"'");
                  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';
                  dynstr_append(&extended_row,"'");
                }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1651 1652
	      }
	      else
1653
	      {
ram@gw.mysql.r18.ru's avatar
ram@gw.mysql.r18.ru committed
1654
		/* change any strings ("inf", "-inf", "nan") into NULL */
1655
		char *ptr = row[i];
monty@mysql.com's avatar
monty@mysql.com committed
1656 1657
		if (my_isalpha(charset_info, *ptr) || (*ptr == '-' &&
		    my_isalpha(charset_info, ptr[1])))
ram@gw.mysql.r18.ru's avatar
ram@gw.mysql.r18.ru committed
1658 1659 1660 1661 1662 1663
		  dynstr_append(&extended_row, "NULL");
		else
		{
		  if (field->type == FIELD_TYPE_DECIMAL)
		  {
		    /* add " signs around */
monty@mishka.local's avatar
monty@mishka.local committed
1664
		    dynstr_append(&extended_row, "'");
ram@gw.mysql.r18.ru's avatar
ram@gw.mysql.r18.ru committed
1665
		    dynstr_append(&extended_row, ptr);
monty@mishka.local's avatar
monty@mishka.local committed
1666
		    dynstr_append(&extended_row, "'");
ram@gw.mysql.r18.ru's avatar
ram@gw.mysql.r18.ru committed
1667 1668 1669 1670
		  }
		  else
		    dynstr_append(&extended_row, ptr);
		}
1671
	      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1672 1673
	    }
	    else
monty@mishka.local's avatar
monty@mishka.local committed
1674
	      dynstr_append(&extended_row,"''");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1675 1676 1677 1678
	  }
	  else if (dynstr_append(&extended_row,"NULL"))
	  {
	    fputs("Aborting dump (out of memory)",stderr);
1679 1680
	    error= EX_EOM;
	    goto err;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1681 1682 1683 1684
	  }
	}
	else
	{
1685
	  if (i && !opt_xml)
1686
	  {
1687
	    fputc(',', md_result_file);
1688 1689
	    check_io(md_result_file);
	  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1690 1691
	  if (row[i])
	  {
1692
	    if (!IS_NUM_FIELD(field))
1693
	    {
1694
	      if (opt_xml)
1695
	      {
1696 1697
	        print_xml_tag1(md_result_file, "\t\t", "field name=",
			      field->name, "");
1698 1699 1700
		print_quoted_xml(md_result_file, row[i], lengths[i]);
		fputs("</field>\n", md_result_file);
	      }
1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714
	      else if (opt_hex_blob && is_blob)
              { /* sakaik got this idea. */
                ulong counter;
                char xx[4];
                unsigned char *ptr= row[i];
                fputs("0x", md_result_file);
                for (counter = 0; counter < lengths[i]; counter++)
                {
                  sprintf(xx, "%02X", ptr[counter]);
                  fputs(xx, md_result_file);
                }
              }
              else
                unescape(md_result_file, row[i], lengths[i]);
1715
	    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1716
	    else
1717
	    {
ram@gw.mysql.r18.ru's avatar
ram@gw.mysql.r18.ru committed
1718
	      /* change any strings ("inf", "-inf", "nan") into NULL */
1719
	      char *ptr = row[i];
1720
	      if (opt_xml)
1721
	      {
1722 1723
	        print_xml_tag1(md_result_file, "\t\t", "field name=",
			       field->name, "");
1724 1725 1726 1727
		fputs(!my_isalpha(charset_info, *ptr) ? ptr: "NULL",
		      md_result_file);
		fputs("</field>\n", md_result_file);
	      }
monty@mysql.com's avatar
monty@mysql.com committed
1728 1729 1730 1731
	      else if (my_isalpha(charset_info, *ptr) ||
		       (*ptr == '-' && my_isalpha(charset_info, ptr[1])))
	        fputs("NULL", md_result_file);
	      else if (field->type == FIELD_TYPE_DECIMAL)
monty@mysql.com's avatar
monty@mysql.com committed
1732 1733
	      {
		/* add " signs around */
monty@mishka.local's avatar
monty@mishka.local committed
1734
		fputc('\'', md_result_file);
monty@mysql.com's avatar
monty@mysql.com committed
1735
		fputs(ptr, md_result_file);
monty@mishka.local's avatar
monty@mishka.local committed
1736
		fputc('\'', md_result_file);
monty@mysql.com's avatar
monty@mysql.com committed
1737
	      }
1738
	      else
monty@mysql.com's avatar
monty@mysql.com committed
1739
		fputs(ptr, md_result_file);
1740
	    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1741
	  }
1742 1743
	  else
            fputs("NULL", md_result_file);
vva@eagle.mysql.r18.ru's avatar
Merge  
vva@eagle.mysql.r18.ru committed
1744
          check_io(md_result_file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1745 1746 1747
	}
      }

jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
1748
      if (opt_xml)
1749
      {
1750
        fputs("\t</row>\n", md_result_file);
1751 1752
	check_io(md_result_file);
      }
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
1753

1754
      if (extended_insert)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1755 1756 1757 1758
      {
	ulong row_length;
	dynstr_append(&extended_row,")");
        row_length = 2 + extended_row.length;
1759
        if (total_length + row_length < opt_net_buffer_length)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1760 1761
        {
	  total_length += row_length;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1762 1763
	  fputc(',',md_result_file);		/* Always row break */
	  fputs(extended_row.str,md_result_file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1764 1765 1766
	}
        else
        {
1767
	  if (row_break)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1768
	    fputs(";\n", md_result_file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1769
	  row_break=1;				/* This is first row */
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1770

1771 1772
          fputs(insert_pat,md_result_file);
          fputs(extended_row.str,md_result_file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1773 1774
	  total_length = row_length+init_length;
        }
1775
	check_io(md_result_file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1776
      }
1777
      else if (!opt_xml)
1778
      {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1779
	fputs(");\n", md_result_file);
1780 1781
	check_io(md_result_file);
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1782
    }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1783

1784
    /* XML - close table tag and supress regular output */
1785
    if (opt_xml)
1786
	fputs("\t</table_data>\n", md_result_file);
1787
    else if (extended_insert && row_break)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1788 1789
      fputs(";\n", md_result_file);		/* If not empty table */
    fflush(md_result_file);
1790
    check_io(md_result_file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1791 1792
    if (mysql_errno(sock))
    {
1793
      sprintf(query,"%s: Error %d: %s when dumping table %s at row: %ld\n",
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1794 1795 1796
	      my_progname,
	      mysql_errno(sock),
	      mysql_error(sock),
1797
	      result_table,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1798 1799
	      rownr);
      fputs(query,stderr);
1800 1801
      error= EX_CONSCHECK;
      goto err;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1802 1803
    }
    if (opt_lock)
1804
    {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1805
      fputs("UNLOCK TABLES;\n", md_result_file);
1806 1807
      check_io(md_result_file);
    }
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
1808
    if (opt_disable_keys)
1809
    {
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
1810
      fprintf(md_result_file,"/*!40000 ALTER TABLE %s ENABLE KEYS */;\n",
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1811
	      opt_quoted_table);
1812 1813
      check_io(md_result_file);
    }
1814
    if (opt_autocommit)
1815
    {
1816
      fprintf(md_result_file, "commit;\n");
1817 1818
      check_io(md_result_file);
    }
1819
    mysql_free_result(res);
1820 1821 1822 1823 1824 1825 1826 1827 1828 1829
    if (query != query_buf)
      my_free(query, MYF(MY_ALLOW_ZERO_PTR));
  } 
  return;

err:
  if (query != query_buf)
    my_free(query, MYF(MY_ALLOW_ZERO_PTR));
  safe_exit(error);
  return;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844
} /* dumpTable */


static char *getTableName(int reset)
{
  static MYSQL_RES *res = NULL;
  MYSQL_ROW    row;

  if (!res)
  {
    if (!(res = mysql_list_tables(sock,NullS)))
      return(NULL);
  }
  if ((row = mysql_fetch_row(res)))
    return((char*) row[0]);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1845

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862
  if (reset)
    mysql_data_seek(res,0);      /* We want to read again */
  else
  {
    mysql_free_result(res);
    res = NULL;
  }
  return(NULL);
} /* getTableName */


static int dump_all_databases()
{
  MYSQL_ROW row;
  MYSQL_RES *tableres;
  int result=0;

1863
  if (mysql_query_with_error_report(sock, &tableres, "SHOW DATABASES"))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1864 1865 1866 1867 1868 1869
    return 1;
  while ((row = mysql_fetch_row(tableres)))
  {
    if (dump_all_tables_in_db(row[0]))
      result=1;
  }
1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884
  if (was_views)
  {
    if (mysql_query(sock, "SHOW DATABASES") ||
        !(tableres = mysql_store_result(sock)))
    {
      my_printf_error(0, "Error: Couldn't execute 'SHOW DATABASES': %s",
                      MYF(0), mysql_error(sock));
      return 1;
    }
    while ((row = mysql_fetch_row(tableres)))
    {
      if (dump_all_views_in_db(row[0]))
        result=1;
    }
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1885 1886 1887 1888 1889 1890 1891 1892
  return result;
}
/* dump_all_databases */


static int dump_databases(char **db_names)
{
  int result=0;
1893 1894
  char **db;
  for (db= db_names ; *db ; db++)
1895
  {
1896
    if (dump_all_tables_in_db(*db))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1897 1898
      result=1;
  }
1899 1900 1901 1902 1903 1904 1905 1906
  if (!result && was_views)
  {
    for (db= db_names ; *db ; db++)
    {
      if (dump_all_views_in_db(*db))
        result=1;
    }
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917
  return result;
} /* dump_databases */


static int init_dumping(char *database)
{
  if (mysql_select_db(sock, database))
  {
    DBerror(sock, "when selecting the database");
    return 1;			/* If --force */
  }
1918
  if (!path && !opt_xml)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1919 1920 1921
  {
    if (opt_databases || opt_alldbs)
    {
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1922
      /*
paul@kite-hub.kitebird.com's avatar
paul@kite-hub.kitebird.com committed
1923
	length of table name * 2 (if name contains quotes), 2 quotes and 0
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1924
      */
1925 1926
      char quoted_database_buf[64*2+3];
      char *qdatabase= quote_name(database,quoted_database_buf,opt_quoted);
1927
      if (opt_comments)
1928
      {
monty@mysql.com's avatar
monty@mysql.com committed
1929
	fprintf(md_result_file,"\n--\n-- Current Database: %s\n--\n", qdatabase);
1930 1931
	check_io(md_result_file);
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1932
      if (!opt_create_db)
1933
      {
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1934
        char qbuf[256];
1935 1936
        MYSQL_ROW row;
        MYSQL_RES *dbinfo;
1937

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1938
        sprintf(qbuf,"SHOW CREATE DATABASE WITH IF NOT EXISTS %s",
1939
		qdatabase);
1940

1941
        if (mysql_query_with_error_report(sock, &dbinfo, qbuf))
1942 1943
        {
          /* Old server version, dump generic CREATE DATABASE */
1944
	  fprintf(md_result_file,
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1945 1946
		  "\nCREATE DATABASE /*!32312 IF NOT EXISTS*/ %s;\n",
		  qdatabase);
1947 1948 1949 1950 1951 1952 1953 1954 1955 1956
	}
	else
        {
	  row = mysql_fetch_row(dbinfo);
	  if (row[1])
	  {
	    fprintf(md_result_file,"\n%s;\n",row[1]);
          }
	}
      }
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1957
      fprintf(md_result_file,"\nUSE %s;\n", qdatabase);
1958
      check_io(md_result_file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1959 1960
    }
  }
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1961 1962
  if (extended_insert && init_dynamic_string(&extended_row, "", 1024, 1024))
    exit(EX_EOM);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1963 1964 1965 1966
  return 0;
} /* init_dumping */


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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1968 1969 1970 1971
static int dump_all_tables_in_db(char *database)
{
  char *table;
  uint numrows;
1972
  char table_buff[NAME_LEN*2+3];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1973 1974 1975

  if (init_dumping(database))
    return 1;
1976
  if (opt_xml)
1977
    print_xml_tag1(md_result_file, "", "database name=", database, "\n");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1978 1979 1980 1981 1982 1983
  if (lock_tables)
  {
    DYNAMIC_STRING query;
    init_dynamic_string(&query, "LOCK TABLES ", 256, 1024);
    for (numrows=0 ; (table = getTableName(1)) ; numrows++)
    {
1984
      dynstr_append(&query, quote_name(table, table_buff, 1));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1985 1986 1987
      dynstr_append(&query, " READ /*!32311 LOCAL */,");
    }
    if (numrows && mysql_real_query(sock, query.str, query.length-1))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1988
      DBerror(sock, "when using LOCK TABLES");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1989 1990 1991 1992 1993 1994
            /* We shall continue here, if --force was given */
    dynstr_free(&query);
  }
  if (flush_logs)
  {
    if (mysql_refresh(sock, REFRESH_LOG))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1995
      DBerror(sock, "when doing refresh");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1996 1997 1998 1999 2000 2001 2002 2003
           /* We shall continue here, if --force was given */
  }
  while ((table = getTableName(0)))
  {
    numrows = getTableStructure(table, database);
    if (!dFlag && numrows > 0)
      dumpTable(numrows,table);
  }
2004
  if (opt_xml)
2005
  {
2006
    fputs("</database>\n", md_result_file);
2007 2008
    check_io(md_result_file);
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2009
  if (lock_tables)
2010
    mysql_query_with_error_report(sock, 0, "UNLOCK TABLES");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2011 2012 2013
  return 0;
} /* dump_all_tables_in_db */

2014 2015 2016 2017 2018 2019
/*
   dump structure of views of database

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

2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066
  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];

  if (init_dumping(database))
    return 1;
  if (opt_xml)
    print_xml_tag1(md_result_file, "", "database name=", database, "\n");
  if (lock_tables)
  {
    DYNAMIC_STRING query;
    init_dynamic_string(&query, "LOCK TABLES ", 256, 1024);
    for (numrows= 0 ; (table= getTableName(1)); numrows++)
    {
      dynstr_append(&query, quote_name(table, table_buff, 1));
      dynstr_append(&query, " READ /*!32311 LOCAL */,");
    }
    if (numrows && mysql_real_query(sock, query.str, query.length-1))
      DBerror(sock, "when using LOCK TABLES");
            /* We shall continue here, if --force was given */
    dynstr_free(&query);
  }
  if (flush_logs)
  {
    if (mysql_refresh(sock, REFRESH_LOG))
      DBerror(sock, "when doing refresh");
           /* We shall continue here, if --force was given */
  }
  while ((table= getTableName(0)))
     getViewStructure(table, database);
  if (opt_xml)
  {
    fputs("</database>\n", md_result_file);
    check_io(md_result_file);
  }
  if (lock_tables)
    mysql_query(sock,"UNLOCK TABLES");
  return 0;
} /* dump_all_tables_in_db */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2067 2068 2069 2070

static int dump_selected_tables(char *db, char **table_names, int tables)
{
  uint numrows;
2071
  int i;
2072
  char table_buff[NAME_LEN*+3];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2073 2074 2075 2076 2077 2078 2079 2080 2081 2082

  if (init_dumping(db))
    return 1;
  if (lock_tables)
  {
    DYNAMIC_STRING query;

    init_dynamic_string(&query, "LOCK TABLES ", 256, 1024);
    for (i=0 ; i < tables ; i++)
    {
2083
      dynstr_append(&query, quote_name(table_names[i], table_buff, 1));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2084 2085 2086
      dynstr_append(&query, " READ /*!32311 LOCAL */,");
    }
    if (mysql_real_query(sock, query.str, query.length-1))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2087
      DBerror(sock, "when doing LOCK TABLES");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2088 2089 2090 2091 2092 2093
       /* We shall countinue here, if --force was given */
    dynstr_free(&query);
  }
  if (flush_logs)
  {
    if (mysql_refresh(sock, REFRESH_LOG))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2094
      DBerror(sock, "when doing refresh");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2095 2096
     /* We shall countinue here, if --force was given */
  }
2097
  if (opt_xml)
2098
    print_xml_tag1(md_result_file, "", "database name=", db, "\n");
2099
  for (i=0 ; i < tables ; i++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2100
  {
2101
    numrows = getTableStructure(table_names[i], db);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2102
    if (!dFlag && numrows > 0)
2103 2104 2105 2106 2107 2108
      dumpTable(numrows, table_names[i]);
  }
  if (was_views)
  {
    for (i=0 ; i < tables ; i++)
      getViewStructure(table_names[i], db);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2109
  }
2110
  if (opt_xml)
2111
  {
2112
    fputs("</database>\n", md_result_file);
2113 2114
    check_io(md_result_file);
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2115
  if (lock_tables)
2116
    mysql_query_with_error_report(sock, 0, "UNLOCK TABLES");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2117 2118 2119 2120
  return 0;
} /* dump_selected_tables */


2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185
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"))
  {
    my_printf_error(0, "Error: Couldn't execute 'SHOW MASTER STATUS': %s",
                    MYF(0), mysql_error(mysql_con));
    return 1;
  }
  else
  {
    row = mysql_fetch_row(master);
    if (row && row[0] && row[1])
    {
      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",
              comment_prefix, row[0], row[1]); 
      check_io(md_result_file);
    }
    mysql_free_result(master);
  }
  return 0;
}


static int do_flush_tables_read_lock(MYSQL *mysql_con)
{
  return 
    mysql_query_with_error_report(mysql_con, 0, "FLUSH TABLES WITH READ LOCK");
}


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


static int start_transaction(MYSQL *mysql_con, my_bool consistent_read_now)
{
  /*
    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).
  */
  return (mysql_query_with_error_report(mysql_con, 0,
                                        consistent_read_now ?
                                        "START TRANSACTION "
                                        "WITH CONSISTENT SNAPSHOT" :
                                        "BEGIN"));
}

2186 2187 2188 2189 2190 2191 2192 2193 2194

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

2195
  *err_pos= 0;                  /* No error yet */
2196
  while (end > x && my_isspace(charset_info, end[-1]))
2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227
    end--;

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

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


bk@work.mysql.com's avatar
bk@work.mysql.com committed
2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244
/* Print a value with a prefix on file */
static void print_value(FILE *file, MYSQL_RES  *result, MYSQL_ROW row,
			const char *prefix, const char *name,
			int string_value)
{
  MYSQL_FIELD	*field;
  mysql_field_seek(result, 0);

  for ( ; (field = mysql_fetch_field(result)) ; row++)
  {
    if (!strcmp(field->name,name))
    {
      if (row[0] && row[0][0] && strcmp(row[0],"0")) /* Skip default */
      {
	fputc(' ',file);
	fputs(prefix, file);
	if (string_value)
2245
	  unescape(file,row[0],(uint) strlen(row[0]));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2246 2247
	else
	  fputs(row[0], file);
2248
	check_io(file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2249 2250 2251 2252 2253 2254 2255 2256
	return;
      }
    }
  }
  return;					/* This shouldn't happen */
} /* print_value */


2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282
/*
  Check if we the table is one of the table types that should be ignored:
  MRG_ISAM, MRG_MYISAM

  SYNOPSIS
    check_if_ignore_table()
    table_name			Table name to check

  GLOBAL VARIABLES
    sock			MySQL socket
    verbose			Write warning messages

  RETURN
    0	Table should be backuped
    #	Type of table (that should be skipped)
*/

static const char *check_if_ignore_table(const char *table_name)
{
  char buff[FN_REFLEN+80], show_name_buff[FN_REFLEN];
  MYSQL_RES *res;
  MYSQL_ROW row;
  const char *result= 0;

  sprintf(buff,"show table status like %s",
	  quote_for_like(table_name, show_name_buff));
2283
  if (mysql_query_with_error_report(sock, &res, buff))
2284 2285 2286 2287 2288 2289 2290 2291 2292 2293
  {
    if (mysql_errno(sock) != ER_PARSE_ERROR)
    {					/* If old MySQL version */
      if (verbose)
	fprintf(stderr,
		"-- Warning: Couldn't get status information for table %s (%s)\n",
		table_name,mysql_error(sock));
      return 0;					/* assume table is ok */
    }
  }
2294
  if (!(row= mysql_fetch_row(res)))
2295 2296 2297 2298 2299 2300 2301 2302
  {
    fprintf(stderr,
	    "Error: Couldn't read status information for table %s (%s)\n",
	    table_name, mysql_error(sock));
    if (res)
      mysql_free_result(res);
    return 0;					/* assume table is ok */
  }
2303 2304 2305 2306 2307 2308 2309 2310
  if (!(row[1]))
      result= "VIEW";
  else
  {
    if (strcmp(row[1], (result= "MRG_MyISAM")) &&
        strcmp(row[1], (result= "MRG_ISAM")))
      result= 0;
  }
2311 2312 2313 2314 2315
  mysql_free_result(res);  
  return result;
}


2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409
/*
  Getting VIEW structure

  SYNOPSIS
    getViewStructure()
    table   view name
    db      db name

  RETURN
    0 OK
    1 ERROR
*/

static my_bool getViewStructure(char *table, char* db)
{
  MYSQL_RES  *tableRes;
  MYSQL_ROW  row;
  MYSQL_FIELD *field;
  char	     *result_table, *opt_quoted_table;
  char	     table_buff[NAME_LEN*2+3];
  char	     table_buff2[NAME_LEN*2+3];
  char       buff[20+FN_REFLEN];
  FILE       *sql_file = md_result_file;
  DBUG_ENTER("getViewStructure");

  if (tFlag)
    DBUG_RETURN(0);

  if (verbose)
    fprintf(stderr, "-- Retrieving view structure for table %s...\n", table);

  sprintf(insert_pat,"SET OPTION SQL_QUOTE_SHOW_CREATE=%d",
	  (opt_quoted || opt_keywords));
  result_table=     quote_name(table, table_buff, 1);
  opt_quoted_table= quote_name(table, table_buff2, 0);

  sprintf(buff,"show create table %s", result_table);
  if (mysql_query(sock, buff))
  {
    fprintf(stderr, "%s: Can't get CREATE TABLE for view %s (%s)\n",
            my_progname, result_table, mysql_error(sock));
    safe_exit(EX_MYSQLERR);
    DBUG_RETURN(0);
  }

  if (path)
  {
    char filename[FN_REFLEN], tmp_path[FN_REFLEN];
    convert_dirname(tmp_path,path,NullS);
    sql_file= my_fopen(fn_format(filename, table, tmp_path, ".sql", 4),
                       O_WRONLY, MYF(MY_WME));
    if (!sql_file)			/* If file couldn't be opened */
    {
      safe_exit(EX_MYSQLERR);
      DBUG_RETURN(1);
    }
    write_header(sql_file, db);
  }
  tableRes= mysql_store_result(sock);
  field= mysql_fetch_field_direct(tableRes, 0);
  if (strcmp(field->name, "View") != 0)
  {
    if (verbose)
      fprintf(stderr, "-- It's base table, skipped\n");
    DBUG_RETURN(0);
  }

  if (!opt_xml && opt_comments)
  {
    fprintf(sql_file, "\n--\n-- View structure for view %s\n--\n\n",
            result_table);
    check_io(sql_file);
  }
  if (opt_drop)
  {
    fprintf(sql_file, "DROP VIEW IF EXISTS %s;\n", opt_quoted_table);
    check_io(sql_file);
  }

  row= mysql_fetch_row(tableRes);
  fprintf(sql_file, "%s;\n", row[1]);
  check_io(sql_file);
  mysql_free_result(tableRes);

  if (sql_file != md_result_file)
  {
    fputs("\n", sql_file);
    write_footer(sql_file);
    my_fclose(sql_file, MYF(MY_WME));
  }
  DBUG_RETURN(0);
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
2410 2411
int main(int argc, char **argv)
{
2412
  compatible_mode_normal_str[0]= 0;
2413

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2414 2415 2416 2417 2418 2419
  MY_INIT(argv[0]);
  if (get_options(&argc, &argv))
  {
    my_end(0);
    exit(EX_USAGE);
  }
2420
  if (dbConnect(current_host, current_user, opt_password))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2421 2422
    exit(EX_MYSQLERR);
  if (!path)
2423 2424
    write_header(md_result_file, *argv);

2425 2426 2427 2428 2429 2430 2431 2432
  if ((opt_lock_all_tables || opt_master_data) &&
      do_flush_tables_read_lock(sock))
    goto err;
  if (opt_single_transaction && start_transaction(sock, test(opt_master_data)))
      goto err;
  if (opt_delete_master_logs && do_reset_master(sock))
    goto err;
  if (opt_lock_all_tables || opt_master_data)
2433
  {
2434 2435 2436
    if (flush_logs && mysql_refresh(sock, REFRESH_LOG))
      goto err;
    flush_logs= 0; /* not anymore; that would not be sensible */
2437
  }
2438 2439 2440 2441 2442
  if (opt_master_data && do_show_master_status(sock))
    goto err;
  if (opt_single_transaction && do_unlock_tables(sock)) // unlock but no commit!
    goto err;

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2443 2444 2445
  if (opt_alldbs)
    dump_all_databases();
  else if (argc > 1 && !opt_databases)
2446 2447
  {
    /* Only one database and selected table(s) */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2448
    dump_selected_tables(*argv, (argv + 1), (argc - 1));
2449
  }
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2450
  else
2451 2452
  {
    /* One or more databases, all tables */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2453
    dump_databases(argv);
2454
  }
2455 2456 2457
#ifdef HAVE_SMEM
  my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR));
#endif
2458 2459 2460 2461 2462 2463 2464
  /*
    No reason to explicitely COMMIT the transaction, neither to explicitely
    UNLOCK TABLES: these will be automatically be done by the server when we
    disconnect now. Saves some code here, some network trips, adds nothing to
    server.
  */
err:
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2465
  dbDisconnect(current_host);
2466 2467
  if (!path)
    write_footer(md_result_file);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2468 2469
  if (md_result_file != stdout)
    my_fclose(md_result_file, MYF(0));
2470
  my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR));
2471
  if (extended_insert)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2472 2473 2474 2475
    dynstr_free(&extended_row);
  my_end(0);
  return(first_error);
} /* main */