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

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

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

unknown's avatar
unknown 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 :-
**
unknown's avatar
unknown committed
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>
unknown's avatar
unknown committed
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
unknown's avatar
unknown committed
37
** 10 Jun 2003: SET NAMES and --no-set-names by Alexander Barkov
unknown's avatar
unknown committed
38
*/
unknown's avatar
unknown committed
39

40
#define DUMP_VERSION "10.10"
unknown's avatar
unknown committed
41

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

48
#include "client_priv.h"
unknown's avatar
unknown committed
49 50 51 52 53 54 55 56 57 58
#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
59
#define EX_EOF 5 /* ferror for output file was got */
unknown's avatar
patch  
unknown committed
60
#define EX_ILLEGAL_TABLE 6
unknown's avatar
unknown committed
61 62 63 64 65 66 67 68 69

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

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

unknown's avatar
unknown committed
73 74
static char *add_load_option(char *ptr, const char *object,
			     const char *statement);
75 76
static ulong find_set(TYPELIB *lib, const char *x, uint length,
		      char **err_pos, uint *err_len);
unknown's avatar
unknown committed
77 78

static char *field_escape(char *to,const char *from,uint length);
79
static my_bool  verbose=0,tFlag=0,dFlag=0,quick= 1, extended_insert= 1,
80 81
		lock_tables=1,ignore_errors=0,flush_logs=0,
		opt_drop=1,opt_keywords=0,opt_lock=1,opt_compress=0,
82
                opt_delayed=0,create_options=1,opt_quoted=0,opt_databases=0,
unknown's avatar
unknown committed
83 84
                opt_alldbs=0,opt_create_db=0,opt_lock_all_tables=0,
                opt_set_charset=0,
85
		opt_autocommit=0,opt_disable_keys=1,opt_xml=0,
unknown's avatar
unknown committed
86
		opt_delete_master_logs=0, tty_password=0,
87
		opt_single_transaction=0, opt_comments= 0, opt_compact= 0,
unknown's avatar
unknown committed
88
		opt_hex_blob=0, opt_order_by_primary=0, opt_ignore=0,
unknown's avatar
unknown committed
89
                opt_complete_insert= 0, opt_drop_database= 0;
90
static ulong opt_max_allowed_packet, opt_net_buffer_length;
unknown's avatar
unknown committed
91
static MYSQL mysql_connection,*sock=0;
92 93 94
static my_bool insert_pat_inited=0;
static DYNAMIC_STRING insert_pat;
static char  *opt_password=0,*current_user=0,
unknown's avatar
unknown committed
95 96
             *current_host=0,*path=0,*fields_terminated=0,
             *lines_terminated=0, *enclosed=0, *opt_enclosed=0, *escaped=0,
97
             *where=0, *order_by=0,
98
             *opt_compatible_mode_str= 0,
99
             *err_ptr= 0;
100
static char compatible_mode_normal_str[255];
101
static ulong opt_compatible_mode= 0;
102 103 104
#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;
unknown's avatar
unknown committed
105 106 107
static my_string opt_mysql_unix_port=0;
static int   first_error=0;
static DYNAMIC_STRING extended_row;
108
#include <sslopt-vars.h>
unknown's avatar
unknown committed
109
FILE  *md_result_file;
110 111 112
#ifdef HAVE_SMEM
static char *shared_memory_base_name=0;
#endif
113
static uint opt_protocol= 0;
114
/*
unknown's avatar
unknown committed
115 116 117
  Constant for detection of default value of default_charset.
  If default_charset is equal to mysql_universal_client_charset, then
  it is the default value which assigned at the very beginning of main().
118
*/
unknown's avatar
unknown committed
119
static const char *mysql_universal_client_charset=
120 121
  MYSQL_UNIVERSAL_CLIENT_CHARSET;
static char *default_charset;
122
static CHARSET_INFO *charset_info= &my_charset_latin1;
unknown's avatar
unknown committed
123
const char *default_dbug_option="d:t:o,/tmp/mysqldump.trace";
124 125
/* do we met VIEWs during tables scaning */
my_bool was_views= 0;
126 127 128 129

const char *compatible_mode_names[]=
{
  "MYSQL323", "MYSQL40", "POSTGRESQL", "ORACLE", "MSSQL", "DB2",
130 131
  "MAXDB", "NO_KEY_OPTIONS", "NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS",
  "ANSI",
132 133
  NullS
};
134 135 136 137 138 139 140 141 142
#define MASK_ANSI_QUOTES \
(\
 (1<<2)  | /* POSTGRESQL */\
 (1<<3)  | /* ORACLE     */\
 (1<<4)  | /* MSSQL      */\
 (1<<5)  | /* DB2        */\
 (1<<6)  | /* MAXDB      */\
 (1<<10)   /* ANSI       */\
)
143
TYPELIB compatible_mode_typelib= {array_elements(compatible_mode_names) - 1,
unknown's avatar
unknown committed
144
				  "", compatible_mode_names, NULL};
145

146
HASH ignore_table;
unknown's avatar
unknown committed
147

