mysqldump.c

Go to the documentation of this file.
00001 /* Copyright (C) 2000 MySQL AB
00002 
00003    This program is free software; you can redistribute it and/or modify
00004    it under the terms of the GNU General Public License as published by
00005    the Free Software Foundation; either version 2 of the License, or
00006    (at your option) any later version.
00007 
00008    This program is distributed in the hope that it will be useful,
00009    but WITHOUT ANY WARRANTY; without even the implied warranty of
00010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011    GNU General Public License for more details.
00012 
00013    You should have received a copy of the GNU General Public License
00014    along with this program; if not, write to the Free Software
00015    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
00016 
00017 /* mysqldump.c  - Dump a tables contents and format to an ASCII file
00018 **
00019 ** The author's original notes follow :-
00020 **
00021 ** AUTHOR: Igor Romanenko (igor@frog.kiev.ua)
00022 ** DATE:   December 3, 1994
00023 ** WARRANTY: None, expressed, impressed, implied
00024 **          or other
00025 ** STATUS: Public domain
00026 ** Adapted and optimized for MySQL by
00027 ** Michael Widenius, Sinisa Milivojevic, Jani Tolonen
00028 ** -w --where added 9/10/98 by Jim Faucette
00029 ** slave code by David Saez Padros <david@ols.es>
00030 ** master/autocommit code by Brian Aker <brian@tangent.org>
00031 ** SSL by
00032 ** Andrei Errapart <andreie@no.spam.ee>
00033 ** Tõnu Samuel  <tonu@please.do.not.remove.this.spam.ee>
00034 ** XML by Gary Huntress <ghuntress@mediaone.net> 10/10/01, cleaned up
00035 ** and adapted to mysqldump 05/11/01 by Jani Tolonen
00036 ** Added --single-transaction option 06/06/2002 by Peter Zaitsev
00037 ** 10 Jun 2003: SET NAMES and --no-set-names by Alexander Barkov
00038 */
00039 
00040 #define DUMP_VERSION "10.10"
00041 
00042 #include <my_global.h>
00043 #include <my_sys.h>
00044 #include <m_string.h>
00045 #include <m_ctype.h>
00046 #include <hash.h>
00047 
00048 #include "client_priv.h"
00049 #include "mysql.h"
00050 #include "mysql_version.h"
00051 #include "mysqld_error.h"
00052 
00053 /* Exit codes */
00054 
00055 #define EX_USAGE 1
00056 #define EX_MYSQLERR 2
00057 #define EX_CONSCHECK 3
00058 #define EX_EOM 4
00059 #define EX_EOF 5 /* ferror for output file was got */
00060 #define EX_ILLEGAL_TABLE 6
00061 
00062 /* index into 'show fields from table' */
00063 
00064 #define SHOW_FIELDNAME  0
00065 #define SHOW_TYPE  1
00066 #define SHOW_NULL  2
00067 #define SHOW_DEFAULT  4
00068 #define SHOW_EXTRA  5
00069 
00070 /* Size of buffer for dump's select query */
00071 #define QUERY_LENGTH 1536
00072 
00073 static char *add_load_option(char *ptr, const char *object,
00074                              const char *statement);
00075 static ulong find_set(TYPELIB *lib, const char *x, uint length,
00076                       char **err_pos, uint *err_len);
00077 
00078 static char *field_escape(char *to,const char *from,uint length);
00079 static my_bool  verbose=0,tFlag=0,dFlag=0,quick= 1, extended_insert= 1,
00080                 lock_tables=1,ignore_errors=0,flush_logs=0,
00081                 opt_drop=1,opt_keywords=0,opt_lock=1,opt_compress=0,
00082                 opt_delayed=0,create_options=1,opt_quoted=0,opt_databases=0,
00083                 opt_alldbs=0,opt_create_db=0,opt_lock_all_tables=0,
00084                 opt_set_charset=0,
00085                 opt_autocommit=0,opt_disable_keys=1,opt_xml=0,
00086                 opt_delete_master_logs=0, tty_password=0,
00087                 opt_single_transaction=0, opt_comments= 0, opt_compact= 0,
00088                 opt_hex_blob=0, opt_order_by_primary=0, opt_ignore=0,
00089                 opt_complete_insert= 0, opt_drop_database= 0;
00090 static ulong opt_max_allowed_packet, opt_net_buffer_length;
00091 static MYSQL mysql_connection,*sock=0;
00092 static my_bool insert_pat_inited=0;
00093 static DYNAMIC_STRING insert_pat;
00094 static char  *opt_password=0,*current_user=0,
00095              *current_host=0,*path=0,*fields_terminated=0,
00096              *lines_terminated=0, *enclosed=0, *opt_enclosed=0, *escaped=0,
00097              *where=0, *order_by=0,
00098              *opt_compatible_mode_str= 0,
00099              *err_ptr= 0;
00100 static char compatible_mode_normal_str[255];
00101 static ulong opt_compatible_mode= 0;
00102 #define MYSQL_OPT_MASTER_DATA_EFFECTIVE_SQL 1
00103 #define MYSQL_OPT_MASTER_DATA_COMMENTED_SQL 2
00104 static uint     opt_mysql_port= 0, err_len= 0, opt_master_data;
00105 static my_string opt_mysql_unix_port=0;
00106 static int   first_error=0;
00107 static DYNAMIC_STRING extended_row;
00108 #include <sslopt-vars.h>
00109 FILE  *md_result_file;
00110 #ifdef HAVE_SMEM
00111 static char *shared_memory_base_name=0;
00112 #endif
00113 static uint opt_protocol= 0;
00114 /*
00115   Constant for detection of default value of default_charset.
00116   If default_charset is equal to mysql_universal_client_charset, then
00117   it is the default value which assigned at the very beginning of main().
00118 */
00119 static const char *mysql_universal_client_charset=
00120   MYSQL_UNIVERSAL_CLIENT_CHARSET;
00121 static char *default_charset;
00122 static CHARSET_INFO *charset_info= &my_charset_latin1;
00123 const char *default_dbug_option="d:t:o,/tmp/mysqldump.trace";
00124 /* do we met VIEWs during tables scaning */
00125 my_bool was_views= 0;
00126 
00127 const char *compatible_mode_names[]=
00128 {
00129   "MYSQL323", "MYSQL40", "POSTGRESQL", "ORACLE", "MSSQL", "DB2",
00130   "MAXDB", "NO_KEY_OPTIONS", "NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS",
00131   "ANSI",
00132   NullS
00133 };
00134 #define MASK_ANSI_QUOTES \
00135 (\
00136  (1<<2)  | /* POSTGRESQL */\
00137  (1<<3)  | /* ORACLE     */\
00138  (1<<4)  | /* MSSQL      */\
00139  (1<<5)  | /* DB2        */\
00140  (1<<6)  | /* MAXDB      */\
00141  (1<<10)   /* ANSI       */\
00142 )
00143 TYPELIB compatible_mode_typelib= {array_elements(compatible_mode_names) - 1,
00144                                   "", compatible_mode_names, NULL};
00145 
00146 HASH ignore_table;
00147 
00148 static struct my_option my_long_options[] =
00149 {
00150   {"all", 'a', "Deprecated. Use --create-options instead.",
00151    (gptr*) &create_options, (gptr*) &create_options, 0, GET_BOOL, NO_ARG, 1,
00152    0, 0, 0, 0, 0},
00153   {"all-databases", 'A',
00154    "Dump all the databases. This will be same as --databases with all databases selected.",
00155    (gptr*) &opt_alldbs, (gptr*) &opt_alldbs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
00156    0, 0},
00157   {"add-drop-database", OPT_DROP_DATABASE, "Add a 'DROP DATABASE' before each create.",
00158    (gptr*) &opt_drop_database, (gptr*) &opt_drop_database, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
00159    0},
00160   {"add-drop-table", OPT_DROP, "Add a 'drop table' before each create.",
00161    (gptr*) &opt_drop, (gptr*) &opt_drop, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0,
00162    0},
00163   {"add-locks", OPT_LOCKS, "Add locks around insert statements.",
00164    (gptr*) &opt_lock, (gptr*) &opt_lock, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0,
00165    0},
00166   {"allow-keywords", OPT_KEYWORDS,
00167    "Allow creation of column names that are keywords.", (gptr*) &opt_keywords,
00168    (gptr*) &opt_keywords, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
00169   {"character-sets-dir", OPT_CHARSETS_DIR,
00170    "Directory where character sets are.", (gptr*) &charsets_dir,
00171    (gptr*) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
00172   {"comments", 'i', "Write additional information.",
00173    (gptr*) &opt_comments, (gptr*) &opt_comments, 0, GET_BOOL, NO_ARG,
00174    1, 0, 0, 0, 0, 0},
00175   {"compatible", OPT_COMPATIBLE,
00176    "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.",
00177    (gptr*) &opt_compatible_mode_str, (gptr*) &opt_compatible_mode_str, 0,
00178    GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
00179   {"compact", OPT_COMPACT,
00180    "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",
00181    (gptr*) &opt_compact, (gptr*) &opt_compact, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
00182    0, 0},
00183   {"complete-insert", 'c', "Use complete insert statements.",
00184    (gptr*) &opt_complete_insert, (gptr*) &opt_complete_insert, 0, GET_BOOL,
00185    NO_ARG, 0, 0, 0, 0, 0, 0},
00186   {"compress", 'C', "Use compression in server/client protocol.",
00187    (gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
00188    0, 0, 0},
00189   {"create-options", OPT_CREATE_OPTIONS,
00190    "Include all MySQL specific create options.",
00191    (gptr*) &create_options, (gptr*) &create_options, 0, GET_BOOL, NO_ARG, 1,
00192    0, 0, 0, 0, 0},
00193   {"databases", 'B',
00194    "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.",
00195    (gptr*) &opt_databases, (gptr*) &opt_databases, 0, GET_BOOL, NO_ARG, 0, 0,
00196    0, 0, 0, 0},
00197 #ifdef DBUG_OFF
00198   {"debug", '#', "This is a non-debug version. Catch this and exit",
00199    0,0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
00200 #else
00201   {"debug", '#', "Output debug log", (gptr*) &default_dbug_option,
00202    (gptr*) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
00203 #endif
00204   {"default-character-set", OPT_DEFAULT_CHARSET,
00205    "Set the default character set.", (gptr*) &default_charset,
00206    (gptr*) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
00207   {"delayed-insert", OPT_DELAYED, "Insert rows with INSERT DELAYED; "
00208    "currently ignored because of http://bugs.mysql.com/bug.php?id=7815 "
00209    "but will be re-enabled later",
00210    (gptr*) &opt_delayed, (gptr*) &opt_delayed, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
00211    0, 0},
00212   {"delete-master-logs", OPT_DELETE_MASTER_LOGS,
00213    "Delete logs on master after backup. This automatically enables --master-data.",
00214    (gptr*) &opt_delete_master_logs, (gptr*) &opt_delete_master_logs, 0,
00215    GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
00216   {"disable-keys", 'K',
00217    "'/*!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,
00218    (gptr*) &opt_disable_keys, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
00219   {"extended-insert", 'e',
00220    "Allows utilization of the new, much faster INSERT syntax.",
00221    (gptr*) &extended_insert, (gptr*) &extended_insert, 0, GET_BOOL, NO_ARG,
00222    1, 0, 0, 0, 0, 0},
00223   {"fields-terminated-by", OPT_FTB,
00224    "Fields in the textfile are terminated by ...", (gptr*) &fields_terminated,
00225    (gptr*) &fields_terminated, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
00226   {"fields-enclosed-by", OPT_ENC,
00227    "Fields in the importfile are enclosed by ...", (gptr*) &enclosed,
00228    (gptr*) &enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0 ,0, 0},
00229   {"fields-optionally-enclosed-by", OPT_O_ENC,
00230    "Fields in the i.file are opt. enclosed by ...", (gptr*) &opt_enclosed,
00231    (gptr*) &opt_enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0 ,0, 0},
00232   {"fields-escaped-by", OPT_ESC, "Fields in the i.file are escaped by ...",
00233    (gptr*) &escaped, (gptr*) &escaped, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
00234   {"first-slave", 'x', "Deprecated, renamed to --lock-all-tables.",
00235    (gptr*) &opt_lock_all_tables, (gptr*) &opt_lock_all_tables, 0, GET_BOOL, NO_ARG,
00236    0, 0, 0, 0, 0, 0},
00237   {"flush-logs", 'F', "Flush logs file in server before starting dump. "
00238    "Note that if you dump many databases at once (using the option "
00239    "--databases= or --all-databases), the logs will be flushed for "
00240    "each database dumped. The exception is when using --lock-all-tables "
00241    "or --master-data: "
00242    "in this case the logs will be flushed only once, corresponding "
00243    "to the moment all tables are locked. So if you want your dump and "
00244    "the log flush to happen at the same exact moment you should use "
00245    "--lock-all-tables or --master-data with --flush-logs",
00246    (gptr*) &flush_logs, (gptr*) &flush_logs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
00247    0, 0},
00248   {"force", 'f', "Continue even if we get an sql-error.",
00249    (gptr*) &ignore_errors, (gptr*) &ignore_errors, 0, GET_BOOL, NO_ARG,
00250    0, 0, 0, 0, 0, 0},
00251   {"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG,
00252    NO_ARG, 0, 0, 0, 0, 0, 0},
00253   {"hex-blob", OPT_HEXBLOB, "Dump binary strings (BINARY, "
00254     "VARBINARY, BLOB) in hexadecimal format.",
00255    (gptr*) &opt_hex_blob, (gptr*) &opt_hex_blob, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
00256   {"host", 'h', "Connect to host.", (gptr*) &current_host,
00257    (gptr*) &current_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
00258   {"ignore-table", OPT_IGNORE_TABLE,
00259    "Do not dump the specified table. To specify more than one table to ignore, "
00260    "use the directive multiple times, once for each table.  Each table must "
00261    "be specified with both database and table names, e.g. --ignore-table=database.table",
00262    0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
00263   {"insert-ignore", OPT_INSERT_IGNORE, "Insert rows with INSERT IGNORE.",
00264    (gptr*) &opt_ignore, (gptr*) &opt_ignore, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
00265    0, 0},
00266   {"lines-terminated-by", OPT_LTB, "Lines in the i.file are terminated by ...",
00267    (gptr*) &lines_terminated, (gptr*) &lines_terminated, 0, GET_STR,
00268    REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
00269   {"lock-all-tables", 'x', "Locks all tables across all databases. This " 
00270    "is achieved by taking a global read lock for the duration of the whole "
00271    "dump. Automatically turns --single-transaction and --lock-tables off.",
00272    (gptr*) &opt_lock_all_tables, (gptr*) &opt_lock_all_tables, 0, GET_BOOL, NO_ARG,
00273    0, 0, 0, 0, 0, 0},
00274   {"lock-tables", 'l', "Lock all tables for read.", (gptr*) &lock_tables,
00275    (gptr*) &lock_tables, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
00276   {"master-data", OPT_MASTER_DATA,
00277    "This causes the binary log position and filename to be appended to the "
00278    "output. If equal to 1, will print it as a CHANGE MASTER command; if equal"
00279    " to 2, that command will be prefixed with a comment symbol. "
00280    "This option will turn --lock-all-tables on, unless "
00281    "--single-transaction is specified too (in which case a "
00282    "global read lock is only taken a short time at the beginning of the dump "
00283    "- don't forget to read about --single-transaction below). In all cases "
00284    "any action on logs will happen at the exact moment of the dump."
00285    "Option automatically turns --lock-tables off.",
00286    (gptr*) &opt_master_data, (gptr*) &opt_master_data, 0,
00287    GET_UINT, OPT_ARG, 0, 0, MYSQL_OPT_MASTER_DATA_COMMENTED_SQL, 0, 0, 0},
00288   {"max_allowed_packet", OPT_MAX_ALLOWED_PACKET, "",
00289     (gptr*) &opt_max_allowed_packet, (gptr*) &opt_max_allowed_packet, 0,
00290     GET_ULONG, REQUIRED_ARG, 24*1024*1024, 4096, 
00291    (longlong) 2L*1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0},
00292   {"net_buffer_length", OPT_NET_BUFFER_LENGTH, "",
00293     (gptr*) &opt_net_buffer_length, (gptr*) &opt_net_buffer_length, 0,
00294     GET_ULONG, REQUIRED_ARG, 1024*1024L-1025, 4096, 16*1024L*1024L,
00295    MALLOC_OVERHEAD-1024, 1024, 0},
00296   {"no-autocommit", OPT_AUTOCOMMIT,
00297    "Wrap tables with autocommit/commit statements.",
00298    (gptr*) &opt_autocommit, (gptr*) &opt_autocommit, 0, GET_BOOL, NO_ARG,
00299    0, 0, 0, 0, 0, 0},
00300   {"no-create-db", 'n',
00301    "'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.}.",
00302    (gptr*) &opt_create_db, (gptr*) &opt_create_db, 0, GET_BOOL, NO_ARG, 0, 0,
00303    0, 0, 0, 0},
00304   {"no-create-info", 't', "Don't write table creation info.",
00305    (gptr*) &tFlag, (gptr*) &tFlag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
00306   {"no-data", 'd', "No row information.", (gptr*) &dFlag, (gptr*) &dFlag, 0,
00307    GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
00308   {"no-set-names", 'N',
00309    "Deprecated. Use --skip-set-charset instead.",
00310    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
00311   {"opt", OPT_OPTIMIZE,
00312    "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.",
00313    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
00314   {"order-by-primary", OPT_ORDER_BY_PRIMARY,
00315    "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.",
00316    (gptr*) &opt_order_by_primary, (gptr*) &opt_order_by_primary, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
00317   {"password", 'p',
00318    "Password to use when connecting to server. If password is not given it's solicited on the tty.",
00319    0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
00320 #ifdef __WIN__
00321   {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG,
00322    NO_ARG, 0, 0, 0, 0, 0, 0},
00323 #endif
00324   {"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port,
00325    (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0,
00326    0},
00327   {"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).",
00328    0, 0, 0, GET_STR,  REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
00329   {"quick", 'q', "Don't buffer query, dump directly to stdout.",
00330    (gptr*) &quick, (gptr*) &quick, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
00331   {"quote-names",'Q', "Quote table and column names with backticks (`).",
00332    (gptr*) &opt_quoted, (gptr*) &opt_quoted, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0,
00333    0, 0},
00334   {"result-file", 'r',
00335    "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).",
00336    0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
00337   {"set-charset", OPT_SET_CHARSET,
00338    "Add 'SET NAMES default_character_set' to the output. Enabled by default; suppress with --skip-set-charset.",
00339    (gptr*) &opt_set_charset, (gptr*) &opt_set_charset, 0, GET_BOOL, NO_ARG, 1,
00340    0, 0, 0, 0, 0},
00341   {"set-variable", 'O',
00342    "Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.",
00343    0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
00344 #ifdef HAVE_SMEM
00345   {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
00346    "Base name of shared memory.", (gptr*) &shared_memory_base_name, (gptr*) &shared_memory_base_name,
00347    0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
00348 #endif
00349   /*
00350     Note that the combination --single-transaction --master-data
00351     will give bullet-proof binlog position only if server >=4.1.3. That's the
00352     old "FLUSH TABLES WITH READ LOCK does not block commit" fixed bug.
00353   */
00354   {"single-transaction", OPT_TRANSACTION,
00355    "Creates a consistent snapshot by dumping all tables in a single "
00356    "transaction. Works ONLY for tables stored in storage engines which "
00357    "support multiversioning (currently only InnoDB does); the dump is NOT "
00358    "guaranteed to be consistent for other storage engines. Option "
00359    "automatically turns off --lock-tables.",
00360    (gptr*) &opt_single_transaction, (gptr*) &opt_single_transaction, 0,
00361    GET_BOOL, NO_ARG,  0, 0, 0, 0, 0, 0},
00362   {"skip-opt", OPT_SKIP_OPTIMIZATION,
00363    "Disable --opt. Disables --add-drop-table, --add-locks, --create-options, --quick, --extended-insert, --lock-tables, --set-charset, and --disable-keys.",
00364    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
00365   {"socket", 'S', "Socket file to use for connection.",
00366    (gptr*) &opt_mysql_unix_port, (gptr*) &opt_mysql_unix_port, 0, GET_STR,
00367    REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
00368 #include <sslopt-longopts.h>
00369   {"tab",'T',
00370    "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.",
00371    (gptr*) &path, (gptr*) &path, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
00372   {"tables", OPT_TABLES, "Overrides option --databases (-B).",
00373    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
00374 #ifndef DONT_ALLOW_USER_CHANGE
00375   {"user", 'u', "User for login if not current user.",
00376    (gptr*) &current_user, (gptr*) &current_user, 0, GET_STR, REQUIRED_ARG,
00377    0, 0, 0, 0, 0, 0},
00378 #endif
00379   {"verbose", 'v', "Print info about the various stages.",
00380    (gptr*) &verbose, (gptr*) &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
00381   {"version",'V', "Output version information and exit.", 0, 0, 0,
00382    GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
00383   {"where", 'w', "Dump only selected records; QUOTES mandatory!",
00384    (gptr*) &where, (gptr*) &where, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
00385   {"xml", 'X', "Dump a database as well formed XML.", 0, 0, 0, GET_NO_ARG,
00386    NO_ARG, 0, 0, 0, 0, 0, 0},
00387   {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
00388 };
00389 
00390 static const char *load_default_groups[]= { "mysqldump","client",0 };
00391 
00392 static void safe_exit(int error);
00393 static void write_header(FILE *sql_file, char *db_name);
00394 static void print_value(FILE *file, MYSQL_RES  *result, MYSQL_ROW row,
00395                         const char *prefix,const char *name,
00396                         int string_value);
00397 static int dump_selected_tables(char *db, char **table_names, int tables);
00398 static int dump_all_tables_in_db(char *db);
00399 static int init_dumping(char *);
00400 static int dump_databases(char **);
00401 static int dump_all_databases();
00402 static char *quote_name(const char *name, char *buff, my_bool force);
00403 static const char *check_if_ignore_table(const char *table_name);
00404 static char *primary_key_fields(const char *table_name);
00405 static my_bool get_view_structure(char *table, char* db);
00406 static my_bool dump_all_views_in_db(char *database);
00407 
00408 #include <help_start.h>
00409 
00410 /*
00411   exit with message if ferror(file)
00412   
00413   SYNOPSIS
00414     check_io()
00415     file        - checked file
00416 */
00417 
00418 void check_io(FILE *file)
00419 {
00420   if (ferror(file))
00421   {
00422     fprintf(stderr, "%s: Got errno %d on write\n", my_progname, errno);
00423     safe_exit(EX_EOF);
00424   }
00425 }
00426 
00427 static void print_version(void)
00428 {
00429   printf("%s  Ver %s Distrib %s, for %s (%s)\n",my_progname,DUMP_VERSION,
00430          MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
00431   NETWARE_SET_SCREEN_MODE(1);
00432 } /* print_version */
00433 
00434 
00435 static void short_usage_sub(void)
00436 {
00437   printf("Usage: %s [OPTIONS] database [tables]\n", my_progname);
00438   printf("OR     %s [OPTIONS] --databases [OPTIONS] DB1 [DB2 DB3...]\n",
00439          my_progname);
00440   printf("OR     %s [OPTIONS] --all-databases [OPTIONS]\n", my_progname);
00441   NETWARE_SET_SCREEN_MODE(1);
00442 }
00443 
00444 
00445 static void usage(void)
00446 {
00447   print_version();
00448   puts("By Igor Romanenko, Monty, Jani & Sinisa");
00449   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");
00450   puts("Dumping definition and data mysql database or table");
00451   short_usage_sub();
00452   print_defaults("my",load_default_groups);
00453   my_print_help(my_long_options);
00454   my_print_variables(my_long_options);
00455 } /* usage */
00456 
00457 
00458 static void short_usage(void)
00459 {
00460   short_usage_sub();
00461   printf("For more options, use %s --help\n", my_progname);
00462 }
00463 
00464 #include <help_end.h>
00465 
00466 
00467 static void write_header(FILE *sql_file, char *db_name)
00468 {
00469   if (opt_xml)
00470   {
00471     fputs("<?xml version=\"1.0\"?>\n", sql_file);
00472     fputs("<mysqldump ", sql_file);
00473     fputs("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"",
00474           sql_file);
00475     fputs(">\n", sql_file);
00476     check_io(sql_file);
00477   }
00478   else if (!opt_compact)
00479   {
00480     if (opt_comments)
00481     {
00482       fprintf(sql_file, "-- MySQL dump %s\n--\n", DUMP_VERSION);
00483       fprintf(sql_file, "-- Host: %s    Database: %s\n",
00484               current_host ? current_host : "localhost", db_name ? db_name :
00485               "");
00486       fputs("-- ------------------------------------------------------\n",
00487             sql_file);
00488       fprintf(sql_file, "-- Server version\t%s\n",
00489               mysql_get_server_info(&mysql_connection));
00490     }
00491     if (opt_set_charset)
00492       fprintf(sql_file,
00493 "\n/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;"
00494 "\n/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;"
00495 "\n/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;"
00496 "\n/*!40101 SET NAMES %s */;\n",default_charset);
00497     if (!path)
00498     {
00499       fprintf(md_result_file,"\;\n\;\n\
00502 ");
00503     }
00504     fprintf(sql_file,
00505             "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='%s%s%s' */;\n"
00506             "/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;\n",
00507             path?"":"NO_AUTO_VALUE_ON_ZERO",compatible_mode_normal_str[0]==0?"":",",
00508             compatible_mode_normal_str);
00509     check_io(sql_file);
00510   }
00511 } /* write_header */
00512 
00513 
00514 static void write_footer(FILE *sql_file)
00515 {
00516   if (opt_xml)
00517   {
00518     fputs("</mysqldump>\n", sql_file);
00519     check_io(sql_file);
00520   }
00521   else if (!opt_compact)
00522   {
00523     fprintf(sql_file,"\n/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;\n");
00524     if (!path)
00525     {
00526       fprintf(md_result_file,"\;\n\;\n");
00529     }
00530     if (opt_set_charset)
00531       fprintf(sql_file,
00532 "/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;\n"
00533 "/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;\n"
00534 "/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;\n");
00535     fprintf(sql_file,
00536             "/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;\n");
00537     fputs("\n", sql_file);
00538     check_io(sql_file);
00539   }
00540 } /* write_footer */
00541 
00542 static void free_table_ent(char *key)
00543 
00544 {
00545   my_free((gptr) key, MYF(0));
00546 }
00547 
00548 
00549 byte* get_table_key(const char *entry, uint *length,
00550                                 my_bool not_used __attribute__((unused)))
00551 {
00552   *length= strlen(entry);
00553   return (byte*) entry;
00554 }
00555 
00556 
00557 void init_table_rule_hash(HASH* h)
00558 {
00559   if (hash_init(h, charset_info, 16, 0, 0,
00560                 (hash_get_key) get_table_key,
00561                 (hash_free_key) free_table_ent, 0))
00562     exit(EX_EOM);
00563 }
00564 
00565 static my_bool
00566 get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
00567                char *argument)
00568 {
00569   switch (optid) {
00570   case 'p':
00571     if (argument)
00572     {
00573       char *start=argument;
00574       my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
00575       opt_password=my_strdup(argument,MYF(MY_FAE));
00576       while (*argument) *argument++= 'x';               /* Destroy argument */
00577       if (*start)
00578         start[1]=0;                             /* Cut length of argument */
00579       tty_password= 0;
00580     }
00581     else
00582       tty_password=1;
00583     break;
00584   case 'r':
00585     if (!(md_result_file = my_fopen(argument, O_WRONLY | FILE_BINARY,
00586                                     MYF(MY_WME))))
00587       exit(1);
00588     break;
00589   case 'W':
00590 #ifdef __WIN__
00591     opt_protocol = MYSQL_PROTOCOL_PIPE;
00592 #endif
00593     break;
00594   case 'N':
00595     opt_set_charset= 0;
00596     break;
00597   case 'T':
00598     opt_disable_keys=0;
00599     break;
00600   case '#':
00601     DBUG_PUSH(argument ? argument : default_dbug_option);
00602     break;
00603 #include <sslopt-case.h>
00604   case 'V': print_version(); exit(0);
00605   case 'X':
00606     opt_xml = 1;
00607     extended_insert= opt_drop= opt_lock= 
00608       opt_disable_keys= opt_autocommit= opt_create_db= 0;
00609     break;
00610   case 'I':
00611   case '?':
00612     usage();
00613     exit(0);
00614   case (int) OPT_MASTER_DATA:
00615     if (!argument) /* work like in old versions */
00616       opt_master_data= MYSQL_OPT_MASTER_DATA_EFFECTIVE_SQL;
00617     break;
00618   case (int) OPT_OPTIMIZE:
00619     extended_insert= opt_drop= opt_lock= quick= create_options=
00620       opt_disable_keys= lock_tables= opt_set_charset= 1;
00621     break;
00622   case (int) OPT_SKIP_OPTIMIZATION:
00623     extended_insert= opt_drop= opt_lock= quick= create_options=
00624       opt_disable_keys= lock_tables= opt_set_charset= 0;
00625     break;
00626   case (int) OPT_COMPACT:
00627   if (opt_compact)
00628   {
00629     opt_comments= opt_drop= opt_disable_keys= opt_lock= 0;
00630     opt_set_charset= 0;
00631   }
00632   case (int) OPT_TABLES:
00633     opt_databases=0;
00634     break;
00635   case (int) OPT_IGNORE_TABLE:
00636   {
00637     if (!strchr(argument, '.'))
00638     {
00639       fprintf(stderr, "Illegal use of option --ignore-table=<database>.<table>\n");
00640       exit(1);
00641     }
00642     if (!hash_inited(&ignore_table))
00643       init_table_rule_hash(&ignore_table);
00644 
00645     if (my_hash_insert(&ignore_table, (byte*)my_strdup(argument, MYF(0))))
00646       exit(EX_EOM);
00647     break;
00648   }
00649   case (int) OPT_COMPATIBLE:
00650     {
00651       char buff[255];
00652       char *end= compatible_mode_normal_str;
00653       int i;
00654       ulong mode;
00655 
00656       opt_quoted= 1;
00657       opt_set_charset= 0;
00658       opt_compatible_mode_str= argument;
00659       opt_compatible_mode= find_set(&compatible_mode_typelib,
00660                                     argument, strlen(argument),
00661                                     &err_ptr, &err_len);
00662       if (err_len)
00663       {
00664         strmake(buff, err_ptr, min(sizeof(buff), err_len));
00665         fprintf(stderr, "Invalid mode to --compatible: %s\n", buff);
00666         exit(1);
00667       }
00668 #if !defined(DBUG_OFF)
00669       {
00670         uint size_for_sql_mode= 0;
00671         const char **ptr;
00672         for (ptr= compatible_mode_names; *ptr; ptr++)
00673           size_for_sql_mode+= strlen(*ptr);
00674         size_for_sql_mode+= sizeof(compatible_mode_names)-1;
00675         DBUG_ASSERT(sizeof(compatible_mode_normal_str)>=size_for_sql_mode);
00676       }
00677 #endif
00678       mode= opt_compatible_mode;
00679       for (i= 0, mode= opt_compatible_mode; mode; mode>>= 1, i++)
00680       {
00681         if (mode & 1)
00682         {
00683           end= strmov(end, compatible_mode_names[i]);
00684           end= strmov(end, ",");
00685         }
00686       }
00687       if (end!=compatible_mode_normal_str)
00688         end[-1]= 0;
00689       /* 
00690         Set charset to the default compiled value if it hasn't
00691         been reset yet by --default-character-set=xxx.
00692       */
00693       if (default_charset == mysql_universal_client_charset)
00694         default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME;
00695       break;
00696     }
00697   case (int) OPT_MYSQL_PROTOCOL:
00698     {
00699       if ((opt_protocol= find_type(argument, &sql_protocol_typelib,0)) <= 0)
00700       {
00701         fprintf(stderr, "Unknown option to protocol: %s\n", argument);
00702         exit(1);
00703       }
00704       break;
00705     }
00706 #ifndef REMOVE_THIS_CODE_WHEN_FIX_BUG_7815
00707   case (int) OPT_DELAYED:
00708     /*
00709       Because of http://bugs.mysql.com/bug.php?id=7815, we disable
00710       --delayed-insert; when the bug gets fixed by checking the storage engine
00711       (using the table definition cache) before printing INSERT DELAYED, we
00712       can correct the option's description and re-enable it again (scheduled
00713       for later 5.0 or 5.1 versions).
00714       It's ok to do the if() below as get_one_option is called after
00715       opt_delayed is set.
00716     */
00717     if (opt_delayed)
00718     {
00719       fprintf(stderr, "Warning: ignoring --delayed-insert (as explained "
00720               "in the output of 'mysqldump --help').\n");
00721       opt_delayed= 0;
00722     }
00723     break;
00724 #endif
00725   }
00726   return 0;
00727 }
00728 
00729 static int get_options(int *argc, char ***argv)
00730 {
00731   int ho_error;
00732   MYSQL_PARAMETERS *mysql_params= mysql_get_parameters();
00733 
00734   opt_max_allowed_packet= *mysql_params->p_max_allowed_packet;
00735   opt_net_buffer_length= *mysql_params->p_net_buffer_length;
00736 
00737   md_result_file= stdout;
00738   load_defaults("my",load_default_groups,argc,argv);
00739 
00740   if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
00741     exit(ho_error);
00742 
00743   *mysql_params->p_max_allowed_packet= opt_max_allowed_packet;
00744   *mysql_params->p_net_buffer_length= opt_net_buffer_length;
00745 
00746   if (opt_delayed)
00747     opt_lock=0;                         /* Can't have lock with delayed */
00748   if (!path && (enclosed || opt_enclosed || escaped || lines_terminated ||
00749                 fields_terminated))
00750   {
00751     fprintf(stderr,
00752             "%s: You must use option --tab with --fields-...\n", my_progname);
00753     return(1);
00754   }
00755 
00756   /* Ensure consistency of the set of binlog & locking options */
00757   if (opt_delete_master_logs && !opt_master_data)
00758     opt_master_data= MYSQL_OPT_MASTER_DATA_COMMENTED_SQL;
00759   if (opt_single_transaction && opt_lock_all_tables)
00760   {
00761     fprintf(stderr, "%s: You can't use --single-transaction and "
00762             "--lock-all-tables at the same time.\n", my_progname);
00763     return(1);
00764   }  
00765   if (opt_master_data)
00766     opt_lock_all_tables= !opt_single_transaction;
00767   if (opt_single_transaction || opt_lock_all_tables)
00768     lock_tables= 0;
00769   if (enclosed && opt_enclosed)
00770   {
00771     fprintf(stderr, "%s: You can't use ..enclosed.. and ..optionally-enclosed.. at the same time.\n", my_progname);
00772     return(1);
00773   }
00774   if ((opt_databases || opt_alldbs) && path)
00775   {
00776     fprintf(stderr,
00777             "%s: --databases or --all-databases can't be used with --tab.\n",
00778             my_progname);
00779     return(1);
00780   }
00781   if (strcmp(default_charset, charset_info->csname) &&
00782       !(charset_info= get_charset_by_csname(default_charset, 
00783                                             MY_CS_PRIMARY, MYF(MY_WME))))
00784     exit(1);
00785   if ((*argc < 1 && !opt_alldbs) || (*argc > 0 && opt_alldbs))
00786   {
00787     short_usage();
00788     return 1;
00789   }
00790   if (tty_password)
00791     opt_password=get_tty_password(NullS);
00792   return(0);
00793 } /* get_options */
00794 
00795 
00796 /*
00797 ** DB_error -- prints mysql error message and exits the program.
00798 */
00799 static void DB_error(MYSQL *mysql, const char *when)
00800 {
00801   DBUG_ENTER("DB_error");
00802   my_printf_error(0,"Got error: %d: %s %s", MYF(0),
00803                   mysql_errno(mysql), mysql_error(mysql), when);
00804   safe_exit(EX_MYSQLERR);
00805   DBUG_VOID_RETURN;
00806 } /* DB_error */
00807 
00808 
00809 /*
00810   Sends a query to server, optionally reads result, prints error message if
00811   some.
00812 
00813   SYNOPSIS
00814     mysql_query_with_error_report()
00815     mysql_con       connection to use
00816     res             if non zero, result will be put there with
00817                     mysql_store_result()
00818     query           query to send to server
00819 
00820   RETURN VALUES
00821     0               query sending and (if res!=0) result reading went ok
00822     1               error
00823 */
00824   
00825 static int mysql_query_with_error_report(MYSQL *mysql_con, MYSQL_RES **res,
00826                                          const char *query)
00827 {
00828   if (mysql_query(mysql_con, query) ||
00829       (res && !((*res)= mysql_store_result(mysql_con))))
00830   {
00831     my_printf_error(0, "%s: Couldn't execute '%s': %s (%d)",
00832                     MYF(0), my_progname, query,
00833                     mysql_error(mysql_con), mysql_errno(mysql_con));
00834     return 1;
00835   }
00836   return 0;
00837 }
00838 
00839 
00840 static void safe_exit(int error)
00841 {
00842   if (!first_error)
00843     first_error= error;
00844   if (ignore_errors)
00845     return;
00846   if (sock)
00847     mysql_close(sock);
00848   exit(error);
00849 }
00850 /* safe_exit */
00851 
00852 
00853 /*
00854 ** dbConnect -- connects to the host and selects DB.
00855 */
00856 static int dbConnect(char *host, char *user,char *passwd)
00857 {
00858   char buff[20+FN_REFLEN];
00859   DBUG_ENTER("dbConnect");
00860   if (verbose)
00861   {
00862     fprintf(stderr, "-- Connecting to %s...\n", host ? host : "localhost");
00863   }
00864   mysql_init(&mysql_connection);
00865   if (opt_compress)
00866     mysql_options(&mysql_connection,MYSQL_OPT_COMPRESS,NullS);
00867 #ifdef HAVE_OPENSSL
00868   if (opt_use_ssl)
00869     mysql_ssl_set(&mysql_connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
00870                   opt_ssl_capath, opt_ssl_cipher);
00871 #endif
00872   if (opt_protocol)
00873     mysql_options(&mysql_connection,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
00874 #ifdef HAVE_SMEM
00875   if (shared_memory_base_name)
00876     mysql_options(&mysql_connection,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
00877 #endif
00878   mysql_options(&mysql_connection, MYSQL_SET_CHARSET_NAME, default_charset);
00879   if (!(sock= mysql_real_connect(&mysql_connection,host,user,passwd,
00880          NULL,opt_mysql_port,opt_mysql_unix_port,
00881          0)))
00882   {
00883     DB_error(&mysql_connection, "when trying to connect");
00884     return 1;
00885   }
00886   /*
00887     Don't dump SET NAMES with a pre-4.1 server (bug#7997).
00888   */
00889   if (mysql_get_server_version(&mysql_connection) < 40100)
00890     opt_set_charset= 0;
00891   /*
00892     As we're going to set SQL_MODE, it would be lost on reconnect, so we
00893     cannot reconnect.
00894   */
00895   sock->reconnect= 0;
00896   my_snprintf(buff, sizeof(buff), "/*!40100 SET @@SQL_MODE='%s' */",
00897               compatible_mode_normal_str);
00898   if (mysql_query_with_error_report(sock, 0, buff))
00899   {
00900     mysql_close(sock);
00901     safe_exit(EX_MYSQLERR);
00902     return 1;
00903   }
00904   return 0;
00905 } /* dbConnect */
00906 
00907 
00908 /*
00909 ** dbDisconnect -- disconnects from the host.
00910 */
00911 static void dbDisconnect(char *host)
00912 {
00913   if (verbose)
00914     fprintf(stderr, "-- Disconnecting from %s...\n", host ? host : "localhost");
00915   mysql_close(sock);
00916 } /* dbDisconnect */
00917 
00918 
00919 static void unescape(FILE *file,char *pos,uint length)
00920 {
00921   char *tmp;
00922   DBUG_ENTER("unescape");
00923   if (!(tmp=(char*) my_malloc(length*2+1, MYF(MY_WME))))
00924   {
00925     ignore_errors=0;                            /* Fatal error */
00926     safe_exit(EX_MYSQLERR);                     /* Force exit */
00927   }
00928   mysql_real_escape_string(&mysql_connection, tmp, pos, length);
00929   fputc('\'', file);
00930   fputs(tmp, file);
00931   fputc('\'', file);
00932   check_io(file);
00933   my_free(tmp, MYF(MY_WME));
00934   DBUG_VOID_RETURN;
00935 } /* unescape */
00936 
00937 
00938 static my_bool test_if_special_chars(const char *str)
00939 {
00940 #if MYSQL_VERSION_ID >= 32300
00941   for ( ; *str ; str++)
00942     if (!my_isvar(charset_info,*str) && *str != '$')
00943       return 1;
00944 #endif
00945   return 0;
00946 } /* test_if_special_chars */
00947 
00948 
00949 
00950 static char *quote_name(const char *name, char *buff, my_bool force)
00951 {
00952   char *to= buff;
00953   char qtype= (opt_compatible_mode & MASK_ANSI_QUOTES) ? '\"' : '`';
00954 
00955   if (!force && !opt_quoted && !test_if_special_chars(name))
00956     return (char*) name;
00957   *to++= qtype;
00958   while (*name)
00959   {
00960     if (*name == qtype)
00961       *to++= qtype;
00962     *to++= *name++;
00963   }
00964   to[0]= qtype;
00965   to[1]= 0;
00966   return buff;
00967 } /* quote_name */
00968 
00969 
00970 /*
00971   Quote a table name so it can be used in "SHOW TABLES LIKE <tabname>"
00972 
00973   SYNOPSIS
00974     quote_for_like()
00975     name     name of the table
00976     buff     quoted name of the table
00977 
00978   DESCRIPTION
00979     Quote \, _, ' and % characters
00980 
00981     Note: Because MySQL uses the C escape syntax in strings
00982     (for example, '\n' to represent newline), you must double
00983     any '\' that you use in your LIKE  strings. For example, to
00984     search for '\n', specify it as '\\n'. To search for '\', specify
00985     it as '\\\\' (the backslashes are stripped once by the parser
00986     and another time when the pattern match is done, leaving a
00987     single backslash to be matched).
00988 
00989     Example: "t\1" => "t\\\\1"
00990 
00991 */
00992 static char *quote_for_like(const char *name, char *buff)
00993 {
00994   char *to= buff;
00995   *to++= '\'';
00996   while (*name)
00997   {
00998     if (*name == '\\')
00999     {
01000       *to++='\\';
01001       *to++='\\';
01002       *to++='\\';
01003     }
01004     else if (*name == '\'' || *name == '_'  || *name == '%')
01005       *to++= '\\';
01006     *to++= *name++;
01007   }
01008   to[0]= '\'';
01009   to[1]= 0;
01010   return buff;
01011 }
01012 
01013 
01014 /*
01015   Quote and print a string.
01016   
01017   SYNOPSIS
01018     print_quoted_xml()
01019     output      - output file
01020     str         - string to print
01021     len         - its length
01022     
01023   DESCRIPTION
01024     Quote '<' '>' '&' '\"' chars and print a string to the xml_file.
01025 */
01026 
01027 static void print_quoted_xml(FILE *xml_file, const char *str, ulong len)
01028 {
01029   const char *end;
01030   
01031   for (end= str + len; str != end; str++)
01032   {
01033     switch (*str) {
01034     case '<':
01035       fputs("&lt;", xml_file);
01036       break;
01037     case '>':
01038       fputs("&gt;", xml_file);
01039       break;
01040     case '&':
01041       fputs("&amp;", xml_file);
01042       break;
01043     case '\"':
01044       fputs("&quot;", xml_file);
01045       break;
01046     default:
01047       fputc(*str, xml_file);
01048       break;
01049     }
01050   }
01051   check_io(xml_file);
01052 }
01053 
01054 
01055 /*
01056   Print xml tag with one attribute.
01057   
01058   SYNOPSIS
01059     print_xml_tag1()
01060     xml_file    - output file
01061     sbeg        - line beginning
01062     stag_atr    - tag and attribute
01063     sval        - value of attribute
01064     send        - line ending
01065     
01066   DESCRIPTION
01067     Print tag with one attribute to the xml_file. Format is:
01068       sbeg<stag_atr="sval">send
01069   NOTE
01070     sval MUST be a NULL terminated string.
01071     sval string will be qouted before output.
01072 */
01073 
01074 static void print_xml_tag1(FILE * xml_file, const char* sbeg,
01075                            const char* stag_atr, const char* sval,
01076                            const char* send)
01077 {
01078   fputs(sbeg, xml_file);
01079   fputs("<", xml_file);
01080   fputs(stag_atr, xml_file);
01081   fputs("\"", xml_file);
01082   print_quoted_xml(xml_file, sval, strlen(sval));
01083   fputs("\">", xml_file);
01084   fputs(send, xml_file);
01085   check_io(xml_file);
01086 }
01087 
01088 
01089 /*
01090   Print xml tag with for a field that is null
01091 
01092   SYNOPSIS
01093     print_xml_null_tag()
01094     xml_file    - output file
01095     sbeg        - line beginning
01096     stag_atr    - tag and attribute
01097     sval        - value of attribute
01098     send        - line ending
01099 
01100   DESCRIPTION
01101     Print tag with one attribute to the xml_file. Format is:
01102       <stag_atr="sval" xsi:nil="true"/>
01103   NOTE
01104     sval MUST be a NULL terminated string.
01105     sval string will be qouted before output.
01106 */
01107 
01108 static void print_xml_null_tag(FILE * xml_file, const char* sbeg,
01109                                const char* stag_atr, const char* sval,
01110                                const char* send)
01111 {
01112   fputs(sbeg, xml_file);
01113   fputs("<", xml_file);
01114   fputs(stag_atr, xml_file);
01115   fputs("\"", xml_file);
01116   print_quoted_xml(xml_file, sval, strlen(sval));
01117   fputs("\" xsi:nil=\"true\" />", xml_file);
01118   fputs(send, xml_file);
01119   check_io(xml_file);
01120 }
01121 
01122 
01123 /*
01124   Print xml tag with many attributes.
01125 
01126   SYNOPSIS
01127     print_xml_row()
01128     xml_file    - output file
01129     row_name    - xml tag name
01130     tableRes    - query result
01131     row         - result row
01132     
01133   DESCRIPTION
01134     Print tag with many attribute to the xml_file. Format is:
01135       \t\t<row_name Atr1="Val1" Atr2="Val2"... />
01136   NOTE
01137     All atributes and values will be quoted before output.
01138 */
01139 
01140 static void print_xml_row(FILE *xml_file, const char *row_name,
01141                           MYSQL_RES *tableRes, MYSQL_ROW *row)
01142 {
01143   uint i;
01144   MYSQL_FIELD *field;
01145   ulong *lengths= mysql_fetch_lengths(tableRes);
01146   
01147   fprintf(xml_file, "\t\t<%s", row_name);
01148   check_io(xml_file);
01149   mysql_field_seek(tableRes, 0);
01150   for (i= 0; (field= mysql_fetch_field(tableRes)); i++)
01151   {
01152     if ((*row)[i])
01153     {
01154       fputc(' ', xml_file);
01155       print_quoted_xml(xml_file, field->name, field->name_length);
01156       fputs("=\"", xml_file);
01157       print_quoted_xml(xml_file, (*row)[i], lengths[i]);
01158       fputc('"', xml_file);
01159       check_io(xml_file);
01160     }
01161   }
01162   fputs(" />\n", xml_file);
01163   check_io(xml_file);
01164 }
01165 
01166 
01167 /*
01168   getTableStructure -- retrievs database structure, prints out corresponding
01169   CREATE statement and fills out insert_pat.
01170 
01171   RETURN
01172     number of fields in table, 0 if error
01173 */
01174 
01175 static uint get_table_structure(char *table, char *db)
01176 {
01177   MYSQL_RES  *tableRes;
01178   MYSQL_ROW  row;
01179   my_bool    init=0;
01180   uint       numFields;
01181   char       *result_table, *opt_quoted_table;
01182   const char *insert_option;
01183   char       name_buff[NAME_LEN+3],table_buff[NAME_LEN*2+3];
01184   char       table_buff2[NAME_LEN*2+3];
01185   char       query_buff[512];
01186   FILE       *sql_file = md_result_file;
01187   int        len;
01188   DBUG_ENTER("get_table_structure");
01189   DBUG_PRINT("enter", ("db: %s, table: %s", db, table));
01190 
01191   if (!insert_pat_inited)
01192   {
01193     insert_pat_inited= init_dynamic_string(&insert_pat, "", 1024, 1024);
01194   }
01195   else
01196     dynstr_set(&insert_pat, "");
01197 
01198   insert_option= ((opt_delayed && opt_ignore) ? " DELAYED IGNORE " : 
01199                   opt_delayed ? " DELAYED " :
01200                   opt_ignore ? " IGNORE " : "");
01201 
01202   if (verbose)
01203     fprintf(stderr, "-- Retrieving table structure for table %s...\n", table);
01204 
01205   len= my_snprintf(query_buff, sizeof(query_buff),
01206                    "SET OPTION SQL_QUOTE_SHOW_CREATE=%d",
01207                    (opt_quoted || opt_keywords));
01208   if (!create_options)
01209     strmov(query_buff+len, "/*!40102 ,SQL_MODE=concat(@@sql_mode, _utf8 ',NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS') */");
01210 
01211   result_table=     quote_name(table, table_buff, 1);
01212   opt_quoted_table= quote_name(table, table_buff2, 0);
01213 
01214   if (opt_order_by_primary)
01215     order_by = primary_key_fields(opt_quoted_table);
01216 
01217   if (!opt_xml && !mysql_query_with_error_report(sock, 0, query_buff))
01218   {
01219     /* using SHOW CREATE statement */
01220     if (!tFlag)
01221     {
01222       /* Make an sql-file, if path was given iow. option -T was given */
01223       char buff[20+FN_REFLEN];
01224       MYSQL_FIELD *field;
01225 
01226       my_snprintf(buff, sizeof(buff), "show create table %s", result_table);
01227       if (mysql_query_with_error_report(sock, 0, buff))
01228       {
01229         safe_exit(EX_MYSQLERR);
01230         DBUG_RETURN(0);
01231       }
01232 
01233       if (path)
01234       {
01235         char filename[FN_REFLEN], tmp_path[FN_REFLEN];
01236         convert_dirname(tmp_path,path,NullS);
01237         sql_file= my_fopen(fn_format(filename, table, tmp_path, ".sql", 4),
01238                                  O_WRONLY, MYF(MY_WME));
01239         if (!sql_file)                  /* If file couldn't be opened */
01240         {
01241           safe_exit(EX_MYSQLERR);
01242           DBUG_RETURN(0);
01243         }
01244         write_header(sql_file, db);
01245       }
01246       if (!opt_xml && opt_comments)
01247       {
01248         fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n",
01249                 result_table);
01250         check_io(sql_file);
01251       }
01252       if (opt_drop)
01253       {
01254         fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", opt_quoted_table);
01255         check_io(sql_file);
01256       }
01257 
01258       tableRes= mysql_store_result(sock);
01259       field= mysql_fetch_field_direct(tableRes, 0);
01260       if (strcmp(field->name, "View") == 0)
01261       {
01262         if (verbose)
01263           fprintf(stderr, "-- It's a view, create dummy table for view\n");
01264 
01265         mysql_free_result(tableRes);
01266 
01267         /* Create a dummy table for the view. ie. a table  which has the
01268            same columns as the view should have. This table is dropped
01269            just before the view is created. The table is used to handle the
01270            case where a view references another view, which hasn't yet been
01271            created(during the load of the dump). BUG#10927 */
01272 
01273         /* Create temp table by selecting from the view */
01274         my_snprintf(query_buff, sizeof(query_buff),
01275                     "CREATE  TEMPORARY TABLE %s SELECT * FROM %s WHERE 0",
01276                     result_table, result_table);
01277         if (mysql_query_with_error_report(sock, 0, query_buff))
01278         {
01279           safe_exit(EX_MYSQLERR);
01280           DBUG_RETURN(0);
01281         }
01282 
01283         /* Get CREATE statement for the temp table */
01284         my_snprintf(query_buff, sizeof(query_buff), "SHOW CREATE TABLE %s",
01285                     result_table);
01286         if (mysql_query_with_error_report(sock, 0, query_buff))
01287         {
01288           safe_exit(EX_MYSQLERR);
01289           DBUG_RETURN(0);
01290         }
01291         tableRes= mysql_store_result(sock);
01292         row= mysql_fetch_row(tableRes);
01293 
01294         if (opt_drop)
01295           fprintf(sql_file, "DROP VIEW IF EXISTS %s;\n",opt_quoted_table);
01296 
01297         /* Print CREATE statement but remove TEMPORARY */
01298         fprintf(sql_file, "CREATE %s;\n", row[1]+17);
01299         check_io(sql_file);
01300 
01301         mysql_free_result(tableRes);
01302 
01303         /* Drop the temp table */
01304         my_snprintf(buff, sizeof(buff),
01305                     "DROP TEMPORARY TABLE %s", result_table);
01306         if (mysql_query_with_error_report(sock, 0, buff))
01307         {
01308           safe_exit(EX_MYSQLERR);
01309           DBUG_RETURN(0);
01310         }
01311         was_views= 1;
01312         DBUG_RETURN(0);
01313       }
01314       row= mysql_fetch_row(tableRes);
01315       fprintf(sql_file, "%s;\n", row[1]);
01316       check_io(sql_file);
01317       mysql_free_result(tableRes);
01318     }
01319     my_snprintf(query_buff, sizeof(query_buff), "show fields from %s",
01320                 result_table);
01321     if (mysql_query_with_error_report(sock, &tableRes, query_buff))
01322     {
01323       if (path)
01324         my_fclose(sql_file, MYF(MY_WME));
01325       safe_exit(EX_MYSQLERR);
01326       DBUG_RETURN(0);
01327     }
01328 
01329     dynstr_append_mem(&insert_pat, "INSERT ", 7);
01330     dynstr_append(&insert_pat, insert_option);
01331     dynstr_append_mem(&insert_pat, "INTO ", 5);
01332     dynstr_append(&insert_pat, opt_quoted_table);
01333     if (opt_complete_insert)
01334     {
01335       dynstr_append_mem(&insert_pat, " (", 2);
01336     }
01337     else
01338     {
01339       dynstr_append_mem(&insert_pat, " VALUES ", 8);
01340       if (!extended_insert)
01341         dynstr_append_mem(&insert_pat, "(", 1);
01342     }
01343 
01344     while ((row=mysql_fetch_row(tableRes)))
01345     {
01346       if (init)
01347       {
01348         if (opt_complete_insert)
01349           dynstr_append_mem(&insert_pat, ", ", 2);
01350       }
01351       init=1;
01352       if (opt_complete_insert)
01353         dynstr_append(&insert_pat,
01354                       quote_name(row[SHOW_FIELDNAME], name_buff, 0));
01355     }
01356     numFields = (uint) mysql_num_rows(tableRes);
01357     mysql_free_result(tableRes);
01358   }
01359   else
01360   {
01361     if (verbose)
01362       fprintf(stderr,
01363               "%s: Warning: Can't set SQL_QUOTE_SHOW_CREATE option (%s)\n",
01364               my_progname, mysql_error(sock));
01365 
01366     my_snprintf(query_buff, sizeof(query_buff), "show fields from %s",
01367                 result_table);
01368     if (mysql_query_with_error_report(sock, &tableRes, query_buff))
01369     {
01370       safe_exit(EX_MYSQLERR);
01371       DBUG_RETURN(0);
01372     }
01373 
01374     /* Make an sql-file, if path was given iow. option -T was given */
01375     if (!tFlag)
01376     {
01377       if (path)
01378       {
01379         char filename[FN_REFLEN], tmp_path[FN_REFLEN];
01380         convert_dirname(tmp_path,path,NullS);
01381         sql_file= my_fopen(fn_format(filename, table, tmp_path, ".sql", 4),
01382                                  O_WRONLY, MYF(MY_WME));
01383         if (!sql_file)                  /* If file couldn't be opened */
01384         {
01385           safe_exit(EX_MYSQLERR);
01386           DBUG_RETURN(0);
01387         }
01388         write_header(sql_file, db);
01389       }
01390       if (!opt_xml && opt_comments)
01391         fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n",
01392                 result_table);
01393       if (opt_drop)
01394         fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n",result_table);
01395       if (!opt_xml)
01396         fprintf(sql_file, "CREATE TABLE %s (\n", result_table);
01397       else
01398         print_xml_tag1(sql_file, "\t", "table_structure name=", table, "\n");
01399       check_io(sql_file);
01400     }
01401 
01402     dynstr_append_mem(&insert_pat, "INSERT ", 7);
01403     dynstr_append(&insert_pat, insert_option);
01404     dynstr_append_mem(&insert_pat, "INTO ", 5);
01405     dynstr_append(&insert_pat, result_table);
01406     if (opt_complete_insert)
01407     {
01408       dynstr_append_mem(&insert_pat, " (", 2);
01409     }
01410     else
01411     {
01412       dynstr_append_mem(&insert_pat, " VALUES ", 8);
01413       if (!extended_insert)
01414         dynstr_append_mem(&insert_pat, "(", 1);
01415     }
01416 
01417     while ((row=mysql_fetch_row(tableRes)))
01418     {
01419       ulong *lengths=mysql_fetch_lengths(tableRes);
01420       if (init)
01421       {
01422         if (!opt_xml && !tFlag)
01423         {
01424           fputs(",\n",sql_file);
01425           check_io(sql_file);
01426         }
01427         if (opt_complete_insert)
01428           dynstr_append_mem(&insert_pat, ", ", 2);
01429       }
01430       init=1;
01431       if (opt_complete_insert)
01432         dynstr_append(&insert_pat,
01433                       quote_name(row[SHOW_FIELDNAME], name_buff, 0));
01434       if (!tFlag)
01435       {
01436         if (opt_xml)
01437         {
01438           print_xml_row(sql_file, "field", tableRes, &row);
01439           continue;
01440         }
01441 
01442         if (opt_keywords)
01443           fprintf(sql_file, "  %s.%s %s", result_table,
01444                   quote_name(row[SHOW_FIELDNAME],name_buff, 0),
01445                   row[SHOW_TYPE]);
01446         else
01447           fprintf(sql_file, "  %s %s", quote_name(row[SHOW_FIELDNAME],
01448                                                   name_buff, 0),
01449                   row[SHOW_TYPE]);
01450         if (row[SHOW_DEFAULT])
01451         {
01452           fputs(" DEFAULT ", sql_file);
01453           unescape(sql_file, row[SHOW_DEFAULT], lengths[SHOW_DEFAULT]);
01454         }
01455         if (!row[SHOW_NULL][0])
01456           fputs(" NOT NULL", sql_file);
01457         if (row[SHOW_EXTRA][0])
01458           fprintf(sql_file, " %s",row[SHOW_EXTRA]);
01459         check_io(sql_file);
01460       }
01461     }
01462     numFields = (uint) mysql_num_rows(tableRes);
01463     mysql_free_result(tableRes);
01464     if (!tFlag)
01465     {
01466       /* Make an sql-file, if path was given iow. option -T was given */
01467       char buff[20+FN_REFLEN];
01468       uint keynr,primary_key;
01469       my_snprintf(buff, sizeof(buff), "show keys from %s", result_table);
01470       if (mysql_query_with_error_report(sock, &tableRes, buff))
01471       {
01472         if (mysql_errno(sock) == ER_WRONG_OBJECT)
01473         {
01474           /* it is VIEW */
01475           fputs("\t\t<options Comment=\"view\" />\n", sql_file);
01476           goto continue_xml;
01477         }
01478         fprintf(stderr, "%s: Can't get keys for table %s (%s)\n",
01479                 my_progname, result_table, mysql_error(sock));
01480         if (path)
01481           my_fclose(sql_file, MYF(MY_WME));
01482         safe_exit(EX_MYSQLERR);
01483         DBUG_RETURN(0);
01484       }
01485 
01486       /* Find first which key is primary key */
01487       keynr=0;
01488       primary_key=INT_MAX;
01489       while ((row=mysql_fetch_row(tableRes)))
01490       {
01491         if (atoi(row[3]) == 1)
01492         {
01493           keynr++;
01494 #ifdef FORCE_PRIMARY_KEY
01495           if (atoi(row[1]) == 0 && primary_key == INT_MAX)
01496             primary_key=keynr;
01497 #endif
01498           if (!strcmp(row[2],"PRIMARY"))
01499           {
01500             primary_key=keynr;
01501             break;
01502           }
01503         }
01504       }
01505       mysql_data_seek(tableRes,0);
01506       keynr=0;
01507       while ((row=mysql_fetch_row(tableRes)))
01508       {
01509         if (opt_xml)
01510         {
01511           print_xml_row(sql_file, "key", tableRes, &row);
01512           continue;
01513         }
01514         
01515         if (atoi(row[3]) == 1)
01516         {
01517           if (keynr++)
01518             putc(')', sql_file);
01519           if (atoi(row[1]))       /* Test if duplicate key */
01520             /* Duplicate allowed */
01521             fprintf(sql_file, ",\n  KEY %s (",quote_name(row[2],name_buff,0));
01522           else if (keynr == primary_key)
01523             fputs(",\n  PRIMARY KEY (",sql_file); /* First UNIQUE is primary */
01524           else
01525             fprintf(sql_file, ",\n  UNIQUE %s (",quote_name(row[2],name_buff,
01526                                                             0));
01527         }
01528         else
01529           putc(',', sql_file);
01530         fputs(quote_name(row[4], name_buff, 0), sql_file);
01531         if (row[7])
01532           fprintf(sql_file, " (%s)",row[7]);      /* Sub key */
01533         check_io(sql_file);
01534       }
01535       if (!opt_xml)
01536       {
01537         if (keynr)
01538           putc(')', sql_file);
01539         fputs("\n)",sql_file);
01540         check_io(sql_file);
01541       }
01542 
01543       /* Get MySQL specific create options */
01544       if (create_options)
01545       {
01546         char show_name_buff[NAME_LEN*2+2+24];
01547 
01548         /* Check memory for quote_for_like() */
01549         my_snprintf(buff, sizeof(buff), "show table status like %s",
01550                     quote_for_like(table, show_name_buff));
01551 
01552         if (mysql_query_with_error_report(sock, &tableRes, buff))
01553         {
01554           if (mysql_errno(sock) != ER_PARSE_ERROR)
01555           {                                     /* If old MySQL version */
01556             if (verbose)
01557               fprintf(stderr,
01558                       "-- Warning: Couldn't get status information for table %s (%s)\n",
01559                       result_table,mysql_error(sock));
01560           }
01561         }
01562         else if (!(row=mysql_fetch_row(tableRes)))
01563         {
01564           fprintf(stderr,
01565                   "Error: Couldn't read status information for table %s (%s)\n",
01566                   result_table,mysql_error(sock));
01567         }
01568         else
01569         {
01570           if (opt_xml)
01571           {
01572             print_xml_row(sql_file, "options", tableRes, &row);
01573           }
01574           else
01575           {
01576             fputs("",sql_file);
01581             check_io(sql_file);
01582           }
01583         }
01584         mysql_free_result(tableRes);            /* Is always safe to free */
01585       }
01586 continue_xml:
01587       if (!opt_xml)
01588         fputs(";\n", sql_file);
01589       else
01590         fputs("\t</table_structure>\n", sql_file);
01591       check_io(sql_file);
01592     }
01593   }
01594   if (opt_complete_insert)
01595   {
01596     dynstr_append_mem(&insert_pat, ") VALUES ", 9);
01597     if (!extended_insert)
01598       dynstr_append_mem(&insert_pat, "(", 1);
01599   }
01600   if (sql_file != md_result_file)
01601   {
01602     fputs("\n", sql_file);
01603     write_footer(sql_file);
01604     my_fclose(sql_file, MYF(MY_WME));
01605   }
01606   DBUG_RETURN(numFields);
01607 } /* get_table_structure */
01608 
01609 
01610 static char *add_load_option(char *ptr,const char *object,
01611                              const char *statement)
01612 {
01613   if (object)
01614   {
01615     /* Don't escape hex constants */
01616     if (object[0] == '0' && (object[1] == 'x' || object[1] == 'X'))
01617       ptr= strxmov(ptr," ",statement," ",object,NullS);
01618     else
01619     {
01620       /* char constant; escape */
01621       ptr= strxmov(ptr," ",statement," '",NullS);
01622       ptr= field_escape(ptr,object,(uint) strlen(object));
01623       *ptr++= '\'';
01624     }
01625   }
01626   return ptr;
01627 } /* add_load_option */
01628 
01629 
01630 /*
01631 ** Allow the user to specify field terminator strings like:
01632 ** "'", "\", "\\" (escaped backslash), "\t" (tab), "\n" (newline)
01633 ** This is done by doubleing ' and add a end -\ if needed to avoid
01634 ** syntax errors from the SQL parser.
01635 */
01636 
01637 static char *field_escape(char *to,const char *from,uint length)
01638 {
01639   const char *end;
01640   uint end_backslashes=0;
01641 
01642   for (end= from+length; from != end; from++)
01643   {
01644     *to++= *from;
01645     if (*from == '\\')
01646       end_backslashes^=1;    /* find odd number of backslashes */
01647     else
01648     {
01649       if (*from == '\'' && !end_backslashes)
01650         *to++= *from;      /* We want a duplicate of "'" for MySQL */
01651       end_backslashes=0;
01652     }
01653   }
01654   /* Add missing backslashes if user has specified odd number of backs.*/
01655   if (end_backslashes)
01656     *to++= '\\';
01657   return to;
01658 } /* field_escape */
01659 
01660 
01661 static char *alloc_query_str(ulong size)
01662 {
01663   char *query;
01664 
01665   if (!(query= (char*) my_malloc(size, MYF(MY_WME))))
01666   {
01667     ignore_errors= 0;                           /* Fatal error */
01668     safe_exit(EX_MYSQLERR);                     /* Force exit */
01669   }
01670   return query;
01671 }
01672 
01673 
01674 /*
01675 ** dump_table saves database contents as a series of INSERT statements.
01676 */
01677 
01678 static void dump_table(uint numFields, char *table)
01679 {
01680   char query_buf[QUERY_LENGTH], *end, buff[256],table_buff[NAME_LEN+3];
01681   char *result_table, table_buff2[NAME_LEN*2+3], *opt_quoted_table;
01682   char *query= query_buf;
01683   MYSQL_RES     *res;
01684   MYSQL_FIELD   *field;
01685   MYSQL_ROW     row;
01686   ulong         rownr, row_break, total_length, init_length;
01687   const char    *table_type;
01688   int error= 0;
01689 
01690   /* Check --no-data flag */
01691   if (dFlag)
01692   {
01693     if (verbose)
01694       fprintf(stderr,
01695               "-- Skipping dump data for table '%s', --no-data was used\n",
01696               table);
01697     return;
01698   }
01699 
01700   /* Check that there are any fields in the table */
01701   if (numFields == 0)
01702   {
01703     if (verbose)
01704       fprintf(stderr,
01705               "-- Skipping dump data for table '%s', it has no fields\n",
01706               table);
01707     return;
01708   }
01709 
01710   result_table= quote_name(table,table_buff, 1);
01711   opt_quoted_table= quote_name(table, table_buff2, 0);
01712 
01713   /* Check table type */
01714   if ((table_type= check_if_ignore_table(table)))
01715   {
01716     if (verbose)
01717       fprintf(stderr,
01718               "-- Skipping data for table '%s' because it's of type %s\n",
01719               table, table_type);
01720     return;
01721   }
01722 
01723   if (verbose)
01724     fprintf(stderr, "-- Sending SELECT query...\n");
01725   if (path)
01726   {
01727     char filename[FN_REFLEN], tmp_path[FN_REFLEN];
01728     convert_dirname(tmp_path,path,NullS);
01729     my_load_path(tmp_path, tmp_path, NULL);
01730     fn_format(filename, table, tmp_path, ".txt", 4);
01731     my_delete(filename, MYF(0)); /* 'INTO OUTFILE' doesn't work, if
01732                                     filename wasn't deleted */
01733     to_unix_path(filename);
01734     my_snprintf(query, QUERY_LENGTH, 
01735                 "SELECT /*!40001 SQL_NO_CACHE */ * INTO OUTFILE '%s'",
01736                 filename);
01737     end= strend(query);
01738 
01739     if (fields_terminated || enclosed || opt_enclosed || escaped)
01740       end= strmov(end, " FIELDS");
01741     end= add_load_option(end, fields_terminated, " TERMINATED BY");
01742     end= add_load_option(end, enclosed, " ENCLOSED BY");
01743     end= add_load_option(end, opt_enclosed, " OPTIONALLY ENCLOSED BY");
01744     end= add_load_option(end, escaped, " ESCAPED BY");
01745     end= add_load_option(end, lines_terminated, " LINES TERMINATED BY");
01746     *end= '\0';
01747 
01748     my_snprintf(buff, sizeof(buff), " FROM %s", result_table);
01749     end= strmov(end,buff);
01750     if (where || order_by)
01751     {
01752       query = alloc_query_str((ulong) ((end - query) + 1 +
01753                              (where ? strlen(where) + 7 : 0) +
01754                              (order_by ? strlen(order_by) + 10 : 0)));
01755       end = strmov(query, query_buf);
01756 
01757       if (where)
01758         end = strxmov(end, " WHERE ", where, NullS);
01759       if (order_by)
01760         end = strxmov(end, " ORDER BY ", order_by, NullS);
01761     }
01762     if (mysql_real_query(sock, query, (uint) (end - query)))
01763     {
01764       DB_error(sock, "when executing 'SELECT INTO OUTFILE'");
01765       return;
01766     }
01767   }
01768   else
01769   {
01770     if (!opt_xml && opt_comments)
01771     {
01772       fprintf(md_result_file,"\n--\n-- Dumping data for table %s\n--\n",
01773               result_table);
01774       check_io(md_result_file);
01775     }
01776     my_snprintf(query, QUERY_LENGTH,
01777                 "SELECT /*!40001 SQL_NO_CACHE */ * FROM %s",
01778                 result_table);
01779     if (where || order_by)
01780     {
01781       query = alloc_query_str((ulong) (strlen(query) + 1 +
01782                              (where ? strlen(where) + 7 : 0) +
01783                              (order_by ? strlen(order_by) + 10 : 0)));
01784       end = strmov(query, query_buf);
01785 
01786       if (where)
01787       {
01788         if (!opt_xml && opt_comments)
01789         {
01790           fprintf(md_result_file, "-- WHERE:  %s\n", where);
01791           check_io(md_result_file);
01792         }
01793         end = strxmov(end, " WHERE ", where, NullS);
01794       }
01795       if (order_by)
01796       {
01797         if (!opt_xml && opt_comments)
01798         {
01799           fprintf(md_result_file, "-- ORDER BY:  %s\n", order_by);
01800           check_io(md_result_file);
01801         }
01802         end = strxmov(end, " ORDER BY ", order_by, NullS);
01803       }
01804     }
01805     if (!opt_xml && !opt_compact)
01806     {
01807       fputs("\n", md_result_file);
01808       check_io(md_result_file);
01809     }
01810     if (mysql_query_with_error_report(sock, 0, query))
01811       DB_error(sock, "when retrieving data from server");
01812     if (quick)
01813       res=mysql_use_result(sock);
01814     else
01815       res=mysql_store_result(sock);
01816     if (!res)
01817       DB_error(sock, "when retrieving data from server");
01818     if (verbose)
01819       fprintf(stderr, "-- Retrieving rows...\n");
01820     if (mysql_num_fields(res) != numFields)
01821     {
01822       fprintf(stderr,"%s: Error in field count for table: %s !  Aborting.\n",
01823               my_progname, result_table);
01824       error= EX_CONSCHECK;
01825       goto err;
01826     }
01827 
01828     if (opt_disable_keys)
01829     {
01830       fprintf(md_result_file, "\n/*!40000 ALTER TABLE %s DISABLE KEYS */;\n",
01831               opt_quoted_table);
01832       check_io(md_result_file);
01833     }
01834     if (opt_lock)
01835     {
01836       fprintf(md_result_file,"LOCK TABLES %s WRITE;\n", opt_quoted_table);
01837       check_io(md_result_file);
01838     }
01839 
01840     total_length= opt_net_buffer_length;                /* Force row break */
01841     row_break=0;
01842     rownr=0;
01843     init_length=(uint) insert_pat.length+4;
01844     if (opt_xml)
01845       print_xml_tag1(md_result_file, "\t", "table_data name=", table, "\n");
01846 
01847     if (opt_autocommit)
01848     {
01849       fprintf(md_result_file, "set autocommit=0;\n");
01850       check_io(md_result_file);
01851     }
01852 
01853     while ((row=mysql_fetch_row(res)))
01854     {
01855       uint i;
01856       ulong *lengths=mysql_fetch_lengths(res);
01857       rownr++;
01858       if (!extended_insert && !opt_xml)
01859       {
01860         fputs(insert_pat.str,md_result_file);
01861         check_io(md_result_file);
01862       }
01863       mysql_field_seek(res,0);
01864 
01865       if (opt_xml)
01866       {
01867         fputs("\t<row>\n", md_result_file);
01868         check_io(md_result_file);
01869       }
01870 
01871       for (i = 0; i < mysql_num_fields(res); i++)
01872       {
01873         int is_blob;
01874         if (!(field = mysql_fetch_field(res)))
01875         {
01876           my_snprintf(query, QUERY_LENGTH,
01877                       "%s: Not enough fields from table %s! Aborting.\n",
01878                       my_progname, result_table);
01879           fputs(query,stderr);
01880           error= EX_CONSCHECK;
01881           goto err;
01882         }
01883         
01884         /*
01885            63 is my_charset_bin. If charsetnr is not 63,
01886            we have not a BLOB but a TEXT column. 
01887            we'll dump in hex only BLOB columns.
01888         */
01889         is_blob= (opt_hex_blob && field->charsetnr == 63 &&
01890                   (field->type == MYSQL_TYPE_STRING ||
01891                    field->type == MYSQL_TYPE_VAR_STRING ||
01892                    field->type == MYSQL_TYPE_VARCHAR ||
01893                    field->type == MYSQL_TYPE_BLOB ||
01894                    field->type == MYSQL_TYPE_LONG_BLOB ||
01895                    field->type == MYSQL_TYPE_MEDIUM_BLOB ||
01896                    field->type == MYSQL_TYPE_TINY_BLOB)) ? 1 : 0;
01897         if (extended_insert)
01898         {
01899           ulong length = lengths[i];
01900           if (i == 0)
01901             dynstr_set(&extended_row,"(");
01902           else
01903             dynstr_append(&extended_row,",");
01904 
01905           if (row[i])
01906           {
01907             if (length)
01908             {
01909               if (!IS_NUM_FIELD(field))
01910               {
01911                 /*
01912                   "length * 2 + 2" is OK for both HEX and non-HEX modes:
01913                   - In HEX mode we need exactly 2 bytes per character
01914                   plus 2 bytes for '0x' prefix.
01915                   - In non-HEX mode we need up to 2 bytes per character,
01916                   plus 2 bytes for leading and trailing '\'' characters.
01917                 */
01918                 if (dynstr_realloc(&extended_row,length * 2+2))
01919                 {
01920                   fputs("Aborting dump (out of memory)",stderr);
01921                   error= EX_EOM;
01922                   goto err;
01923                 }
01924                 if (opt_hex_blob && is_blob)
01925                 {
01926                   dynstr_append(&extended_row, "0x");
01927                   extended_row.length+= mysql_hex_string(extended_row.str + 
01928                                                          extended_row.length,
01929                                                          row[i], length);
01930                   extended_row.str[extended_row.length]= '\0';
01931                 }
01932                 else
01933                 {
01934                   dynstr_append(&extended_row,"'");
01935                   extended_row.length +=
01936                   mysql_real_escape_string(&mysql_connection,
01937                                            &extended_row.str[extended_row.length],
01938                                            row[i],length);
01939                   extended_row.str[extended_row.length]='\0';
01940                   dynstr_append(&extended_row,"'");
01941                 }
01942               }
01943               else
01944               {
01945                 /* change any strings ("inf", "-inf", "nan") into NULL */
01946                 char *ptr = row[i];
01947                 if (my_isalpha(charset_info, *ptr) || (*ptr == '-' &&
01948                     my_isalpha(charset_info, ptr[1])))
01949                   dynstr_append(&extended_row, "NULL");
01950                 else
01951                 {
01952                   if (field->type == FIELD_TYPE_DECIMAL)
01953                   {
01954                     /* add " signs around */
01955                     dynstr_append(&extended_row, "'");
01956                     dynstr_append(&extended_row, ptr);
01957                     dynstr_append(&extended_row, "'");
01958                   }
01959                   else
01960                     dynstr_append(&extended_row, ptr);
01961                 }
01962               }
01963             }
01964             else
01965               dynstr_append(&extended_row,"''");
01966           }
01967           else if (dynstr_append(&extended_row,"NULL"))
01968           {
01969             fputs("Aborting dump (out of memory)",stderr);
01970             error= EX_EOM;
01971             goto err;
01972           }
01973         }
01974         else
01975         {
01976           if (i && !opt_xml)
01977           {
01978             fputc(',', md_result_file);
01979             check_io(md_result_file);
01980           }
01981           if (row[i])
01982           {
01983             if (!IS_NUM_FIELD(field))
01984             {
01985               if (opt_xml)
01986               {
01987                 print_xml_tag1(md_result_file, "\t\t", "field name=",
01988                               field->name, "");
01989                 print_quoted_xml(md_result_file, row[i], lengths[i]);
01990                 fputs("</field>\n", md_result_file);
01991               }
01992               else if (opt_hex_blob && is_blob)
01993               {
01994                 /* sakaik got the idea to to provide blob's in hex notation. */
01995                 char *ptr= row[i], *end= ptr+ lengths[i];
01996                 fputs("0x", md_result_file);
01997                 for (; ptr < end ; ptr++)
01998                   fprintf(md_result_file, "%02X", *((uchar *)ptr));
01999               }
02000               else
02001                 unescape(md_result_file, row[i], lengths[i]);
02002             }
02003             else
02004             {
02005               /* change any strings ("inf", "-inf", "nan") into NULL */
02006               char *ptr = row[i];
02007               if (opt_xml)
02008               {
02009                 print_xml_tag1(md_result_file, "\t\t", "field name=",
02010                                field->name, "");
02011                 fputs(!my_isalpha(charset_info, *ptr) ? ptr: "NULL",
02012                       md_result_file);
02013                 fputs("</field>\n", md_result_file);
02014               }
02015               else if (my_isalpha(charset_info, *ptr) ||
02016                        (*ptr == '-' && my_isalpha(charset_info, ptr[1])))
02017                 fputs("NULL", md_result_file);
02018               else if (field->type == FIELD_TYPE_DECIMAL)
02019               {
02020                 /* add " signs around */
02021                 fputc('\'', md_result_file);
02022                 fputs(ptr, md_result_file);
02023                 fputc('\'', md_result_file);
02024               }
02025               else
02026                 fputs(ptr, md_result_file);
02027             }
02028           }
02029           else
02030           {
02031             /* The field value is NULL */
02032             if (!opt_xml)
02033               fputs("NULL", md_result_file);
02034             else
02035               print_xml_null_tag(md_result_file, "\t\t", "field name=",
02036                                  field->name, "\n");
02037           }
02038           check_io(md_result_file);
02039         }
02040       }
02041 
02042       if (opt_xml)
02043       {
02044         fputs("\t</row>\n", md_result_file);
02045         check_io(md_result_file);
02046       }
02047 
02048       if (extended_insert)
02049       {
02050         ulong row_length;
02051         dynstr_append(&extended_row,")");
02052         row_length = 2 + extended_row.length;
02053         if (total_length + row_length < opt_net_buffer_length)
02054         {
02055           total_length += row_length;
02056           fputc(',',md_result_file);            /* Always row break */
02057           fputs(extended_row.str,md_result_file);
02058         }
02059         else
02060         {
02061           if (row_break)
02062             fputs(";\n", md_result_file);
02063           row_break=1;                          /* This is first row */
02064 
02065           fputs(insert_pat.str,md_result_file);
02066           fputs(extended_row.str,md_result_file);
02067           total_length = row_length+init_length;
02068         }
02069         check_io(md_result_file);
02070       }
02071       else if (!opt_xml)
02072       {
02073         fputs(");\n", md_result_file);
02074         check_io(md_result_file);
02075       }
02076     }
02077 
02078     /* XML - close table tag and supress regular output */
02079     if (opt_xml)
02080         fputs("\t</table_data>\n", md_result_file);
02081     else if (extended_insert && row_break)
02082       fputs(";\n", md_result_file);             /* If not empty table */
02083     fflush(md_result_file);
02084     check_io(md_result_file);
02085     if (mysql_errno(sock))
02086     {
02087       my_snprintf(query, QUERY_LENGTH,
02088                   "%s: Error %d: %s when dumping table %s at row: %ld\n",
02089                   my_progname,
02090                   mysql_errno(sock),
02091                   mysql_error(sock),
02092                   result_table,
02093                   rownr);
02094       fputs(query,stderr);
02095       error= EX_CONSCHECK;
02096       goto err;
02097     }
02098     if (opt_lock)
02099     {
02100       fputs("UNLOCK TABLES;\n", md_result_file);
02101       check_io(md_result_file);
02102     }
02103     if (opt_disable_keys)
02104     {
02105       fprintf(md_result_file,"/*!40000 ALTER TABLE %s ENABLE KEYS */;\n",
02106               opt_quoted_table);
02107       check_io(md_result_file);
02108     }
02109     if (opt_autocommit)
02110     {
02111       fprintf(md_result_file, "commit;\n");
02112       check_io(md_result_file);
02113     }
02114     mysql_free_result(res);
02115     if (query != query_buf)
02116       my_free(query, MYF(MY_ALLOW_ZERO_PTR));
02117   } 
02118   return;
02119 
02120 err:
02121   if (query != query_buf)
02122     my_free(query, MYF(MY_ALLOW_ZERO_PTR));
02123   safe_exit(error);
02124   return;
02125 } /* dump_table */
02126 
02127 
02128 static char *getTableName(int reset)
02129 {
02130   static MYSQL_RES *res = NULL;
02131   MYSQL_ROW    row;
02132 
02133   if (!res)
02134   {
02135     if (!(res = mysql_list_tables(sock,NullS)))
02136       return(NULL);
02137   }
02138   if ((row = mysql_fetch_row(res)))
02139     return((char*) row[0]);
02140 
02141   if (reset)
02142     mysql_data_seek(res,0);      /* We want to read again */
02143   else
02144   {
02145     mysql_free_result(res);
02146     res = NULL;
02147   }
02148   return(NULL);
02149 } /* getTableName */
02150 
02151 
02152 static int dump_all_databases()
02153 {
02154   MYSQL_ROW row;
02155   MYSQL_RES *tableres;
02156   int result=0;
02157 
02158   if (mysql_query_with_error_report(sock, &tableres, "SHOW DATABASES"))
02159     return 1;
02160   while ((row = mysql_fetch_row(tableres)))
02161   {
02162     if (dump_all_tables_in_db(row[0]))
02163       result=1;
02164   }
02165   if (was_views)
02166   {
02167     if (mysql_query(sock, "SHOW DATABASES") ||
02168         !(tableres = mysql_store_result(sock)))
02169     {
02170       my_printf_error(0, "Error: Couldn't execute 'SHOW DATABASES': %s",
02171                       MYF(0), mysql_error(sock));
02172       return 1;
02173     }
02174     while ((row = mysql_fetch_row(tableres)))
02175     {
02176       if (dump_all_views_in_db(row[0]))
02177         result=1;
02178     }
02179   }
02180   return result;
02181 }
02182 /* dump_all_databases */
02183 
02184 
02185 static int dump_databases(char **db_names)
02186 {
02187   int result=0;
02188   char **db;
02189   for (db= db_names ; *db ; db++)
02190   {
02191     if (dump_all_tables_in_db(*db))
02192       result=1;
02193   }
02194   if (!result && was_views)
02195   {
02196     for (db= db_names ; *db ; db++)
02197     {
02198       if (dump_all_views_in_db(*db))
02199         result=1;
02200     }
02201   }
02202   return result;
02203 } /* dump_databases */
02204 
02205 
02206 static int init_dumping(char *database)
02207 {
02208   if (mysql_get_server_version(sock) >= 50003 &&
02209       !my_strcasecmp(&my_charset_latin1, database, "information_schema"))
02210     return 1; 
02211 
02212   if (mysql_select_db(sock, database))
02213   {
02214     DB_error(sock, "when selecting the database");
02215     return 1;                   /* If --force */
02216   }
02217   if (!path && !opt_xml)
02218   {
02219     if (opt_databases || opt_alldbs)
02220     {
02221       /*
02222         length of table name * 2 (if name contains quotes), 2 quotes and 0
02223       */
02224       char quoted_database_buf[64*2+3];
02225       char *qdatabase= quote_name(database,quoted_database_buf,opt_quoted);
02226       if (opt_comments)
02227       {
02228         fprintf(md_result_file,"\n--\n-- Current Database: %s\n--\n", qdatabase);
02229         check_io(md_result_file);
02230       }
02231       if (!opt_create_db)
02232       {
02233         char qbuf[256];
02234         MYSQL_ROW row;
02235         MYSQL_RES *dbinfo;
02236 
02237         my_snprintf(qbuf, sizeof(qbuf), 
02238                     "SHOW CREATE DATABASE IF NOT EXISTS %s",
02239                     qdatabase);
02240 
02241         if (mysql_query(sock, qbuf) || !(dbinfo = mysql_store_result(sock)))
02242         {
02243           /* Old server version, dump generic CREATE DATABASE */
02244           if (opt_drop_database)
02245             fprintf(md_result_file,
02246                     "\n/*!40000 DROP DATABASE IF EXISTS %s;*/\n",
02247                     qdatabase);
02248           fprintf(md_result_file,
02249                   "\nCREATE DATABASE /*!32312 IF NOT EXISTS*/ %s;\n",
02250                   qdatabase);
02251         }
02252         else
02253         {
02254           if (opt_drop_database)
02255             fprintf(md_result_file,
02256                     "\n/*!40000 DROP DATABASE IF EXISTS %s*/;\n",
02257                     qdatabase);
02258           row = mysql_fetch_row(dbinfo);
02259           if (row[1])
02260           {
02261             fprintf(md_result_file,"\n%s;\n",row[1]);
02262           }
02263         }
02264       }
02265       fprintf(md_result_file,"\nUSE %s;\n", qdatabase);
02266       check_io(md_result_file);
02267     }
02268   }
02269   if (extended_insert && init_dynamic_string(&extended_row, "", 1024, 1024))
02270     exit(EX_EOM);
02271   return 0;
02272 } /* init_dumping */
02273 
02274 
02275 my_bool include_table(byte* hash_key, uint len)
02276 {
02277   if (hash_search(&ignore_table, (byte*) hash_key, len))
02278     return FALSE;
02279 
02280   return TRUE;
02281 }
02282 
02283 
02284 static int dump_all_tables_in_db(char *database)
02285 {
02286   char *table;
02287   uint numrows;
02288   char table_buff[NAME_LEN*2+3];
02289 
02290   char hash_key[2*NAME_LEN+2];  /* "db.tablename" */
02291   char *afterdot;
02292 
02293   afterdot= strmov(hash_key, database);
02294   *afterdot++= '.';
02295 
02296   if (init_dumping(database))
02297     return 1;
02298   if (opt_xml)
02299     print_xml_tag1(md_result_file, "", "database name=", database, "\n");
02300   if (lock_tables)
02301   {
02302     DYNAMIC_STRING query;
02303     init_dynamic_string(&query, "LOCK TABLES ", 256, 1024);
02304     for (numrows= 0 ; (table= getTableName(1)) ; numrows++)
02305     {
02306       dynstr_append(&query, quote_name(table, table_buff, 1));
02307       dynstr_append(&query, " READ /*!32311 LOCAL */,");
02308     }
02309     if (numrows && mysql_real_query(sock, query.str, query.length-1))
02310       DB_error(sock, "when using LOCK TABLES");
02311             /* We shall continue here, if --force was given */
02312     dynstr_free(&query);
02313   }
02314   if (flush_logs)
02315   {
02316     if (mysql_refresh(sock, REFRESH_LOG))
02317       DB_error(sock, "when doing refresh");
02318            /* We shall continue here, if --force was given */
02319   }
02320   while ((table= getTableName(0)))
02321   {
02322     char *end= strmov(afterdot, table);
02323     if (include_table(hash_key, end - hash_key))
02324     {
02325       numrows = get_table_structure(table, database);
02326       dump_table(numrows,table);
02327       my_free(order_by, MYF(MY_ALLOW_ZERO_PTR));
02328       order_by= 0;
02329     }
02330   }
02331   if (opt_xml)
02332   {
02333     fputs("</database>\n", md_result_file);
02334     check_io(md_result_file);
02335   }
02336   if (lock_tables)
02337     mysql_query_with_error_report(sock, 0, "UNLOCK TABLES");
02338   return 0;
02339 } /* dump_all_tables_in_db */
02340 
02341 
02342 /*
02343    dump structure of views of database
02344 
02345    SYNOPSIS
02346      dump_all_views_in_db()
02347      database  database name
02348 
02349   RETURN
02350     0 OK
02351     1 ERROR
02352 */
02353 
02354 static my_bool dump_all_views_in_db(char *database)
02355 {
02356   char *table;
02357   uint numrows;
02358   char table_buff[NAME_LEN*2+3];
02359 
02360   if (init_dumping(database))
02361     return 1;
02362   if (opt_xml)
02363     print_xml_tag1(md_result_file, "", "database name=", database, "\n");
02364   if (lock_tables)
02365   {
02366     DYNAMIC_STRING query;
02367     init_dynamic_string(&query, "LOCK TABLES ", 256, 1024);
02368     for (numrows= 0 ; (table= getTableName(1)); numrows++)
02369     {
02370       dynstr_append(&query, quote_name(table, table_buff, 1));
02371       dynstr_append(&query, " READ /*!32311 LOCAL */,");
02372     }
02373     if (numrows && mysql_real_query(sock, query.str, query.length-1))
02374       DB_error(sock, "when using LOCK TABLES");
02375             /* We shall continue here, if --force was given */
02376     dynstr_free(&query);
02377   }
02378   if (flush_logs)
02379   {
02380     if (mysql_refresh(sock, REFRESH_LOG))
02381       DB_error(sock, "when doing refresh");
02382            /* We shall continue here, if --force was given */
02383   }
02384   while ((table= getTableName(0)))
02385      get_view_structure(table, database);
02386   if (opt_xml)
02387   {
02388     fputs("</database>\n", md_result_file);
02389     check_io(md_result_file);
02390   }
02391   if (lock_tables)
02392     mysql_query(sock,"UNLOCK TABLES");
02393   return 0;
02394 } /* dump_all_tables_in_db */
02395 
02396 
02397 /*
02398   get_actual_table_name -- executes a SHOW TABLES LIKE '%s' to get the actual 
02399   table name from the server for the table name given on the command line.  
02400   we do this because the table name given on the command line may be a 
02401   different case (e.g.  T1 vs t1)
02402   
02403   RETURN
02404     int - 0 if a tablename was retrieved.  1 if not
02405 */
02406 
02407 static int get_actual_table_name(const char *old_table_name, 
02408                                   char *new_table_name, 
02409                                   int buf_size)
02410 {
02411   int retval;
02412   MYSQL_RES  *table_res;
02413   MYSQL_ROW  row;
02414   char query[50 + 2*NAME_LEN];
02415   char show_name_buff[FN_REFLEN];
02416   DBUG_ENTER("get_actual_table_name");
02417 
02418   /* Check memory for quote_for_like() */
02419   DBUG_ASSERT(2*sizeof(old_table_name) < sizeof(show_name_buff));
02420   my_snprintf(query, sizeof(query), "SHOW TABLES LIKE %s", 
02421               quote_for_like(old_table_name, show_name_buff));
02422 
02423   if (mysql_query_with_error_report(sock, 0, query))
02424   {
02425     safe_exit(EX_MYSQLERR);
02426   }
02427 
02428   retval = 1;
02429   
02430   if ((table_res= mysql_store_result(sock)))
02431   {
02432     my_ulonglong num_rows= mysql_num_rows(table_res);
02433     if (num_rows > 0)
02434     {
02435       /*
02436         Return first row
02437         TODO: Return all matching rows
02438       */
02439       row= mysql_fetch_row(table_res);
02440       strmake(new_table_name, row[0], buf_size-1);
02441       retval= 0;
02442     }
02443     mysql_free_result(table_res);
02444   }
02445   return retval;
02446 }
02447 
02448 
02449 static int dump_selected_tables(char *db, char **table_names, int tables)
02450 {
02451   uint numrows, i;
02452   char table_buff[NAME_LEN*+3];
02453   char new_table_name[NAME_LEN];
02454   DYNAMIC_STRING lock_tables_query;
02455   HASH dump_tables;
02456   char *table_name;
02457   DBUG_ENTER("dump_selected_tables");
02458 
02459   if (init_dumping(db))
02460     return 1;
02461 
02462   /* Init hash table for storing the actual name of tables to dump */
02463   if (hash_init(&dump_tables, charset_info, 16, 0, 0,
02464                  (hash_get_key) get_table_key, (hash_free_key) free_table_ent,
02465                 0))
02466     exit(EX_EOM);
02467 
02468   init_dynamic_string(&lock_tables_query, "LOCK TABLES ", 256, 1024);
02469   for (; tables > 0 ; tables-- , table_names++)
02470   {
02471     /* the table name passed on commandline may be wrong case */
02472     if (!get_actual_table_name(*table_names,
02473                                new_table_name, sizeof(new_table_name)))
02474     {
02475       /* Add found table name to lock_tables_query */
02476       if (lock_tables)
02477       {
02478         dynstr_append(&lock_tables_query,
02479                       quote_name(new_table_name, table_buff, 1));
02480         dynstr_append(&lock_tables_query, " READ /*!32311 LOCAL */,");
02481       }
02482 
02483       /* Add found table name to dump_tables list */
02484       if (my_hash_insert(&dump_tables,
02485                          (byte*)my_strdup(new_table_name, MYF(0))))
02486         exit(EX_EOM);
02487 
02488     }
02489     else
02490     {
02491        my_printf_error(0,"Couldn't find table: \"%s\"\n", MYF(0),
02492                        *table_names);
02493        safe_exit(EX_ILLEGAL_TABLE);
02494        /* We shall countinue here, if --force was given */
02495     }
02496   }
02497 
02498   if (lock_tables)
02499   {
02500     if (mysql_real_query(sock, lock_tables_query.str,
02501                          lock_tables_query.length-1))
02502       DB_error(sock, "when doing LOCK TABLES");
02503        /* We shall countinue here, if --force was given */
02504   }
02505   dynstr_free(&lock_tables_query);
02506   if (flush_logs)
02507   {
02508     if (mysql_refresh(sock, REFRESH_LOG))
02509       DB_error(sock, "when doing refresh");
02510      /* We shall countinue here, if --force was given */
02511   }
02512   if (opt_xml)
02513     print_xml_tag1(md_result_file, "", "database name=", db, "\n");
02514 
02515   /* Dump each selected table */
02516   for (i= 0; i < dump_tables.records; i++)
02517   {
02518     table_name= hash_element(&dump_tables, i);
02519     DBUG_PRINT("info",("Dumping table %s", table_name));
02520     numrows= get_table_structure(table_name, db);
02521     dump_table(numrows, table_name);
02522   }
02523 
02524   /* Dump each selected view */
02525   if (was_views)
02526   {
02527     for(i=0; i < dump_tables.records; i++)
02528     {
02529       table_name= hash_element(&dump_tables, i);
02530       get_view_structure(table_name, db);
02531     }
02532   }
02533   hash_free(&dump_tables);
02534   my_free(order_by, MYF(MY_ALLOW_ZERO_PTR));
02535   order_by= 0;
02536   if (opt_xml)
02537   {
02538     fputs("</database>\n", md_result_file);
02539     check_io(md_result_file);
02540   }
02541   if (lock_tables)
02542     mysql_query_with_error_report(sock, 0, "UNLOCK TABLES");
02543   DBUG_RETURN(0);
02544 } /* dump_selected_tables */
02545 
02546 
02547 static int do_show_master_status(MYSQL *mysql_con)
02548 {
02549   MYSQL_ROW row;
02550   MYSQL_RES *master;
02551   const char *comment_prefix=
02552     (opt_master_data == MYSQL_OPT_MASTER_DATA_COMMENTED_SQL) ? "-- " : "";
02553   if (mysql_query_with_error_report(mysql_con, &master, "SHOW MASTER STATUS"))
02554   {
02555     my_printf_error(0, "Error: Couldn't execute 'SHOW MASTER STATUS': %s",
02556                     MYF(0), mysql_error(mysql_con));
02557     return 1;
02558   }
02559   else
02560   {
02561     row = mysql_fetch_row(master);
02562     if (row && row[0] && row[1])
02563     {
02564       /* SHOW MASTER STATUS reports file and position */
02565       if (opt_comments)
02566         fprintf(md_result_file,
02567                 "\n--\n-- Position to start replication or point-in-time "
02568                 "recovery from\n--\n\n");
02569       fprintf(md_result_file,
02570               "%sCHANGE MASTER TO MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n",
02571               comment_prefix, row[0], row[1]); 
02572       check_io(md_result_file);
02573     }
02574     else if (!ignore_errors)
02575     {
02576       /* SHOW MASTER STATUS reports nothing and --force is not enabled */
02577       my_printf_error(0, "Error: Binlogging on server not active", 
02578                       MYF(0), mysql_error(mysql_con));
02579       mysql_free_result(master);
02580       return 1;
02581     }
02582     mysql_free_result(master);
02583   }
02584   return 0;
02585 }
02586 
02587 
02588 static int do_flush_tables_read_lock(MYSQL *mysql_con)
02589 {
02590   /*
02591     We do first a FLUSH TABLES. If a long update is running, the FLUSH TABLES
02592     will wait but will not stall the whole mysqld, and when the long update is
02593     done the FLUSH TABLES WITH READ LOCK will start and succeed quickly. So,
02594     FLUSH TABLES is to lower the probability of a stage where both mysqldump
02595     and most client connections are stalled. Of course, if a second long
02596     update starts between the two FLUSHes, we have that bad stall.
02597   */
02598   return 
02599     ( mysql_query_with_error_report(mysql_con, 0, "FLUSH TABLES") ||
02600       mysql_query_with_error_report(mysql_con, 0,
02601                                     "FLUSH TABLES WITH READ LOCK") );
02602 }
02603 
02604 
02605 static int do_unlock_tables(MYSQL *mysql_con)
02606 {
02607   return mysql_query_with_error_report(mysql_con, 0, "UNLOCK TABLES");
02608 }
02609 
02610 
02611 static int do_reset_master(MYSQL *mysql_con)
02612 {
02613   return mysql_query_with_error_report(mysql_con, 0, "RESET MASTER");
02614 }
02615 
02616 
02617 static int start_transaction(MYSQL *mysql_con, my_bool consistent_read_now)
02618 {
02619   /*
02620     We use BEGIN for old servers. --single-transaction --master-data will fail
02621     on old servers, but that's ok as it was already silently broken (it didn't
02622     do a consistent read, so better tell people frankly, with the error).
02623 
02624     We want the first consistent read to be used for all tables to dump so we
02625     need the REPEATABLE READ level (not anything lower, for example READ
02626     COMMITTED would give one new consistent read per dumped table).
02627   */
02628   return (mysql_query_with_error_report(mysql_con, 0,
02629                                         "SET SESSION TRANSACTION ISOLATION "
02630                                         "LEVEL REPEATABLE READ") ||
02631           mysql_query_with_error_report(mysql_con, 0,
02632                                         consistent_read_now ?
02633                                         "START TRANSACTION "
02634                                         "WITH CONSISTENT SNAPSHOT" :
02635                                         "BEGIN"));
02636 }
02637 
02638 
02639 static ulong find_set(TYPELIB *lib, const char *x, uint length,
02640                       char **err_pos, uint *err_len)
02641 {
02642   const char *end= x + length;
02643   ulong found= 0;
02644   uint find;
02645   char buff[255];
02646 
02647   *err_pos= 0;                  /* No error yet */
02648   while (end > x && my_isspace(charset_info, end[-1]))
02649     end--;
02650 
02651   *err_len= 0;
02652   if (x != end)
02653   {
02654     const char *start= x;
02655     for (;;)
02656     {
02657       const char *pos= start;
02658       uint var_len;
02659 
02660       for (; pos != end && *pos != ','; pos++) ;
02661       var_len= (uint) (pos - start);
02662       strmake(buff, start, min(sizeof(buff), var_len));
02663       find= find_type(buff, lib, var_len);
02664       if (!find)
02665       {
02666         *err_pos= (char*) start;
02667         *err_len= var_len;
02668       }
02669       else
02670         found|= ((longlong) 1 << (find - 1));
02671       if (pos == end)
02672         break;
02673       start= pos + 1;
02674     }
02675   }
02676   return found;
02677 }
02678 
02679 
02680 /* Print a value with a prefix on file */
02681 static void print_value(FILE *file, MYSQL_RES  *result, MYSQL_ROW row,
02682                         const char *prefix, const char *name,
02683                         int string_value)
02684 {
02685   MYSQL_FIELD   *field;
02686   mysql_field_seek(result, 0);
02687 
02688   for ( ; (field = mysql_fetch_field(result)) ; row++)
02689   {
02690     if (!strcmp(field->name,name))
02691     {
02692       if (row[0] && row[0][0] && strcmp(row[0],"0")) /* Skip default */
02693       {
02694         fputc(' ',file);
02695         fputs(prefix, file);
02696         if (string_value)
02697           unescape(file,row[0],(uint) strlen(row[0]));
02698         else
02699           fputs(row[0], file);
02700         check_io(file);
02701         return;
02702       }
02703     }
02704   }
02705   return;                                       /* This shouldn't happen */
02706 } /* print_value */
02707 
02708 
02709 /*
02710   Check if we the table is one of the table types that should be ignored:
02711   MRG_ISAM, MRG_MYISAM
02712 
02713   SYNOPSIS
02714     check_if_ignore_table()
02715     table_name                  Table name to check
02716 
02717   GLOBAL VARIABLES
02718     sock                        MySQL socket
02719     verbose                     Write warning messages
02720 
02721   RETURN
02722     0   Table should be backuped
02723     #   Type of table (that should be skipped)
02724 */
02725 
02726 static const char *check_if_ignore_table(const char *table_name)
02727 {
02728   char buff[FN_REFLEN+80], show_name_buff[FN_REFLEN];
02729   MYSQL_RES *res;
02730   MYSQL_ROW row;
02731   const char *result= 0;
02732 
02733   /* Check memory for quote_for_like() */
02734   DBUG_ASSERT(2*sizeof(table_name) < sizeof(show_name_buff));
02735   my_snprintf(buff, sizeof(buff), "show table status like %s",
02736               quote_for_like(table_name, show_name_buff));
02737   if (mysql_query_with_error_report(sock, &res, buff))
02738   {
02739     if (mysql_errno(sock) != ER_PARSE_ERROR)
02740     {                                   /* If old MySQL version */
02741       if (verbose)
02742         fprintf(stderr,
02743                 "-- Warning: Couldn't get status information for table %s (%s)\n",
02744                 table_name,mysql_error(sock));
02745       return 0;                                 /* assume table is ok */
02746     }
02747   }
02748   if (!(row= mysql_fetch_row(res)))
02749   {
02750     fprintf(stderr,
02751             "Error: Couldn't read status information for table %s (%s)\n",
02752             table_name, mysql_error(sock));
02753     mysql_free_result(res);
02754     return 0;                                   /* assume table is ok */
02755   }
02756   if (!(row[1]))
02757       result= "VIEW";
02758   else
02759   {
02760     if (strcmp(row[1], (result= "MRG_MyISAM")) &&
02761         strcmp(row[1], (result= "MRG_ISAM")))
02762       result= 0;
02763   }
02764   mysql_free_result(res);
02765   return result;
02766 }
02767 
02768 /*
02769   Get string of comma-separated primary key field names
02770 
02771   SYNOPSIS
02772     char *primary_key_fields(const char *table_name)
02773     RETURNS     pointer to allocated buffer (must be freed by caller)
02774     table_name  quoted table name
02775 
02776   DESCRIPTION
02777     Use SHOW KEYS FROM table_name, allocate a buffer to hold the
02778     field names, and then build that string and return the pointer
02779     to that buffer.
02780 
02781     Returns NULL if there is no PRIMARY or UNIQUE key on the table,
02782     or if there is some failure.  It is better to continue to dump
02783     the table unsorted, rather than exit without dumping the data.
02784 */
02785 static char *primary_key_fields(const char *table_name)
02786 {
02787   MYSQL_RES  *res = NULL;
02788   MYSQL_ROW  row;
02789   /* SHOW KEYS FROM + table name * 2 (escaped) + 2 quotes + \0 */
02790   char show_keys_buff[15 + 64 * 2 + 3];
02791   uint result_length = 0;
02792   char *result = 0;
02793 
02794   my_snprintf(show_keys_buff, sizeof(show_keys_buff), 
02795               "SHOW KEYS FROM %s", table_name);
02796   if (mysql_query(sock, show_keys_buff) ||
02797       !(res = mysql_store_result(sock)))
02798   {
02799     fprintf(stderr, "Warning: Couldn't read keys from table %s;"
02800             " records are NOT sorted (%s)\n",
02801             table_name, mysql_error(sock));
02802     /* Don't exit, because it's better to print out unsorted records */
02803     goto cleanup;
02804   }
02805 
02806   /*
02807    * Figure out the length of the ORDER BY clause result.
02808    * Note that SHOW KEYS is ordered:  a PRIMARY key is always the first
02809    * row, and UNIQUE keys come before others.  So we only need to check
02810    * the first key, not all keys.
02811    */
02812   if ((row = mysql_fetch_row(res)) && atoi(row[1]) == 0)
02813   {
02814     /* Key is unique */
02815     do
02816       result_length += strlen(row[4]) + 1;      /* + 1 for ',' or \0 */
02817     while ((row = mysql_fetch_row(res)) && atoi(row[3]) > 1);
02818   }
02819 
02820   /* Build the ORDER BY clause result */
02821   if (result_length) {
02822     char *end;
02823     /* result (terminating \0 is already in result_length) */
02824     result = my_malloc(result_length + 10, MYF(MY_WME));
02825     if (!result) {
02826       fprintf(stderr, "Error: Not enough memory to store ORDER BY clause\n");
02827       goto cleanup;
02828     }
02829     mysql_data_seek(res, 0);
02830     row = mysql_fetch_row(res);
02831     end = strmov(result, row[4]);
02832     while ((row = mysql_fetch_row(res)) && atoi(row[3]) > 1)
02833       end = strxmov(end, ",", row[4], NullS);
02834   }
02835 
02836 cleanup:
02837   if (res)
02838     mysql_free_result(res);
02839 
02840   return result;
02841 }
02842 
02843 
02844 /*
02845   Getting VIEW structure
02846 
02847   SYNOPSIS
02848     get_view_structure()
02849     table   view name
02850     db      db name
02851 
02852   RETURN
02853     0 OK
02854     1 ERROR
02855 */
02856 
02857 static my_bool get_view_structure(char *table, char* db)
02858 {
02859   MYSQL_RES  *table_res;
02860   MYSQL_ROW  row;
02861   MYSQL_FIELD *field;
02862   char       *result_table, *opt_quoted_table;
02863   char       table_buff[NAME_LEN*2+3];
02864   char       table_buff2[NAME_LEN*2+3];
02865   char       buff[20+FN_REFLEN];
02866   FILE       *sql_file = md_result_file;
02867   DBUG_ENTER("get_view_structure");
02868 
02869   if (tFlag)
02870     DBUG_RETURN(0);
02871 
02872   if (verbose)
02873     fprintf(stderr, "-- Retrieving view structure for table %s...\n", table);
02874 
02875 #ifdef NOT_REALLY_USED_YET
02876   sprintf(insert_pat,"SET OPTION SQL_QUOTE_SHOW_CREATE=%d",
02877           (opt_quoted || opt_keywords));
02878 #endif
02879 
02880   result_table=     quote_name(table, table_buff, 1);
02881   opt_quoted_table= quote_name(table, table_buff2, 0);
02882 
02883   sprintf(buff,"show create table %s", result_table);
02884   if (mysql_query(sock, buff))
02885   {
02886     fprintf(stderr, "%s: Can't get CREATE TABLE for view %s (%s)\n",
02887             my_progname, result_table, mysql_error(sock));
02888     safe_exit(EX_MYSQLERR);
02889     DBUG_RETURN(0);
02890   }
02891 
02892   if (path)
02893   {
02894     char filename[FN_REFLEN], tmp_path[FN_REFLEN];
02895     convert_dirname(tmp_path,path,NullS);
02896     sql_file= my_fopen(fn_format(filename, table, tmp_path, ".sql", 4),
02897                        O_WRONLY, MYF(MY_WME));
02898     if (!sql_file)                      /* If file couldn't be opened */
02899     {
02900       safe_exit(EX_MYSQLERR);
02901       DBUG_RETURN(1);
02902     }
02903     write_header(sql_file, db);
02904   }
02905   table_res= mysql_store_result(sock);
02906   field= mysql_fetch_field_direct(table_res, 0);
02907   if (strcmp(field->name, "View") != 0)
02908   {
02909     if (verbose)
02910       fprintf(stderr, "-- It's base table, skipped\n");
02911     DBUG_RETURN(0);
02912   }
02913 
02914   if (!opt_xml && opt_comments)
02915   {
02916     fprintf(sql_file, "\n--\n-- View structure for view %s\n--\n\n",
02917             result_table);
02918     check_io(sql_file);
02919   }
02920   if (opt_drop)
02921   {
02922     fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", opt_quoted_table);
02923     fprintf(sql_file, "DROP VIEW IF EXISTS %s;\n", opt_quoted_table);
02924     check_io(sql_file);
02925   }
02926 
02927   row= mysql_fetch_row(table_res);
02928   fprintf(sql_file, "%s;\n", row[1]);
02929   check_io(sql_file);
02930   mysql_free_result(table_res);
02931 
02932   if (sql_file != md_result_file)
02933   {
02934     fputs("\n", sql_file);
02935     write_footer(sql_file);
02936     my_fclose(sql_file, MYF(MY_WME));
02937   }
02938   DBUG_RETURN(0);
02939 }
02940 
02941 
02942 int main(int argc, char **argv)
02943 {
02944   compatible_mode_normal_str[0]= 0;
02945   default_charset= (char *)mysql_universal_client_charset;
02946   bzero((char*) &ignore_table, sizeof(ignore_table));
02947 
02948   MY_INIT("mysqldump");
02949   if (get_options(&argc, &argv))
02950   {
02951     my_end(0);
02952     exit(EX_USAGE);
02953   }
02954   if (dbConnect(current_host, current_user, opt_password))
02955     exit(EX_MYSQLERR);
02956   if (!path)
02957     write_header(md_result_file, *argv);
02958 
02959   if ((opt_lock_all_tables || opt_master_data) &&
02960       do_flush_tables_read_lock(sock))
02961     goto err;
02962   if (opt_single_transaction && start_transaction(sock, test(opt_master_data)))
02963       goto err;
02964   if (opt_delete_master_logs && do_reset_master(sock))
02965     goto err;
02966   if (opt_lock_all_tables || opt_master_data)
02967   {
02968     if (flush_logs && mysql_refresh(sock, REFRESH_LOG))
02969       goto err;
02970     flush_logs= 0; /* not anymore; that would not be sensible */
02971   }
02972   if (opt_master_data && do_show_master_status(sock))
02973     goto err;
02974   if (opt_single_transaction && do_unlock_tables(sock)) /* unlock but no commit! */
02975     goto err;
02976 
02977   if (opt_alldbs)
02978     dump_all_databases();
02979   else if (argc > 1 && !opt_databases)
02980   {
02981     /* Only one database and selected table(s) */
02982     dump_selected_tables(*argv, (argv + 1), (argc - 1));
02983   }
02984   else
02985   {
02986     /* One or more databases, all tables */
02987     dump_databases(argv);
02988   }
02989 #ifdef HAVE_SMEM
02990   my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR));
02991 #endif
02992   /*
02993     No reason to explicitely COMMIT the transaction, neither to explicitely
02994     UNLOCK TABLES: these will be automatically be done by the server when we
02995     disconnect now. Saves some code here, some network trips, adds nothing to
02996     server.
02997   */
02998 err:
02999   dbDisconnect(current_host);
03000   if (!path)
03001     write_footer(md_result_file);
03002   if (md_result_file != stdout)
03003     my_fclose(md_result_file, MYF(0));
03004   my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR));
03005   if (hash_inited(&ignore_table))
03006     hash_free(&ignore_table);
03007   if (extended_insert)
03008     dynstr_free(&extended_row);
03009   if (insert_pat_inited)
03010     dynstr_free(&insert_pat);
03011   my_end(0);
03012   return(first_error);
03013 } /* main */

Generated on Wed Jul 20 21:04:06 2005 for MySQL 5.0.9 Beta by  doxygen 1.4.3