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

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

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

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

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

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

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

48
#include "client_priv.h"
bk@work.mysql.com's avatar
bk@work.mysql.com 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 */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
60 61 62 63 64 65 66 67 68

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

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

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

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

const char *compatible_mode_names[]=
{
  "MYSQL323", "MYSQL40", "POSTGRESQL", "ORACLE", "MSSQL", "DB2",
125 126
  "MAXDB", "NO_KEY_OPTIONS", "NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS",
  "ANSI",
127 128
  NullS
};
129 130 131 132 133 134 135 136 137
#define MASK_ANSI_QUOTES \
(\
 (1<<2)  | /* POSTGRESQL */\
 (1<<3)  | /* ORACLE     */\
 (1<<4)  | /* MSSQL      */\
 (1<<5)  | /* DB2        */\
 (1<<6)  | /* MAXDB      */\
 (1<<10)   /* ANSI       */\
)
138
TYPELIB compatible_mode_typelib= {array_elements(compatible_mode_names) - 1,
bar@mysql.com's avatar
bar@mysql.com committed
139
				  "", compatible_mode_names, NULL};
140

141 142 143 144 145 146 147 148 149
#define TABLE_RULE_HASH_SIZE   16

typedef struct st_table_rule_ent
{
  char* key;    /* dbname.tablename */
  uint key_len;
} TABLE_RULE_ENT;

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

151
static struct my_option my_long_options[] =
bk@work.mysql.com's avatar
bk@work.mysql.com committed
152
{
153 154 155
  {"all", 'a', "Deprecated. Use --create-options instead.",
   (gptr*) &create_options, (gptr*) &create_options, 0, GET_BOOL, NO_ARG, 1,
   0, 0, 0, 0, 0},
156 157 158 159 160
  {"all-databases", 'A',
   "Dump all the databases. This will be same as --databases with all databases selected.",
   (gptr*) &opt_alldbs, (gptr*) &opt_alldbs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
   0, 0},
  {"add-drop-table", OPT_DROP, "Add a 'drop table' before each create.",
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},
paul@kite-hub.kitebird.com's avatar
paul@kite-hub.kitebird.com 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,
monty@mishka.local's avatar
monty@mishka.local 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},
179
  {"compact", OPT_COMPACT,
serg@serg.mylan's avatar
serg@serg.mylan 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",
181 182
   (gptr*) &opt_compact, (gptr*) &opt_compact, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
   0, 0},