148
static struct my_option my_long_options[] =
unknown's avatar
unknown committed
149
{
150 151 152
  {"all", 'a', "Deprecated. Use --create-options instead.",
   (gptr*) &create_options, (gptr*) &create_options, 0, GET_BOOL, NO_ARG, 1,
   0, 0, 0, 0, 0},
153 154 155 156
  {"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},
unknown's avatar
unknown committed
157 158 159
  {"add-drop-database", OPT_DROP_DATABASE, "Add a 'DROP DATABASE' before each create.",
   (gptr*) &opt_drop_database, (gptr*) &opt_drop_database, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
   0},
160
  {"add-drop-table", OPT_DROP, "Add a 'drop table' before each create.",
161
   (gptr*) &opt_drop, (gptr*) &opt_drop, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0,
162 163
   0},
  {"add-locks", OPT_LOCKS, "Add locks around insert statements.",
164
   (gptr*) &opt_lock, (gptr*) &opt_lock, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0,
165 166 167 168 169
   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,
170
   "Directory where character sets are.", (gptr*) &charsets_dir,
171
   (gptr*) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
unknown's avatar
unknown committed
172 173 174
  {"comments", 'i', "Write additional information.",
   (gptr*) &opt_comments, (gptr*) &opt_comments, 0, GET_BOOL, NO_ARG,
   1, 0, 0, 0, 0, 0},
175
  {"compatible", OPT_COMPATIBLE,
unknown's avatar
unknown committed
176
   "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.",
177 178
   (gptr*) &opt_compatible_mode_str, (gptr*) &opt_compatible_mode_str, 0,
   GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
unknown's avatar
unknown committed
179
  {"compact", OPT_COMPACT,
unknown's avatar
unknown committed
180
   "Give less verbose output (useful for debugging). Disables structure comments and header/footer constructs.  Enables options --skip-add-drop-table --no-set-names --skip-disable-keys --skip-add-locks",
unknown's avatar
unknown committed
181 182
   (gptr*) &opt_compact, (gptr*) &opt_compact, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
   0, 0},
183 184 185
  {"complete-insert", 'c', "Use complete insert statements.",
   (gptr*) &opt_complete_insert, (gptr*) &opt_complete_insert, 0, GET_BOOL,
   NO_ARG, 0, 0, 0, 0, 0, 0},
186 187 188
  {"compress", 'C', "Use compression in server/client protocol.",
   (gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
   0, 0, 0},
unknown's avatar
unknown committed
189 190 191 192
  {"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},
193 194 195 196
  {"databases", 'B',
   "To dump several databases. Note the difference in usage; In this case no tables are given. All name arguments are regarded as databasenames. 'USE db_name;' will be included in the output.",
   (gptr*) &opt_databases, (gptr*) &opt_databases, 0, GET_BOOL, NO_ARG, 0, 0,
   0, 0, 0, 0},
unknown's avatar
unknown committed
197 198 199 200 201 202 203
#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
204 205 206
  {"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},
207 208 209
  {"delayed-insert", OPT_DELAYED, "Insert rows with INSERT DELAYED; "
   "currently ignored because of http://bugs.mysql.com/bug.php?id=7815 "
   "but will be re-enabled later",
210 211
   (gptr*) &opt_delayed, (gptr*) &opt_delayed, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
   0, 0},
unknown's avatar
unknown committed
212
  {"delete-master-logs", OPT_DELETE_MASTER_LOGS,
213 214 215
   "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},
216 217
  {"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,
218
   (gptr*) &opt_disable_keys, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
219 220 221
  {"extended-insert", 'e',
   "Allows utilization of the new, much faster INSERT syntax.",
   (gptr*) &extended_insert, (gptr*) &extended_insert, 0, GET_BOOL, NO_ARG,
222
   1, 0, 0, 0, 0, 0},
223 224 225 226 227 228 229 230 231 232
  {"fields-terminated-by", OPT_FTB,
   "Fields in the textfile are terminated by ...", (gptr*) &fields_terminated,
   (gptr*) &fields_terminated, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  {"fields-enclosed-by", OPT_ENC,
   "Fields in the importfile are enclosed by ...", (gptr*) &enclosed,
   (gptr*) &enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0 ,0, 0},
  {"fields-optionally-enclosed-by", OPT_O_ENC,
   "Fields in the i.file are opt. enclosed by ...", (gptr*) &opt_enclosed,
   (gptr*) &opt_enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0 ,0, 0},
  {"fields-escaped-by", OPT_ESC, "Fields in the i.file are escaped by ...",
unknown's avatar
unknown committed
233
   (gptr*) &escaped, (gptr*) &escaped, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
234 235
  {"first-slave", 'x', "Deprecated, renamed to --lock-all-tables.",
   (gptr*) &opt_lock_all_tables, (gptr*) &opt_lock_all_tables, 0, GET_BOOL, NO_ARG,
236
   0, 0, 0, 0, 0, 0},
unknown's avatar
unknown committed
237
  {"flush-logs", 'F', "Flush logs file in server before starting dump. "
238 239 240 241 242 243 244 245
   "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",
246 247 248 249 250 251 252
   (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},
unknown's avatar
unknown committed
253 254 255
  {"hex-blob", OPT_HEXBLOB, "Dump binary strings (BINARY, "
    "VARBINARY, BLOB) in hexadecimal format.",
   (gptr*) &opt_hex_blob, (gptr*) &opt_hex_blob, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
256
  {"host", 'h', "Connect to host.", (gptr*) &current_host,
257
   (gptr*) &current_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
258 259 260 261 262
  {"ignore-table", OPT_IGNORE_TABLE,
   "Do not dump the specified table. To specify more than one table to ignore, "
   "use the directive multiple times, once for each table.  Each table must "
   "be specified with both database and table names, e.g. --ignore-table=database.table",
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
unknown's avatar
unknown committed
263 264 265
  {"insert-ignore", OPT_INSERT_IGNORE, "Insert rows with INSERT IGNORE.",
   (gptr*) &opt_ignore, (gptr*) &opt_ignore, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
   0, 0},
266 267 268
  {"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},
269 270 271 272 273
  {"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},
274
  {"lock-tables", 'l', "Lock all tables for read.", (gptr*) &lock_tables,
275
   (gptr*) &lock_tables, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
276
  {"master-data", OPT_MASTER_DATA,
277 278 279 280 281 282 283 284 285 286
   "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,
287
   GET_UINT, OPT_ARG, 0, 0, MYSQL_OPT_MASTER_DATA_COMMENTED_SQL, 0, 0, 0},
unknown's avatar
unknown committed
288 289 290 291 292 293 294 295
  {"max_allowed_packet", OPT_MAX_ALLOWED_PACKET, "",
    (gptr*) &opt_max_allowed_packet, (gptr*) &opt_max_allowed_packet, 0,
    GET_ULONG, REQUIRED_ARG, 24*1024*1024, 4096, 
   (longlong) 2L*1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0},
  {"net_buffer_length", OPT_NET_BUFFER_LENGTH, "",
    (gptr*) &opt_net_buffer_length, (gptr*) &opt_net_buffer_length, 0,
    GET_ULONG, REQUIRED_ARG, 1024*1024L-1025, 4096, 16*1024L*1024L,
   MALLOC_OVERHEAD-1024, 1024, 0},
296 297 298 299 300
  {"no-autocommit", OPT_AUTOCOMMIT,
   "Wrap tables with autocommit/commit statements.",
   (gptr*) &opt_autocommit, (gptr*) &opt_autocommit, 0, GET_BOOL, NO_ARG,
   0, 0, 0, 0, 0, 0},
  {"no-create-db", 'n',
301
   "'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.}.",
302 303 304
   (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.",
305 306 307
   (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},
unknown's avatar
unknown committed
308
  {"no-set-names", 'N',
309
   "Deprecated. Use --skip-set-charset instead.",
310
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
311
  {"opt", OPT_OPTIMIZE,
312
   "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.",
313
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
unknown's avatar
unknown committed
314 315 316
  {"order-by-primary", OPT_ORDER_BY_PRIMARY,
   "Sorts each table's rows by primary key, or first unique key, if such a key exists.  Useful when dumping a MyISAM table to be loaded into an InnoDB table, but will make the dump itself take considerably longer.",
   (gptr*) &opt_order_by_primary, (gptr*) &opt_order_by_primary, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
317 318 319
  {"password", 'p',
   "Password to use when connecting to server. If password is not given it's solicited on the tty.",
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
unknown's avatar
unknown committed
320
#ifdef __WIN__
321
  {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG,
322
   NO_ARG, 0, 0, 0, 0, 0, 0},
unknown's avatar
unknown committed
323
#endif
324 325 326
  {"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},
327
  {"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).",
328
   0, 0, 0, GET_STR,  REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
329
  {"quick", 'q', "Don't buffer query, dump directly to stdout.",
330
   (gptr*) &quick, (gptr*) &quick, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
331
  {"quote-names",'Q', "Quote table and column names with backticks (`).",
332
   (gptr*) &opt_quoted, (gptr*) &opt_quoted, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0,
333 334
   0, 0},
  {"result-file", 'r',
unknown's avatar
unknown committed
335
   "Direct output to a given file. This option should be used in MSDOS, because it prevents new line '\\n' from being converted to '\\r\\n' (carriage return + line feed).",
unknown's avatar
unknown committed
336
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
unknown's avatar
unknown committed
337 338 339 340
  {"set-charset", OPT_SET_CHARSET,
   "Add 'SET NAMES default_character_set' to the output. Enabled by default; suppress with --skip-set-charset.",
   (gptr*) &opt_set_charset, (gptr*) &opt_set_charset, 0, GET_BOOL, NO_ARG, 1,
   0, 0, 0, 0, 0},
341 342 343
  {"set-variable", 'O',
   "Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.",
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
344
#ifdef HAVE_SMEM
345
  {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
346
   "Base name of shared memory.", (gptr*) &shared_memory_base_name, (gptr*) &shared_memory_base_name,
347 348
   0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#endif
unknown's avatar
unknown committed
349 350 351 352 353
  /*
    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.
  */
354
  {"single-transaction", OPT_TRANSACTION,
unknown's avatar
unknown committed
355 356 357 358 359 360 361
   "Creates a consistent snapshot by dumping all tables in a single "
   "transaction. Works ONLY for tables stored in storage engines which "
   "support multiversioning (currently only InnoDB does); the dump is NOT "
   "guaranteed to be consistent for other storage engines. Option "
   "automatically turns off --lock-tables.",
   (gptr*) &opt_single_transaction, (gptr*) &opt_single_transaction, 0,
   GET_BOOL, NO_ARG,  0, 0, 0, 0, 0, 0},
362
  {"skip-opt", OPT_SKIP_OPTIMIZATION,
363
   "Disable --opt. Disables --add-drop-table, --add-locks, --create-options, --quick, --extended-insert, --lock-tables, --set-charset, and --disable-keys.",
364
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
365 366 367
  {"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},
368
#include <sslopt-longopts.h>
369 370 371 372 373
  {"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},
unknown's avatar
unknown committed
374
#ifndef DONT_ALLOW_USER_CHANGE
375 376 377
  {"user", 'u', "User for login if not current user.",
   (gptr*) &current_user, (gptr*) &current_user, 0, GET_STR, REQUIRED_ARG,
   0, 0, 0, 0, 0, 0},
unknown's avatar
unknown committed
378
#endif
379 380 381 382 383 384 385 386
  {"verbose", 'v', "Print info about the various stages.",
   (gptr*) &verbose, (gptr*) &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
  {"version",'V', "Output version information and exit.", 0, 0, 0,
   GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
  {"where", 'w', "Dump only selected records; QUOTES mandatory!",
   (gptr*) &where, (gptr*) &where, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  {"xml", 'X', "Dump a database as well formed XML.", 0, 0, 0, GET_NO_ARG,
   NO_ARG, 0, 0, 0, 0, 0, 0},
unknown's avatar
unknown committed
387
  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
unknown's avatar
unknown committed
388 389 390 391 392
};

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

static void safe_exit(int error);
393
static void write_header(FILE *sql_file, char *db_name);
unknown's avatar
unknown committed
394 395 396 397 398 399 400 401
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();
unknown's avatar
unknown committed
402
static char *quote_name(const char *name, char *buff, my_bool force);
403
static const char *check_if_ignore_table(const char *table_name);
404
static char *primary_key_fields(const char *table_name);
405
static my_bool get_view_structure(char *table, char* db);
406
static my_bool dump_all_views_in_db(char *database);
407

unknown's avatar
unknown committed
408
#include <help_start.h>
unknown's avatar
unknown committed
409

410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
/*
  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);
  }
}

unknown's avatar
unknown committed
427 428 429
static void print_version(void)
{
  printf("%s  Ver %s Distrib %s, for %s (%s)\n",my_progname,DUMP_VERSION,
unknown's avatar
unknown committed
430 431
         MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
  NETWARE_SET_SCREEN_MODE(1);
unknown's avatar
unknown committed
432 433 434
} /* print_version */


435 436 437 438 439 440
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);
unknown's avatar
unknown committed
441
  NETWARE_SET_SCREEN_MODE(1);
442 443
}

unknown's avatar
unknown committed
444

unknown's avatar
unknown committed
445 446 447 448 449 450
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");
451
  short_usage_sub();
unknown's avatar
unknown committed
452
  print_defaults("my",load_default_groups);
453 454
  my_print_help(my_long_options);
  my_print_variables(my_long_options);
unknown's avatar
unknown committed
455 456 457
} /* usage */


458 459 460 461 462 463
static void short_usage(void)
{
  short_usage_sub();
  printf("For more options, use %s --help\n", my_progname);
}

unknown's avatar
unknown committed
464 465
#include <help_end.h>

466

467
static void write_header(FILE *sql_file, char *db_name)
unknown's avatar
unknown committed
468
{
unknown's avatar
unknown committed
469
  if (opt_xml)
unknown's avatar
unknown committed
470
  {
471
    fputs("<?xml version=\"1.0\"?>\n", sql_file);
472 473 474 475
    fputs("<mysqldump ", sql_file);
    fputs("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"",
          sql_file);
    fputs(">\n", sql_file);
476
    check_io(sql_file);
unknown's avatar
unknown committed
477
  }
unknown's avatar
unknown committed
478
  else if (!opt_compact)
unknown's avatar
unknown committed
479
  {
unknown's avatar
unknown committed
480 481 482 483 484 485 486 487 488 489 490
    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));
    }
491
    if (opt_set_charset)
unknown's avatar
unknown committed
492 493 494 495 496
      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);
497 498 499
    if (!path)
    {
      fprintf(md_result_file,"\
500 501 502
/*!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\
");
503 504
    }
    fprintf(sql_file,
505 506
	    "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='%s%s%s' */;\n"
	    "/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;\n",
unknown's avatar
Merge  
unknown committed
507 508
	    path?"":"NO_AUTO_VALUE_ON_ZERO",compatible_mode_normal_str[0]==0?"":",",
	    compatible_mode_normal_str);
509
    check_io(sql_file);
unknown's avatar
unknown committed
510
  }
511
} /* write_header */
unknown's avatar
unknown committed
512

513

unknown's avatar
unknown committed
514 515 516
static void write_footer(FILE *sql_file)
{
  if (opt_xml)
517
  {
unknown's avatar
unknown committed
518
    fputs("</mysqldump>\n", sql_file);
519 520
    check_io(sql_file);
  }
unknown's avatar
unknown committed
521
  else if (!opt_compact)
522
  {
523 524 525 526
    fprintf(sql_file,"\n/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;\n");
    if (!path)
    {
      fprintf(md_result_file,"\
527
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;\n\
unknown's avatar
unknown committed
528
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;\n");
529
    }
530
    if (opt_set_charset)
531
      fprintf(sql_file,
unknown's avatar
unknown committed
532 533 534
"/*!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");
535
    fprintf(sql_file,
536
	    "/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;\n");
unknown's avatar
unknown committed
537
    fputs("\n", sql_file);
538
    check_io(sql_file);
539
  }
unknown's avatar
unknown committed
540
} /* write_footer */
unknown's avatar
unknown committed
541

unknown's avatar
unknown committed
542 543 544 545 546 547
static void free_table_ent(char *key)

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

548

unknown's avatar
patch  
unknown committed
549 550
byte* get_table_key(const char *entry, uint *length,
				my_bool not_used __attribute__((unused)))
551
{
unknown's avatar
patch  
unknown committed
552 553
  *length= strlen(entry);
  return (byte*) entry;
554 555 556
}


unknown's avatar
unknown committed
557
void init_table_rule_hash(HASH* h)
558
{
unknown's avatar
unknown committed
559 560 561
  if (hash_init(h, charset_info, 16, 0, 0,
                (hash_get_key) get_table_key,
                (hash_free_key) free_table_ent, 0))
unknown's avatar
unknown committed
562
    exit(EX_EOM);
563 564
}

565 566 567
static my_bool
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
	       char *argument)
unknown's avatar
unknown committed
568
{
unknown's avatar
unknown committed
569
  switch (optid) {
570 571 572 573 574 575 576 577 578
  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 */
579
      tty_password= 0;
580 581 582 583 584
    }
    else
      tty_password=1;
    break;
  case 'r':
unknown's avatar
unknown committed
585
    if (!(md_result_file = my_fopen(argument, O_WRONLY | FILE_BINARY,
586 587 588 589
				    MYF(MY_WME))))
      exit(1);
    break;
  case 'W':
unknown's avatar
unknown committed
590
#ifdef __WIN__
591
    opt_protocol = MYSQL_PROTOCOL_PIPE;
unknown's avatar
unknown committed
592
#endif
593
    break;
594 595 596
  case 'N':
    opt_set_charset= 0;
    break;
597 598 599 600
  case 'T':
    opt_disable_keys=0;
    break;
  case '#':
unknown's avatar
unknown committed
601
    DBUG_PUSH(argument ? argument : default_dbug_option);
602
    break;
603
#include <sslopt-case.h>
604 605 606
  case 'V': print_version(); exit(0);
  case 'X':
    opt_xml = 1;
607 608
    extended_insert= opt_drop= opt_lock= 
      opt_disable_keys= opt_autocommit= opt_create_db= 0;
609 610 611 612 613
    break;
  case 'I':
  case '?':
    usage();
    exit(0);
614 615 616 617
  case (int) OPT_MASTER_DATA:
    if (!argument) /* work like in old versions */
      opt_master_data= MYSQL_OPT_MASTER_DATA_EFFECTIVE_SQL;
    break;
618
  case (int) OPT_OPTIMIZE:
619
    extended_insert= opt_drop= opt_lock= quick= create_options=
620
      opt_disable_keys= lock_tables= opt_set_charset= 1;
621
    break;
622 623
  case (int) OPT_SKIP_OPTIMIZATION:
    extended_insert= opt_drop= opt_lock= quick= create_options=
unknown's avatar
unknown committed
624
      opt_disable_keys= lock_tables= opt_set_charset= 0;
625
    break;
unknown's avatar
unknown committed
626 627 628 629
  case (int) OPT_COMPACT:
  if (opt_compact)
  {
    opt_comments= opt_drop= opt_disable_keys= opt_lock= 0;
630
    opt_set_charset= 0;
unknown's avatar
unknown committed
631
  }
632 633 634
  case (int) OPT_TABLES:
    opt_databases=0;
    break;
635 636
  case (int) OPT_IGNORE_TABLE:
  {
unknown's avatar
unknown committed
637
    if (!strchr(argument, '.'))
638
    {
unknown's avatar
unknown committed
639
      fprintf(stderr, "Illegal use of option --ignore-table=<database>.<table>\n");
640 641
      exit(1);
    }
unknown's avatar
unknown committed
642 643 644
    if (!hash_inited(&ignore_table))
      init_table_rule_hash(&ignore_table);

unknown's avatar
patch  
unknown committed
645
    if (my_hash_insert(&ignore_table, (byte*)my_strdup(argument, MYF(0))))
unknown's avatar
unknown committed
646
      exit(EX_EOM);
647 648
    break;
  }
649
  case (int) OPT_COMPATIBLE:
unknown's avatar
unknown committed
650
    {
651
      char buff[255];
652 653 654
      char *end= compatible_mode_normal_str;
      int i;
      ulong mode;
655 656

      opt_quoted= 1;
657
      opt_set_charset= 0;
658 659 660 661 662 663 664 665 666 667
      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);
      }
668 669
#if !defined(DBUG_OFF)
      {
unknown's avatar
unknown committed
670
	uint size_for_sql_mode= 0;
671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688
	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;
689 690 691 692
      /* 
        Set charset to the default compiled value if it hasn't
        been reset yet by --default-character-set=xxx.
      */
693
      if (default_charset == mysql_universal_client_charset)
694
        default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME;
695 696 697
      break;
    }
  case (int) OPT_MYSQL_PROTOCOL:
698
    {
699
      if ((opt_protocol= find_type(argument, &sql_protocol_typelib,0)) <= 0)
700 701 702 703 704
      {
	fprintf(stderr, "Unknown option to protocol: %s\n", argument);
	exit(1);
      }
      break;
705
    }
706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724
#ifndef REMOVE_THIS_CODE_WHEN_FIX_BUG_7815
  case (int) OPT_DELAYED:
    /*
      Because of http://bugs.mysql.com/bug.php?id=7815, we disable
      --delayed-insert; when the bug gets fixed by checking the storage engine
      (using the table definition cache) before printing INSERT DELAYED, we
      can correct the option's description and re-enable it again (scheduled
      for later 5.0 or 5.1 versions).
      It's ok to do the if() below as get_one_option is called after
      opt_delayed is set.
    */
    if (opt_delayed)
    {
      fprintf(stderr, "Warning: ignoring --delayed-insert (as explained "
	      "in the output of 'mysqldump --help').\n");
      opt_delayed= 0;
    }
    break;
#endif
unknown's avatar
unknown committed
725
  }
726 727 728 729 730 731
  return 0;
}

static int get_options(int *argc, char ***argv)
{
  int ho_error;
732 733 734 735
  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;
736 737 738 739

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

740
  if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
741
    exit(ho_error);
742

743 744 745
  *mysql_params->p_max_allowed_packet= opt_max_allowed_packet;
  *mysql_params->p_net_buffer_length= opt_net_buffer_length;

unknown's avatar
unknown committed
746 747 748 749 750
  if (opt_delayed)
    opt_lock=0;				/* Can't have lock with delayed */
  if (!path && (enclosed || opt_enclosed || escaped || lines_terminated ||
		fields_terminated))
  {
751 752
    fprintf(stderr,
	    "%s: You must use option --tab with --fields-...\n", my_progname);
unknown's avatar
unknown committed
753 754
    return(1);
  }
755 756 757 758 759 760 761 762 763 764 765 766 767

  /* 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)
768
    lock_tables= 0;
unknown's avatar
unknown committed
769 770 771 772 773 774 775 776 777 778 779 780
  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 ((opt_databases || opt_alldbs) && path)
  {
    fprintf(stderr,
	    "%s: --databases or --all-databases can't be used with --tab.\n",
	    my_progname);
    return(1);
  }
781 782
  if (strcmp(default_charset, charset_info->csname) &&
      !(charset_info= get_charset_by_csname(default_charset, 
783
  					    MY_CS_PRIMARY, MYF(MY_WME))))
784
    exit(1);
unknown's avatar
unknown committed
785 786
  if ((*argc < 1 && !opt_alldbs) || (*argc > 0 && opt_alldbs))
  {
787
    short_usage();
unknown's avatar
unknown committed
788 789 790
    return 1;
  }
  if (tty_password)
791
    opt_password=get_tty_password(NullS);
unknown's avatar
unknown committed
792 793 794 795 796
  return(0);
} /* get_options */


/*
797
** DB_error -- prints mysql error message and exits the program.
unknown's avatar
unknown committed
798
*/
799
static void DB_error(MYSQL *mysql, const char *when)
unknown's avatar
unknown committed
800
{
801
  DBUG_ENTER("DB_error");
unknown's avatar
unknown committed
802
  my_printf_error(0,"Got error: %d: %s %s", MYF(0),
unknown's avatar
unknown committed
803 804 805
		  mysql_errno(mysql), mysql_error(mysql), when);
  safe_exit(EX_MYSQLERR);
  DBUG_VOID_RETURN;
806
} /* DB_error */
unknown's avatar
unknown committed
807 808


809 810 811 812 813 814 815
/*
  Sends a query to server, optionally reads result, prints error message if
  some.

  SYNOPSIS
    mysql_query_with_error_report()
    mysql_con       connection to use
unknown's avatar
unknown committed
816 817
    res             if non zero, result will be put there with
		    mysql_store_result()
818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839
    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;
}


unknown's avatar
unknown committed
840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857
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.
*/
static int dbConnect(char *host, char *user,char *passwd)
{
858
  char buff[20+FN_REFLEN];
unknown's avatar
unknown committed
859 860 861
  DBUG_ENTER("dbConnect");
  if (verbose)
  {
862
    fprintf(stderr, "-- Connecting to %s...\n", host ? host : "localhost");
unknown's avatar
unknown committed
863 864 865 866 867 868 869
  }
  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,
870
		  opt_ssl_capath, opt_ssl_cipher);
871 872 873 874 875 876
#endif
  if (opt_protocol)
    mysql_options(&mysql_connection,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
#ifdef HAVE_SMEM
  if (shared_memory_base_name)
    mysql_options(&mysql_connection,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
unknown's avatar
unknown committed
877
#endif
878
  mysql_options(&mysql_connection, MYSQL_SET_CHARSET_NAME, default_charset);
unknown's avatar
unknown committed
879 880 881 882
  if (!(sock= mysql_real_connect(&mysql_connection,host,user,passwd,
         NULL,opt_mysql_port,opt_mysql_unix_port,
         0)))
  {
883
    DB_error(&mysql_connection, "when trying to connect");
unknown's avatar
unknown committed
884 885
    return 1;
  }
unknown's avatar
unknown committed
886 887 888 889 890
  /*
    Don't dump SET NAMES with a pre-4.1 server (bug#7997).
  */
  if (mysql_get_server_version(&mysql_connection) < 40100)
    opt_set_charset= 0;
891 892 893 894 895
  /*
    As we're going to set SQL_MODE, it would be lost on reconnect, so we
    cannot reconnect.
  */
  sock->reconnect= 0;
896 897
  my_snprintf(buff, sizeof(buff), "/*!40100 SET @@SQL_MODE='%s' */",
	      compatible_mode_normal_str);
898
  if (mysql_query_with_error_report(sock, 0, buff))
899 900 901 902 903
  {
    mysql_close(sock);
    safe_exit(EX_MYSQLERR);
    return 1;
  }
unknown's avatar
unknown committed
904 905 906 907 908 909 910 911 912 913
  return 0;
} /* dbConnect */


/*
** dbDisconnect -- disconnects from the host.
*/
static void dbDisconnect(char *host)
{
  if (verbose)
914
    fprintf(stderr, "-- Disconnecting from %s...\n", host ? host : "localhost");
unknown's avatar
unknown committed
915 916 917 918 919 920 921 922 923 924 925 926 927
  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 */
  }
unknown's avatar
unknown committed
928
  mysql_real_escape_string(&mysql_connection, tmp, pos, length);
unknown's avatar
unknown committed
929 930 931
  fputc('\'', file);
  fputs(tmp, file);
  fputc('\'', file);
932
  check_io(file);
unknown's avatar
unknown committed
933 934 935 936 937 938 939 940 941
  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++)
942
    if (!my_isvar(charset_info,*str) && *str != '$')
unknown's avatar
unknown committed
943 944 945 946 947
      return 1;
#endif
  return 0;
} /* test_if_special_chars */

unknown's avatar
unknown committed
948

unknown's avatar
unknown committed
949

unknown's avatar
unknown committed
950
static char *quote_name(const char *name, char *buff, my_bool force)
unknown's avatar
unknown committed
951
{
unknown's avatar
unknown committed
952
  char *to= buff;
953 954
  char qtype= (opt_compatible_mode & MASK_ANSI_QUOTES) ? '\"' : '`';

unknown's avatar
unknown committed
955 956
  if (!force && !opt_quoted && !test_if_special_chars(name))
    return (char*) name;
957
  *to++= qtype;
unknown's avatar
unknown committed
958 959
  while (*name)
  {
960 961
    if (*name == qtype)
      *to++= qtype;
unknown's avatar
unknown committed
962 963
    *to++= *name++;
  }
964 965
  to[0]= qtype;
  to[1]= 0;
unknown's avatar
unknown committed
966 967 968
  return buff;
} /* quote_name */

unknown's avatar
unknown committed
969

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

unknown's avatar
patch  
unknown committed
973
  SYNOPSIS
unknown's avatar
unknown committed
974 975 976
    quote_for_like()
    name     name of the table
    buff     quoted name of the table
unknown's avatar
patch  
unknown committed
977 978 979

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

unknown's avatar
patch  
unknown committed
981 982 983 984 985 986 987 988 989 990 991
    Note: Because MySQL uses the C escape syntax in strings
    (for example, '\n' to represent newline), you must double
    any '\' that you use in your LIKE  strings. For example, to
    search for '\n', specify it as '\\n'. To search for '\', specify
    it as '\\\\' (the backslashes are stripped once by the parser
    and another time when the pattern match is done, leaving a
    single backslash to be matched).

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

*/
992 993 994 995 996 997
static char *quote_for_like(const char *name, char *buff)
{
  char *to= buff;
  *to++= '\'';
  while (*name)
  {
unknown's avatar
patch  
unknown committed
998 999 1000 1001 1002 1003 1004
    if (*name == '\\')
    {
      *to++='\\';
      *to++='\\';
      *to++='\\';
    }
    else if (*name == '\'' || *name == '_'  || *name == '%')
1005 1006 1007 1008 1009 1010 1011 1012 1013
      *to++= '\\';
    *to++= *name++;
  }
  to[0]= '\'';
  to[1]= 0;
  return buff;
}


1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
/*
  Quote and print a string.
  
  SYNOPSIS
    print_quoted_xml()
    output	- output file
    str		- string to print
    len		- its length
    
  DESCRIPTION
1024
    Quote '<' '>' '&' '\"' chars and print a string to the xml_file.
1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050
*/

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;
    }
  }
1051
  check_io(xml_file);
1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084
}


/*
  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);
1085
  check_io(xml_file);
1086 1087 1088
}


1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122
/*
  Print xml tag with for a field that is null

  SYNOPSIS
    print_xml_null_tag()
    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:
      <stag_atr="sval" xsi:nil="true"/>
  NOTE
    sval MUST be a NULL terminated string.
    sval string will be qouted before output.
*/

static void print_xml_null_tag(FILE * xml_file, const char* sbeg,
                               const char* stag_atr, const char* sval,
                               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("\" xsi:nil=\"true\" />", xml_file);
  fputs(send, xml_file);
  check_io(xml_file);
}


1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141
/*
  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)
1142 1143 1144 1145 1146 1147
{
  uint i;
  MYSQL_FIELD *field;
  ulong *lengths= mysql_fetch_lengths(tableRes);
  
  fprintf(xml_file, "\t\t<%s", row_name);
1148
  check_io(xml_file);
1149 1150 1151
  mysql_field_seek(tableRes, 0);
  for (i= 0; (field= mysql_fetch_field(tableRes)); i++)
  {
1152
    if ((*row)[i])
1153
    {
unknown's avatar
unknown committed
1154
      fputc(' ', xml_file);
1155
      print_quoted_xml(xml_file, field->name, field->name_length);
1156 1157
      fputs("=\"", xml_file);
      print_quoted_xml(xml_file, (*row)[i], lengths[i]);
unknown's avatar
unknown committed
1158
      fputc('"', xml_file);
1159
      check_io(xml_file);
1160 1161 1162
    }
  }
  fputs(" />\n", xml_file);
1163
  check_io(xml_file);
1164 1165
}

1166

unknown's avatar
unknown committed
1167
/*
1168
  getTableStructure -- retrievs database structure, prints out corresponding
unknown's avatar
unknown committed
1169 1170 1171 1172
  CREATE statement and fills out insert_pat.

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

1175
static uint get_table_structure(char *table, char *db)
unknown's avatar
unknown committed
1176 1177 1178 1179 1180
{
  MYSQL_RES  *tableRes;
  MYSQL_ROW  row;
  my_bool    init=0;
  uint       numFields;
1181
  char	     *result_table, *opt_quoted_table;
unknown's avatar
unknown committed
1182
  const char *insert_option;
unknown's avatar
unknown committed
1183 1184
  char	     name_buff[NAME_LEN+3],table_buff[NAME_LEN*2+3];
  char	     table_buff2[NAME_LEN*2+3];
1185
  char       query_buff[512];
unknown's avatar
unknown committed
1186
  FILE       *sql_file = md_result_file;
1187
  int        len;
1188
  DBUG_ENTER("get_table_structure");
unknown's avatar
patch  
unknown committed
1189
  DBUG_PRINT("enter", ("db: %s, table: %s", db, table));
unknown's avatar
unknown committed
1190

1191 1192 1193 1194 1195 1196 1197
  if (!insert_pat_inited)
  {
    insert_pat_inited= init_dynamic_string(&insert_pat, "", 1024, 1024);
  }
  else
    dynstr_set(&insert_pat, "");

unknown's avatar
unknown committed
1198 1199 1200
  insert_option= ((opt_delayed && opt_ignore) ? " DELAYED IGNORE " : 
                  opt_delayed ? " DELAYED " :
                  opt_ignore ? " IGNORE " : "");
unknown's avatar
unknown committed
1201 1202

  if (verbose)
1203
    fprintf(stderr, "-- Retrieving table structure for table %s...\n", table);
unknown's avatar
unknown committed
1204

1205 1206 1207
  len= my_snprintf(query_buff, sizeof(query_buff),
                   "SET OPTION SQL_QUOTE_SHOW_CREATE=%d",
                   (opt_quoted || opt_keywords));
unknown's avatar
unknown committed
1208
  if (!create_options)
1209
    strmov(query_buff+len, "/*!40102 ,SQL_MODE=concat(@@sql_mode, _utf8 ',NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS') */");
unknown's avatar
unknown committed
1210

unknown's avatar
unknown committed
1211 1212
  result_table=     quote_name(table, table_buff, 1);
  opt_quoted_table= quote_name(table, table_buff2, 0);
1213 1214 1215 1216

  if (opt_order_by_primary)
    order_by = primary_key_fields(opt_quoted_table);

1217
  if (!opt_xml && !mysql_query_with_error_report(sock, 0, query_buff))
unknown's avatar
unknown committed
1218
  {
1219 1220
    /* using SHOW CREATE statement */
    if (!tFlag)
unknown's avatar
unknown committed
1221
    {
1222 1223
      /* Make an sql-file, if path was given iow. option -T was given */
      char buff[20+FN_REFLEN];
1224
      MYSQL_FIELD *field;
1225

1226
      my_snprintf(buff, sizeof(buff), "show create table %s", result_table);
1227
      if (mysql_query_with_error_report(sock, 0, buff))
unknown's avatar
unknown committed
1228
      {
1229 1230
        safe_exit(EX_MYSQLERR);
        DBUG_RETURN(0);
unknown's avatar
unknown committed
1231 1232
      }

1233 1234 1235
      if (path)
      {
        char filename[FN_REFLEN], tmp_path[FN_REFLEN];
1236
        convert_dirname(tmp_path,path,NullS);
1237
        sql_file= my_fopen(fn_format(filename, table, tmp_path, ".sql", 4),
1238
				 O_WRONLY, MYF(MY_WME));
1239 1240
        if (!sql_file)			/* If file couldn't be opened */
        {
unknown's avatar
unknown committed
1241 1242
	  safe_exit(EX_MYSQLERR);
	  DBUG_RETURN(0);
1243
        }
1244
        write_header(sql_file, db);
1245
      }
1246
      if (!opt_xml && opt_comments)
1247
      {
unknown's avatar
unknown committed
1248
        fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n",
unknown's avatar
unknown committed
1249
		result_table);
1250 1251
	check_io(sql_file);
      }
1252
      if (opt_drop)
1253
      {
unknown's avatar
unknown committed
1254
        fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", opt_quoted_table);
1255 1256
	check_io(sql_file);
      }
1257

1258 1259 1260 1261 1262
      tableRes= mysql_store_result(sock);
      field= mysql_fetch_field_direct(tableRes, 0);
      if (strcmp(field->name, "View") == 0)
      {
        if (verbose)
1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274
          fprintf(stderr, "-- It's a view, create dummy table for view\n");

        mysql_free_result(tableRes);

        /* Create a dummy table for the view. ie. a table  which has the
           same columns as the view should have. This table is dropped
           just before the view is created. The table is used to handle the
           case where a view references another view, which hasn't yet been
           created(during the load of the dump). BUG#10927 */

        /* Create temp table by selecting from the view */
        my_snprintf(query_buff, sizeof(query_buff),
unknown's avatar
unknown committed
1275
                    "CREATE  TEMPORARY TABLE %s SELECT * FROM %s WHERE 0",
1276 1277 1278 1279 1280 1281 1282 1283
                    result_table, result_table);
        if (mysql_query_with_error_report(sock, 0, query_buff))
        {
          safe_exit(EX_MYSQLERR);
          DBUG_RETURN(0);
        }

        /* Get CREATE statement for the temp table */
unknown's avatar
unknown committed
1284
        my_snprintf(query_buff, sizeof(query_buff), "SHOW CREATE TABLE %s",
1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310
                    result_table);
        if (mysql_query_with_error_report(sock, 0, query_buff))
        {
          safe_exit(EX_MYSQLERR);
          DBUG_RETURN(0);
        }
        tableRes= mysql_store_result(sock);
        row= mysql_fetch_row(tableRes);

        if (opt_drop)
          fprintf(sql_file, "DROP VIEW IF EXISTS %s;\n",opt_quoted_table);

        /* Print CREATE statement but remove TEMPORARY */
        fprintf(sql_file, "CREATE %s;\n", row[1]+17);
        check_io(sql_file);

        mysql_free_result(tableRes);

        /* Drop the temp table */
        my_snprintf(buff, sizeof(buff),
                    "DROP TEMPORARY TABLE %s", result_table);
        if (mysql_query_with_error_report(sock, 0, buff))
        {
          safe_exit(EX_MYSQLERR);
          DBUG_RETURN(0);
        }
1311 1312 1313 1314
        was_views= 1;
        DBUG_RETURN(0);
      }
      row= mysql_fetch_row(tableRes);
1315
      fprintf(sql_file, "%s;\n", row[1]);
1316
      check_io(sql_file);
1317 1318
      mysql_free_result(tableRes);
    }
1319
    my_snprintf(query_buff, sizeof(query_buff), "show fields from %s",
1320
		result_table);
1321
    if (mysql_query_with_error_report(sock, &tableRes, query_buff))
unknown's avatar
unknown committed
1322
    {
1323 1324
      if (path)
	my_fclose(sql_file, MYF(MY_WME));
1325 1326
      safe_exit(EX_MYSQLERR);
      DBUG_RETURN(0);
unknown's avatar
unknown committed
1327
    }
1328

1329
    dynstr_append_mem(&insert_pat, "INSERT ", 7);
unknown's avatar
unknown committed
1330
    dynstr_append(&insert_pat, insert_option);
1331 1332 1333 1334 1335 1336
    dynstr_append_mem(&insert_pat, "INTO ", 5);
    dynstr_append(&insert_pat, opt_quoted_table);
    if (opt_complete_insert)
    {
      dynstr_append_mem(&insert_pat, " (", 2);
    }
1337
    else
unknown's avatar
unknown committed
1338
    {
1339
      dynstr_append_mem(&insert_pat, " VALUES ", 8);
1340
      if (!extended_insert)
1341
        dynstr_append_mem(&insert_pat, "(", 1);
1342 1343 1344 1345 1346
    }

    while ((row=mysql_fetch_row(tableRes)))
    {
      if (init)
unknown's avatar
unknown committed
1347
      {
1348 1349
        if (opt_complete_insert)
          dynstr_append_mem(&insert_pat, ", ", 2);
unknown's avatar
unknown committed
1350
      }
1351
      init=1;
1352 1353 1354
      if (opt_complete_insert)
        dynstr_append(&insert_pat,
                      quote_name(row[SHOW_FIELDNAME], name_buff, 0));
unknown's avatar
unknown committed
1355
    }
1356 1357
    numFields = (uint) mysql_num_rows(tableRes);
    mysql_free_result(tableRes);
unknown's avatar
unknown committed
1358
  }
1359
  else
unknown's avatar
unknown committed
1360
  {
unknown's avatar
unknown committed
1361 1362 1363 1364
    if (verbose)
      fprintf(stderr,
              "%s: Warning: Can't set SQL_QUOTE_SHOW_CREATE option (%s)\n",
              my_progname, mysql_error(sock));
1365

1366
    my_snprintf(query_buff, sizeof(query_buff), "show fields from %s",
1367
		result_table);
1368
    if (mysql_query_with_error_report(sock, &tableRes, query_buff))
unknown's avatar
unknown committed
1369 1370 1371 1372 1373
    {
      safe_exit(EX_MYSQLERR);
      DBUG_RETURN(0);
    }

1374 1375
    /* Make an sql-file, if path was given iow. option -T was given */
    if (!tFlag)
unknown's avatar
unknown committed
1376
    {
1377
      if (path)
unknown's avatar
unknown committed
1378
      {
1379
        char filename[FN_REFLEN], tmp_path[FN_REFLEN];
1380
        convert_dirname(tmp_path,path,NullS);
1381 1382 1383 1384
        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 */
        {
1385 1386
	  safe_exit(EX_MYSQLERR);
	  DBUG_RETURN(0);
1387
        }
1388
        write_header(sql_file, db);
unknown's avatar
unknown committed
1389
      }
1390
      if (!opt_xml && opt_comments)
unknown's avatar
unknown committed
1391 1392
	fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n",
		result_table);
1393
      if (opt_drop)
1394
        fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n",result_table);
1395 1396 1397
      if (!opt_xml)
	fprintf(sql_file, "CREATE TABLE %s (\n", result_table);
      else
1398
        print_xml_tag1(sql_file, "\t", "table_structure name=", table, "\n");
1399
      check_io(sql_file);
1400
    }
1401 1402

    dynstr_append_mem(&insert_pat, "INSERT ", 7);
unknown's avatar
unknown committed
1403
    dynstr_append(&insert_pat, insert_option);
1404 1405 1406 1407 1408 1409
    dynstr_append_mem(&insert_pat, "INTO ", 5);
    dynstr_append(&insert_pat, result_table);
    if (opt_complete_insert)
    {
      dynstr_append_mem(&insert_pat, " (", 2);
    }
1410 1411
    else
    {
1412
      dynstr_append_mem(&insert_pat, " VALUES ", 8);
1413
      if (!extended_insert)
1414
        dynstr_append_mem(&insert_pat, "(", 1);
unknown's avatar
unknown committed
1415
    }
1416

unknown's avatar
unknown committed
1417 1418
    while ((row=mysql_fetch_row(tableRes)))
    {
1419 1420
      ulong *lengths=mysql_fetch_lengths(tableRes);
      if (init)
unknown's avatar
unknown committed
1421
      {
1422
        if (!opt_xml && !tFlag)
1423
	{
1424
	  fputs(",\n",sql_file);
1425 1426
	  check_io(sql_file);
	}
1427 1428
        if (opt_complete_insert)
          dynstr_append_mem(&insert_pat, ", ", 2);
1429 1430
      }
      init=1;
1431 1432 1433
      if (opt_complete_insert)
        dynstr_append(&insert_pat,
                      quote_name(row[SHOW_FIELDNAME], name_buff, 0));
1434 1435
      if (!tFlag)
      {
1436 1437 1438 1439 1440
	if (opt_xml)
	{
	  print_xml_row(sql_file, "field", tableRes, &row);
	  continue;
	}
1441

1442
        if (opt_keywords)
1443
	  fprintf(sql_file, "  %s.%s %s", result_table,
unknown's avatar
unknown committed
1444 1445
		  quote_name(row[SHOW_FIELDNAME],name_buff, 0),
		  row[SHOW_TYPE]);
1446
        else
unknown's avatar
unknown committed
1447
	  fprintf(sql_file, "  %s %s", quote_name(row[SHOW_FIELDNAME],
unknown's avatar
unknown committed
1448 1449
						  name_buff, 0),
		  row[SHOW_TYPE]);
1450 1451
        if (row[SHOW_DEFAULT])
        {
unknown's avatar
unknown committed
1452
	  fputs(" DEFAULT ", sql_file);
unknown's avatar
unknown committed
1453
	  unescape(sql_file, row[SHOW_DEFAULT], lengths[SHOW_DEFAULT]);
1454 1455
        }
        if (!row[SHOW_NULL][0])
unknown's avatar
unknown committed
1456
	  fputs(" NOT NULL", sql_file);
1457
        if (row[SHOW_EXTRA][0])
unknown's avatar
unknown committed
1458
	  fprintf(sql_file, " %s",row[SHOW_EXTRA]);
1459
	check_io(sql_file);
unknown's avatar
unknown committed
1460 1461
      }
    }
1462 1463 1464
    numFields = (uint) mysql_num_rows(tableRes);
    mysql_free_result(tableRes);
    if (!tFlag)
unknown's avatar
unknown committed
1465
    {
1466 1467 1468
      /* Make an sql-file, if path was given iow. option -T was given */
      char buff[20+FN_REFLEN];
      uint keynr,primary_key;
1469
      my_snprintf(buff, sizeof(buff), "show keys from %s", result_table);
1470
      if (mysql_query_with_error_report(sock, &tableRes, buff))
unknown's avatar
unknown committed
1471
      {
1472 1473 1474 1475 1476 1477 1478 1479
        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));
1480
        if (path)
unknown's avatar
unknown committed
1481
	  my_fclose(sql_file, MYF(MY_WME));
1482 1483
        safe_exit(EX_MYSQLERR);
        DBUG_RETURN(0);
unknown's avatar
unknown committed
1484
      }
1485 1486 1487 1488 1489

      /* Find first which key is primary key */
      keynr=0;
      primary_key=INT_MAX;
      while ((row=mysql_fetch_row(tableRes)))
unknown's avatar
unknown committed
1490
      {
1491 1492
        if (atoi(row[3]) == 1)
        {
unknown's avatar
unknown committed
1493 1494 1495 1496 1497 1498 1499 1500 1501 1502
	  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;
	  }
1503
        }
unknown's avatar
unknown committed
1504
      }
1505 1506 1507 1508
      mysql_data_seek(tableRes,0);
      keynr=0;
      while ((row=mysql_fetch_row(tableRes)))
      {
1509 1510 1511 1512 1513 1514
	if (opt_xml)
	{
	  print_xml_row(sql_file, "key", tableRes, &row);
	  continue;
	}
        
1515 1516
        if (atoi(row[3]) == 1)
        {
unknown's avatar
unknown committed
1517 1518 1519 1520
	  if (keynr++)
	    putc(')', sql_file);
	  if (atoi(row[1]))       /* Test if duplicate key */
	    /* Duplicate allowed */
unknown's avatar
unknown committed
1521
	    fprintf(sql_file, ",\n  KEY %s (",quote_name(row[2],name_buff,0));
unknown's avatar
unknown committed
1522 1523 1524
	  else if (keynr == primary_key)
	    fputs(",\n  PRIMARY KEY (",sql_file); /* First UNIQUE is primary */
	  else
unknown's avatar
unknown committed
1525 1526
	    fprintf(sql_file, ",\n  UNIQUE %s (",quote_name(row[2],name_buff,
							    0));
1527 1528
        }
        else
unknown's avatar
unknown committed
1529
	  putc(',', sql_file);
unknown's avatar
unknown committed
1530
        fputs(quote_name(row[4], name_buff, 0), sql_file);
1531
        if (row[7])
unknown's avatar
unknown committed
1532
	  fprintf(sql_file, " (%s)",row[7]);      /* Sub key */
1533
	check_io(sql_file);
1534
      }
1535 1536 1537 1538 1539
      if (!opt_xml)
      {
	if (keynr)
	  putc(')', sql_file);
	fputs("\n)",sql_file);
1540
	check_io(sql_file);
1541
      }
1542 1543 1544

      /* Get MySQL specific create options */
      if (create_options)
unknown's avatar
unknown committed
1545
      {
unknown's avatar
unknown committed
1546
	char show_name_buff[NAME_LEN*2+2+24];
1547 1548 1549 1550 1551

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

1552
        if (mysql_query_with_error_report(sock, &tableRes, buff))
1553
        {
unknown's avatar
unknown committed
1554 1555 1556 1557
	  if (mysql_errno(sock) != ER_PARSE_ERROR)
	  {					/* If old MySQL version */
	    if (verbose)
	      fprintf(stderr,
unknown's avatar
unknown committed
1558 1559
		      "-- Warning: Couldn't get status information for table %s (%s)\n",
		      result_table,mysql_error(sock));
unknown's avatar
unknown committed
1560
	  }
1561
        }
1562
        else if (!(row=mysql_fetch_row(tableRes)))
1563
        {
unknown's avatar
unknown committed
1564
	  fprintf(stderr,
unknown's avatar
unknown committed
1565 1566
		  "Error: Couldn't read status information for table %s (%s)\n",
		  result_table,mysql_error(sock));
1567 1568 1569
        }
        else
        {
1570 1571 1572 1573 1574 1575 1576
	  if (opt_xml)
	  {
	    print_xml_row(sql_file, "options", tableRes, &row);
	  }
	  else
	  {
	    fputs("/*!",sql_file);
unknown's avatar
unknown committed
1577
	    print_value(sql_file,tableRes,row,"engine=","Engine",0);
1578 1579 1580
	    print_value(sql_file,tableRes,row,"","Create_options",0);
	    print_value(sql_file,tableRes,row,"comment=","Comment",1);
	    fputs(" */",sql_file);
1581
	    check_io(sql_file);
1582
	  }
1583 1584
        }
        mysql_free_result(tableRes);		/* Is always safe to free */
unknown's avatar
unknown committed
1585
      }
1586
continue_xml:
1587 1588 1589 1590
      if (!opt_xml)
	fputs(";\n", sql_file);
      else
	fputs("\t</table_structure>\n", sql_file);
1591
      check_io(sql_file);
unknown's avatar
unknown committed
1592 1593
    }
  }
1594
  if (opt_complete_insert)
unknown's avatar
unknown committed
1595
  {
1596
    dynstr_append_mem(&insert_pat, ") VALUES ", 9);
unknown's avatar
unknown committed
1597
    if (!extended_insert)
1598
      dynstr_append_mem(&insert_pat, "(", 1);
unknown's avatar
unknown committed
1599
  }
1600
  if (sql_file != md_result_file)
1601 1602 1603
  {
    fputs("\n", sql_file);
    write_footer(sql_file);
1604
    my_fclose(sql_file, MYF(MY_WME));
1605
  }
unknown's avatar
unknown committed
1606
  DBUG_RETURN(numFields);
1607
} /* get_table_structure */
unknown's avatar
unknown committed
1608 1609 1610 1611 1612 1613 1614


static char *add_load_option(char *ptr,const char *object,
			     const char *statement)
{
  if (object)
  {
1615 1616 1617 1618 1619 1620 1621 1622 1623 1624
    /* 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++= '\'';
    }
unknown's avatar
unknown committed
1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660
  }
  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 */


1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672
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;
}

1673

unknown's avatar
unknown committed
1674
/*
1675
** dump_table saves database contents as a series of INSERT statements.
unknown's avatar
unknown committed
1676
*/
1677 1678

static void dump_table(uint numFields, char *table)
unknown's avatar
unknown committed
1679
{
1680
  char query_buf[QUERY_LENGTH], *end, buff[256],table_buff[NAME_LEN+3];
unknown's avatar
unknown committed
1681
  char *result_table, table_buff2[NAME_LEN*2+3], *opt_quoted_table;
1682
  char *query= query_buf;
unknown's avatar
unknown committed
1683
  MYSQL_RES	*res;
unknown's avatar
unknown committed
1684 1685
  MYSQL_FIELD	*field;
  MYSQL_ROW	row;
unknown's avatar
unknown committed
1686
  ulong		rownr, row_break, total_length, init_length;
1687
  const char    *table_type;
1688
  int error= 0;
unknown's avatar
unknown committed
1689

1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700
  /* Check --no-data flag */
  if (dFlag)
  {
    if (verbose)
      fprintf(stderr,
              "-- Skipping dump data for table '%s', --no-data was used\n",
	      table);
    return;
  }

  /* Check that there are any fields in the table */
unknown's avatar
unknown committed
1701
  if (numFields == 0)
1702 1703 1704 1705 1706 1707 1708 1709
  {
    if (verbose)
      fprintf(stderr,
	      "-- Skipping dump data for table '%s', it has no fields\n",
	      table);
    return;
  }

unknown's avatar
unknown committed
1710 1711
  result_table= quote_name(table,table_buff, 1);
  opt_quoted_table= quote_name(table, table_buff2, 0);
1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724

  /* 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");
unknown's avatar
unknown committed
1725 1726 1727
  if (path)
  {
    char filename[FN_REFLEN], tmp_path[FN_REFLEN];
1728
    convert_dirname(tmp_path,path,NullS);
unknown's avatar
unknown committed
1729 1730 1731 1732 1733
    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);
1734 1735 1736
    my_snprintf(query, QUERY_LENGTH, 
		"SELECT /*!40001 SQL_NO_CACHE */ * INTO OUTFILE '%s'",
		filename);
unknown's avatar
unknown committed
1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747
    end= strend(query);

    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';

1748
    my_snprintf(buff, sizeof(buff), " FROM %s", result_table);
unknown's avatar
unknown committed
1749
    end= strmov(end,buff);
1750
    if (where || order_by)
1751
    {
1752 1753 1754 1755 1756 1757 1758 1759 1760
      query = alloc_query_str((ulong) ((end - query) + 1 +
                             (where ? strlen(where) + 7 : 0) +
                             (order_by ? strlen(order_by) + 10 : 0)));
      end = strmov(query, query_buf);

      if (where)
        end = strxmov(end, " WHERE ", where, NullS);
      if (order_by)
        end = strxmov(end, " ORDER BY ", order_by, NullS);
1761 1762
    }
    if (mysql_real_query(sock, query, (uint) (end - query)))
unknown's avatar
unknown committed
1763
    {
1764
      DB_error(sock, "when executing 'SELECT INTO OUTFILE'");
unknown's avatar
unknown committed
1765 1766 1767 1768 1769
      return;
    }
  }
  else
  {
1770
    if (!opt_xml && opt_comments)
1771
    {
unknown's avatar
unknown committed
1772 1773
      fprintf(md_result_file,"\n--\n-- Dumping data for table %s\n--\n",
	      result_table);
1774 1775
      check_io(md_result_file);
    }
1776 1777 1778
    my_snprintf(query, QUERY_LENGTH,
		"SELECT /*!40001 SQL_NO_CACHE */ * FROM %s",
		result_table);
1779
    if (where || order_by)
unknown's avatar
unknown committed
1780
    {
1781 1782 1783 1784 1785 1786
      query = alloc_query_str((ulong) (strlen(query) + 1 +
                             (where ? strlen(where) + 7 : 0) +
                             (order_by ? strlen(order_by) + 10 : 0)));
      end = strmov(query, query_buf);

      if (where)
1787
      {
1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802
        if (!opt_xml && opt_comments)
        {
          fprintf(md_result_file, "-- WHERE:  %s\n", where);
          check_io(md_result_file);
        }
        end = strxmov(end, " WHERE ", where, NullS);
      }
      if (order_by)
      {
        if (!opt_xml && opt_comments)
        {
          fprintf(md_result_file, "-- ORDER BY:  %s\n", order_by);
          check_io(md_result_file);
        }
        end = strxmov(end, " ORDER BY ", order_by, NullS);
1803
      }
unknown's avatar
unknown committed
1804
    }
unknown's avatar
unknown committed
1805
    if (!opt_xml && !opt_compact)
1806
    {
unknown's avatar
merge  
unknown committed
1807
      fputs("\n", md_result_file);
1808 1809
      check_io(md_result_file);
    }
1810
    if (mysql_query_with_error_report(sock, 0, query))
1811
      DB_error(sock, "when retrieving data from server");
unknown's avatar
unknown committed
1812 1813 1814 1815 1816
    if (quick)
      res=mysql_use_result(sock);
    else
      res=mysql_store_result(sock);
    if (!res)
1817
      DB_error(sock, "when retrieving data from server");
unknown's avatar
unknown committed
1818
    if (verbose)
1819
      fprintf(stderr, "-- Retrieving rows...\n");
unknown's avatar
unknown committed
1820 1821
    if (mysql_num_fields(res) != numFields)
    {
unknown's avatar
unknown committed
1822 1823
      fprintf(stderr,"%s: Error in field count for table: %s !  Aborting.\n",
	      my_progname, result_table);
1824 1825
      error= EX_CONSCHECK;
      goto err;
unknown's avatar
unknown committed
1826 1827
    }

unknown's avatar
merge  
unknown committed
1828
    if (opt_disable_keys)
1829
    {
unknown's avatar
unknown committed
1830
      fprintf(md_result_file, "\n/*!40000 ALTER TABLE %s DISABLE KEYS */;\n",
unknown's avatar
unknown committed
1831
	      opt_quoted_table);
1832 1833
      check_io(md_result_file);
    }
unknown's avatar
unknown committed
1834
    if (opt_lock)
1835
    {
unknown's avatar
unknown committed
1836
      fprintf(md_result_file,"LOCK TABLES %s WRITE;\n", opt_quoted_table);
1837 1838
      check_io(md_result_file);
    }
unknown's avatar
unknown committed
1839

1840
    total_length= opt_net_buffer_length;		/* Force row break */
unknown's avatar
unknown committed
1841 1842
    row_break=0;
    rownr=0;
1843
    init_length=(uint) insert_pat.length+4;
unknown's avatar
unknown committed
1844
    if (opt_xml)
1845
      print_xml_tag1(md_result_file, "\t", "table_data name=", table, "\n");
unknown's avatar
unknown committed
1846

unknown's avatar
unknown committed
1847
    if (opt_autocommit)
1848
    {
unknown's avatar
unknown committed
1849
      fprintf(md_result_file, "set autocommit=0;\n");
1850 1851
      check_io(md_result_file);
    }
unknown's avatar
unknown committed
1852

unknown's avatar
unknown committed
1853 1854 1855 1856 1857
    while ((row=mysql_fetch_row(res)))
    {
      uint i;
      ulong *lengths=mysql_fetch_lengths(res);
      rownr++;
unknown's avatar
unknown committed
1858
      if (!extended_insert && !opt_xml)
1859
      {
1860
	fputs(insert_pat.str,md_result_file);
1861 1862
	check_io(md_result_file);
      }
unknown's avatar
unknown committed
1863 1864
      mysql_field_seek(res,0);

unknown's avatar
merge  
unknown committed
1865
      if (opt_xml)
1866
      {
1867
        fputs("\t<row>\n", md_result_file);
1868 1869
	check_io(md_result_file);
      }
unknown's avatar
merge  
unknown committed
1870

unknown's avatar
unknown committed
1871 1872
      for (i = 0; i < mysql_num_fields(res); i++)
      {
1873
        int is_blob;
unknown's avatar
unknown committed
1874 1875
	if (!(field = mysql_fetch_field(res)))
	{
1876 1877 1878
	  my_snprintf(query, QUERY_LENGTH,
		      "%s: Not enough fields from table %s! Aborting.\n",
		      my_progname, result_table);
unknown's avatar
unknown committed
1879
	  fputs(query,stderr);
1880 1881
	  error= EX_CONSCHECK;
	  goto err;
unknown's avatar
unknown committed
1882
	}
1883 1884 1885 1886
	
	/*
	   63 is my_charset_bin. If charsetnr is not 63,
	   we have not a BLOB but a TEXT column. 
unknown's avatar
unknown committed
1887
	   we'll dump in hex only BLOB columns.
1888 1889
	*/
        is_blob= (opt_hex_blob && field->charsetnr == 63 &&
1890 1891 1892 1893 1894 1895 1896
                  (field->type == MYSQL_TYPE_STRING ||
                   field->type == MYSQL_TYPE_VAR_STRING ||
                   field->type == MYSQL_TYPE_VARCHAR ||
                   field->type == MYSQL_TYPE_BLOB ||
                   field->type == MYSQL_TYPE_LONG_BLOB ||
                   field->type == MYSQL_TYPE_MEDIUM_BLOB ||
                   field->type == MYSQL_TYPE_TINY_BLOB)) ? 1 : 0;
1897
	if (extended_insert)
unknown's avatar
unknown committed
1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908
	{
	  ulong length = lengths[i];
	  if (i == 0)
	    dynstr_set(&extended_row,"(");
	  else
	    dynstr_append(&extended_row,",");

	  if (row[i])
	  {
	    if (length)
	    {
1909
	      if (!IS_NUM_FIELD(field))
unknown's avatar
unknown committed
1910
	      {
unknown's avatar
unknown committed
1911 1912 1913 1914 1915 1916 1917
	        /*
	          "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.
	        */
unknown's avatar
unknown committed
1918 1919 1920
		if (dynstr_realloc(&extended_row,length * 2+2))
		{
		  fputs("Aborting dump (out of memory)",stderr);
1921 1922
		  error= EX_EOM;
		  goto err;
unknown's avatar
unknown committed
1923
		}
1924 1925 1926
                if (opt_hex_blob && is_blob)
                {
                  dynstr_append(&extended_row, "0x");
unknown's avatar
unknown committed
1927 1928 1929 1930
                  extended_row.length+= mysql_hex_string(extended_row.str + 
                                                         extended_row.length,
                                                         row[i], length);
                  extended_row.str[extended_row.length]= '\0';
1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941
                }
                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,"'");
                }
unknown's avatar
unknown committed
1942 1943
	      }
	      else
1944
	      {
unknown's avatar
unknown committed
1945
		/* change any strings ("inf", "-inf", "nan") into NULL */
1946
		char *ptr = row[i];
unknown's avatar
unknown committed
1947 1948
		if (my_isalpha(charset_info, *ptr) || (*ptr == '-' &&
		    my_isalpha(charset_info, ptr[1])))
unknown's avatar
unknown committed
1949 1950 1951 1952 1953 1954
		  dynstr_append(&extended_row, "NULL");
		else
		{
		  if (field->type == FIELD_TYPE_DECIMAL)
		  {
		    /* add " signs around */
unknown's avatar
unknown committed
1955
		    dynstr_append(&extended_row, "'");
unknown's avatar
unknown committed
1956
		    dynstr_append(&extended_row, ptr);
unknown's avatar
unknown committed
1957
		    dynstr_append(&extended_row, "'");
unknown's avatar
unknown committed
1958 1959 1960 1961
		  }
		  else
		    dynstr_append(&extended_row, ptr);
		}
1962
	      }
unknown's avatar
unknown committed
1963 1964
	    }
	    else
unknown's avatar
unknown committed
1965
	      dynstr_append(&extended_row,"''");
unknown's avatar
unknown committed
1966 1967 1968 1969
	  }
	  else if (dynstr_append(&extended_row,"NULL"))
	  {
	    fputs("Aborting dump (out of memory)",stderr);
1970 1971
	    error= EX_EOM;
	    goto err;
unknown's avatar
unknown committed
1972 1973 1974 1975
	  }
	}
	else
	{
unknown's avatar
unknown committed
1976
	  if (i && !opt_xml)
1977
	  {
unknown's avatar
unknown committed
1978
	    fputc(',', md_result_file);
1979 1980
	    check_io(md_result_file);
	  }
unknown's avatar
unknown committed
1981 1982
	  if (row[i])
	  {
1983
	    if (!IS_NUM_FIELD(field))
1984
	    {
unknown's avatar
unknown committed
1985
	      if (opt_xml)
1986
	      {
1987 1988
	        print_xml_tag1(md_result_file, "\t\t", "field name=",
			      field->name, "");
1989 1990 1991
		print_quoted_xml(md_result_file, row[i], lengths[i]);
		fputs("</field>\n", md_result_file);
	      }
1992
	      else if (opt_hex_blob && is_blob)
unknown's avatar
unknown committed
1993 1994
              {
                /* sakaik got the idea to to provide blob's in hex notation. */
1995
                char *ptr= row[i], *end= ptr+ lengths[i];
1996
                fputs("0x", md_result_file);
unknown's avatar
unknown committed
1997
                for (; ptr < end ; ptr++)
1998
		  fprintf(md_result_file, "%02X", *((uchar *)ptr));
1999 2000 2001
              }
              else
                unescape(md_result_file, row[i], lengths[i]);
unknown's avatar
unknown committed
2002
	    }
unknown's avatar
unknown committed
2003
	    else
2004
	    {
unknown's avatar
unknown committed
2005
	      /* change any strings ("inf", "-inf", "nan") into NULL */
2006
	      char *ptr = row[i];
unknown's avatar
unknown committed
2007
	      if (opt_xml)
2008
	      {
2009 2010
	        print_xml_tag1(md_result_file, "\t\t", "field name=",
			       field->name, "");
2011 2012 2013 2014
		fputs(!my_isalpha(charset_info, *ptr) ? ptr: "NULL",
		      md_result_file);
		fputs("</field>\n", md_result_file);
	      }
unknown's avatar
unknown committed
2015 2016 2017 2018
	      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)
unknown's avatar
unknown committed
2019 2020
	      {
		/* add " signs around */
unknown's avatar
unknown committed
2021
		fputc('\'', md_result_file);
unknown's avatar
unknown committed
2022
		fputs(ptr, md_result_file);
unknown's avatar
unknown committed
2023
		fputc('\'', md_result_file);
unknown's avatar
unknown committed
2024
	      }
unknown's avatar
unknown committed
2025
	      else
unknown's avatar
unknown committed
2026
		fputs(ptr, md_result_file);
2027
	    }
unknown's avatar
unknown committed
2028
	  }
2029
	  else
2030 2031 2032 2033 2034 2035 2036 2037
          {
            /* The field value is NULL */
            if (!opt_xml)
              fputs("NULL", md_result_file);
            else
              print_xml_null_tag(md_result_file, "\t\t", "field name=",
                                 field->name, "\n");
          }
unknown's avatar
Merge  
unknown committed
2038
          check_io(md_result_file);
unknown's avatar
unknown committed
2039 2040 2041
	}
      }

unknown's avatar
merge  
unknown committed
2042
      if (opt_xml)
2043
      {
2044
        fputs("\t</row>\n", md_result_file);
2045 2046
	check_io(md_result_file);
      }
unknown's avatar
merge  
unknown committed
2047

2048
      if (extended_insert)
unknown's avatar
unknown committed
2049 2050 2051 2052
      {
	ulong row_length;
	dynstr_append(&extended_row,")");
        row_length = 2 + extended_row.length;
2053
        if (total_length + row_length < opt_net_buffer_length)
unknown's avatar
unknown committed
2054 2055
        {
	  total_length += row_length;
unknown's avatar
unknown committed
2056 2057
	  fputc(',',md_result_file);		/* Always row break */
	  fputs(extended_row.str,md_result_file);
unknown's avatar
unknown committed
2058 2059 2060
	}
        else
        {
2061
	  if (row_break)
unknown's avatar
unknown committed
2062
	    fputs(";\n", md_result_file);
unknown's avatar
unknown committed
2063
	  row_break=1;				/* This is first row */
unknown's avatar
unknown committed
2064

2065
          fputs(insert_pat.str,md_result_file);
2066
          fputs(extended_row.str,md_result_file);
unknown's avatar
unknown committed
2067 2068
	  total_length = row_length+init_length;
        }
2069
	check_io(md_result_file);
unknown's avatar
unknown committed
2070
      }
unknown's avatar
unknown committed
2071
      else if (!opt_xml)
2072
      {
unknown's avatar
unknown committed
2073
	fputs(");\n", md_result_file);
2074 2075
	check_io(md_result_file);
      }
unknown's avatar
unknown committed
2076
    }
unknown's avatar
unknown committed
2077

unknown's avatar
unknown committed
2078
    /* XML - close table tag and supress regular output */
unknown's avatar
unknown committed
2079
    if (opt_xml)
2080
	fputs("\t</table_data>\n", md_result_file);
unknown's avatar
unknown committed
2081
    else if (extended_insert && row_break)
unknown's avatar
unknown committed
2082 2083
      fputs(";\n", md_result_file);		/* If not empty table */
    fflush(md_result_file);
2084
    check_io(md_result_file);
unknown's avatar
unknown committed
2085 2086
    if (mysql_errno(sock))
    {
2087 2088 2089 2090 2091 2092 2093
      my_snprintf(query, QUERY_LENGTH,
		  "%s: Error %d: %s when dumping table %s at row: %ld\n",
		  my_progname,
		  mysql_errno(sock),
		  mysql_error(sock),
		  result_table,
		  rownr);
unknown's avatar
unknown committed
2094
      fputs(query,stderr);
2095 2096
      error= EX_CONSCHECK;
      goto err;
unknown's avatar
unknown committed
2097 2098
    }
    if (opt_lock)
2099
    {
unknown's avatar
unknown committed
2100
      fputs("UNLOCK TABLES;\n", md_result_file);
2101 2102
      check_io(md_result_file);
    }
unknown's avatar
merge  
unknown committed
2103
    if (opt_disable_keys)
2104
    {
unknown's avatar
merge  
unknown committed
2105
      fprintf(md_result_file,"/*!40000 ALTER TABLE %s ENABLE KEYS */;\n",
unknown's avatar
unknown committed
2106
	      opt_quoted_table);
2107 2108
      check_io(md_result_file);
    }
unknown's avatar
unknown committed
2109
    if (opt_autocommit)
2110
    {
unknown's avatar
unknown committed
2111
      fprintf(md_result_file, "commit;\n");
2112 2113
      check_io(md_result_file);
    }
2114
    mysql_free_result(res);
2115 2116 2117 2118 2119 2120 2121 2122 2123 2124
    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;
2125
} /* dump_table */
unknown's avatar
unknown committed
2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139


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]);
unknown's avatar
unknown committed
2140

unknown's avatar
unknown committed
2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157
  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;

2158
  if (mysql_query_with_error_report(sock, &tableres, "SHOW DATABASES"))
unknown's avatar
unknown committed
2159 2160 2161 2162 2163 2164
    return 1;
  while ((row = mysql_fetch_row(tableres)))
  {
    if (dump_all_tables_in_db(row[0]))
      result=1;
  }
2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179
  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;
    }
  }
unknown's avatar
unknown committed
2180 2181 2182 2183 2184 2185 2186 2187
  return result;
}
/* dump_all_databases */


static int dump_databases(char **db_names)
{
  int result=0;
2188 2189
  char **db;
  for (db= db_names ; *db ; db++)
2190
  {
2191
    if (dump_all_tables_in_db(*db))
unknown's avatar
unknown committed
2192 2193
      result=1;
  }
2194 2195 2196 2197 2198 2199 2200 2201
  if (!result && was_views)
  {
    for (db= db_names ; *db ; db++)
    {
      if (dump_all_views_in_db(*db))
        result=1;
    }
  }
unknown's avatar
unknown committed
2202 2203 2204 2205 2206 2207
  return result;
} /* dump_databases */


static int init_dumping(char *database)
{
2208
  if (mysql_get_server_version(sock) >= 50003 &&
unknown's avatar
unknown committed
2209 2210
      !my_strcasecmp(&my_charset_latin1, database, "information_schema"))
    return 1; 
2211

unknown's avatar
unknown committed
2212 2213
  if (mysql_select_db(sock, database))
  {
2214
    DB_error(sock, "when selecting the database");
unknown's avatar
unknown committed
2215 2216
    return 1;			/* If --force */
  }
unknown's avatar
unknown committed
2217
  if (!path && !opt_xml)
unknown's avatar
unknown committed
2218 2219 2220
  {
    if (opt_databases || opt_alldbs)
    {
unknown's avatar
unknown committed
2221
      /*
unknown's avatar
unknown committed
2222
	length of table name * 2 (if name contains quotes), 2 quotes and 0
unknown's avatar
unknown committed
2223
      */
unknown's avatar
unknown committed
2224 2225
      char quoted_database_buf[64*2+3];
      char *qdatabase= quote_name(database,quoted_database_buf,opt_quoted);
2226
      if (opt_comments)
2227
      {
unknown's avatar
unknown committed
2228
	fprintf(md_result_file,"\n--\n-- Current Database: %s\n--\n", qdatabase);
2229 2230
	check_io(md_result_file);
      }
unknown's avatar
unknown committed
2231
      if (!opt_create_db)
2232
      {
unknown's avatar
unknown committed
2233
        char qbuf[256];
2234 2235
        MYSQL_ROW row;
        MYSQL_RES *dbinfo;
2236

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

2241
        if (mysql_query(sock, qbuf) || !(dbinfo = mysql_store_result(sock)))
2242 2243
        {
          /* Old server version, dump generic CREATE DATABASE */
unknown's avatar
unknown committed
2244 2245 2246 2247
          if (opt_drop_database)
            fprintf(md_result_file,
                    "\n/*!40000 DROP DATABASE IF EXISTS %s;*/\n",
                    qdatabase);
2248
	  fprintf(md_result_file,
unknown's avatar
unknown committed
2249 2250
		  "\nCREATE DATABASE /*!32312 IF NOT EXISTS*/ %s;\n",
		  qdatabase);
2251 2252 2253
	}
	else
        {
unknown's avatar
unknown committed
2254 2255 2256 2257
          if (opt_drop_database)
            fprintf(md_result_file,
                    "\n/*!40000 DROP DATABASE IF EXISTS %s*/;\n",
                    qdatabase);
2258 2259 2260 2261 2262 2263 2264
	  row = mysql_fetch_row(dbinfo);
	  if (row[1])
	  {
	    fprintf(md_result_file,"\n%s;\n",row[1]);
          }
	}
      }
unknown's avatar
unknown committed
2265
      fprintf(md_result_file,"\nUSE %s;\n", qdatabase);
2266
      check_io(md_result_file);
unknown's avatar
unknown committed
2267 2268
    }
  }
unknown's avatar
unknown committed
2269 2270
  if (extended_insert && init_dynamic_string(&extended_row, "", 1024, 1024))
    exit(EX_EOM);
unknown's avatar
unknown committed
2271 2272 2273 2274
  return 0;
} /* init_dumping */


2275 2276
my_bool include_table(byte* hash_key, uint len)
{
unknown's avatar
unknown committed
2277
  if (hash_search(&ignore_table, (byte*) hash_key, len))
2278 2279 2280 2281 2282
    return FALSE;

  return TRUE;
}

unknown's avatar
unknown committed
2283

unknown's avatar
unknown committed
2284 2285 2286 2287
static int dump_all_tables_in_db(char *database)
{
  char *table;
  uint numrows;
unknown's avatar
unknown committed
2288
  char table_buff[NAME_LEN*2+3];
unknown's avatar
unknown committed
2289

2290 2291 2292 2293 2294 2295
  char hash_key[2*NAME_LEN+2];  /* "db.tablename" */
  char *afterdot;

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

unknown's avatar
unknown committed
2296 2297
  if (init_dumping(database))
    return 1;
unknown's avatar
unknown committed
2298
  if (opt_xml)
2299
    print_xml_tag1(md_result_file, "", "database name=", database, "\n");
unknown's avatar
unknown committed
2300 2301 2302 2303
  if (lock_tables)
  {
    DYNAMIC_STRING query;
    init_dynamic_string(&query, "LOCK TABLES ", 256, 1024);
2304
    for (numrows= 0 ; (table= getTableName(1)) ; numrows++)
unknown's avatar
unknown committed
2305
    {
unknown's avatar
unknown committed
2306
      dynstr_append(&query, quote_name(table, table_buff, 1));
unknown's avatar
unknown committed
2307 2308 2309
      dynstr_append(&query, " READ /*!32311 LOCAL */,");
    }
    if (numrows && mysql_real_query(sock, query.str, query.length-1))
2310
      DB_error(sock, "when using LOCK TABLES");
unknown's avatar
unknown committed
2311 2312 2313 2314 2315 2316
            /* We shall continue here, if --force was given */
    dynstr_free(&query);
  }
  if (flush_logs)
  {
    if (mysql_refresh(sock, REFRESH_LOG))
2317
      DB_error(sock, "when doing refresh");
unknown's avatar
unknown committed
2318 2319
           /* We shall continue here, if --force was given */
  }
2320
  while ((table= getTableName(0)))
unknown's avatar
unknown committed
2321
  {
2322 2323 2324
    char *end= strmov(afterdot, table);
    if (include_table(hash_key, end - hash_key))
    {
2325
      numrows = get_table_structure(table, database);
2326
      dump_table(numrows,table);
2327 2328 2329
      my_free(order_by, MYF(MY_ALLOW_ZERO_PTR));
      order_by= 0;
    }
unknown's avatar
unknown committed
2330
  }
unknown's avatar
unknown committed
2331
  if (opt_xml)
2332
  {
2333
    fputs("</database>\n", md_result_file);
2334 2335
    check_io(md_result_file);
  }
unknown's avatar
unknown committed
2336
  if (lock_tables)
2337
    mysql_query_with_error_report(sock, 0, "UNLOCK TABLES");
unknown's avatar
unknown committed
2338 2339 2340 2341
  return 0;
} /* dump_all_tables_in_db */


2342 2343 2344 2345 2346 2347
/*
   dump structure of views of database

   SYNOPSIS
     dump_all_views_in_db()
     database  database name
unknown's avatar
unknown committed
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
  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))
2374
      DB_error(sock, "when using LOCK TABLES");
2375 2376 2377 2378 2379 2380
            /* We shall continue here, if --force was given */
    dynstr_free(&query);
  }
  if (flush_logs)
  {
    if (mysql_refresh(sock, REFRESH_LOG))
2381
      DB_error(sock, "when doing refresh");
2382 2383 2384
           /* We shall continue here, if --force was given */
  }
  while ((table= getTableName(0)))
2385
     get_view_structure(table, database);
2386 2387 2388 2389 2390 2391 2392 2393 2394
  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 */
unknown's avatar
unknown committed
2395

unknown's avatar
unknown committed
2396

2397
/*
2398 2399 2400 2401
  get_actual_table_name -- executes a SHOW TABLES LIKE '%s' to get the actual 
  table name from the server for the table name given on the command line.  
  we do this because the table name given on the command line may be a 
  different case (e.g.  T1 vs t1)
2402 2403
  
  RETURN
2404
    int - 0 if a tablename was retrieved.  1 if not
2405 2406
*/

2407
static int get_actual_table_name(const char *old_table_name, 
2408 2409 2410
                                  char *new_table_name, 
                                  int buf_size)
{
2411
  int retval;
2412
  MYSQL_RES  *table_res;
2413
  MYSQL_ROW  row;
2414
  char query[50 + 2*NAME_LEN];
2415
  char show_name_buff[FN_REFLEN];
2416
  DBUG_ENTER("get_actual_table_name");
2417

2418 2419 2420 2421 2422
  /* Check memory for quote_for_like() */
  DBUG_ASSERT(2*sizeof(old_table_name) < sizeof(show_name_buff));
  my_snprintf(query, sizeof(query), "SHOW TABLES LIKE %s", 
	      quote_for_like(old_table_name, show_name_buff));

2423 2424 2425 2426
  if (mysql_query_with_error_report(sock, 0, query))
  {
    safe_exit(EX_MYSQLERR);
  }
2427

2428
  retval = 1;
2429 2430
  
  if ((table_res= mysql_store_result(sock)))
2431
  {
2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443
    my_ulonglong num_rows= mysql_num_rows(table_res);
    if (num_rows > 0)
    {
      /*
        Return first row
        TODO: Return all matching rows
      */
      row= mysql_fetch_row(table_res);
      strmake(new_table_name, row[0], buf_size-1);
      retval= 0;
    }
    mysql_free_result(table_res);
2444
  }
2445
  return retval;
2446
}
2447

unknown's avatar
unknown committed
2448 2449 2450

static int dump_selected_tables(char *db, char **table_names, int tables)
{
unknown's avatar
patch  
unknown committed
2451
  uint numrows, i;
unknown's avatar
unknown committed
2452
  char table_buff[NAME_LEN*+3];
unknown's avatar
patch  
unknown committed
2453 2454 2455
  char new_table_name[NAME_LEN];
  DYNAMIC_STRING lock_tables_query;
  HASH dump_tables;
2456
  char *table_name;
unknown's avatar
patch  
unknown committed
2457
  DBUG_ENTER("dump_selected_tables");
unknown's avatar
unknown committed
2458 2459 2460

  if (init_dumping(db))
    return 1;
unknown's avatar
patch  
unknown committed
2461 2462 2463

  /* Init hash table for storing the actual name of tables to dump */
  if (hash_init(&dump_tables, charset_info, 16, 0, 0,
unknown's avatar
unknown committed
2464
                 (hash_get_key) get_table_key, (hash_free_key) free_table_ent,
unknown's avatar
unknown committed
2465
                0))
unknown's avatar
patch  
unknown committed
2466 2467 2468 2469
    exit(EX_EOM);

  init_dynamic_string(&lock_tables_query, "LOCK TABLES ", 256, 1024);
  for (; tables > 0 ; tables-- , table_names++)
unknown's avatar
unknown committed
2470
  {
unknown's avatar
patch  
unknown committed
2471
    /* the table name passed on commandline may be wrong case */
unknown's avatar
unknown committed
2472
    if (!get_actual_table_name(*table_names,
unknown's avatar
unknown committed
2473
                               new_table_name, sizeof(new_table_name)))
unknown's avatar
unknown committed
2474
    {
unknown's avatar
patch  
unknown committed
2475 2476 2477 2478 2479 2480 2481
      /* Add found table name to lock_tables_query */
      if (lock_tables)
      {
        dynstr_append(&lock_tables_query,
                      quote_name(new_table_name, table_buff, 1));
        dynstr_append(&lock_tables_query, " READ /*!32311 LOCAL */,");
      }
unknown's avatar
unknown committed
2482

unknown's avatar
patch  
unknown committed
2483 2484 2485 2486 2487
      /* Add found table name to dump_tables list */
      if (my_hash_insert(&dump_tables,
                         (byte*)my_strdup(new_table_name, MYF(0))))
        exit(EX_EOM);

unknown's avatar
unknown committed
2488
    }
unknown's avatar
patch  
unknown committed
2489
    else
unknown's avatar
unknown committed
2490
    {
unknown's avatar
patch  
unknown committed
2491 2492 2493 2494
       my_printf_error(0,"Couldn't find table: \"%s\"\n", MYF(0),
                       *table_names);
       safe_exit(EX_ILLEGAL_TABLE);
       /* We shall countinue here, if --force was given */
unknown's avatar
unknown committed
2495
    }
unknown's avatar
patch  
unknown committed
2496 2497 2498 2499 2500 2501
  }

  if (lock_tables)
  {
    if (mysql_real_query(sock, lock_tables_query.str,
                         lock_tables_query.length-1))
2502
      DB_error(sock, "when doing LOCK TABLES");
unknown's avatar
unknown committed
2503 2504
       /* We shall countinue here, if --force was given */
  }
unknown's avatar
patch  
unknown committed
2505
  dynstr_free(&lock_tables_query);
unknown's avatar
unknown committed
2506 2507 2508
  if (flush_logs)
  {
    if (mysql_refresh(sock, REFRESH_LOG))
2509
      DB_error(sock, "when doing refresh");
unknown's avatar
unknown committed
2510 2511
     /* We shall countinue here, if --force was given */
  }
unknown's avatar
unknown committed
2512
  if (opt_xml)
2513
    print_xml_tag1(md_result_file, "", "database name=", db, "\n");
2514

unknown's avatar
patch  
unknown committed
2515
  /* Dump each selected table */
unknown's avatar
unknown committed
2516
  for (i= 0; i < dump_tables.records; i++)
unknown's avatar
unknown committed
2517
  {
unknown's avatar
patch  
unknown committed
2518 2519
    table_name= hash_element(&dump_tables, i);
    DBUG_PRINT("info",("Dumping table %s", table_name));
unknown's avatar
unknown committed
2520
    numrows= get_table_structure(table_name, db);
unknown's avatar
unknown committed
2521
    dump_table(numrows, table_name);
2522
  }
2523 2524

  /* Dump each selected view */
2525 2526
  if (was_views)
  {
unknown's avatar
unknown committed
2527 2528 2529 2530
    for(i=0; i < dump_tables.records; i++)
    {
      table_name= hash_element(&dump_tables, i);
      get_view_structure(table_name, db);
unknown's avatar
unknown committed
2531
    }
unknown's avatar
unknown committed
2532
  }
unknown's avatar
patch  
unknown committed
2533 2534 2535
  hash_free(&dump_tables);
  my_free(order_by, MYF(MY_ALLOW_ZERO_PTR));
  order_by= 0;
unknown's avatar
unknown committed
2536
  if (opt_xml)
2537
  {
2538
    fputs("</database>\n", md_result_file);
2539 2540
    check_io(md_result_file);
  }
unknown's avatar
unknown committed
2541
  if (lock_tables)
2542
    mysql_query_with_error_report(sock, 0, "UNLOCK TABLES");
unknown's avatar
patch  
unknown committed
2543
  DBUG_RETURN(0);
unknown's avatar
unknown committed
2544 2545 2546
} /* dump_selected_tables */


2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580
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)
{
2581 2582 2583 2584 2585 2586 2587 2588
  /*
    We do first a FLUSH TABLES. If a long update is running, the FLUSH TABLES
    will wait but will not stall the whole mysqld, and when the long update is
    done the FLUSH TABLES WITH READ LOCK will start and succeed quickly. So,
    FLUSH TABLES is to lower the probability of a stage where both mysqldump
    and most client connections are stalled. Of course, if a second long
    update starts between the two FLUSHes, we have that bad stall.
  */
2589
  return 
2590 2591 2592
    ( mysql_query_with_error_report(mysql_con, 0, "FLUSH TABLES") ||
      mysql_query_with_error_report(mysql_con, 0,
                                    "FLUSH TABLES WITH READ LOCK") );
2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613
}


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).
2614 2615 2616 2617

    We want the first consistent read to be used for all tables to dump so we
    need the REPEATABLE READ level (not anything lower, for example READ
    COMMITTED would give one new consistent read per dumped table).
2618 2619
  */
  return (mysql_query_with_error_report(mysql_con, 0,
2620 2621 2622
                                        "SET SESSION TRANSACTION ISOLATION "
                                        "LEVEL REPEATABLE READ") ||
          mysql_query_with_error_report(mysql_con, 0,
2623 2624 2625 2626 2627 2628
                                        consistent_read_now ?
                                        "START TRANSACTION "
                                        "WITH CONSISTENT SNAPSHOT" :
                                        "BEGIN"));
}

2629 2630 2631 2632 2633 2634 2635 2636 2637

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];

2638
  *err_pos= 0;                  /* No error yet */
2639
  while (end > x && my_isspace(charset_info, end[-1]))
2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670
    end--;

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

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


unknown's avatar
unknown committed
2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687
/* 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)
unknown's avatar
unknown committed
2688
	  unescape(file,row[0],(uint) strlen(row[0]));
unknown's avatar
unknown committed
2689 2690
	else
	  fputs(row[0], file);
2691
	check_io(file);
unknown's avatar
unknown committed
2692 2693 2694 2695 2696 2697 2698 2699
	return;
      }
    }
  }
  return;					/* This shouldn't happen */
} /* print_value */


2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723
/*
  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;

2724 2725 2726 2727
  /* Check memory for quote_for_like() */
  DBUG_ASSERT(2*sizeof(table_name) < sizeof(show_name_buff));
  my_snprintf(buff, sizeof(buff), "show table status like %s",
	      quote_for_like(table_name, show_name_buff));
2728
  if (mysql_query_with_error_report(sock, &res, buff))
2729 2730 2731 2732 2733 2734 2735 2736 2737 2738
  {
    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 */
    }
  }
2739
  if (!(row= mysql_fetch_row(res)))
2740 2741 2742 2743
  {
    fprintf(stderr,
	    "Error: Couldn't read status information for table %s (%s)\n",
	    table_name, mysql_error(sock));
2744
    mysql_free_result(res);
2745 2746
    return 0;					/* assume table is ok */
  }
2747 2748 2749 2750 2751 2752 2753 2754
  if (!(row[1]))
      result= "VIEW";
  else
  {
    if (strcmp(row[1], (result= "MRG_MyISAM")) &&
        strcmp(row[1], (result= "MRG_ISAM")))
      result= 0;
  }
2755
  mysql_free_result(res);
2756 2757 2758
  return result;
}

2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781
/*
  Get string of comma-separated primary key field names

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

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

    Returns NULL if there is no PRIMARY or UNIQUE key on the table,
    or if there is some failure.  It is better to continue to dump
    the table unsorted, rather than exit without dumping the data.
*/
static char *primary_key_fields(const char *table_name)
{
  MYSQL_RES  *res = NULL;
  MYSQL_ROW  row;
  /* SHOW KEYS FROM + table name * 2 (escaped) + 2 quotes + \0 */
  char show_keys_buff[15 + 64 * 2 + 3];
unknown's avatar
unknown committed
2782
  uint result_length = 0;
2783 2784
  char *result = 0;

2785 2786
  my_snprintf(show_keys_buff, sizeof(show_keys_buff), 
	      "SHOW KEYS FROM %s", table_name);
2787 2788 2789 2790 2791 2792 2793 2794 2795 2796
  if (mysql_query(sock, show_keys_buff) ||
      !(res = mysql_store_result(sock)))
  {
    fprintf(stderr, "Warning: Couldn't read keys from table %s;"
            " records are NOT sorted (%s)\n",
            table_name, mysql_error(sock));
    /* Don't exit, because it's better to print out unsorted records */
    goto cleanup;
  }

unknown's avatar
unknown committed
2797 2798 2799 2800 2801 2802 2803
  /*
   * Figure out the length of the ORDER BY clause result.
   * Note that SHOW KEYS is ordered:  a PRIMARY key is always the first
   * row, and UNIQUE keys come before others.  So we only need to check
   * the first key, not all keys.
   */
  if ((row = mysql_fetch_row(res)) && atoi(row[1]) == 0)
2804
  {
unknown's avatar
unknown committed
2805 2806 2807 2808
    /* Key is unique */
    do
      result_length += strlen(row[4]) + 1;      /* + 1 for ',' or \0 */
    while ((row = mysql_fetch_row(res)) && atoi(row[3]) > 1);
2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819
  }

  /* Build the ORDER BY clause result */
  if (result_length) {
    char *end;
    /* result (terminating \0 is already in result_length) */
    result = my_malloc(result_length + 10, MYF(MY_WME));
    if (!result) {
      fprintf(stderr, "Error: Not enough memory to store ORDER BY clause\n");
      goto cleanup;
    }
unknown's avatar
unknown committed
2820
    mysql_data_seek(res, 0);
2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833
    row = mysql_fetch_row(res);
    end = strmov(result, row[4]);
    while ((row = mysql_fetch_row(res)) && atoi(row[3]) > 1)
      end = strxmov(end, ",", row[4], NullS);
  }

cleanup:
  if (res)
    mysql_free_result(res);

  return result;
}

2834

2835 2836 2837 2838
/*
  Getting VIEW structure

  SYNOPSIS
2839
    get_view_structure()
2840 2841 2842 2843 2844 2845 2846 2847
    table   view name
    db      db name

  RETURN
    0 OK
    1 ERROR
*/

2848
static my_bool get_view_structure(char *table, char* db)
2849
{
2850
  MYSQL_RES  *table_res;
2851 2852 2853 2854 2855 2856 2857
  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;
2858
  DBUG_ENTER("get_view_structure");
2859 2860 2861 2862 2863 2864 2865

  if (tFlag)
    DBUG_RETURN(0);

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

unknown's avatar
unknown committed
2866
#ifdef NOT_REALLY_USED_YET
2867 2868
  sprintf(insert_pat,"SET OPTION SQL_QUOTE_SHOW_CREATE=%d",
	  (opt_quoted || opt_keywords));
unknown's avatar
unknown committed
2869 2870
#endif

2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895
  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);
  }
2896 2897
  table_res= mysql_store_result(sock);
  field= mysql_fetch_field_direct(table_res, 0);
2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912
  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)
  {
2913
    fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", opt_quoted_table);
2914 2915 2916 2917
    fprintf(sql_file, "DROP VIEW IF EXISTS %s;\n", opt_quoted_table);
    check_io(sql_file);
  }

2918
  row= mysql_fetch_row(table_res);
2919 2920
  fprintf(sql_file, "%s;\n", row[1]);
  check_io(sql_file);
2921
  mysql_free_result(table_res);
2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932

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


unknown's avatar
unknown committed
2933 2934
int main(int argc, char **argv)
{
2935
  compatible_mode_normal_str[0]= 0;
2936
  default_charset= (char *)mysql_universal_client_charset;
unknown's avatar
unknown committed
2937
  bzero((char*) &ignore_table, sizeof(ignore_table));
unknown's avatar
unknown committed
2938

2939
  MY_INIT("mysqldump");
unknown's avatar
unknown committed
2940 2941 2942 2943 2944
  if (get_options(&argc, &argv))
  {
    my_end(0);
    exit(EX_USAGE);
  }
2945
  if (dbConnect(current_host, current_user, opt_password))
unknown's avatar
unknown committed
2946 2947
    exit(EX_MYSQLERR);
  if (!path)
2948 2949
    write_header(md_result_file, *argv);

2950 2951 2952 2953 2954 2955 2956 2957
  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)
2958
  {
2959 2960 2961
    if (flush_logs && mysql_refresh(sock, REFRESH_LOG))
      goto err;
    flush_logs= 0; /* not anymore; that would not be sensible */
2962
  }