183 184
  {"complete-insert", 'c', "Use complete insert statements.", (gptr*) &cFlag,
   (gptr*) &cFlag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
185 186 187
  {"compress", 'C', "Use compression in server/client protocol.",
   (gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
   0, 0, 0},
monty@mishka.local's avatar
monty@mishka.local committed
188 189 190 191
  {"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},
192 193 194 195
  {"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},
196 197 198 199 200 201 202
#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
203 204 205 206 207 208
  {"default-character-set", OPT_DEFAULT_CHARSET,
   "Set the default character set.", (gptr*) &default_charset,
   (gptr*) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  {"delayed-insert", OPT_DELAYED, "Insert rows with INSERT DELAYED.",
   (gptr*) &opt_delayed, (gptr*) &opt_delayed, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
   0, 0},
209
  {"delete-master-logs", OPT_DELETE_MASTER_LOGS,
210 211 212
   "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},
213 214
  {"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,
215
   (gptr*) &opt_disable_keys, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
216 217 218
  {"extended-insert", 'e',
   "Allows utilization of the new, much faster INSERT syntax.",
   (gptr*) &extended_insert, (gptr*) &extended_insert, 0, GET_BOOL, NO_ARG,
219
   1, 0, 0, 0, 0, 0},
220 221 222 223 224 225 226 227 228 229
  {"fields-terminated-by", OPT_FTB,
   "Fields in the textfile are terminated by ...", (gptr*) &fields_terminated,
   (gptr*) &fields_terminated, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  {"fields-enclosed-by", OPT_ENC,
   "Fields in the importfile are enclosed by ...", (gptr*) &enclosed,
   (gptr*) &enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0 ,0, 0},
  {"fields-optionally-enclosed-by", OPT_O_ENC,
   "Fields in the i.file are opt. enclosed by ...", (gptr*) &opt_enclosed,
   (gptr*) &opt_enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0 ,0, 0},
  {"fields-escaped-by", OPT_ESC, "Fields in the i.file are escaped by ...",
serg@serg.mylan's avatar
serg@serg.mylan committed
230
   (gptr*) &escaped, (gptr*) &escaped, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
231 232
  {"first-slave", 'x', "Deprecated, renamed to --lock-all-tables.",
   (gptr*) &opt_lock_all_tables, (gptr*) &opt_lock_all_tables, 0, GET_BOOL, NO_ARG,
233
   0, 0, 0, 0, 0, 0},
serg@serg.mylan's avatar
serg@serg.mylan committed
234
  {"flush-logs", 'F', "Flush logs file in server before starting dump. "
235 236 237 238 239 240 241 242
   "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",
243 244 245 246 247 248 249
   (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},
paul@kite-hub.kitebird.com's avatar
paul@kite-hub.kitebird.com committed
250 251 252
  {"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},
253
  {"host", 'h', "Connect to host.", (gptr*) &current_host,
254
   (gptr*) &current_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
255 256 257 258 259
  {"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},
260 261 262
  {"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},
263 264 265 266 267
  {"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},
268
  {"lock-tables", 'l', "Lock all tables for read.", (gptr*) &lock_tables,
269
   (gptr*) &lock_tables, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
270
  {"master-data", OPT_MASTER_DATA,
271 272 273 274 275 276 277 278 279 280
   "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,
281
   GET_UINT, OPT_ARG, 0, 0, MYSQL_OPT_MASTER_DATA_COMMENTED_SQL, 0, 0, 0},
monty@mysql.com's avatar
monty@mysql.com committed
282 283 284 285 286 287 288 289
  {"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},
290 291 292 293 294
  {"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',
295
   "'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.}.",
296 297 298
   (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.",
299 300 301
   (gptr*) &tFlag, (gptr*) &tFlag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
  {"no-data", 'd', "No row information.", (gptr*) &dFlag, (gptr*) &dFlag, 0,
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
302
  {"no-set-names", 'N',
303
   "Deprecated. Use --skip-set-charset instead.",
304
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
305
  {"opt", OPT_OPTIMIZE,
306
   "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.",
307
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
paul@kite-hub.kitebird.com's avatar
paul@kite-hub.kitebird.com committed
308 309 310
  {"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},
311 312 313
  {"password", 'p',
   "Password to use when connecting to server. If password is not given it's solicited on the tty.",
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
bk@work.mysql.com's avatar
bk@work.mysql.com committed
314
#ifdef __WIN__
315
  {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG,
316
   NO_ARG, 0, 0, 0, 0, 0, 0},
bk@work.mysql.com's avatar
bk@work.mysql.com committed
317
#endif
318 319 320
  {"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},
321
  {"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).",
322
   0, 0, 0, GET_STR,  REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
323
  {"quick", 'q', "Don't buffer query, dump directly to stdout.",
324
   (gptr*) &quick, (gptr*) &quick, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
325
  {"quote-names",'Q', "Quote table and column names with backticks (`).",
326
   (gptr*) &opt_quoted, (gptr*) &opt_quoted, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0,
327 328
   0, 0},
  {"result-file", 'r',
serg@sergbook.mysql.com's avatar
serg@sergbook.mysql.com committed
329
   "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).",
330
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
monty@mysql.com's avatar
monty@mysql.com committed
331 332 333 334
  {"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},
335 336 337
  {"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},
338
#ifdef HAVE_SMEM
339
  {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
340
   "Base name of shared memory.", (gptr*) &shared_memory_base_name, (gptr*) &shared_memory_base_name,
341 342
   0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#endif
monty@mysql.com's avatar
monty@mysql.com committed
343 344 345 346 347
  /*
    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.
  */
348
  {"single-transaction", OPT_TRANSACTION,
monty@mysql.com's avatar
monty@mysql.com committed
349 350 351 352 353 354 355
   "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},
356
  {"skip-opt", OPT_SKIP_OPTIMIZATION,
357
   "Disable --opt. Disables --add-drop-table, --add-locks, --create-options, --quick, --extended-insert, --lock-tables, --set-charset, and --disable-keys.",
358
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
359 360 361
  {"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},
362
#include <sslopt-longopts.h>
363 364 365 366 367
  {"tab",'T',
   "Creates tab separated textfile for each table to given path. (creates .sql and .txt files). NOTE: This only works if mysqldump is run on the same machine as the mysqld daemon.",
   (gptr*) &path, (gptr*) &path, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  {"tables", OPT_TABLES, "Overrides option --databases (-B).",
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
bk@work.mysql.com's avatar
bk@work.mysql.com committed
368
#ifndef DONT_ALLOW_USER_CHANGE
369 370 371
  {"user", 'u', "User for login if not current user.",
   (gptr*) &current_user, (gptr*) &current_user, 0, GET_STR, REQUIRED_ARG,
   0, 0, 0, 0, 0, 0},
bk@work.mysql.com's avatar
bk@work.mysql.com committed
372
#endif
373 374 375 376 377 378 379 380
  {"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},
381
  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
382 383 384 385 386
};

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

static void safe_exit(int error);
387
static void write_header(FILE *sql_file, char *db_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
388 389 390 391 392 393 394 395
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();
396
static char *quote_name(const char *name, char *buff, my_bool force);
397
static const char *check_if_ignore_table(const char *table_name);
398
static char *primary_key_fields(const char *table_name);
399 400
static my_bool getViewStructure(char *table, char* db);
static my_bool dump_all_views_in_db(char *database);
401

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

404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420
/*
  exit with message if ferror(file)
  
  SYNOPSIS
    check_io()
    file	- checked file
*/

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
421 422 423
static void print_version(void)
{
  printf("%s  Ver %s Distrib %s, for %s (%s)\n",my_progname,DUMP_VERSION,
monty@mysql.com's avatar
monty@mysql.com committed
424 425
         MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
  NETWARE_SET_SCREEN_MODE(1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
426 427 428
} /* print_version */


429 430 431 432 433 434
static void short_usage_sub(void)
{
  printf("Usage: %s [OPTIONS] database [tables]\n", my_progname);
  printf("OR     %s [OPTIONS] --databases [OPTIONS] DB1 [DB2 DB3...]\n",
	 my_progname);
  printf("OR     %s [OPTIONS] --all-databases [OPTIONS]\n", my_progname);
monty@mysql.com's avatar
monty@mysql.com committed
435
  NETWARE_SET_SCREEN_MODE(1);
436 437
}

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
439 440 441 442 443 444
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");
445
  short_usage_sub();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
446
  print_defaults("my",load_default_groups);
447 448
  my_print_help(my_long_options);
  my_print_variables(my_long_options);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
449 450 451
} /* usage */


452 453 454 455 456 457
static void short_usage(void)
{
  short_usage_sub();
  printf("For more options, use %s --help\n", my_progname);
}

monty@mysql.com's avatar
monty@mysql.com committed
458 459
#include <help_end.h>

460

461
static void write_header(FILE *sql_file, char *db_name)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
462
{
463
  if (opt_xml)
464
  {
465 466
    fputs("<?xml version=\"1.0\"?>\n", sql_file);
    fputs("<mysqldump>\n", sql_file);
467
    check_io(sql_file);
468
  }
469
  else if (!opt_compact)
470
  {
471 472 473 474 475 476 477 478 479 480 481
    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));
    }
482
    if (opt_set_charset)
bar@bar.intranet.mysql.r18.ru's avatar
bar@bar.intranet.mysql.r18.ru committed
483 484 485 486 487
      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);
488 489 490
    if (!path)
    {
      fprintf(md_result_file,"\
491 492 493
/*!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\
");
494 495
    }
    fprintf(sql_file,
496 497
	    "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='%s%s%s' */;\n"
	    "/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;\n",
vva@eagle.mysql.r18.ru's avatar
Merge  
vva@eagle.mysql.r18.ru committed
498 499
	    path?"":"NO_AUTO_VALUE_ON_ZERO",compatible_mode_normal_str[0]==0?"":",",
	    compatible_mode_normal_str);
500
    check_io(sql_file);
501
  }
502
} /* write_header */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
503

504

505 506 507
static void write_footer(FILE *sql_file)
{
  if (opt_xml)
508
  {
509
    fputs("</mysqldump>\n", sql_file);
510 511
    check_io(sql_file);
  }
512
  else if (!opt_compact)
513
  {
514 515 516 517
    fprintf(sql_file,"\n/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;\n");
    if (!path)
    {
      fprintf(md_result_file,"\
518
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;\n\
519
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;\n");
520
    }
521
    if (opt_set_charset)
522
      fprintf(sql_file,
bar@bar.intranet.mysql.r18.ru's avatar
bar@bar.intranet.mysql.r18.ru committed
523 524 525
"/*!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");
526
    fprintf(sql_file,
527
	    "/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;\n");
528
    fputs("\n", sql_file);
529
    check_io(sql_file);
530
  }
531
} /* write_footer */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
532

533

534 535 536 537 538 539 540 541 542 543 544 545 546 547
static void free_table_ent(TABLE_RULE_ENT* e)
{
  my_free((gptr) e, MYF(0));
}


static byte* get_table_key(TABLE_RULE_ENT* e, uint* len,
			   my_bool not_used __attribute__((unused)))
{
  *len= e->key_len;
  return (byte*)e->key;
}


serg@serg.mylan's avatar
serg@serg.mylan committed
548
void init_table_rule_hash(HASH* h)
549 550 551 552
{
  if(hash_init(h, charset_info, TABLE_RULE_HASH_SIZE, 0, 0,
	       (hash_get_key) get_table_key,
	       (hash_free_key) free_table_ent, 0))
serg@serg.mylan's avatar
serg@serg.mylan committed
553
    exit(EX_EOM);
554 555
}

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

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

serg@serg.mylan's avatar
serg@serg.mylan committed
644 645 646
    if (!hash_inited(&ignore_table))
      init_table_rule_hash(&ignore_table);

647
    if(my_hash_insert(&ignore_table, (byte*)e))
serg@serg.mylan's avatar
serg@serg.mylan committed
648
      exit(EX_EOM);
649 650
    break;
  }
651
  case (int) OPT_COMPATIBLE:
serg@serg.mylan's avatar
serg@serg.mylan committed
652
    {
653
      char buff[255];
654 655 656
      char *end= compatible_mode_normal_str;
      int i;
      ulong mode;
657 658

      opt_quoted= 1;
659
      opt_set_charset= 0;
660 661 662 663 664 665 666 667 668 669
      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);
      }
670 671
#if !defined(DBUG_OFF)
      {
monty@mysql.com's avatar
monty@mysql.com committed
672
	uint size_for_sql_mode= 0;
673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
	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;
691 692 693 694
      /* 
        Set charset to the default compiled value if it hasn't
        been reset yet by --default-character-set=xxx.
      */
695
      if (default_charset == mysql_universal_client_charset)
696
        default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME;
697 698 699
      break;
    }
  case (int) OPT_MYSQL_PROTOCOL:
700
    {
701
      if ((opt_protocol= find_type(argument, &sql_protocol_typelib,0)) <= 0)
702 703 704 705 706
      {
	fprintf(stderr, "Unknown option to protocol: %s\n", argument);
	exit(1);
      }
      break;
707
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
708
  }
709 710 711 712 713 714
  return 0;
}

static int get_options(int *argc, char ***argv)
{
  int ho_error;
715 716 717 718
  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;
719 720 721 722

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

723
  if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
724
    exit(ho_error);
725

726 727 728
  *mysql_params->p_max_allowed_packet= opt_max_allowed_packet;
  *mysql_params->p_net_buffer_length= opt_net_buffer_length;

bk@work.mysql.com's avatar
bk@work.mysql.com committed
729 730 731 732 733
  if (opt_delayed)
    opt_lock=0;				/* Can't have lock with delayed */
  if (!path && (enclosed || opt_enclosed || escaped || lines_terminated ||
		fields_terminated))
  {
734 735
    fprintf(stderr,
	    "%s: You must use option --tab with --fields-...\n", my_progname);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
736 737
    return(1);
  }
738 739 740 741 742 743 744 745 746 747 748 749 750

  /* 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)
751
    lock_tables= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
752 753 754 755 756 757 758 759 760 761 762 763
  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);
  }
764 765
  if (strcmp(default_charset, charset_info->csname) &&
      !(charset_info= get_charset_by_csname(default_charset, 
766
  					    MY_CS_PRIMARY, MYF(MY_WME))))
767
    exit(1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
768 769
  if ((*argc < 1 && !opt_alldbs) || (*argc > 0 && opt_alldbs))
  {
770
    short_usage();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
771 772 773
    return 1;
  }
  if (tty_password)
774
    opt_password=get_tty_password(NullS);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
775 776 777 778 779 780 781 782 783 784
  return(0);
} /* get_options */


/*
** DBerror -- prints mysql error message and exits the program.
*/
static void DBerror(MYSQL *mysql, const char *when)
{
  DBUG_ENTER("DBerror");
785
  my_printf_error(0,"Got error: %d: %s %s", MYF(0),
bk@work.mysql.com's avatar
bk@work.mysql.com committed
786 787 788 789 790 791
		  mysql_errno(mysql), mysql_error(mysql), when);
  safe_exit(EX_MYSQLERR);
  DBUG_VOID_RETURN;
} /* DBerror */


792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821
/*
  Sends a query to server, optionally reads result, prints error message if
  some.

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

  RETURN VALUES
    0               query sending and (if res!=0) result reading went ok
    1               error
*/
  
static int mysql_query_with_error_report(MYSQL *mysql_con, MYSQL_RES **res,
                                         const char *query)
{
  if (mysql_query(mysql_con, query) ||
      (res && !((*res)= mysql_store_result(mysql_con))))
  {
    my_printf_error(0, "%s: Couldn't execute '%s': %s (%d)",
                    MYF(0), my_progname, query,
                    mysql_error(mysql_con), mysql_errno(mysql_con));
    return 1;
  }
  return 0;
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839
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)
{
840
  char buff[20+FN_REFLEN];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
841 842 843
  DBUG_ENTER("dbConnect");
  if (verbose)
  {
844
    fprintf(stderr, "-- Connecting to %s...\n", host ? host : "localhost");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
845 846 847 848 849 850 851
  }
  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,
852
		  opt_ssl_capath, opt_ssl_cipher);
853 854 855 856 857 858
#endif
  if (opt_protocol)
    mysql_options(&mysql_connection,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
#ifdef HAVE_SMEM
  if (shared_memory_base_name)
    mysql_options(&mysql_connection,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
859
#endif
860
  mysql_options(&mysql_connection, MYSQL_SET_CHARSET_NAME, default_charset);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
861 862 863 864 865 866 867
  if (!(sock= mysql_real_connect(&mysql_connection,host,user,passwd,
         NULL,opt_mysql_port,opt_mysql_unix_port,
         0)))
  {
    DBerror(&mysql_connection, "when trying to connect");
    return 1;
  }
bar@mysql.com's avatar
bar@mysql.com committed
868 869 870 871 872
  /*
    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;
873 874 875 876 877
  /*
    As we're going to set SQL_MODE, it would be lost on reconnect, so we
    cannot reconnect.
  */
  sock->reconnect= 0;
878 879
  my_snprintf(buff, sizeof(buff), "/*!40100 SET @@SQL_MODE='%s' */",
	      compatible_mode_normal_str);
880
  if (mysql_query_with_error_report(sock, 0, buff))
881 882 883 884 885
  {
    mysql_close(sock);
    safe_exit(EX_MYSQLERR);
    return 1;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
886 887 888 889 890 891 892 893 894 895
  return 0;
} /* dbConnect */


/*
** dbDisconnect -- disconnects from the host.
*/
static void dbDisconnect(char *host)
{
  if (verbose)
896
    fprintf(stderr, "-- Disconnecting from %s...\n", host ? host : "localhost");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
897 898 899 900 901 902 903 904 905 906 907 908 909
  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 */
  }
910
  mysql_real_escape_string(&mysql_connection, tmp, pos, length);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
911 912 913
  fputc('\'', file);
  fputs(tmp, file);
  fputc('\'', file);
914
  check_io(file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
915 916 917 918 919 920 921 922 923
  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++)
924
    if (!my_isvar(charset_info,*str) && *str != '$')
bk@work.mysql.com's avatar
bk@work.mysql.com committed
925 926 927 928 929
      return 1;
#endif
  return 0;
} /* test_if_special_chars */

930

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

932
static char *quote_name(const char *name, char *buff, my_bool force)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
933
{
934
  char *to= buff;
935 936
  char qtype= (opt_compatible_mode & MASK_ANSI_QUOTES) ? '\"' : '`';

937 938
  if (!force && !opt_quoted && !test_if_special_chars(name))
    return (char*) name;
939
  *to++= qtype;
940 941
  while (*name)
  {
942 943
    if (*name == qtype)
      *to++= qtype;
944 945
    *to++= *name++;
  }
946 947
  to[0]= qtype;
  to[1]= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
948 949 950 951
  return buff;
} /* quote_name */


952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968

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


969 970 971 972 973 974 975 976 977 978
/*
  Quote and print a string.
  
  SYNOPSIS
    print_quoted_xml()
    output	- output file
    str		- string to print
    len		- its length
    
  DESCRIPTION
979
    Quote '<' '>' '&' '\"' chars and print a string to the xml_file.
980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005
*/

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;
    }
  }
1006
  check_io(xml_file);
1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039
}


/*
  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);
1040
  check_io(xml_file);
1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062
}


/*
  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)
1063 1064 1065 1066 1067 1068
{
  uint i;
  MYSQL_FIELD *field;
  ulong *lengths= mysql_fetch_lengths(tableRes);
  
  fprintf(xml_file, "\t\t<%s", row_name);
1069
  check_io(xml_file);
1070 1071 1072
  mysql_field_seek(tableRes, 0);
  for (i= 0; (field= mysql_fetch_field(tableRes)); i++)
  {
1073
    if ((*row)[i])
1074
    {
monty@mishka.local's avatar
monty@mishka.local committed
1075
      fputc(' ', xml_file);
1076
      print_quoted_xml(xml_file, field->name, field->name_length);
1077 1078
      fputs("=\"", xml_file);
      print_quoted_xml(xml_file, (*row)[i], lengths[i]);
monty@mishka.local's avatar
monty@mishka.local committed
1079
      fputc('"', xml_file);
1080
      check_io(xml_file);
1081 1082 1083
    }
  }
  fputs(" />\n", xml_file);
1084
  check_io(xml_file);
1085 1086
}

1087

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1088
/*
1089 1090 1091 1092 1093
  getStructure -- retrievs database structure, prints out corresponding
  CREATE statement and fills out insert_pat.

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1096 1097 1098 1099 1100 1101
static uint getTableStructure(char *table, char* db)
{
  MYSQL_RES  *tableRes;
  MYSQL_ROW  row;
  my_bool    init=0;
  uint       numFields;
1102
  char	     *strpos, *result_table, *opt_quoted_table;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1103
  const char *delayed;
1104 1105
  char	     name_buff[NAME_LEN+3],table_buff[NAME_LEN*2+3];
  char	     table_buff2[NAME_LEN*2+3];
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1106
  FILE       *sql_file = md_result_file;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1107 1108 1109 1110 1111
  DBUG_ENTER("getTableStructure");

  delayed= opt_delayed ? " DELAYED " : "";

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

1114 1115 1116
  my_snprintf(insert_pat, sizeof(insert_pat), 
	      "SET OPTION SQL_QUOTE_SHOW_CREATE=%d",
	      (opt_quoted || opt_keywords));
monty@mishka.local's avatar
monty@mishka.local committed
1117
  if (!create_options)
monty@mysql.com's avatar
monty@mysql.com committed
1118
    strmov(strend(insert_pat), "/*!40102 ,SQL_MODE=concat(@@sql_mode, _utf8 ',NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS') */");
monty@mishka.local's avatar
monty@mishka.local committed
1119

1120 1121
  result_table=     quote_name(table, table_buff, 1);
  opt_quoted_table= quote_name(table, table_buff2, 0);
1122 1123 1124 1125

  if (opt_order_by_primary)
    order_by = primary_key_fields(opt_quoted_table);

1126
  if (!opt_xml && !mysql_query_with_error_report(sock, 0, insert_pat))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1127
  {
1128 1129
    /* using SHOW CREATE statement */
    if (!tFlag)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1130
    {
1131 1132
      /* Make an sql-file, if path was given iow. option -T was given */
      char buff[20+FN_REFLEN];
1133
      MYSQL_FIELD *field;
1134

1135
      my_snprintf(buff, sizeof(buff), "show create table %s", result_table);
1136
      if (mysql_query_with_error_report(sock, 0, buff))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1137
      {
1138 1139
        safe_exit(EX_MYSQLERR);
        DBUG_RETURN(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1140 1141
      }

1142 1143 1144
      if (path)
      {
        char filename[FN_REFLEN], tmp_path[FN_REFLEN];
1145
        convert_dirname(tmp_path,path,NullS);
1146
        sql_file= my_fopen(fn_format(filename, table, tmp_path, ".sql", 4),
1147
				 O_WRONLY, MYF(MY_WME));
1148 1149
        if (!sql_file)			/* If file couldn't be opened */
        {
1150 1151
	  safe_exit(EX_MYSQLERR);
	  DBUG_RETURN(0);
1152
        }
1153
        write_header(sql_file, db);
1154
      }
1155
      if (!opt_xml && opt_comments)
1156
      {
monty@mysql.com's avatar
monty@mysql.com committed
1157
        fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n",
1158
		result_table);
1159 1160
	check_io(sql_file);
      }
1161
      if (opt_drop)
1162
      {
1163
        fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", opt_quoted_table);
1164 1165
	check_io(sql_file);
      }
1166

1167 1168 1169 1170 1171 1172 1173 1174 1175 1176
      tableRes= mysql_store_result(sock);
      field= mysql_fetch_field_direct(tableRes, 0);
      if (strcmp(field->name, "View") == 0)
      {
        if (verbose)
          fprintf(stderr, "-- It's a view, skipped\n");
        was_views= 1;
        DBUG_RETURN(0);
      }
      row= mysql_fetch_row(tableRes);
1177
      fprintf(sql_file, "%s;\n", row[1]);
1178
      check_io(sql_file);
1179 1180
      mysql_free_result(tableRes);
    }
1181 1182
    my_snprintf(insert_pat, sizeof(insert_pat), "show fields from %s", 
		result_table);
1183
    if (mysql_query_with_error_report(sock, &tableRes, insert_pat))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1184
    {
1185 1186
      if (path)
	my_fclose(sql_file, MYF(MY_WME));
1187 1188
      safe_exit(EX_MYSQLERR);
      DBUG_RETURN(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1189
    }
1190

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1191
    if (cFlag)
1192 1193
      my_snprintf(insert_pat, sizeof(insert_pat), "INSERT %sINTO %s (", 
		  delayed, opt_quoted_table);
1194
    else
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1195
    {
1196 1197
      my_snprintf(insert_pat, sizeof(insert_pat), "INSERT %sINTO %s VALUES ", 
		  delayed, opt_quoted_table);
1198 1199 1200 1201 1202 1203 1204 1205
      if (!extended_insert)
        strcat(insert_pat,"(");
    }

    strpos=strend(insert_pat);
    while ((row=mysql_fetch_row(tableRes)))
    {
      if (init)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1206
      {
1207
        if (cFlag)
1208
	  strpos=strmov(strpos,", ");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1209
      }
1210 1211
      init=1;
      if (cFlag)
1212
        strpos=strmov(strpos,quote_name(row[SHOW_FIELDNAME], name_buff, 0));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1213
    }
1214 1215
    numFields = (uint) mysql_num_rows(tableRes);
    mysql_free_result(tableRes);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1216
  }
1217
  else
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1218
  {
monty@mishka.local's avatar
monty@mishka.local committed
1219 1220 1221 1222
    if (verbose)
      fprintf(stderr,
              "%s: Warning: Can't set SQL_QUOTE_SHOW_CREATE option (%s)\n",
              my_progname, mysql_error(sock));
1223

1224 1225
    my_snprintf(insert_pat, sizeof(insert_pat), "show fields from %s", 
		result_table);
1226
    if (mysql_query_with_error_report(sock, &tableRes, insert_pat))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1227 1228 1229 1230 1231
    {
      safe_exit(EX_MYSQLERR);
      DBUG_RETURN(0);
    }

1232 1233
    /* Make an sql-file, if path was given iow. option -T was given */
    if (!tFlag)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1234
    {
1235
      if (path)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1236
      {
1237
        char filename[FN_REFLEN], tmp_path[FN_REFLEN];
1238
        convert_dirname(tmp_path,path,NullS);
1239 1240 1241 1242
        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 */
        {
1243 1244
	  safe_exit(EX_MYSQLERR);
	  DBUG_RETURN(0);
1245
        }
1246
        write_header(sql_file, db);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1247
      }
1248
      if (!opt_xml && opt_comments)
1249 1250
	fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n",
		result_table);
1251
      if (opt_drop)
1252
        fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n",result_table);
1253 1254 1255
      if (!opt_xml)
	fprintf(sql_file, "CREATE TABLE %s (\n", result_table);
      else
1256
        print_xml_tag1(sql_file, "\t", "table_structure name=", table, "\n");
1257
      check_io(sql_file);
1258 1259
    }
    if (cFlag)
1260 1261
      my_snprintf(insert_pat, sizeof(insert_pat), "INSERT %sINTO %s (", 
		  delayed, result_table);
1262 1263
    else
    {
1264 1265
      my_snprintf(insert_pat, sizeof(insert_pat), "INSERT %sINTO %s VALUES ",
		  delayed, result_table);
1266 1267
      if (!extended_insert)
        strcat(insert_pat,"(");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1268
    }
1269 1270

    strpos=strend(insert_pat);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1271 1272
    while ((row=mysql_fetch_row(tableRes)))
    {
1273 1274
      ulong *lengths=mysql_fetch_lengths(tableRes);
      if (init)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1275
      {
1276
        if (!opt_xml && !tFlag)
1277
	{
1278
	  fputs(",\n",sql_file);
1279 1280
	  check_io(sql_file);
	}
1281
        if (cFlag)
1282
	  strpos=strmov(strpos,", ");
1283 1284 1285
      }
      init=1;
      if (cFlag)
1286
        strpos=strmov(strpos,quote_name(row[SHOW_FIELDNAME], name_buff, 0));
1287 1288
      if (!tFlag)
      {
1289 1290 1291 1292 1293 1294
	if (opt_xml)
	{
	  print_xml_row(sql_file, "field", tableRes, &row);
	  continue;
	}
	
1295
        if (opt_keywords)
1296
	  fprintf(sql_file, "  %s.%s %s", result_table,
1297 1298
		  quote_name(row[SHOW_FIELDNAME],name_buff, 0),
		  row[SHOW_TYPE]);
1299
        else
1300
	  fprintf(sql_file, "  %s %s", quote_name(row[SHOW_FIELDNAME],
1301 1302
						  name_buff, 0),
		  row[SHOW_TYPE]);
1303 1304
        if (row[SHOW_DEFAULT])
        {
1305
	  fputs(" DEFAULT ", sql_file);
1306
	  unescape(sql_file, row[SHOW_DEFAULT], lengths[SHOW_DEFAULT]);
1307 1308
        }
        if (!row[SHOW_NULL][0])
1309
	  fputs(" NOT NULL", sql_file);
1310
        if (row[SHOW_EXTRA][0])
1311
	  fprintf(sql_file, " %s",row[SHOW_EXTRA]);
1312
	check_io(sql_file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1313 1314
      }
    }
1315 1316 1317
    numFields = (uint) mysql_num_rows(tableRes);
    mysql_free_result(tableRes);
    if (!tFlag)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1318
    {
1319 1320 1321
      /* Make an sql-file, if path was given iow. option -T was given */
      char buff[20+FN_REFLEN];
      uint keynr,primary_key;
1322
      my_snprintf(buff, sizeof(buff), "show keys from %s", result_table);
1323
      if (mysql_query_with_error_report(sock, &tableRes, buff))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1324
      {
1325 1326 1327 1328 1329 1330 1331 1332
        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));
1333
        if (path)
1334
	  my_fclose(sql_file, MYF(MY_WME));
1335 1336
        safe_exit(EX_MYSQLERR);
        DBUG_RETURN(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1337
      }
1338 1339 1340 1341 1342

      /* Find first which key is primary key */
      keynr=0;
      primary_key=INT_MAX;
      while ((row=mysql_fetch_row(tableRes)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1343
      {
1344 1345
        if (atoi(row[3]) == 1)
        {
1346 1347 1348 1349 1350 1351 1352 1353 1354 1355
	  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;
	  }
1356
        }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1357
      }
1358 1359 1360 1361
      mysql_data_seek(tableRes,0);
      keynr=0;
      while ((row=mysql_fetch_row(tableRes)))
      {
1362 1363 1364 1365 1366 1367
	if (opt_xml)
	{
	  print_xml_row(sql_file, "key", tableRes, &row);
	  continue;
	}
        
1368 1369
        if (atoi(row[3]) == 1)
        {
1370 1371 1372 1373
	  if (keynr++)
	    putc(')', sql_file);
	  if (atoi(row[1]))       /* Test if duplicate key */
	    /* Duplicate allowed */
1374
	    fprintf(sql_file, ",\n  KEY %s (",quote_name(row[2],name_buff,0));
1375 1376 1377
	  else if (keynr == primary_key)
	    fputs(",\n  PRIMARY KEY (",sql_file); /* First UNIQUE is primary */
	  else
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1378 1379
	    fprintf(sql_file, ",\n  UNIQUE %s (",quote_name(row[2],name_buff,
							    0));
1380 1381
        }
        else
1382
	  putc(',', sql_file);
1383
        fputs(quote_name(row[4], name_buff, 0), sql_file);
1384
        if (row[7])
1385
	  fprintf(sql_file, " (%s)",row[7]);      /* Sub key */
1386
	check_io(sql_file);
1387
      }
1388 1389 1390 1391 1392
      if (!opt_xml)
      {
	if (keynr)
	  putc(')', sql_file);
	fputs("\n)",sql_file);
1393
	check_io(sql_file);
1394
      }
1395 1396 1397

      /* Get MySQL specific create options */
      if (create_options)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1398
      {
1399
	char show_name_buff[FN_REFLEN];
1400 1401 1402 1403 1404 1405

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

1406
        if (mysql_query_with_error_report(sock, &tableRes, buff))
1407
        {
1408 1409 1410 1411
	  if (mysql_errno(sock) != ER_PARSE_ERROR)
	  {					/* If old MySQL version */
	    if (verbose)
	      fprintf(stderr,
1412 1413
		      "-- Warning: Couldn't get status information for table %s (%s)\n",
		      result_table,mysql_error(sock));
1414
	  }
1415
        }
1416
        else if (!(row=mysql_fetch_row(tableRes)))
1417
        {
1418
	  fprintf(stderr,
1419 1420
		  "Error: Couldn't read status information for table %s (%s)\n",
		  result_table,mysql_error(sock));
1421 1422 1423
        }
        else
        {
1424 1425 1426 1427 1428 1429 1430
	  if (opt_xml)
	  {
	    print_xml_row(sql_file, "options", tableRes, &row);
	  }
	  else
	  {
	    fputs("/*!",sql_file);
monty@mishka.local's avatar
monty@mishka.local committed
1431
	    print_value(sql_file,tableRes,row,"engine=","Engine",0);
1432 1433 1434
	    print_value(sql_file,tableRes,row,"","Create_options",0);
	    print_value(sql_file,tableRes,row,"comment=","Comment",1);
	    fputs(" */",sql_file);
1435
	    check_io(sql_file);
1436
	  }
1437 1438
        }
        mysql_free_result(tableRes);		/* Is always safe to free */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1439
      }
1440
continue_xml:
1441 1442 1443 1444
      if (!opt_xml)
	fputs(";\n", sql_file);
      else
	fputs("\t</table_structure>\n", sql_file);
1445
      check_io(sql_file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1446 1447 1448 1449 1450 1451 1452 1453
    }
  }
  if (cFlag)
  {
    strpos=strmov(strpos,") VALUES ");
    if (!extended_insert)
      strpos=strmov(strpos,"(");
  }
1454
  if (sql_file != md_result_file)
1455 1456 1457
  {
    fputs("\n", sql_file);
    write_footer(sql_file);
1458
    my_fclose(sql_file, MYF(MY_WME));
1459
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1460 1461 1462 1463 1464 1465 1466 1467 1468
  DBUG_RETURN(numFields);
} /* getTableStructure */


static char *add_load_option(char *ptr,const char *object,
			     const char *statement)
{
  if (object)
  {
1469 1470 1471 1472 1473 1474 1475 1476 1477 1478
    /* Don't escape hex constants */
    if (object[0] == '0' && (object[1] == 'x' || object[1] == 'X'))
      ptr= strxmov(ptr," ",statement," ",object,NullS);
    else
    {
      /* char constant; escape */
      ptr= strxmov(ptr," ",statement," '",NullS);
      ptr= field_escape(ptr,object,(uint) strlen(object));
      *ptr++= '\'';
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514
  }
  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 */


1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526
static char *alloc_query_str(ulong size)
{
  char *query;

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1527 1528 1529 1530 1531
/*
** dumpTable saves database contents as a series of INSERT statements.
*/
static void dumpTable(uint numFields, char *table)
{
1532
  char query_buf[QUERY_LENGTH], *end, buff[256],table_buff[NAME_LEN+3];
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1533
  char *result_table, table_buff2[NAME_LEN*2+3], *opt_quoted_table;
1534
  char *query= query_buf;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1535
  MYSQL_RES	*res;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1536 1537
  MYSQL_FIELD	*field;
  MYSQL_ROW	row;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1538
  ulong		rownr, row_break, total_length, init_length;
1539
  const char    *table_type;
1540
  int error= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1541

1542 1543
  result_table= quote_name(table,table_buff, 1);
  opt_quoted_table= quote_name(table, table_buff2, 0);
1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556

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

  if (verbose)
    fprintf(stderr, "-- Sending SELECT query...\n");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1557 1558 1559
  if (path)
  {
    char filename[FN_REFLEN], tmp_path[FN_REFLEN];
1560
    convert_dirname(tmp_path,path,NullS);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1561 1562 1563 1564 1565
    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);
1566 1567 1568
    my_snprintf(query, QUERY_LENGTH, 
		"SELECT /*!40001 SQL_NO_CACHE */ * INTO OUTFILE '%s'",
		filename);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579
    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';

1580
    my_snprintf(buff, sizeof(buff), " FROM %s", result_table);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1581
    end= strmov(end,buff);
1582
    if (where || order_by)
1583
    {
1584 1585 1586 1587 1588 1589 1590 1591 1592
      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);
1593 1594
    }
    if (mysql_real_query(sock, query, (uint) (end - query)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1595 1596 1597 1598 1599 1600 1601
    {
      DBerror(sock, "when executing 'SELECT INTO OUTFILE'");
      return;
    }
  }
  else
  {
1602
    if (!opt_xml && opt_comments)
1603
    {
1604 1605
      fprintf(md_result_file,"\n--\n-- Dumping data for table %s\n--\n",
	      result_table);
1606 1607
      check_io(md_result_file);
    }
1608 1609 1610
    my_snprintf(query, QUERY_LENGTH,
		"SELECT /*!40001 SQL_NO_CACHE */ * FROM %s",
		result_table);
1611
    if (where || order_by)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1612
    {
1613 1614 1615 1616 1617 1618
      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)
1619
      {
1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634
        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);
1635
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1636
    }
1637
    if (!opt_xml && !opt_compact)
1638
    {
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
1639
      fputs("\n", md_result_file);
1640 1641
      check_io(md_result_file);
    }
1642
    if (mysql_query_with_error_report(sock, 0, query))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1643 1644 1645 1646 1647 1648 1649 1650
      DBerror(sock, "when retrieving data from server");
    if (quick)
      res=mysql_use_result(sock);
    else
      res=mysql_store_result(sock);
    if (!res)
      DBerror(sock, "when retrieving data from server");
    if (verbose)
1651
      fprintf(stderr, "-- Retrieving rows...\n");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1652 1653
    if (mysql_num_fields(res) != numFields)
    {
1654 1655
      fprintf(stderr,"%s: Error in field count for table: %s !  Aborting.\n",
	      my_progname, result_table);
1656 1657
      error= EX_CONSCHECK;
      goto err;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1658 1659
    }

jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
1660
    if (opt_disable_keys)
1661
    {
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1662
      fprintf(md_result_file, "\n/*!40000 ALTER TABLE %s DISABLE KEYS */;\n",
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1663
	      opt_quoted_table);
1664 1665
      check_io(md_result_file);
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1666
    if (opt_lock)
1667
    {
1668
      fprintf(md_result_file,"LOCK TABLES %s WRITE;\n", opt_quoted_table);
1669 1670
      check_io(md_result_file);
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1671

1672
    total_length= opt_net_buffer_length;		/* Force row break */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1673 1674
    row_break=0;
    rownr=0;
1675
    init_length=(uint) strlen(insert_pat)+4;
1676
    if (opt_xml)
1677
      print_xml_tag1(md_result_file, "\t", "table_data name=", table, "\n");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1678

1679
    if (opt_autocommit)
1680
    {
1681
      fprintf(md_result_file, "set autocommit=0;\n");
1682 1683
      check_io(md_result_file);
    }
1684

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1685 1686 1687 1688 1689
    while ((row=mysql_fetch_row(res)))
    {
      uint i;
      ulong *lengths=mysql_fetch_lengths(res);
      rownr++;
1690
      if (!extended_insert && !opt_xml)
1691
      {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1692
	fputs(insert_pat,md_result_file);
1693 1694
	check_io(md_result_file);
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1695 1696
      mysql_field_seek(res,0);

jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
1697
      if (opt_xml)
1698
      {
1699
        fputs("\t<row>\n", md_result_file);
1700 1701
	check_io(md_result_file);
      }
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
1702

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1703 1704
      for (i = 0; i < mysql_num_fields(res); i++)
      {
1705
        int is_blob;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1706 1707
	if (!(field = mysql_fetch_field(res)))
	{
1708 1709 1710
	  my_snprintf(query, QUERY_LENGTH,
		      "%s: Not enough fields from table %s! Aborting.\n",
		      my_progname, result_table);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1711
	  fputs(query,stderr);
1712 1713
	  error= EX_CONSCHECK;
	  goto err;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1714
	}
1715 1716 1717 1718
	
	/*
	   63 is my_charset_bin. If charsetnr is not 63,
	   we have not a BLOB but a TEXT column. 
bar@mysql.com's avatar
bar@mysql.com committed
1719
	   we'll dump in hex only BLOB columns.
1720 1721
	*/
        is_blob= (opt_hex_blob && field->charsetnr == 63 &&
1722 1723 1724 1725 1726 1727 1728
                  (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;
1729
	if (extended_insert)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740
	{
	  ulong length = lengths[i];
	  if (i == 0)
	    dynstr_set(&extended_row,"(");
	  else
	    dynstr_append(&extended_row,",");

	  if (row[i])
	  {
	    if (length)
	    {
1741
	      if (!IS_NUM_FIELD(field))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1742
	      {
bar@mysql.com's avatar
bar@mysql.com committed
1743 1744 1745 1746 1747 1748 1749
	        /*
	          "length * 2 + 2" is OK for both HEX and non-HEX modes:
	          - In HEX mode we need exactly 2 bytes per character
	          plus 2 bytes for '0x' prefix.
	          - In non-HEX mode we need up to 2 bytes per character,
	          plus 2 bytes for leading and trailing '\'' characters.
	        */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1750 1751 1752
		if (dynstr_realloc(&extended_row,length * 2+2))
		{
		  fputs("Aborting dump (out of memory)",stderr);
1753 1754
		  error= EX_EOM;
		  goto err;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1755
		}
1756 1757 1758
                if (opt_hex_blob && is_blob)
                {
                  dynstr_append(&extended_row, "0x");
bar@mysql.com's avatar
bar@mysql.com committed
1759 1760 1761 1762
                  extended_row.length+= mysql_hex_string(extended_row.str + 
                                                         extended_row.length,
                                                         row[i], length);
                  extended_row.str[extended_row.length]= '\0';
1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773
                }
                else
                {
                  dynstr_append(&extended_row,"'");
                  extended_row.length +=
                  mysql_real_escape_string(&mysql_connection,
                                           &extended_row.str[extended_row.length],
                                           row[i],length);
                  extended_row.str[extended_row.length]='\0';
                  dynstr_append(&extended_row,"'");
                }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1774 1775
	      }
	      else
1776
	      {
ram@gw.mysql.r18.ru's avatar
ram@gw.mysql.r18.ru committed
1777
		/* change any strings ("inf", "-inf", "nan") into NULL */
1778
		char *ptr = row[i];
monty@mysql.com's avatar
monty@mysql.com committed
1779 1780
		if (my_isalpha(charset_info, *ptr) || (*ptr == '-' &&
		    my_isalpha(charset_info, ptr[1])))
ram@gw.mysql.r18.ru's avatar
ram@gw.mysql.r18.ru committed
1781 1782 1783 1784 1785 1786
		  dynstr_append(&extended_row, "NULL");
		else
		{
		  if (field->type == FIELD_TYPE_DECIMAL)
		  {
		    /* add " signs around */
monty@mishka.local's avatar
monty@mishka.local committed
1787
		    dynstr_append(&extended_row, "'");
ram@gw.mysql.r18.ru's avatar
ram@gw.mysql.r18.ru committed
1788
		    dynstr_append(&extended_row, ptr);
monty@mishka.local's avatar
monty@mishka.local committed
1789
		    dynstr_append(&extended_row, "'");
ram@gw.mysql.r18.ru's avatar
ram@gw.mysql.r18.ru committed
1790 1791 1792 1793
		  }
		  else
		    dynstr_append(&extended_row, ptr);
		}
1794
	      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1795 1796
	    }
	    else
monty@mishka.local's avatar
monty@mishka.local committed
1797
	      dynstr_append(&extended_row,"''");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1798 1799 1800 1801
	  }
	  else if (dynstr_append(&extended_row,"NULL"))
	  {
	    fputs("Aborting dump (out of memory)",stderr);
1802 1803
	    error= EX_EOM;
	    goto err;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1804 1805 1806 1807
	  }
	}
	else
	{
1808
	  if (i && !opt_xml)
1809
	  {
1810
	    fputc(',', md_result_file);
1811 1812
	    check_io(md_result_file);
	  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1813 1814
	  if (row[i])
	  {
1815
	    if (!IS_NUM_FIELD(field))
1816
	    {
1817
	      if (opt_xml)
1818
	      {
1819 1820
	        print_xml_tag1(md_result_file, "\t\t", "field name=",
			      field->name, "");
1821 1822 1823
		print_quoted_xml(md_result_file, row[i], lengths[i]);
		fputs("</field>\n", md_result_file);
	      }
1824
	      else if (opt_hex_blob && is_blob)
monty@mysql.com's avatar
monty@mysql.com committed
1825 1826
              {
                /* sakaik got the idea to to provide blob's in hex notation. */
1827
                char *ptr= row[i], *end= ptr+ lengths[i];
1828
                fputs("0x", md_result_file);
monty@mysql.com's avatar
monty@mysql.com committed
1829
                for (; ptr < end ; ptr++)
1830
		  fprintf(md_result_file, "%02X", *((uchar *)ptr));
1831 1832 1833
              }
              else
                unescape(md_result_file, row[i], lengths[i]);
1834
	    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1835
	    else
1836
	    {
ram@gw.mysql.r18.ru's avatar
ram@gw.mysql.r18.ru committed
1837
	      /* change any strings ("inf", "-inf", "nan") into NULL */
1838
	      char *ptr = row[i];
1839
	      if (opt_xml)
1840
	      {
1841 1842
	        print_xml_tag1(md_result_file, "\t\t", "field name=",
			       field->name, "");
1843 1844 1845 1846
		fputs(!my_isalpha(charset_info, *ptr) ? ptr: "NULL",
		      md_result_file);
		fputs("</field>\n", md_result_file);
	      }
monty@mysql.com's avatar
monty@mysql.com committed
1847 1848 1849 1850
	      else if (my_isalpha(charset_info, *ptr) ||
		       (*ptr == '-' && my_isalpha(charset_info, ptr[1])))
	        fputs("NULL", md_result_file);
	      else if (field->type == FIELD_TYPE_DECIMAL)
monty@mysql.com's avatar
monty@mysql.com committed
1851 1852
	      {
		/* add " signs around */
monty@mishka.local's avatar
monty@mishka.local committed
1853
		fputc('\'', md_result_file);
monty@mysql.com's avatar
monty@mysql.com committed
1854
		fputs(ptr, md_result_file);
monty@mishka.local's avatar
monty@mishka.local committed
1855
		fputc('\'', md_result_file);
monty@mysql.com's avatar
monty@mysql.com committed
1856
	      }
1857
	      else
monty@mysql.com's avatar
monty@mysql.com committed
1858
		fputs(ptr, md_result_file);
1859
	    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1860
	  }
1861 1862
	  else
            fputs("NULL", md_result_file);
vva@eagle.mysql.r18.ru's avatar
Merge  
vva@eagle.mysql.r18.ru committed
1863
          check_io(md_result_file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1864 1865 1866
	}
      }

jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
1867
      if (opt_xml)
1868
      {
1869
        fputs("\t</row>\n", md_result_file);
1870 1871
	check_io(md_result_file);
      }
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
1872

1873
      if (extended_insert)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1874 1875 1876 1877
      {
	ulong row_length;
	dynstr_append(&extended_row,")");
        row_length = 2 + extended_row.length;
1878
        if (total_length + row_length < opt_net_buffer_length)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1879 1880
        {
	  total_length += row_length;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1881 1882
	  fputc(',',md_result_file);		/* Always row break */
	  fputs(extended_row.str,md_result_file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1883 1884 1885
	}
        else
        {
1886
	  if (row_break)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1887
	    fputs(";\n", md_result_file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1888
	  row_break=1;				/* This is first row */
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1889

1890 1891
          fputs(insert_pat,md_result_file);
          fputs(extended_row.str,md_result_file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1892 1893
	  total_length = row_length+init_length;
        }
1894
	check_io(md_result_file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1895
      }
1896
      else if (!opt_xml)
1897
      {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1898
	fputs(");\n", md_result_file);
1899 1900
	check_io(md_result_file);
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1901
    }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1902

1903
    /* XML - close table tag and supress regular output */
1904
    if (opt_xml)
1905
	fputs("\t</table_data>\n", md_result_file);
1906
    else if (extended_insert && row_break)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1907 1908
      fputs(";\n", md_result_file);		/* If not empty table */
    fflush(md_result_file);
1909
    check_io(md_result_file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1910 1911
    if (mysql_errno(sock))
    {
1912 1913 1914 1915 1916 1917 1918
      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);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1919
      fputs(query,stderr);
1920 1921
      error= EX_CONSCHECK;
      goto err;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1922 1923
    }
    if (opt_lock)
1924
    {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1925
      fputs("UNLOCK TABLES;\n", md_result_file);
1926 1927
      check_io(md_result_file);
    }
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
1928
    if (opt_disable_keys)
1929
    {
jani@hynda.mysql.fi's avatar
merge  
jani@hynda.mysql.fi committed
1930
      fprintf(md_result_file,"/*!40000 ALTER TABLE %s ENABLE KEYS */;\n",
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1931
	      opt_quoted_table);
1932 1933
      check_io(md_result_file);
    }
1934
    if (opt_autocommit)
1935
    {
1936
      fprintf(md_result_file, "commit;\n");
1937 1938
      check_io(md_result_file);
    }
1939
    mysql_free_result(res);
1940 1941 1942 1943 1944 1945 1946 1947 1948 1949
    if (query != query_buf)
      my_free(query, MYF(MY_ALLOW_ZERO_PTR));
  } 
  return;

err:
  if (query != query_buf)
    my_free(query, MYF(MY_ALLOW_ZERO_PTR));
  safe_exit(error);
  return;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964
} /* dumpTable */


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

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982
  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;

1983
  if (mysql_query_with_error_report(sock, &tableres, "SHOW DATABASES"))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1984 1985 1986 1987 1988 1989
    return 1;
  while ((row = mysql_fetch_row(tableres)))
  {
    if (dump_all_tables_in_db(row[0]))
      result=1;
  }
1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004
  if (was_views)
  {
    if (mysql_query(sock, "SHOW DATABASES") ||
        !(tableres = mysql_store_result(sock)))
    {
      my_printf_error(0, "Error: Couldn't execute 'SHOW DATABASES': %s",
                      MYF(0), mysql_error(sock));
      return 1;
    }
    while ((row = mysql_fetch_row(tableres)))
    {
      if (dump_all_views_in_db(row[0]))
        result=1;
    }
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2005 2006 2007 2008 2009 2010 2011 2012
  return result;
}
/* dump_all_databases */


static int dump_databases(char **db_names)
{
  int result=0;
2013 2014
  char **db;
  for (db= db_names ; *db ; db++)
2015
  {
2016
    if (dump_all_tables_in_db(*db))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2017 2018
      result=1;
  }
2019 2020 2021 2022 2023 2024 2025 2026
  if (!result && was_views)
  {
    for (db= db_names ; *db ; db++)
    {
      if (dump_all_views_in_db(*db))
        result=1;
    }
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2027 2028 2029 2030 2031 2032
  return result;
} /* dump_databases */


static int init_dumping(char *database)
{
2033
  if (mysql_get_server_version(sock) >= 50003 &&
2034 2035
      !my_strcasecmp(&my_charset_latin1, database, "information_schema"))
    return 1; 
2036

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2037 2038 2039 2040 2041
  if (mysql_select_db(sock, database))
  {
    DBerror(sock, "when selecting the database");
    return 1;			/* If --force */
  }
2042
  if (!path && !opt_xml)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2043 2044 2045
  {
    if (opt_databases || opt_alldbs)
    {
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2046
      /*
paul@kite-hub.kitebird.com's avatar
paul@kite-hub.kitebird.com committed
2047
	length of table name * 2 (if name contains quotes), 2 quotes and 0
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2048
      */
2049 2050
      char quoted_database_buf[64*2+3];
      char *qdatabase= quote_name(database,quoted_database_buf,opt_quoted);
2051
      if (opt_comments)
2052
      {
monty@mysql.com's avatar
monty@mysql.com committed
2053
	fprintf(md_result_file,"\n--\n-- Current Database: %s\n--\n", qdatabase);
2054 2055
	check_io(md_result_file);
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2056
      if (!opt_create_db)
2057
      {
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2058
        char qbuf[256];
2059 2060
        MYSQL_ROW row;
        MYSQL_RES *dbinfo;
2061

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

2066
        if (mysql_query(sock, qbuf) || !(dbinfo = mysql_store_result(sock)))
2067 2068
        {
          /* Old server version, dump generic CREATE DATABASE */
2069
	  fprintf(md_result_file,
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2070 2071
		  "\nCREATE DATABASE /*!32312 IF NOT EXISTS*/ %s;\n",
		  qdatabase);
2072 2073 2074 2075 2076 2077 2078 2079 2080 2081
	}
	else
        {
	  row = mysql_fetch_row(dbinfo);
	  if (row[1])
	  {
	    fprintf(md_result_file,"\n%s;\n",row[1]);
          }
	}
      }
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2082
      fprintf(md_result_file,"\nUSE %s;\n", qdatabase);
2083
      check_io(md_result_file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2084 2085
    }
  }
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2086 2087
  if (extended_insert && init_dynamic_string(&extended_row, "", 1024, 1024))
    exit(EX_EOM);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2088 2089 2090 2091
  return 0;
} /* init_dumping */


2092 2093
my_bool include_table(byte* hash_key, uint len)
{
serg@serg.mylan's avatar
serg@serg.mylan committed
2094
  if (hash_search(&ignore_table, (byte*) hash_key, len))
2095 2096 2097 2098 2099
    return FALSE;

  return TRUE;
}

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2101 2102 2103 2104
static int dump_all_tables_in_db(char *database)
{
  char *table;
  uint numrows;
2105
  char table_buff[NAME_LEN*2+3];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2106

2107 2108 2109 2110 2111 2112
  char hash_key[2*NAME_LEN+2];  /* "db.tablename" */
  char *afterdot;

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

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2113 2114
  if (init_dumping(database))
    return 1;
2115
  if (opt_xml)
2116
    print_xml_tag1(md_result_file, "", "database name=", database, "\n");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2117 2118 2119 2120
  if (lock_tables)
  {
    DYNAMIC_STRING query;
    init_dynamic_string(&query, "LOCK TABLES ", 256, 1024);
2121
    for (numrows= 0 ; (table= getTableName(1)) ; numrows++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2122
    {
2123
      dynstr_append(&query, quote_name(table, table_buff, 1));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2124 2125 2126
      dynstr_append(&query, " READ /*!32311 LOCAL */,");
    }
    if (numrows && mysql_real_query(sock, query.str, query.length-1))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2127
      DBerror(sock, "when using LOCK TABLES");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2128 2129 2130 2131 2132 2133
            /* We shall continue here, if --force was given */
    dynstr_free(&query);
  }
  if (flush_logs)
  {
    if (mysql_refresh(sock, REFRESH_LOG))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2134
      DBerror(sock, "when doing refresh");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2135 2136
           /* We shall continue here, if --force was given */
  }
2137
  while ((table= getTableName(0)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2138
  {
2139 2140 2141 2142 2143 2144 2145 2146 2147
    char *end= strmov(afterdot, table);
    if (include_table(hash_key, end - hash_key))
    {
      numrows = getTableStructure(table, database);
      if (!dFlag && numrows > 0)
	dumpTable(numrows,table);
      my_free(order_by, MYF(MY_ALLOW_ZERO_PTR));
      order_by= 0;
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2148
  }
2149
  if (opt_xml)
2150
  {
2151
    fputs("</database>\n", md_result_file);
2152 2153
    check_io(md_result_file);
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2154
  if (lock_tables)
2155
    mysql_query_with_error_report(sock, 0, "UNLOCK TABLES");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2156 2157 2158 2159
  return 0;
} /* dump_all_tables_in_db */


2160 2161 2162 2163 2164 2165
/*
   dump structure of views of database

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

2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212
  RETURN
    0 OK
    1 ERROR
*/

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

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

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

2215
/*
2216 2217 2218 2219
  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)
2220 2221 2222 2223 2224
  
  RETURN
    void
*/

2225 2226 2227 2228 2229 2230
static void get_actual_table_name(const char *old_table_name, 
                                  char *new_table_name, 
                                  int buf_size)
{
  MYSQL_RES  *tableRes;
  MYSQL_ROW  row;
2231
  char query[50 + 2*NAME_LEN];
2232
  char show_name_buff[FN_REFLEN];
2233
  DBUG_ENTER("get_actual_table_name");
2234

2235 2236 2237 2238 2239
  /* 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));

2240 2241 2242 2243
  if (mysql_query_with_error_report(sock, 0, query))
  {
    safe_exit(EX_MYSQLERR);
  }
2244

2245 2246 2247 2248 2249
  tableRes= mysql_store_result( sock );
  row= mysql_fetch_row( tableRes );
  strmake(new_table_name, row[0], buf_size-1);
  mysql_free_result(tableRes);
}
2250

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2251 2252 2253 2254

static int dump_selected_tables(char *db, char **table_names, int tables)
{
  uint numrows;
2255
  int i;
2256
  char table_buff[NAME_LEN*+3];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2257 2258 2259 2260 2261 2262 2263 2264 2265 2266

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

    init_dynamic_string(&query, "LOCK TABLES ", 256, 1024);
    for (i=0 ; i < tables ; i++)
    {
2267
      dynstr_append(&query, quote_name(table_names[i], table_buff, 1));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2268 2269 2270
      dynstr_append(&query, " READ /*!32311 LOCAL */,");
    }
    if (mysql_real_query(sock, query.str, query.length-1))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2271
      DBerror(sock, "when doing LOCK TABLES");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2272 2273 2274 2275 2276 2277
       /* We shall countinue here, if --force was given */
    dynstr_free(&query);
  }
  if (flush_logs)
  {
    if (mysql_refresh(sock, REFRESH_LOG))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2278
      DBerror(sock, "when doing refresh");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2279 2280
     /* We shall countinue here, if --force was given */
  }
2281
  if (opt_xml)
2282
    print_xml_tag1(md_result_file, "", "database name=", db, "\n");
2283
  for (i=0 ; i < tables ; i++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2284
  {
2285
     char new_table_name[NAME_LEN];
2286 2287

     /* the table name passed on commandline may be wrong case */
reggie@bob.(none)'s avatar
Merge  
reggie@bob.(none) committed
2288
     get_actual_table_name( table_names[i], new_table_name, sizeof(new_table_name) );
2289 2290

    numrows = getTableStructure(new_table_name, db);
reggie@bob.(none)'s avatar
Merge  
reggie@bob.(none) committed
2291 2292

    dumpTable(numrows, new_table_name);
2293 2294
    my_free(order_by, MYF(MY_ALLOW_ZERO_PTR));
    order_by= 0;
2295 2296 2297 2298 2299
  }
  if (was_views)
  {
    for (i=0 ; i < tables ; i++)
      getViewStructure(table_names[i], db);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2300
  }
2301
  if (opt_xml)
2302
  {
2303
    fputs("</database>\n", md_result_file);
2304 2305
    check_io(md_result_file);
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2306
  if (lock_tables)
2307
    mysql_query_with_error_report(sock, 0, "UNLOCK TABLES");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2308 2309 2310 2311
  return 0;
} /* dump_selected_tables */


2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345
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)
{
2346 2347 2348 2349 2350 2351 2352 2353
  /*
    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.
  */
2354
  return 
2355 2356 2357
    ( mysql_query_with_error_report(mysql_con, 0, "FLUSH TABLES") ||
      mysql_query_with_error_report(mysql_con, 0,
                                    "FLUSH TABLES WITH READ LOCK") );
2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378
}


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).
2379 2380 2381 2382

    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).
2383 2384
  */
  return (mysql_query_with_error_report(mysql_con, 0,
2385 2386 2387
                                        "SET SESSION TRANSACTION ISOLATION "
                                        "LEVEL REPEATABLE READ") ||
          mysql_query_with_error_report(mysql_con, 0,
2388 2389 2390 2391 2392 2393
                                        consistent_read_now ?
                                        "START TRANSACTION "
                                        "WITH CONSISTENT SNAPSHOT" :
                                        "BEGIN"));
}

2394 2395 2396 2397 2398 2399 2400 2401 2402

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

2403
  *err_pos= 0;                  /* No error yet */
2404
  while (end > x && my_isspace(charset_info, end[-1]))
2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435
    end--;

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

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


bk@work.mysql.com's avatar
bk@work.mysql.com committed
2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452
/* 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)
2453
	  unescape(file,row[0],(uint) strlen(row[0]));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2454 2455
	else
	  fputs(row[0], file);
2456
	check_io(file);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2457 2458 2459 2460 2461 2462 2463 2464
	return;
      }
    }
  }
  return;					/* This shouldn't happen */
} /* print_value */


2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488
/*
  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;

2489 2490 2491 2492
  /* 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));
2493
  if (mysql_query_with_error_report(sock, &res, buff))
2494 2495 2496 2497 2498 2499 2500 2501 2502 2503
  {
    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 */
    }
  }
2504
  if (!(row= mysql_fetch_row(res)))
2505 2506 2507 2508
  {
    fprintf(stderr,
	    "Error: Couldn't read status information for table %s (%s)\n",
	    table_name, mysql_error(sock));
2509
    mysql_free_result(res);
2510 2511
    return 0;					/* assume table is ok */
  }
2512 2513 2514 2515 2516 2517 2518 2519
  if (!(row[1]))
      result= "VIEW";
  else
  {
    if (strcmp(row[1], (result= "MRG_MyISAM")) &&
        strcmp(row[1], (result= "MRG_ISAM")))
      result= 0;
  }
2520
  mysql_free_result(res);
2521 2522 2523
  return result;
}

2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546
/*
  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];
tsmith@build.mysql.com's avatar
tsmith@build.mysql.com committed
2547
  uint result_length = 0;
2548 2549
  char *result = 0;

2550 2551
  my_snprintf(show_keys_buff, sizeof(show_keys_buff), 
	      "SHOW KEYS FROM %s", table_name);
2552 2553 2554 2555 2556 2557 2558 2559 2560 2561
  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;
  }

tsmith@build.mysql.com's avatar
tsmith@build.mysql.com committed
2562 2563 2564 2565 2566 2567 2568
  /*
   * 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)
2569
  {
tsmith@build.mysql.com's avatar
tsmith@build.mysql.com committed
2570 2571 2572 2573
    /* Key is unique */
    do
      result_length += strlen(row[4]) + 1;      /* + 1 for ',' or \0 */
    while ((row = mysql_fetch_row(res)) && atoi(row[3]) > 1);
2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584
  }

  /* 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;
    }
tsmith@build.mysql.com's avatar
tsmith@build.mysql.com committed
2585
    mysql_data_seek(res, 0);
2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598
    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;
}

2599

2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 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 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693
/*
  Getting VIEW structure

  SYNOPSIS
    getViewStructure()
    table   view name
    db      db name

  RETURN
    0 OK
    1 ERROR
*/

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

  if (tFlag)
    DBUG_RETURN(0);

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

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

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

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

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

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

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


bk@work.mysql.com's avatar
bk@work.mysql.com committed
2694 2695
int main(int argc, char **argv)
{
2696
  compatible_mode_normal_str[0]= 0;
2697
  default_charset= (char *)mysql_universal_client_charset;
2698

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2699 2700 2701 2702 2703 2704
  MY_INIT(argv[0]);
  if (get_options(&argc, &argv))
  {
    my_end(0);
    exit(EX_USAGE);
  }
2705
  if (dbConnect(current_host, current_user, opt_password))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2706 2707
    exit(EX_MYSQLERR);
  if (!path)
2708 2709
    write_header(md_result_file, *argv);

2710 2711 2712 2713 2714 2715 2716 2717
  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)
2718
  {
2719 2720 2721
    if (flush_logs && mysql_refresh(sock, REFRESH_LOG))
      goto err;
    flush_logs= 0; /* not anymore; that would not be sensible */
2722
  }
2723 2724
  if (opt_master_data && do_show_master_status(sock))
    goto err;
2725
  if (opt_single_transaction && do_unlock_tables(sock)) /* unlock but no commit! */
2726 2727
    goto err;

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2728 2729 2730
  if (opt_alldbs)
    dump_all_databases();
  else if (argc > 1 && !opt_databases)
2731 2732
  {
    /* Only one database and selected table(s) */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2733
    dump_selected_tables(*argv, (argv + 1), (argc - 1));
2734
  }
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2735
  else
2736 2737
  {
    /* One or more databases, all tables */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2738
    dump_databases(argv);
2739
  }
2740 2741 2742
#ifdef HAVE_SMEM
  my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR));
#endif
2743 2744 2745 2746 2747 2748 2749
  /*
    No reason to explicitely COMMIT the transaction, neither to explicitely
    UNLOCK TABLES: these will be automatically be done by the server when we
    disconnect now. Saves some code here, some network trips, adds nothing to
    server.
  */
err:
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2750
  dbDisconnect(current_host);
2751 2752
  if (!path)
    write_footer(md_result_file);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2753 2754
  if (md_result_file != stdout)
    my_fclose(md_result_file, MYF(0));
2755
  my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR));
2756
  if (extended_insert)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2757 2758 2759 2760
    dynstr_free(&extended_row);
  my_end(0);
  return(first_error);
} /* main */