2963 2964
  if (opt_master_data && do_show_master_status(sock))
    goto err;
2965
  if (opt_single_transaction && do_unlock_tables(sock)) /* unlock but no commit! */
2966 2967
    goto err;

unknown's avatar
unknown committed
2968 2969 2970
  if (opt_alldbs)
    dump_all_databases();
  else if (argc > 1 && !opt_databases)
2971 2972
  {
    /* Only one database and selected table(s) */
unknown's avatar
unknown committed
2973
    dump_selected_tables(*argv, (argv + 1), (argc - 1));
2974
  }
unknown's avatar
unknown committed
2975
  else
2976 2977
  {
    /* One or more databases, all tables */
unknown's avatar
unknown committed
2978
    dump_databases(argv);
2979
  }
2980 2981 2982
#ifdef HAVE_SMEM
  my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR));
#endif
2983 2984 2985 2986 2987 2988 2989
  /*
    No reason to explicitely COMMIT the transaction, neither to explicitely
    UNLOCK TABLES: these will be automatically be done by the server when we
    disconnect now. Saves some code here, some network trips, adds nothing to
    server.
  */
err:
unknown's avatar
unknown committed
2990
  dbDisconnect(current_host);
2991 2992
  if (!path)
    write_footer(md_result_file);
unknown's avatar
unknown committed
2993 2994
  if (md_result_file != stdout)
    my_fclose(md_result_file, MYF(0));
2995
  my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR));
unknown's avatar
unknown committed
2996 2997
  if (hash_inited(&ignore_table))
    hash_free(&ignore_table);
2998
  if (extended_insert)
unknown's avatar
unknown committed
2999
    dynstr_free(&extended_row);
3000 3001
  if (insert_pat_inited)
    dynstr_free(&insert_pat);
unknown's avatar
unknown committed
3002 3003 3004
  my_end(0);
  return(first_error);
} /* main */