| 1 | /* |
| 2 | Copyright (c) 2000, 2013, Oracle and/or its affiliates. |
| 3 | Copyright (c) 2010, 2017, MariaDB Corporation. |
| 4 | |
| 5 | This program is free software; you can redistribute it and/or modify |
| 6 | it under the terms of the GNU General Public License as published by |
| 7 | the Free Software Foundation; version 2 of the License. |
| 8 | |
| 9 | This program is distributed in the hope that it will be useful, |
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | GNU General Public License for more details. |
| 13 | |
| 14 | You should have received a copy of the GNU General Public License |
| 15 | along with this program; if not, write to the Free Software |
| 16 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
| 17 | */ |
| 18 | |
| 19 | /* mysqldump.c - Dump a tables contents and format to an ASCII file |
| 20 | ** |
| 21 | ** The author's original notes follow :- |
| 22 | ** |
| 23 | ** AUTHOR: Igor Romanenko (igor@frog.kiev.ua) |
| 24 | ** DATE: December 3, 1994 |
| 25 | ** WARRANTY: None, expressed, impressed, implied |
| 26 | ** or other |
| 27 | ** STATUS: Public domain |
| 28 | ** Adapted and optimized for MySQL by |
| 29 | ** Michael Widenius, Sinisa Milivojevic, Jani Tolonen |
| 30 | ** -w --where added 9/10/98 by Jim Faucette |
| 31 | ** slave code by David Saez Padros <david@ols.es> |
| 32 | ** master/autocommit code by Brian Aker <brian@tangent.org> |
| 33 | ** SSL by |
| 34 | ** Andrei Errapart <andreie@no.spam.ee> |
| 35 | ** Tõnu Samuel <tonu@please.do.not.remove.this.spam.ee> |
| 36 | ** XML by Gary Huntress <ghuntress@mediaone.net> 10/10/01, cleaned up |
| 37 | ** and adapted to mysqldump 05/11/01 by Jani Tolonen |
| 38 | ** Added --single-transaction option 06/06/2002 by Peter Zaitsev |
| 39 | ** 10 Jun 2003: SET NAMES and --no-set-names by Alexander Barkov |
| 40 | */ |
| 41 | |
| 42 | #define DUMP_VERSION "10.16" |
| 43 | |
| 44 | #include <my_global.h> |
| 45 | #include <my_sys.h> |
| 46 | #include <my_user.h> |
| 47 | #include <m_string.h> |
| 48 | #include <m_ctype.h> |
| 49 | #include <hash.h> |
| 50 | #include <stdarg.h> |
| 51 | |
| 52 | #include "client_priv.h" |
| 53 | #include "mysql.h" |
| 54 | #include "mysql_version.h" |
| 55 | #include "mysqld_error.h" |
| 56 | |
| 57 | #include <welcome_copyright_notice.h> /* ORACLE_WELCOME_COPYRIGHT_NOTICE */ |
| 58 | |
| 59 | /* Exit codes */ |
| 60 | |
| 61 | #define EX_USAGE 1 |
| 62 | #define EX_MYSQLERR 2 |
| 63 | #define EX_CONSCHECK 3 |
| 64 | #define EX_EOM 4 |
| 65 | #define EX_EOF 5 /* ferror for output file was got */ |
| 66 | #define EX_ILLEGAL_TABLE 6 |
| 67 | |
| 68 | /* index into 'show fields from table' */ |
| 69 | |
| 70 | #define SHOW_FIELDNAME 0 |
| 71 | #define SHOW_TYPE 1 |
| 72 | #define SHOW_NULL 2 |
| 73 | #define SHOW_DEFAULT 4 |
| 74 | #define 5 |
| 75 | |
| 76 | /* Size of buffer for dump's select query */ |
| 77 | #define QUERY_LENGTH 1536 |
| 78 | |
| 79 | /* Size of comment buffer. */ |
| 80 | #define 2048 |
| 81 | |
| 82 | /* ignore table flags */ |
| 83 | #define IGNORE_NONE 0x00 /* no ignore */ |
| 84 | #define IGNORE_DATA 0x01 /* don't dump data for this table */ |
| 85 | #define IGNORE_INSERT_DELAYED 0x02 /* table doesn't support INSERT DELAYED */ |
| 86 | |
| 87 | /* Chars needed to store LONGLONG, excluding trailing '\0'. */ |
| 88 | #define LONGLONG_LEN 20 |
| 89 | |
| 90 | /* Max length GTID position that we will output. */ |
| 91 | #define MAX_GTID_LENGTH 1024 |
| 92 | |
| 93 | static void add_load_option(DYNAMIC_STRING *str, const char *option, |
| 94 | const char *option_value); |
| 95 | static ulong find_set(TYPELIB *, const char *, size_t, char **, uint *); |
| 96 | static char *alloc_query_str(size_t size); |
| 97 | |
| 98 | static void field_escape(DYNAMIC_STRING* in, const char *from); |
| 99 | static my_bool verbose= 0, opt_no_create_info= 0, opt_no_data= 0, opt_no_data_med= 1, |
| 100 | quick= 1, extended_insert= 1, |
| 101 | lock_tables=1,ignore_errors=0,flush_logs=0,flush_privileges=0, |
| 102 | opt_drop=1,opt_keywords=0,opt_lock=1,opt_compress=0, |
| 103 | opt_delayed=0,create_options=1,opt_quoted=0,opt_databases=0, |
| 104 | opt_alldbs=0,opt_create_db=0,opt_lock_all_tables=0, |
| 105 | opt_set_charset=0, opt_dump_date=1, |
| 106 | opt_autocommit=0,opt_disable_keys=1,opt_xml=0, |
| 107 | opt_delete_master_logs=0, tty_password=0, |
| 108 | opt_single_transaction=0, = 0, opt_compact= 0, |
| 109 | opt_hex_blob=0, opt_order_by_primary=0, opt_ignore=0, |
| 110 | opt_complete_insert= 0, opt_drop_database= 0, |
| 111 | opt_replace_into= 0, |
| 112 | opt_dump_triggers= 0, opt_routines=0, opt_tz_utc=1, |
| 113 | opt_slave_apply= 0, |
| 114 | opt_include_master_host_port= 0, |
| 115 | opt_events= 0, = 0, |
| 116 | opt_alltspcs=0, opt_notspcs= 0, opt_logging, |
| 117 | opt_drop_trigger= 0 ; |
| 118 | static my_bool insert_pat_inited= 0, debug_info_flag= 0, debug_check_flag= 0, |
| 119 | select_field_names_inited= 0; |
| 120 | static ulong opt_max_allowed_packet, opt_net_buffer_length; |
| 121 | static MYSQL mysql_connection,*mysql=0; |
| 122 | static DYNAMIC_STRING insert_pat, select_field_names; |
| 123 | static char *opt_password=0,*current_user=0, |
| 124 | *current_host=0,*path=0,*fields_terminated=0, |
| 125 | *lines_terminated=0, *enclosed=0, *opt_enclosed=0, *escaped=0, |
| 126 | *where=0, *order_by=0, |
| 127 | *opt_compatible_mode_str= 0, |
| 128 | *err_ptr= 0, |
| 129 | *log_error_file= NULL; |
| 130 | static char **defaults_argv= 0; |
| 131 | static char compatible_mode_normal_str[255]; |
| 132 | /* Server supports character_set_results session variable? */ |
| 133 | static my_bool server_supports_switching_charsets= TRUE; |
| 134 | static ulong opt_compatible_mode= 0; |
| 135 | #define MYSQL_OPT_MASTER_DATA_EFFECTIVE_SQL 1 |
| 136 | #define 2 |
| 137 | #define MYSQL_OPT_SLAVE_DATA_EFFECTIVE_SQL 1 |
| 138 | #define 2 |
| 139 | static uint opt_mysql_port= 0, opt_master_data; |
| 140 | static uint opt_slave_data; |
| 141 | static uint opt_use_gtid; |
| 142 | static uint my_end_arg; |
| 143 | static char * opt_mysql_unix_port=0; |
| 144 | static int first_error=0; |
| 145 | /* |
| 146 | multi_source is 0 if old server or 2 if server that support multi source |
| 147 | This is choosen this was as multi_source has 2 extra columns first in |
| 148 | SHOW ALL SLAVES STATUS. |
| 149 | */ |
| 150 | static uint multi_source= 0; |
| 151 | static DYNAMIC_STRING extended_row; |
| 152 | static DYNAMIC_STRING dynamic_where; |
| 153 | static MYSQL_RES *get_table_name_result= NULL; |
| 154 | static MEM_ROOT glob_root; |
| 155 | static MYSQL_RES *routine_res, *routine_list_res; |
| 156 | |
| 157 | |
| 158 | #include <sslopt-vars.h> |
| 159 | FILE *md_result_file= 0; |
| 160 | FILE *stderror_file=0; |
| 161 | |
| 162 | #ifdef HAVE_SMEM |
| 163 | static char *shared_memory_base_name=0; |
| 164 | #endif |
| 165 | static uint opt_protocol= 0; |
| 166 | static char *opt_plugin_dir= 0, *opt_default_auth= 0; |
| 167 | |
| 168 | /* |
| 169 | Dynamic_string wrapper functions. In this file use these |
| 170 | wrappers, they will terminate the process if there is |
| 171 | an allocation failure. |
| 172 | */ |
| 173 | static void init_dynamic_string_checked(DYNAMIC_STRING *str, const char *init_str, |
| 174 | size_t init_alloc, size_t alloc_increment); |
| 175 | static void dynstr_append_checked(DYNAMIC_STRING* dest, const char* src); |
| 176 | static void dynstr_set_checked(DYNAMIC_STRING *str, const char *init_str); |
| 177 | static void dynstr_append_mem_checked(DYNAMIC_STRING *str, const char *append, |
| 178 | uint length); |
| 179 | static void dynstr_realloc_checked(DYNAMIC_STRING *str, ulong additional_size); |
| 180 | |
| 181 | static int do_start_slave_sql(MYSQL *mysql_con); |
| 182 | /* |
| 183 | Constant for detection of default value of default_charset. |
| 184 | If default_charset is equal to mysql_universal_client_charset, then |
| 185 | it is the default value which assigned at the very beginning of main(). |
| 186 | */ |
| 187 | static const char *mysql_universal_client_charset= |
| 188 | MYSQL_UNIVERSAL_CLIENT_CHARSET; |
| 189 | static char *default_charset; |
| 190 | static CHARSET_INFO *charset_info= &my_charset_latin1; |
| 191 | const char *default_dbug_option="d:t:o,/tmp/mysqldump.trace" ; |
| 192 | /* have we seen any VIEWs during table scanning? */ |
| 193 | my_bool seen_views= 0; |
| 194 | const char *compatible_mode_names[]= |
| 195 | { |
| 196 | "MYSQL323" , "MYSQL40" , "POSTGRESQL" , "ORACLE" , "MSSQL" , "DB2" , |
| 197 | "MAXDB" , "NO_KEY_OPTIONS" , "NO_TABLE_OPTIONS" , "NO_FIELD_OPTIONS" , |
| 198 | "ANSI" , |
| 199 | NullS |
| 200 | }; |
| 201 | #define MASK_ANSI_QUOTES \ |
| 202 | (\ |
| 203 | (1U<<2) | /* POSTGRESQL */\ |
| 204 | (1U<<3) | /* ORACLE */\ |
| 205 | (1U<<4) | /* MSSQL */\ |
| 206 | (1U<<5) | /* DB2 */\ |
| 207 | (1U<<6) | /* MAXDB */\ |
| 208 | (1U<<10) /* ANSI */\ |
| 209 | ) |
| 210 | TYPELIB compatible_mode_typelib= {array_elements(compatible_mode_names) - 1, |
| 211 | "" , compatible_mode_names, NULL}; |
| 212 | |
| 213 | #define MED_ENGINES "MRG_MyISAM, MRG_ISAM, CONNECT, OQGRAPH, SPIDER, VP, FEDERATED" |
| 214 | |
| 215 | static HASH ignore_table; |
| 216 | |
| 217 | static HASH ignore_database; |
| 218 | |
| 219 | static struct my_option my_long_options[] = |
| 220 | { |
| 221 | {"all-databases" , 'A', |
| 222 | "Dump all the databases. This will be same as --databases with all databases selected." , |
| 223 | &opt_alldbs, &opt_alldbs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, |
| 224 | 0, 0}, |
| 225 | {"all-tablespaces" , 'Y', |
| 226 | "Dump all the tablespaces." , |
| 227 | &opt_alltspcs, &opt_alltspcs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, |
| 228 | 0, 0}, |
| 229 | {"no-tablespaces" , 'y', |
| 230 | "Do not dump any tablespace information." , |
| 231 | &opt_notspcs, &opt_notspcs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, |
| 232 | 0, 0}, |
| 233 | {"add-drop-database" , OPT_DROP_DATABASE, "Add a DROP DATABASE before each create." , |
| 234 | &opt_drop_database, &opt_drop_database, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, |
| 235 | 0}, |
| 236 | {"add-drop-table" , OPT_DROP, "Add a DROP TABLE before each create." , |
| 237 | &opt_drop, &opt_drop, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, |
| 238 | 0}, |
| 239 | {"add-drop-trigger" , 0, "Add a DROP TRIGGER before each create." , |
| 240 | &opt_drop_trigger, &opt_drop_trigger, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, |
| 241 | 0}, |
| 242 | {"add-locks" , OPT_LOCKS, "Add locks around INSERT statements." , |
| 243 | &opt_lock, &opt_lock, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, |
| 244 | 0}, |
| 245 | {"allow-keywords" , OPT_KEYWORDS, |
| 246 | "Allow creation of column names that are keywords." , &opt_keywords, |
| 247 | &opt_keywords, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 248 | {"apply-slave-statements" , OPT_MYSQLDUMP_SLAVE_APPLY, |
| 249 | "Adds 'STOP SLAVE' prior to 'CHANGE MASTER' and 'START SLAVE' to bottom of dump." , |
| 250 | &opt_slave_apply, &opt_slave_apply, 0, GET_BOOL, NO_ARG, |
| 251 | 0, 0, 0, 0, 0, 0}, |
| 252 | {"character-sets-dir" , OPT_CHARSETS_DIR, |
| 253 | "Directory for character set files." , (char **)&charsets_dir, |
| 254 | (char **)&charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
| 255 | {"comments" , 'i', "Write additional information." , |
| 256 | &opt_comments, &opt_comments, 0, GET_BOOL, NO_ARG, |
| 257 | 1, 0, 0, 0, 0, 0}, |
| 258 | {"compatible" , OPT_COMPATIBLE, |
| 259 | "Change the dump to be compatible with a given mode. By default tables " |
| 260 | "are dumped in a format optimized for MySQL. Legal modes are: ansi, " |
| 261 | "mysql323, mysql40, postgresql, oracle, mssql, db2, maxdb, no_key_options, " |
| 262 | "no_table_options, no_field_options. One can use several modes separated " |
| 263 | "by commas. Note: Requires MySQL server version 4.1.0 or higher. " |
| 264 | "This option is ignored with earlier server versions." , |
| 265 | &opt_compatible_mode_str, &opt_compatible_mode_str, 0, |
| 266 | GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
| 267 | {"compact" , OPT_COMPACT, |
| 268 | "Give less verbose output (useful for debugging). Disables structure " |
| 269 | "comments and header/footer constructs. Enables options --skip-add-" |
| 270 | "drop-table --skip-add-locks --skip-comments --skip-disable-keys " |
| 271 | "--skip-set-charset." , |
| 272 | &opt_compact, &opt_compact, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 273 | {"complete-insert" , 'c', "Use complete insert statements." , |
| 274 | &opt_complete_insert, &opt_complete_insert, 0, GET_BOOL, |
| 275 | NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 276 | {"compress" , 'C', "Use compression in server/client protocol." , |
| 277 | &opt_compress, &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, |
| 278 | 0, 0, 0}, |
| 279 | {"create-options" , 'a', |
| 280 | "Include all MySQL specific create options." , |
| 281 | &create_options, &create_options, 0, GET_BOOL, NO_ARG, 1, |
| 282 | 0, 0, 0, 0, 0}, |
| 283 | {"databases" , 'B', |
| 284 | "Dump several databases. Note the difference in usage; in this case no tables are given. All name arguments are regarded as database names. 'USE db_name;' will be included in the output." , |
| 285 | &opt_databases, &opt_databases, 0, GET_BOOL, NO_ARG, 0, 0, |
| 286 | 0, 0, 0, 0}, |
| 287 | #ifdef DBUG_OFF |
| 288 | {"debug" , '#', "This is a non-debug version. Catch this and exit." , |
| 289 | 0,0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0}, |
| 290 | #else |
| 291 | {"debug" , '#', "Output debug log." , (char *)&default_dbug_option, |
| 292 | (char *)&default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, |
| 293 | #endif |
| 294 | {"debug-check" , OPT_DEBUG_CHECK, "Check memory and open file usage at exit." , |
| 295 | &debug_check_flag, &debug_check_flag, 0, |
| 296 | GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 297 | {"debug-info" , OPT_DEBUG_INFO, "Print some debug info at exit." , |
| 298 | &debug_info_flag, &debug_info_flag, |
| 299 | 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 300 | {"default-character-set" , OPT_DEFAULT_CHARSET, |
| 301 | "Set the default character set." , &default_charset, |
| 302 | &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
| 303 | {"delayed-insert" , OPT_DELAYED, "Insert rows with INSERT DELAYED." , |
| 304 | &opt_delayed, &opt_delayed, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, |
| 305 | 0, 0}, |
| 306 | {"delete-master-logs" , OPT_DELETE_MASTER_LOGS, |
| 307 | "Delete logs on master after backup. This automatically enables --master-data." , |
| 308 | &opt_delete_master_logs, &opt_delete_master_logs, 0, |
| 309 | GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 310 | {"disable-keys" , 'K', |
| 311 | "'/*!40000 ALTER TABLE tb_name DISABLE KEYS */; and '/*!40000 ALTER " |
| 312 | "TABLE tb_name ENABLE KEYS */; will be put in the output." , &opt_disable_keys, |
| 313 | &opt_disable_keys, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, |
| 314 | {"dump-slave" , OPT_MYSQLDUMP_SLAVE_DATA, |
| 315 | "This causes the binary log position and filename of the master to be " |
| 316 | "appended to the dumped data output. Setting the value to 1, will print" |
| 317 | "it as a CHANGE MASTER command in the dumped data output; if equal" |
| 318 | " to 2, that command will be prefixed with a comment symbol. " |
| 319 | "This option will turn --lock-all-tables on, unless " |
| 320 | "--single-transaction is specified too (in which case a " |
| 321 | "global read lock is only taken a short time at the beginning of the dump " |
| 322 | "- don't forget to read about --single-transaction below). In all cases " |
| 323 | "any action on logs will happen at the exact moment of the dump." |
| 324 | "Option automatically turns --lock-tables off." , |
| 325 | &opt_slave_data, &opt_slave_data, 0, |
| 326 | GET_UINT, OPT_ARG, 0, 0, MYSQL_OPT_SLAVE_DATA_COMMENTED_SQL, 0, 0, 0}, |
| 327 | {"events" , 'E', "Dump events." , |
| 328 | &opt_events, &opt_events, 0, GET_BOOL, |
| 329 | NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 330 | {"extended-insert" , 'e', |
| 331 | "Use multiple-row INSERT syntax that include several VALUES lists." , |
| 332 | &extended_insert, &extended_insert, 0, GET_BOOL, NO_ARG, |
| 333 | 1, 0, 0, 0, 0, 0}, |
| 334 | {"fields-terminated-by" , OPT_FTB, |
| 335 | "Fields in the output file are terminated by the given string." , |
| 336 | &fields_terminated, &fields_terminated, 0, |
| 337 | GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
| 338 | {"fields-enclosed-by" , OPT_ENC, |
| 339 | "Fields in the output file are enclosed by the given character." , |
| 340 | &enclosed, &enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0 ,0, 0}, |
| 341 | {"fields-optionally-enclosed-by" , OPT_O_ENC, |
| 342 | "Fields in the output file are optionally enclosed by the given character." , |
| 343 | &opt_enclosed, &opt_enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0 ,0, 0}, |
| 344 | {"fields-escaped-by" , OPT_ESC, |
| 345 | "Fields in the output file are escaped by the given character." , |
| 346 | &escaped, &escaped, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
| 347 | {"flush-logs" , 'F', "Flush logs file in server before starting dump. " |
| 348 | "Note that if you dump many databases at once (using the option " |
| 349 | "--databases= or --all-databases), the logs will be flushed for " |
| 350 | "each database dumped. The exception is when using --lock-all-tables " |
| 351 | "or --master-data: " |
| 352 | "in this case the logs will be flushed only once, corresponding " |
| 353 | "to the moment all tables are locked. So if you want your dump and " |
| 354 | "the log flush to happen at the same exact moment you should use " |
| 355 | "--lock-all-tables or --master-data with --flush-logs." , |
| 356 | &flush_logs, &flush_logs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, |
| 357 | 0, 0}, |
| 358 | {"flush-privileges" , OPT_ESC, "Emit a FLUSH PRIVILEGES statement " |
| 359 | "after dumping the mysql database. This option should be used any " |
| 360 | "time the dump contains the mysql database and any other database " |
| 361 | "that depends on the data in the mysql database for proper restore. " , |
| 362 | &flush_privileges, &flush_privileges, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, |
| 363 | 0, 0}, |
| 364 | {"force" , 'f', "Continue even if we get an SQL error." , |
| 365 | &ignore_errors, &ignore_errors, 0, GET_BOOL, NO_ARG, |
| 366 | 0, 0, 0, 0, 0, 0}, |
| 367 | {"gtid" , 0, "Used together with --master-data=1 or --dump-slave=1." |
| 368 | "When enabled, the output from those options will set the GTID position " |
| 369 | "instead of the binlog file and offset; the file/offset will appear only as " |
| 370 | "a comment. When disabled, the GTID position will still appear in the " |
| 371 | "output, but only commented." , |
| 372 | &opt_use_gtid, &opt_use_gtid, 0, GET_BOOL, NO_ARG, |
| 373 | 0, 0, 0, 0, 0, 0}, |
| 374 | {"help" , '?', "Display this help message and exit." , 0, 0, 0, GET_NO_ARG, |
| 375 | NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 376 | {"hex-blob" , OPT_HEXBLOB, "Dump binary strings (BINARY, " |
| 377 | "VARBINARY, BLOB) in hexadecimal format." , |
| 378 | &opt_hex_blob, &opt_hex_blob, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 379 | {"host" , 'h', "Connect to host." , ¤t_host, |
| 380 | ¤t_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
| 381 | {"ignore-database" , OPT_IGNORE_DATABASE, |
| 382 | "Do not dump the specified database. To specify more than one database to ignore, " |
| 383 | "use the directive multiple times, once for each database. Only takes effect " |
| 384 | "when used together with --all-databases|-A" , |
| 385 | 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
| 386 | {"ignore-table" , OPT_IGNORE_TABLE, |
| 387 | "Do not dump the specified table. To specify more than one table to ignore, " |
| 388 | "use the directive multiple times, once for each table. Each table must " |
| 389 | "be specified with both database and table names, e.g., " |
| 390 | "--ignore-table=database.table." , |
| 391 | 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
| 392 | {"include-master-host-port" , OPT_MYSQLDUMP_INCLUDE_MASTER_HOST_PORT, |
| 393 | "Adds 'MASTER_HOST=<host>, MASTER_PORT=<port>' to 'CHANGE MASTER TO..' " |
| 394 | "in dump produced with --dump-slave." , &opt_include_master_host_port, |
| 395 | &opt_include_master_host_port, 0, GET_BOOL, NO_ARG, |
| 396 | 0, 0, 0, 0, 0, 0}, |
| 397 | {"insert-ignore" , OPT_INSERT_IGNORE, "Insert rows with INSERT IGNORE." , |
| 398 | &opt_ignore, &opt_ignore, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, |
| 399 | 0, 0}, |
| 400 | {"lines-terminated-by" , OPT_LTB, |
| 401 | "Lines in the output file are terminated by the given string." , |
| 402 | &lines_terminated, &lines_terminated, 0, GET_STR, |
| 403 | REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
| 404 | {"lock-all-tables" , 'x', "Locks all tables across all databases. This " |
| 405 | "is achieved by taking a global read lock for the duration of the whole " |
| 406 | "dump. Automatically turns --single-transaction and --lock-tables off." , |
| 407 | &opt_lock_all_tables, &opt_lock_all_tables, 0, GET_BOOL, NO_ARG, |
| 408 | 0, 0, 0, 0, 0, 0}, |
| 409 | {"lock-tables" , 'l', "Lock all tables for read." , &lock_tables, |
| 410 | &lock_tables, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, |
| 411 | {"log-error" , OPT_ERROR_LOG_FILE, "Append warnings and errors to given file." , |
| 412 | &log_error_file, &log_error_file, 0, GET_STR, |
| 413 | REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
| 414 | {"log-queries" , 0, "When restoring the dump, the server will, if logging turned on, log the queries to the general and slow query log." , |
| 415 | &opt_logging, &opt_logging, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, |
| 416 | {"master-data" , OPT_MASTER_DATA, |
| 417 | "This causes the binary log position and filename to be appended to the " |
| 418 | "output. If equal to 1, will print it as a CHANGE MASTER command; if equal" |
| 419 | " to 2, that command will be prefixed with a comment symbol. " |
| 420 | "This option will turn --lock-all-tables on, unless --single-transaction " |
| 421 | "is specified too (on servers before MariaDB 5.3 this will still take a " |
| 422 | "global read lock for a short time at the beginning of the dump; " |
| 423 | "don't forget to read about --single-transaction below). In all cases, " |
| 424 | "any action on logs will happen at the exact moment of the dump. " |
| 425 | "Option automatically turns --lock-tables off." , |
| 426 | &opt_master_data, &opt_master_data, 0, |
| 427 | GET_UINT, OPT_ARG, 0, 0, MYSQL_OPT_MASTER_DATA_COMMENTED_SQL, 0, 0, 0}, |
| 428 | {"max_allowed_packet" , OPT_MAX_ALLOWED_PACKET, |
| 429 | "The maximum packet length to send to or receive from server." , |
| 430 | &opt_max_allowed_packet, &opt_max_allowed_packet, 0, |
| 431 | GET_ULONG, REQUIRED_ARG, 24*1024*1024, 4096, |
| 432 | (longlong) 2L*1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0}, |
| 433 | {"net_buffer_length" , OPT_NET_BUFFER_LENGTH, |
| 434 | "The buffer size for TCP/IP and socket communication." , |
| 435 | &opt_net_buffer_length, &opt_net_buffer_length, 0, |
| 436 | GET_ULONG, REQUIRED_ARG, 1024*1024L-1025, 4096, 16*1024L*1024L, |
| 437 | MALLOC_OVERHEAD-1024, 1024, 0}, |
| 438 | {"no-autocommit" , OPT_AUTOCOMMIT, |
| 439 | "Wrap tables with autocommit/commit statements." , |
| 440 | &opt_autocommit, &opt_autocommit, 0, GET_BOOL, NO_ARG, |
| 441 | 0, 0, 0, 0, 0, 0}, |
| 442 | {"no-create-db" , 'n', |
| 443 | "Suppress the CREATE DATABASE ... IF EXISTS statement that normally is " |
| 444 | "output for each dumped database if --all-databases or --databases is " |
| 445 | "given." , |
| 446 | &opt_create_db, &opt_create_db, 0, |
| 447 | GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 448 | {"no-create-info" , 't', "Don't write table creation info." , |
| 449 | &opt_no_create_info, &opt_no_create_info, 0, GET_BOOL, |
| 450 | NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 451 | {"no-data" , 'd', "No row information." , &opt_no_data, |
| 452 | &opt_no_data, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 453 | {"no-data-med" , 0, "No row information for engines that " |
| 454 | "Manage External Data (" MED_ENGINES ")." , &opt_no_data_med, |
| 455 | &opt_no_data_med, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, |
| 456 | {"no-set-names" , 'N', "Same as --skip-set-charset." , |
| 457 | 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 458 | {"opt" , OPT_OPTIMIZE, |
| 459 | "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." , |
| 460 | 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 461 | {"order-by-primary" , OPT_ORDER_BY_PRIMARY, |
| 462 | "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." , |
| 463 | &opt_order_by_primary, &opt_order_by_primary, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 464 | {"password" , 'p', |
| 465 | "Password to use when connecting to server. If password is not given it's solicited on the tty." , |
| 466 | 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, |
| 467 | #ifdef __WIN__ |
| 468 | {"pipe" , 'W', "Use named pipes to connect to server." , 0, 0, 0, GET_NO_ARG, |
| 469 | NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 470 | #endif |
| 471 | {"port" , 'P', "Port number to use for connection." , &opt_mysql_port, |
| 472 | &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, |
| 473 | 0}, |
| 474 | {"protocol" , OPT_MYSQL_PROTOCOL, |
| 475 | "The protocol to use for connection (tcp, socket, pipe, memory)." , |
| 476 | 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
| 477 | {"quick" , 'q', "Don't buffer query, dump directly to stdout." , |
| 478 | &quick, &quick, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, |
| 479 | {"quote-names" ,'Q', "Quote table and column names with backticks (`)." , |
| 480 | &opt_quoted, &opt_quoted, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, |
| 481 | 0, 0}, |
| 482 | {"replace" , OPT_MYSQL_REPLACE_INTO, "Use REPLACE INTO instead of INSERT INTO." , |
| 483 | &opt_replace_into, &opt_replace_into, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, |
| 484 | 0, 0}, |
| 485 | {"result-file" , 'r', |
| 486 | "Direct output to a given file. This option should be used in systems " |
| 487 | "(e.g., DOS, Windows) that use carriage-return linefeed pairs (\\r\\n) " |
| 488 | "to separate text lines. This option ensures that only a single newline " |
| 489 | "is used." , 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
| 490 | {"routines" , 'R', "Dump stored routines (functions and procedures)." , |
| 491 | &opt_routines, &opt_routines, 0, GET_BOOL, |
| 492 | NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 493 | {"set-charset" , OPT_SET_CHARSET, |
| 494 | "Add 'SET NAMES default_character_set' to the output." , |
| 495 | &opt_set_charset, &opt_set_charset, 0, GET_BOOL, NO_ARG, 1, |
| 496 | 0, 0, 0, 0, 0}, |
| 497 | #ifdef HAVE_SMEM |
| 498 | {"shared-memory-base-name" , OPT_SHARED_MEMORY_BASE_NAME, |
| 499 | "Base name of shared memory." , &shared_memory_base_name, &shared_memory_base_name, |
| 500 | 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
| 501 | #endif |
| 502 | /* |
| 503 | Note that the combination --single-transaction --master-data |
| 504 | will give bullet-proof binlog position only if server >=4.1.3. That's the |
| 505 | old "FLUSH TABLES WITH READ LOCK does not block commit" fixed bug. |
| 506 | */ |
| 507 | {"single-transaction" , OPT_TRANSACTION, |
| 508 | "Creates a consistent snapshot by dumping all tables in a single " |
| 509 | "transaction. Works ONLY for tables stored in storage engines which " |
| 510 | "support multiversioning (currently only InnoDB does); the dump is NOT " |
| 511 | "guaranteed to be consistent for other storage engines. " |
| 512 | "While a --single-transaction dump is in process, to ensure a valid " |
| 513 | "dump file (correct table contents and binary log position), no other " |
| 514 | "connection should use the following statements: ALTER TABLE, DROP " |
| 515 | "TABLE, RENAME TABLE, TRUNCATE TABLE, as consistent snapshot is not " |
| 516 | "isolated from them. Option automatically turns off --lock-tables." , |
| 517 | &opt_single_transaction, &opt_single_transaction, 0, |
| 518 | GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 519 | {"dump-date" , OPT_DUMP_DATE, "Put a dump date to the end of the output." , |
| 520 | &opt_dump_date, &opt_dump_date, 0, |
| 521 | GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, |
| 522 | {"skip-opt" , OPT_SKIP_OPTIMIZATION, |
| 523 | "Disable --opt. Disables --add-drop-table, --add-locks, --create-options, --quick, --extended-insert, --lock-tables, --set-charset, and --disable-keys." , |
| 524 | 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 525 | {"socket" , 'S', "The socket file to use for connection." , |
| 526 | &opt_mysql_unix_port, &opt_mysql_unix_port, 0, |
| 527 | GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
| 528 | #include <sslopt-longopts.h> |
| 529 | {"tab" ,'T', |
| 530 | "Create tab-separated textfile for each table to given path. (Create .sql " |
| 531 | "and .txt files.) NOTE: This only works if mysqldump is run on the same " |
| 532 | "machine as the mysqld server." , |
| 533 | &path, &path, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
| 534 | {"tables" , OPT_TABLES, "Overrides option --databases (-B)." , |
| 535 | 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 536 | {"triggers" , OPT_TRIGGERS, "Dump triggers for each dumped table." , |
| 537 | &opt_dump_triggers, &opt_dump_triggers, 0, GET_BOOL, |
| 538 | NO_ARG, 1, 0, 0, 0, 0, 0}, |
| 539 | {"tz-utc" , OPT_TZ_UTC, |
| 540 | "SET TIME_ZONE='+00:00' at top of dump to allow dumping of TIMESTAMP data when a server has data in different time zones or data is being moved between servers with different time zones." , |
| 541 | &opt_tz_utc, &opt_tz_utc, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, |
| 542 | #ifndef DONT_ALLOW_USER_CHANGE |
| 543 | {"user" , 'u', "User for login if not current user." , |
| 544 | ¤t_user, ¤t_user, 0, GET_STR, REQUIRED_ARG, |
| 545 | 0, 0, 0, 0, 0, 0}, |
| 546 | #endif |
| 547 | {"verbose" , 'v', "Print info about the various stages." , |
| 548 | &verbose, &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 549 | {"version" ,'V', "Output version information and exit." , 0, 0, 0, |
| 550 | GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 551 | {"where" , 'w', "Dump only selected records. Quotes are mandatory." , |
| 552 | &where, &where, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
| 553 | {"xml" , 'X', "Dump a database as well formed XML." , 0, 0, 0, GET_NO_ARG, |
| 554 | NO_ARG, 0, 0, 0, 0, 0, 0}, |
| 555 | {"plugin_dir" , OPT_PLUGIN_DIR, "Directory for client-side plugins." , |
| 556 | &opt_plugin_dir, &opt_plugin_dir, 0, |
| 557 | GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
| 558 | {"default_auth" , OPT_DEFAULT_AUTH, |
| 559 | "Default authentication client-side plugin to use." , |
| 560 | &opt_default_auth, &opt_default_auth, 0, |
| 561 | GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
| 562 | {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} |
| 563 | }; |
| 564 | |
| 565 | static const char *load_default_groups[]= |
| 566 | { "mysqldump" , "client" , "client-server" , "client-mariadb" , 0 }; |
| 567 | |
| 568 | static void maybe_exit(int error); |
| 569 | static void die(int error, const char* reason, ...); |
| 570 | static void maybe_die(int error, const char* reason, ...); |
| 571 | static void write_header(FILE *sql_file, char *db_name); |
| 572 | static void print_value(FILE *file, MYSQL_RES *result, MYSQL_ROW row, |
| 573 | const char *prefix,const char *name, |
| 574 | int string_value); |
| 575 | static int dump_selected_tables(char *db, char **table_names, int tables); |
| 576 | static int dump_all_tables_in_db(char *db); |
| 577 | static int init_dumping_views(char *); |
| 578 | static int init_dumping_tables(char *); |
| 579 | static int init_dumping(char *, int init_func(char*)); |
| 580 | static int dump_databases(char **); |
| 581 | static int dump_all_databases(); |
| 582 | static char *quote_name(const char *name, char *buff, my_bool force); |
| 583 | char check_if_ignore_table(const char *table_name, char *table_type); |
| 584 | static char *primary_key_fields(const char *table_name); |
| 585 | static my_bool get_view_structure(char *table, char* db); |
| 586 | static my_bool dump_all_views_in_db(char *database); |
| 587 | static int dump_all_tablespaces(); |
| 588 | static int dump_tablespaces_for_tables(char *db, char **table_names, int tables); |
| 589 | static int dump_tablespaces_for_databases(char** databases); |
| 590 | static int dump_tablespaces(char* ts_where); |
| 591 | static void print_comment(FILE *, my_bool, const char *, ...); |
| 592 | |
| 593 | /* |
| 594 | Print the supplied message if in verbose mode |
| 595 | |
| 596 | SYNOPSIS |
| 597 | verbose_msg() |
| 598 | fmt format specifier |
| 599 | ... variable number of parameters |
| 600 | */ |
| 601 | |
| 602 | static void verbose_msg(const char *fmt, ...) |
| 603 | { |
| 604 | va_list args; |
| 605 | DBUG_ENTER("verbose_msg" ); |
| 606 | |
| 607 | if (!verbose) |
| 608 | DBUG_VOID_RETURN; |
| 609 | |
| 610 | va_start(args, fmt); |
| 611 | vfprintf(stderr, fmt, args); |
| 612 | va_end(args); |
| 613 | |
| 614 | fflush(stderr); |
| 615 | |
| 616 | DBUG_VOID_RETURN; |
| 617 | } |
| 618 | |
| 619 | /* |
| 620 | exit with message if ferror(file) |
| 621 | |
| 622 | SYNOPSIS |
| 623 | check_io() |
| 624 | file - checked file |
| 625 | */ |
| 626 | |
| 627 | void check_io(FILE *file) |
| 628 | { |
| 629 | if (ferror(file)) |
| 630 | die(EX_EOF, "Got errno %d on write" , errno); |
| 631 | } |
| 632 | |
| 633 | static void print_version(void) |
| 634 | { |
| 635 | printf("%s Ver %s Distrib %s, for %s (%s)\n" ,my_progname_short,DUMP_VERSION, |
| 636 | MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE); |
| 637 | } /* print_version */ |
| 638 | |
| 639 | |
| 640 | static void short_usage_sub(FILE *f) |
| 641 | { |
| 642 | fprintf(f, "Usage: %s [OPTIONS] database [tables]\n" , my_progname_short); |
| 643 | fprintf(f, "OR %s [OPTIONS] --databases [OPTIONS] DB1 [DB2 DB3...]\n" , |
| 644 | my_progname_short); |
| 645 | fprintf(f, "OR %s [OPTIONS] --all-databases [OPTIONS]\n" , my_progname_short); |
| 646 | } |
| 647 | |
| 648 | |
| 649 | static void usage(void) |
| 650 | { |
| 651 | print_version(); |
| 652 | puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000" )); |
| 653 | puts("Dumping structure and contents of MySQL databases and tables." ); |
| 654 | short_usage_sub(stdout); |
| 655 | print_defaults("my" ,load_default_groups); |
| 656 | puts("" ); |
| 657 | my_print_help(my_long_options); |
| 658 | my_print_variables(my_long_options); |
| 659 | } /* usage */ |
| 660 | |
| 661 | |
| 662 | static void short_usage(FILE *f) |
| 663 | { |
| 664 | short_usage_sub(f); |
| 665 | fprintf(f, "For more options, use %s --help\n" , my_progname_short); |
| 666 | } |
| 667 | |
| 668 | |
| 669 | /** returns a string fixed to be safely printed inside a -- comment |
| 670 | |
| 671 | that is, any new line in it gets prefixed with -- |
| 672 | */ |
| 673 | static const char *(const char *ident) |
| 674 | { |
| 675 | static char buf[1024]; |
| 676 | char c, *s= buf; |
| 677 | |
| 678 | while ((c= *s++= *ident++)) |
| 679 | { |
| 680 | if (s >= buf + sizeof(buf) - 10) |
| 681 | { |
| 682 | strmov(s, "..." ); |
| 683 | break; |
| 684 | } |
| 685 | if (c == '\n') |
| 686 | s= strmov(s, "-- " ); |
| 687 | } |
| 688 | |
| 689 | return buf; |
| 690 | } |
| 691 | |
| 692 | |
| 693 | static void (FILE *sql_file, char *db_name) |
| 694 | { |
| 695 | if (opt_xml) |
| 696 | { |
| 697 | fputs("<?xml version=\"1.0\"?>\n" , sql_file); |
| 698 | /* |
| 699 | Schema reference. Allows use of xsi:nil for NULL values and |
| 700 | xsi:type to define an element's data type. |
| 701 | */ |
| 702 | fputs("<mysqldump " , sql_file); |
| 703 | fputs("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" , |
| 704 | sql_file); |
| 705 | fputs(">\n" , sql_file); |
| 706 | check_io(sql_file); |
| 707 | } |
| 708 | else if (!opt_compact) |
| 709 | { |
| 710 | print_comment(sql_file, 0, |
| 711 | "-- MySQL dump %s Distrib %s, for %s (%s)\n--\n" , |
| 712 | DUMP_VERSION, MYSQL_SERVER_VERSION, SYSTEM_TYPE, |
| 713 | MACHINE_TYPE); |
| 714 | print_comment(sql_file, 0, "-- Host: %s " , |
| 715 | fix_for_comment(current_host ? current_host : "localhost" )); |
| 716 | print_comment(sql_file, 0, "Database: %s\n" , |
| 717 | fix_for_comment(db_name ? db_name : "" )); |
| 718 | print_comment(sql_file, 0, |
| 719 | "-- ------------------------------------------------------\n" |
| 720 | ); |
| 721 | print_comment(sql_file, 0, "-- Server version\t%s\n" , |
| 722 | mysql_get_server_info(&mysql_connection)); |
| 723 | |
| 724 | if (!opt_logging) |
| 725 | fprintf(sql_file, |
| 726 | "\n/*M!100101 SET LOCAL SQL_LOG_OFF=0, LOCAL SLOW_QUERY_LOG=0 */;" ); |
| 727 | |
| 728 | if (opt_set_charset) |
| 729 | fprintf(sql_file, |
| 730 | "\n/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;" |
| 731 | "\n/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;" |
| 732 | "\n/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;" |
| 733 | "\n/*!40101 SET NAMES %s */;\n" ,default_charset); |
| 734 | |
| 735 | if (opt_tz_utc) |
| 736 | { |
| 737 | fprintf(sql_file, "/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;\n" ); |
| 738 | fprintf(sql_file, "/*!40103 SET TIME_ZONE='+00:00' */;\n" ); |
| 739 | } |
| 740 | |
| 741 | if (!path) |
| 742 | { |
| 743 | if (!opt_no_create_info) |
| 744 | { |
| 745 | /* We don't need unique checks as the table is created just before */ |
| 746 | fprintf(md_result_file,"\ |
| 747 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;\n" ); |
| 748 | } |
| 749 | fprintf(md_result_file,"\ |
| 750 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;\n\ |
| 751 | " ); |
| 752 | } |
| 753 | fprintf(sql_file, |
| 754 | "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='%s%s%s' */;\n" |
| 755 | "/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;\n" , |
| 756 | path?"" :"NO_AUTO_VALUE_ON_ZERO" ,compatible_mode_normal_str[0]==0?"" :"," , |
| 757 | compatible_mode_normal_str); |
| 758 | check_io(sql_file); |
| 759 | } |
| 760 | } /* write_header */ |
| 761 | |
| 762 | |
| 763 | static void (FILE *sql_file) |
| 764 | { |
| 765 | if (opt_xml) |
| 766 | { |
| 767 | fputs("</mysqldump>\n" , sql_file); |
| 768 | check_io(sql_file); |
| 769 | } |
| 770 | else if (!opt_compact) |
| 771 | { |
| 772 | if (opt_tz_utc) |
| 773 | fprintf(sql_file,"/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;\n" ); |
| 774 | |
| 775 | fprintf(sql_file,"\n/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;\n" ); |
| 776 | if (!path) |
| 777 | { |
| 778 | fprintf(md_result_file,"\ |
| 779 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;\n" ); |
| 780 | if (!opt_no_create_info) |
| 781 | { |
| 782 | fprintf(md_result_file,"\ |
| 783 | /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;\n" ); |
| 784 | } |
| 785 | } |
| 786 | if (opt_set_charset) |
| 787 | fprintf(sql_file, |
| 788 | "/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;\n" |
| 789 | "/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;\n" |
| 790 | "/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;\n" ); |
| 791 | fprintf(sql_file, |
| 792 | "/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;\n" ); |
| 793 | fputs("\n" , sql_file); |
| 794 | |
| 795 | if (opt_dump_date) |
| 796 | { |
| 797 | char time_str[20]; |
| 798 | get_date(time_str, GETDATE_DATE_TIME, 0); |
| 799 | print_comment(sql_file, 0, "-- Dump completed on %s\n" , time_str); |
| 800 | } |
| 801 | else |
| 802 | print_comment(sql_file, 0, "-- Dump completed\n" ); |
| 803 | |
| 804 | check_io(sql_file); |
| 805 | } |
| 806 | } /* write_footer */ |
| 807 | |
| 808 | |
| 809 | uchar* get_table_key(const char *entry, size_t *length, |
| 810 | my_bool not_used __attribute__((unused))) |
| 811 | { |
| 812 | *length= strlen(entry); |
| 813 | return (uchar*) entry; |
| 814 | } |
| 815 | |
| 816 | |
| 817 | static my_bool |
| 818 | get_one_option(int optid, const struct my_option *opt __attribute__((unused)), |
| 819 | char *argument) |
| 820 | { |
| 821 | switch (optid) { |
| 822 | case 'p': |
| 823 | if (argument == disabled_my_option) |
| 824 | argument= (char*) "" ; /* Don't require password */ |
| 825 | if (argument) |
| 826 | { |
| 827 | char *start=argument; |
| 828 | my_free(opt_password); |
| 829 | opt_password=my_strdup(argument,MYF(MY_FAE)); |
| 830 | while (*argument) *argument++= 'x'; /* Destroy argument */ |
| 831 | if (*start) |
| 832 | start[1]=0; /* Cut length of argument */ |
| 833 | tty_password= 0; |
| 834 | } |
| 835 | else |
| 836 | tty_password=1; |
| 837 | break; |
| 838 | case 'r': |
| 839 | if (!(md_result_file= my_fopen(argument, O_WRONLY | FILE_BINARY, |
| 840 | MYF(MY_WME)))) |
| 841 | exit(1); |
| 842 | break; |
| 843 | case 'W': |
| 844 | #ifdef __WIN__ |
| 845 | opt_protocol= MYSQL_PROTOCOL_PIPE; |
| 846 | #endif |
| 847 | break; |
| 848 | case 'N': |
| 849 | opt_set_charset= 0; |
| 850 | break; |
| 851 | case 'T': |
| 852 | opt_disable_keys=0; |
| 853 | |
| 854 | if (strlen(argument) >= FN_REFLEN) |
| 855 | { |
| 856 | /* |
| 857 | This check is made because the some the file functions below |
| 858 | have FN_REFLEN sized stack allocated buffers and will cause |
| 859 | a crash even if the input destination buffer is large enough |
| 860 | to hold the output. |
| 861 | */ |
| 862 | die(EX_USAGE, "Input filename too long: %s" , argument); |
| 863 | } |
| 864 | |
| 865 | break; |
| 866 | case '#': |
| 867 | DBUG_PUSH(argument ? argument : default_dbug_option); |
| 868 | debug_check_flag= 1; |
| 869 | break; |
| 870 | #include <sslopt-case.h> |
| 871 | case 'V': print_version(); exit(0); |
| 872 | case 'X': |
| 873 | opt_xml= 1; |
| 874 | extended_insert= opt_drop= opt_lock= |
| 875 | opt_disable_keys= opt_autocommit= opt_create_db= 0; |
| 876 | break; |
| 877 | case 'i': |
| 878 | opt_comments_used= 1; |
| 879 | break; |
| 880 | case 'I': |
| 881 | case '?': |
| 882 | usage(); |
| 883 | exit(0); |
| 884 | case (int) OPT_MASTER_DATA: |
| 885 | if (!argument) /* work like in old versions */ |
| 886 | opt_master_data= MYSQL_OPT_MASTER_DATA_EFFECTIVE_SQL; |
| 887 | break; |
| 888 | case (int) OPT_MYSQLDUMP_SLAVE_DATA: |
| 889 | if (!argument) /* work like in old versions */ |
| 890 | opt_slave_data= MYSQL_OPT_SLAVE_DATA_EFFECTIVE_SQL; |
| 891 | break; |
| 892 | case (int) OPT_OPTIMIZE: |
| 893 | extended_insert= opt_drop= opt_lock= quick= create_options= |
| 894 | opt_disable_keys= lock_tables= opt_set_charset= 1; |
| 895 | break; |
| 896 | case (int) OPT_SKIP_OPTIMIZATION: |
| 897 | extended_insert= opt_drop= opt_lock= quick= create_options= |
| 898 | opt_disable_keys= lock_tables= opt_set_charset= 0; |
| 899 | break; |
| 900 | case (int) OPT_COMPACT: |
| 901 | if (opt_compact) |
| 902 | { |
| 903 | opt_comments= opt_drop= opt_disable_keys= opt_lock= 0; |
| 904 | opt_set_charset= 0; |
| 905 | } |
| 906 | break; |
| 907 | case (int) OPT_TABLES: |
| 908 | opt_databases=0; |
| 909 | break; |
| 910 | case (int) OPT_IGNORE_DATABASE: |
| 911 | if (my_hash_insert(&ignore_database, (uchar*) my_strdup(argument, MYF(0)))) |
| 912 | exit(EX_EOM); |
| 913 | break; |
| 914 | case (int) OPT_IGNORE_TABLE: |
| 915 | { |
| 916 | if (!strchr(argument, '.')) |
| 917 | { |
| 918 | fprintf(stderr, "Illegal use of option --ignore-table=<database>.<table>\n" ); |
| 919 | exit(1); |
| 920 | } |
| 921 | if (my_hash_insert(&ignore_table, (uchar*)my_strdup(argument, MYF(0)))) |
| 922 | exit(EX_EOM); |
| 923 | break; |
| 924 | } |
| 925 | case (int) OPT_COMPATIBLE: |
| 926 | { |
| 927 | char buff[255]; |
| 928 | char *end= compatible_mode_normal_str; |
| 929 | int i; |
| 930 | ulong mode; |
| 931 | uint err_len; |
| 932 | |
| 933 | opt_quoted= 1; |
| 934 | opt_set_charset= 0; |
| 935 | opt_compatible_mode_str= argument; |
| 936 | opt_compatible_mode= find_set(&compatible_mode_typelib, |
| 937 | argument, strlen(argument), |
| 938 | &err_ptr, &err_len); |
| 939 | if (err_len) |
| 940 | { |
| 941 | strmake(buff, err_ptr, MY_MIN(sizeof(buff) - 1, err_len)); |
| 942 | fprintf(stderr, "Invalid mode to --compatible: %s\n" , buff); |
| 943 | exit(1); |
| 944 | } |
| 945 | #if !defined(DBUG_OFF) |
| 946 | { |
| 947 | size_t size_for_sql_mode= 0; |
| 948 | const char **ptr; |
| 949 | for (ptr= compatible_mode_names; *ptr; ptr++) |
| 950 | size_for_sql_mode+= strlen(*ptr); |
| 951 | size_for_sql_mode+= sizeof(compatible_mode_names)-1; |
| 952 | DBUG_ASSERT(sizeof(compatible_mode_normal_str)>=size_for_sql_mode); |
| 953 | } |
| 954 | #endif |
| 955 | mode= opt_compatible_mode; |
| 956 | for (i= 0, mode= opt_compatible_mode; mode; mode>>= 1, i++) |
| 957 | { |
| 958 | if (mode & 1) |
| 959 | { |
| 960 | end= strmov(end, compatible_mode_names[i]); |
| 961 | end= strmov(end, "," ); |
| 962 | } |
| 963 | } |
| 964 | if (end!=compatible_mode_normal_str) |
| 965 | end[-1]= 0; |
| 966 | /* |
| 967 | Set charset to the default compiled value if it hasn't |
| 968 | been reset yet by --default-character-set=xxx. |
| 969 | */ |
| 970 | if (default_charset == mysql_universal_client_charset) |
| 971 | default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME; |
| 972 | break; |
| 973 | } |
| 974 | case (int) OPT_MYSQL_PROTOCOL: |
| 975 | if ((opt_protocol= find_type_with_warning(argument, &sql_protocol_typelib, |
| 976 | opt->name)) <= 0) |
| 977 | { |
| 978 | sf_leaking_memory= 1; /* no memory leak reports here */ |
| 979 | exit(1); |
| 980 | } |
| 981 | break; |
| 982 | } |
| 983 | return 0; |
| 984 | } |
| 985 | |
| 986 | static int get_options(int *argc, char ***argv) |
| 987 | { |
| 988 | int ho_error; |
| 989 | MYSQL_PARAMETERS *mysql_params= mysql_get_parameters(); |
| 990 | |
| 991 | opt_max_allowed_packet= *mysql_params->p_max_allowed_packet; |
| 992 | opt_net_buffer_length= *mysql_params->p_net_buffer_length; |
| 993 | |
| 994 | md_result_file= stdout; |
| 995 | load_defaults_or_exit("my" , load_default_groups, argc, argv); |
| 996 | defaults_argv= *argv; |
| 997 | |
| 998 | if (my_hash_init(&ignore_database, charset_info, 16, 0, 0, |
| 999 | (my_hash_get_key) get_table_key, my_free, 0)) |
| 1000 | return(EX_EOM); |
| 1001 | if (my_hash_init(&ignore_table, charset_info, 16, 0, 0, |
| 1002 | (my_hash_get_key) get_table_key, my_free, 0)) |
| 1003 | return(EX_EOM); |
| 1004 | /* Don't copy internal log tables */ |
| 1005 | if (my_hash_insert(&ignore_table, |
| 1006 | (uchar*) my_strdup("mysql.apply_status" , MYF(MY_WME))) || |
| 1007 | my_hash_insert(&ignore_table, |
| 1008 | (uchar*) my_strdup("mysql.schema" , MYF(MY_WME))) || |
| 1009 | my_hash_insert(&ignore_table, |
| 1010 | (uchar*) my_strdup("mysql.general_log" , MYF(MY_WME))) || |
| 1011 | my_hash_insert(&ignore_table, |
| 1012 | (uchar*) my_strdup("mysql.slow_log" , MYF(MY_WME))) || |
| 1013 | my_hash_insert(&ignore_table, |
| 1014 | (uchar*) my_strdup("mysql.transaction_registry" , MYF(MY_WME)))) |
| 1015 | return(EX_EOM); |
| 1016 | |
| 1017 | if ((ho_error= handle_options(argc, argv, my_long_options, get_one_option))) |
| 1018 | return(ho_error); |
| 1019 | |
| 1020 | *mysql_params->p_max_allowed_packet= opt_max_allowed_packet; |
| 1021 | *mysql_params->p_net_buffer_length= opt_net_buffer_length; |
| 1022 | if (debug_info_flag) |
| 1023 | my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO; |
| 1024 | if (debug_check_flag) |
| 1025 | my_end_arg= MY_CHECK_ERROR; |
| 1026 | |
| 1027 | if (opt_delayed) |
| 1028 | opt_lock=0; /* Can't have lock with delayed */ |
| 1029 | if (!path && (enclosed || opt_enclosed || escaped || lines_terminated || |
| 1030 | fields_terminated)) |
| 1031 | { |
| 1032 | fprintf(stderr, |
| 1033 | "%s: You must use option --tab with --fields-...\n" , my_progname_short); |
| 1034 | return(EX_USAGE); |
| 1035 | } |
| 1036 | |
| 1037 | /* We don't delete master logs if slave data option */ |
| 1038 | if (opt_slave_data) |
| 1039 | { |
| 1040 | opt_lock_all_tables= !opt_single_transaction; |
| 1041 | opt_master_data= 0; |
| 1042 | opt_delete_master_logs= 0; |
| 1043 | } |
| 1044 | |
| 1045 | /* Ensure consistency of the set of binlog & locking options */ |
| 1046 | if (opt_delete_master_logs && !opt_master_data) |
| 1047 | opt_master_data= MYSQL_OPT_MASTER_DATA_COMMENTED_SQL; |
| 1048 | if (opt_single_transaction && opt_lock_all_tables) |
| 1049 | { |
| 1050 | fprintf(stderr, "%s: You can't use --single-transaction and " |
| 1051 | "--lock-all-tables at the same time.\n" , my_progname_short); |
| 1052 | return(EX_USAGE); |
| 1053 | } |
| 1054 | if (opt_master_data) |
| 1055 | { |
| 1056 | opt_lock_all_tables= !opt_single_transaction; |
| 1057 | opt_slave_data= 0; |
| 1058 | } |
| 1059 | if (opt_single_transaction || opt_lock_all_tables) |
| 1060 | lock_tables= 0; |
| 1061 | if (enclosed && opt_enclosed) |
| 1062 | { |
| 1063 | fprintf(stderr, "%s: You can't use ..enclosed.. and ..optionally-enclosed.. at the same time.\n" , my_progname_short); |
| 1064 | return(EX_USAGE); |
| 1065 | } |
| 1066 | if ((opt_databases || opt_alldbs) && path) |
| 1067 | { |
| 1068 | fprintf(stderr, |
| 1069 | "%s: --databases or --all-databases can't be used with --tab.\n" , |
| 1070 | my_progname_short); |
| 1071 | return(EX_USAGE); |
| 1072 | } |
| 1073 | if (ignore_database.records && !opt_alldbs) |
| 1074 | { |
| 1075 | fprintf(stderr, |
| 1076 | "%s: --ignore-database can only be used together with --all-databases.\n" , |
| 1077 | my_progname_short); |
| 1078 | return(EX_USAGE); |
| 1079 | } |
| 1080 | if (strcmp(default_charset, charset_info->csname) && |
| 1081 | !(charset_info= get_charset_by_csname(default_charset, |
| 1082 | MY_CS_PRIMARY, MYF(MY_WME)))) |
| 1083 | exit(1); |
| 1084 | if ((*argc < 1 && !opt_alldbs) || (*argc > 0 && opt_alldbs)) |
| 1085 | { |
| 1086 | short_usage(stderr); |
| 1087 | return EX_USAGE; |
| 1088 | } |
| 1089 | if (tty_password) |
| 1090 | opt_password=get_tty_password(NullS); |
| 1091 | return(0); |
| 1092 | } /* get_options */ |
| 1093 | |
| 1094 | |
| 1095 | /* |
| 1096 | ** DB_error -- prints mysql error message and exits the program. |
| 1097 | */ |
| 1098 | static void DB_error(MYSQL *mysql_arg, const char *when) |
| 1099 | { |
| 1100 | DBUG_ENTER("DB_error" ); |
| 1101 | maybe_die(EX_MYSQLERR, "Got error: %d: \"%s\" %s" , |
| 1102 | mysql_errno(mysql_arg), mysql_error(mysql_arg), when); |
| 1103 | DBUG_VOID_RETURN; |
| 1104 | } |
| 1105 | |
| 1106 | |
| 1107 | |
| 1108 | /* |
| 1109 | Prints out an error message and kills the process. |
| 1110 | |
| 1111 | SYNOPSIS |
| 1112 | die() |
| 1113 | error_num - process return value |
| 1114 | fmt_reason - a format string for use by my_vsnprintf. |
| 1115 | ... - variable arguments for above fmt_reason string |
| 1116 | |
| 1117 | DESCRIPTION |
| 1118 | This call prints out the formatted error message to stderr and then |
| 1119 | terminates the process. |
| 1120 | */ |
| 1121 | static void die(int error_num, const char* fmt_reason, ...) |
| 1122 | { |
| 1123 | char buffer[1000]; |
| 1124 | va_list args; |
| 1125 | va_start(args,fmt_reason); |
| 1126 | my_vsnprintf(buffer, sizeof(buffer), fmt_reason, args); |
| 1127 | va_end(args); |
| 1128 | |
| 1129 | fprintf(stderr, "%s: %s\n" , my_progname_short, buffer); |
| 1130 | fflush(stderr); |
| 1131 | |
| 1132 | ignore_errors= 0; /* force the exit */ |
| 1133 | maybe_exit(error_num); |
| 1134 | } |
| 1135 | |
| 1136 | |
| 1137 | /* |
| 1138 | Prints out an error message and maybe kills the process. |
| 1139 | |
| 1140 | SYNOPSIS |
| 1141 | maybe_die() |
| 1142 | error_num - process return value |
| 1143 | fmt_reason - a format string for use by my_vsnprintf. |
| 1144 | ... - variable arguments for above fmt_reason string |
| 1145 | |
| 1146 | DESCRIPTION |
| 1147 | This call prints out the formatted error message to stderr and then |
| 1148 | terminates the process, unless the --force command line option is used. |
| 1149 | |
| 1150 | This call should be used for non-fatal errors (such as database |
| 1151 | errors) that the code may still be able to continue to the next unit |
| 1152 | of work. |
| 1153 | |
| 1154 | */ |
| 1155 | static void maybe_die(int error_num, const char* fmt_reason, ...) |
| 1156 | { |
| 1157 | char buffer[1000]; |
| 1158 | va_list args; |
| 1159 | va_start(args,fmt_reason); |
| 1160 | my_vsnprintf(buffer, sizeof(buffer), fmt_reason, args); |
| 1161 | va_end(args); |
| 1162 | |
| 1163 | fprintf(stderr, "%s: %s\n" , my_progname_short, buffer); |
| 1164 | fflush(stderr); |
| 1165 | |
| 1166 | maybe_exit(error_num); |
| 1167 | } |
| 1168 | |
| 1169 | |
| 1170 | |
| 1171 | /* |
| 1172 | Sends a query to server, optionally reads result, prints error message if |
| 1173 | some. |
| 1174 | |
| 1175 | SYNOPSIS |
| 1176 | mysql_query_with_error_report() |
| 1177 | mysql_con connection to use |
| 1178 | res if non zero, result will be put there with |
| 1179 | mysql_store_result() |
| 1180 | query query to send to server |
| 1181 | |
| 1182 | RETURN VALUES |
| 1183 | 0 query sending and (if res!=0) result reading went ok |
| 1184 | 1 error |
| 1185 | */ |
| 1186 | |
| 1187 | static int mysql_query_with_error_report(MYSQL *mysql_con, MYSQL_RES **res, |
| 1188 | const char *query) |
| 1189 | { |
| 1190 | if (mysql_query(mysql_con, query) || |
| 1191 | (res && !((*res)= mysql_store_result(mysql_con)))) |
| 1192 | { |
| 1193 | maybe_die(EX_MYSQLERR, "Couldn't execute '%s': %s (%d)" , |
| 1194 | query, mysql_error(mysql_con), mysql_errno(mysql_con)); |
| 1195 | return 1; |
| 1196 | } |
| 1197 | return 0; |
| 1198 | } |
| 1199 | |
| 1200 | |
| 1201 | static int fetch_db_collation(const char *db_name, |
| 1202 | char *db_cl_name, |
| 1203 | int db_cl_size) |
| 1204 | { |
| 1205 | my_bool err_status= FALSE; |
| 1206 | MYSQL_RES *db_cl_res; |
| 1207 | MYSQL_ROW db_cl_row; |
| 1208 | |
| 1209 | if (mysql_select_db(mysql, db_name)) |
| 1210 | { |
| 1211 | DB_error(mysql, "when selecting the database" ); |
| 1212 | return 1; /* If --force */ |
| 1213 | } |
| 1214 | |
| 1215 | if (mysql_query_with_error_report(mysql, &db_cl_res, |
| 1216 | "select @@collation_database" )) |
| 1217 | return 1; |
| 1218 | |
| 1219 | do |
| 1220 | { |
| 1221 | if (mysql_num_rows(db_cl_res) != 1) |
| 1222 | { |
| 1223 | err_status= TRUE; |
| 1224 | break; |
| 1225 | } |
| 1226 | |
| 1227 | if (!(db_cl_row= mysql_fetch_row(db_cl_res))) |
| 1228 | { |
| 1229 | err_status= TRUE; |
| 1230 | break; |
| 1231 | } |
| 1232 | |
| 1233 | strncpy(db_cl_name, db_cl_row[0], db_cl_size-1); |
| 1234 | db_cl_name[db_cl_size - 1]= 0; |
| 1235 | |
| 1236 | } while (FALSE); |
| 1237 | |
| 1238 | mysql_free_result(db_cl_res); |
| 1239 | |
| 1240 | return err_status ? 1 : 0; |
| 1241 | } |
| 1242 | |
| 1243 | |
| 1244 | /* |
| 1245 | Check if server supports non-blocking binlog position using the |
| 1246 | binlog_snapshot_file and binlog_snapshot_position status variables. If it |
| 1247 | does, also return the position obtained if output pointers are non-NULL. |
| 1248 | Returns 1 if position available, 0 if not. |
| 1249 | */ |
| 1250 | static int |
| 1251 | check_consistent_binlog_pos(char *binlog_pos_file, char *binlog_pos_offset) |
| 1252 | { |
| 1253 | MYSQL_RES *res; |
| 1254 | MYSQL_ROW row; |
| 1255 | int found; |
| 1256 | |
| 1257 | if (mysql_query_with_error_report(mysql, &res, |
| 1258 | "SHOW STATUS LIKE 'binlog_snapshot_%'" )) |
| 1259 | return 0; |
| 1260 | |
| 1261 | found= 0; |
| 1262 | while ((row= mysql_fetch_row(res))) |
| 1263 | { |
| 1264 | if (0 == strcmp(row[0], "Binlog_snapshot_file" )) |
| 1265 | { |
| 1266 | if (binlog_pos_file) |
| 1267 | strmake(binlog_pos_file, row[1], FN_REFLEN-1); |
| 1268 | found++; |
| 1269 | } |
| 1270 | else if (0 == strcmp(row[0], "Binlog_snapshot_position" )) |
| 1271 | { |
| 1272 | if (binlog_pos_offset) |
| 1273 | strmake(binlog_pos_offset, row[1], LONGLONG_LEN); |
| 1274 | found++; |
| 1275 | } |
| 1276 | } |
| 1277 | mysql_free_result(res); |
| 1278 | |
| 1279 | return (found == 2); |
| 1280 | } |
| 1281 | |
| 1282 | |
| 1283 | /* |
| 1284 | Get the GTID position corresponding to a given old-style binlog position. |
| 1285 | This uses BINLOG_GTID_POS(). The advantage is that the GTID position can |
| 1286 | be obtained completely non-blocking in this way (without the need for |
| 1287 | FLUSH TABLES WITH READ LOCK), as the old-style position can be obtained |
| 1288 | with START TRANSACTION WITH CONSISTENT SNAPSHOT. |
| 1289 | |
| 1290 | Returns 0 if ok, non-zero if error. |
| 1291 | */ |
| 1292 | static int |
| 1293 | get_binlog_gtid_pos(char *binlog_pos_file, char *binlog_pos_offset, |
| 1294 | char *out_gtid_pos) |
| 1295 | { |
| 1296 | DYNAMIC_STRING query; |
| 1297 | MYSQL_RES *res; |
| 1298 | MYSQL_ROW row; |
| 1299 | int err; |
| 1300 | char file_buf[FN_REFLEN*2+1], offset_buf[LONGLONG_LEN*2+1]; |
| 1301 | size_t len_pos_file= strlen(binlog_pos_file); |
| 1302 | size_t len_pos_offset= strlen(binlog_pos_offset); |
| 1303 | |
| 1304 | if (len_pos_file >= FN_REFLEN || len_pos_offset > LONGLONG_LEN) |
| 1305 | return 0; |
| 1306 | mysql_real_escape_string(mysql, file_buf, binlog_pos_file, (ulong)len_pos_file); |
| 1307 | mysql_real_escape_string(mysql, offset_buf, binlog_pos_offset, (ulong)len_pos_offset); |
| 1308 | init_dynamic_string_checked(&query, "SELECT BINLOG_GTID_POS('" , 256, 1024); |
| 1309 | dynstr_append_checked(&query, file_buf); |
| 1310 | dynstr_append_checked(&query, "', '" ); |
| 1311 | dynstr_append_checked(&query, offset_buf); |
| 1312 | dynstr_append_checked(&query, "')" ); |
| 1313 | |
| 1314 | err= mysql_query_with_error_report(mysql, &res, query.str); |
| 1315 | dynstr_free(&query); |
| 1316 | if (err) |
| 1317 | return err; |
| 1318 | |
| 1319 | err= 1; |
| 1320 | if ((row= mysql_fetch_row(res))) |
| 1321 | { |
| 1322 | strmake(out_gtid_pos, row[0], MAX_GTID_LENGTH-1); |
| 1323 | err= 0; |
| 1324 | } |
| 1325 | mysql_free_result(res); |
| 1326 | |
| 1327 | return err; |
| 1328 | } |
| 1329 | |
| 1330 | |
| 1331 | /* |
| 1332 | Get the GTID position on a master or slave. |
| 1333 | The parameter MASTER is non-zero to get the position on a master |
| 1334 | (@@gtid_binlog_pos) or zero for a slave (@@gtid_slave_pos). |
| 1335 | |
| 1336 | This uses the @@gtid_binlog_pos or @@gtid_slave_pos, so requires FLUSH TABLES |
| 1337 | WITH READ LOCK or similar to be consistent. |
| 1338 | |
| 1339 | Returns 0 if ok, non-zero for error. |
| 1340 | */ |
| 1341 | static int |
| 1342 | get_gtid_pos(char *out_gtid_pos, int master) |
| 1343 | { |
| 1344 | MYSQL_RES *res; |
| 1345 | MYSQL_ROW row; |
| 1346 | int found; |
| 1347 | |
| 1348 | if (mysql_query_with_error_report(mysql, &res, |
| 1349 | (master ? |
| 1350 | "SELECT @@GLOBAL.gtid_binlog_pos" : |
| 1351 | "SELECT @@GLOBAL.gtid_slave_pos" ))) |
| 1352 | return 1; |
| 1353 | |
| 1354 | found= 0; |
| 1355 | if ((row= mysql_fetch_row(res))) |
| 1356 | { |
| 1357 | strmake(out_gtid_pos, row[0], MAX_GTID_LENGTH-1); |
| 1358 | found++; |
| 1359 | } |
| 1360 | mysql_free_result(res); |
| 1361 | |
| 1362 | return (found != 1); |
| 1363 | } |
| 1364 | |
| 1365 | |
| 1366 | static char *my_case_str(const char *str, |
| 1367 | size_t str_len, |
| 1368 | const char *token, |
| 1369 | uint token_len) |
| 1370 | { |
| 1371 | my_match_t match; |
| 1372 | |
| 1373 | uint status= my_charset_latin1.coll->instr(&my_charset_latin1, |
| 1374 | str, str_len, |
| 1375 | token, token_len, |
| 1376 | &match, 1); |
| 1377 | |
| 1378 | return status ? (char *) str + match.end : NULL; |
| 1379 | } |
| 1380 | |
| 1381 | |
| 1382 | static int switch_db_collation(FILE *sql_file, |
| 1383 | const char *db_name, |
| 1384 | const char *delimiter, |
| 1385 | const char *current_db_cl_name, |
| 1386 | const char *required_db_cl_name, |
| 1387 | int *db_cl_altered) |
| 1388 | { |
| 1389 | if (strcmp(current_db_cl_name, required_db_cl_name) != 0) |
| 1390 | { |
| 1391 | char quoted_db_buf[NAME_LEN * 2 + 3]; |
| 1392 | char *quoted_db_name= quote_name(db_name, quoted_db_buf, FALSE); |
| 1393 | |
| 1394 | CHARSET_INFO *db_cl= get_charset_by_name(required_db_cl_name, MYF(0)); |
| 1395 | |
| 1396 | if (!db_cl) |
| 1397 | return 1; |
| 1398 | |
| 1399 | fprintf(sql_file, |
| 1400 | "ALTER DATABASE %s CHARACTER SET %s COLLATE %s %s\n" , |
| 1401 | (const char *) quoted_db_name, |
| 1402 | (const char *) db_cl->csname, |
| 1403 | (const char *) db_cl->name, |
| 1404 | (const char *) delimiter); |
| 1405 | |
| 1406 | *db_cl_altered= 1; |
| 1407 | |
| 1408 | return 0; |
| 1409 | } |
| 1410 | |
| 1411 | *db_cl_altered= 0; |
| 1412 | |
| 1413 | return 0; |
| 1414 | } |
| 1415 | |
| 1416 | |
| 1417 | static int restore_db_collation(FILE *sql_file, |
| 1418 | const char *db_name, |
| 1419 | const char *delimiter, |
| 1420 | const char *db_cl_name) |
| 1421 | { |
| 1422 | char quoted_db_buf[NAME_LEN * 2 + 3]; |
| 1423 | char *quoted_db_name= quote_name(db_name, quoted_db_buf, FALSE); |
| 1424 | |
| 1425 | CHARSET_INFO *db_cl= get_charset_by_name(db_cl_name, MYF(0)); |
| 1426 | |
| 1427 | if (!db_cl) |
| 1428 | return 1; |
| 1429 | |
| 1430 | fprintf(sql_file, |
| 1431 | "ALTER DATABASE %s CHARACTER SET %s COLLATE %s %s\n" , |
| 1432 | (const char *) quoted_db_name, |
| 1433 | (const char *) db_cl->csname, |
| 1434 | (const char *) db_cl->name, |
| 1435 | (const char *) delimiter); |
| 1436 | |
| 1437 | return 0; |
| 1438 | } |
| 1439 | |
| 1440 | |
| 1441 | static void switch_cs_variables(FILE *sql_file, |
| 1442 | const char *delimiter, |
| 1443 | const char *character_set_client, |
| 1444 | const char *character_set_results, |
| 1445 | const char *collation_connection) |
| 1446 | { |
| 1447 | fprintf(sql_file, |
| 1448 | "/*!50003 SET @saved_cs_client = @@character_set_client */ %s\n" |
| 1449 | "/*!50003 SET @saved_cs_results = @@character_set_results */ %s\n" |
| 1450 | "/*!50003 SET @saved_col_connection = @@collation_connection */ %s\n" |
| 1451 | "/*!50003 SET character_set_client = %s */ %s\n" |
| 1452 | "/*!50003 SET character_set_results = %s */ %s\n" |
| 1453 | "/*!50003 SET collation_connection = %s */ %s\n" , |
| 1454 | (const char *) delimiter, |
| 1455 | (const char *) delimiter, |
| 1456 | (const char *) delimiter, |
| 1457 | |
| 1458 | (const char *) character_set_client, |
| 1459 | (const char *) delimiter, |
| 1460 | |
| 1461 | (const char *) character_set_results, |
| 1462 | (const char *) delimiter, |
| 1463 | |
| 1464 | (const char *) collation_connection, |
| 1465 | (const char *) delimiter); |
| 1466 | } |
| 1467 | |
| 1468 | |
| 1469 | static void restore_cs_variables(FILE *sql_file, |
| 1470 | const char *delimiter) |
| 1471 | { |
| 1472 | fprintf(sql_file, |
| 1473 | "/*!50003 SET character_set_client = @saved_cs_client */ %s\n" |
| 1474 | "/*!50003 SET character_set_results = @saved_cs_results */ %s\n" |
| 1475 | "/*!50003 SET collation_connection = @saved_col_connection */ %s\n" , |
| 1476 | (const char *) delimiter, |
| 1477 | (const char *) delimiter, |
| 1478 | (const char *) delimiter); |
| 1479 | } |
| 1480 | |
| 1481 | |
| 1482 | static void switch_sql_mode(FILE *sql_file, |
| 1483 | const char *delimiter, |
| 1484 | const char *sql_mode) |
| 1485 | { |
| 1486 | fprintf(sql_file, |
| 1487 | "/*!50003 SET @saved_sql_mode = @@sql_mode */ %s\n" |
| 1488 | "/*!50003 SET sql_mode = '%s' */ %s\n" , |
| 1489 | (const char *) delimiter, |
| 1490 | |
| 1491 | (const char *) sql_mode, |
| 1492 | (const char *) delimiter); |
| 1493 | } |
| 1494 | |
| 1495 | |
| 1496 | static void restore_sql_mode(FILE *sql_file, |
| 1497 | const char *delimiter) |
| 1498 | { |
| 1499 | fprintf(sql_file, |
| 1500 | "/*!50003 SET sql_mode = @saved_sql_mode */ %s\n" , |
| 1501 | (const char *) delimiter); |
| 1502 | } |
| 1503 | |
| 1504 | |
| 1505 | static void switch_time_zone(FILE *sql_file, |
| 1506 | const char *delimiter, |
| 1507 | const char *time_zone) |
| 1508 | { |
| 1509 | fprintf(sql_file, |
| 1510 | "/*!50003 SET @saved_time_zone = @@time_zone */ %s\n" |
| 1511 | "/*!50003 SET time_zone = '%s' */ %s\n" , |
| 1512 | (const char *) delimiter, |
| 1513 | |
| 1514 | (const char *) time_zone, |
| 1515 | (const char *) delimiter); |
| 1516 | } |
| 1517 | |
| 1518 | |
| 1519 | static void restore_time_zone(FILE *sql_file, |
| 1520 | const char *delimiter) |
| 1521 | { |
| 1522 | fprintf(sql_file, |
| 1523 | "/*!50003 SET time_zone = @saved_time_zone */ %s\n" , |
| 1524 | (const char *) delimiter); |
| 1525 | } |
| 1526 | |
| 1527 | |
| 1528 | /** |
| 1529 | Switch charset for results to some specified charset. If the server does not |
| 1530 | support character_set_results variable, nothing can be done here. As for |
| 1531 | whether something should be done here, future new callers of this function |
| 1532 | should be aware that the server lacking the facility of switching charsets is |
| 1533 | treated as success. |
| 1534 | |
| 1535 | @note If the server lacks support, then nothing is changed and no error |
| 1536 | condition is returned. |
| 1537 | |
| 1538 | @returns whether there was an error or not |
| 1539 | */ |
| 1540 | static int switch_character_set_results(MYSQL *mysql, const char *cs_name) |
| 1541 | { |
| 1542 | char query_buffer[QUERY_LENGTH]; |
| 1543 | size_t query_length; |
| 1544 | |
| 1545 | /* Server lacks facility. This is not an error, by arbitrary decision . */ |
| 1546 | if (!server_supports_switching_charsets) |
| 1547 | return FALSE; |
| 1548 | |
| 1549 | query_length= my_snprintf(query_buffer, |
| 1550 | sizeof (query_buffer), |
| 1551 | "SET SESSION character_set_results = '%s'" , |
| 1552 | (const char *) cs_name); |
| 1553 | |
| 1554 | return mysql_real_query(mysql, query_buffer, (ulong)query_length); |
| 1555 | } |
| 1556 | |
| 1557 | /** |
| 1558 | Rewrite statement, enclosing DEFINER clause in version-specific comment. |
| 1559 | |
| 1560 | This function parses any CREATE statement and encloses DEFINER-clause in |
| 1561 | version-specific comment: |
| 1562 | input query: CREATE DEFINER=a@b FUNCTION ... |
| 1563 | rewritten query: CREATE * / / *!50020 DEFINER=a@b * / / *!50003 FUNCTION ... |
| 1564 | |
| 1565 | @note This function will go away when WL#3995 is implemented. |
| 1566 | |
| 1567 | @param[in] stmt_str CREATE statement string. |
| 1568 | @param[in] stmt_length Length of the stmt_str. |
| 1569 | @param[in] definer_version_str Minimal MySQL version number when |
| 1570 | DEFINER clause is supported in the |
| 1571 | given statement. |
| 1572 | @param[in] definer_version_length Length of definer_version_str. |
| 1573 | @param[in] stmt_version_str Minimal MySQL version number when the |
| 1574 | given statement is supported. |
| 1575 | @param[in] stmt_version_length Length of stmt_version_str. |
| 1576 | @param[in] keyword_str Keyword to look for after CREATE. |
| 1577 | @param[in] keyword_length Length of keyword_str. |
| 1578 | |
| 1579 | @return pointer to the new allocated query string. |
| 1580 | */ |
| 1581 | |
| 1582 | static char *cover_definer_clause(const char *stmt_str, |
| 1583 | size_t stmt_length, |
| 1584 | const char *definer_version_str, |
| 1585 | uint definer_version_length, |
| 1586 | const char *stmt_version_str, |
| 1587 | uint stmt_version_length, |
| 1588 | const char *keyword_str, |
| 1589 | uint keyword_length) |
| 1590 | { |
| 1591 | char *definer_begin= my_case_str(stmt_str, stmt_length, |
| 1592 | C_STRING_WITH_LEN(" DEFINER" )); |
| 1593 | char *definer_end= NULL; |
| 1594 | |
| 1595 | char *query_str= NULL; |
| 1596 | char *query_ptr; |
| 1597 | |
| 1598 | if (!definer_begin) |
| 1599 | return NULL; |
| 1600 | |
| 1601 | definer_end= my_case_str(definer_begin, strlen(definer_begin), |
| 1602 | keyword_str, keyword_length); |
| 1603 | |
| 1604 | if (!definer_end) |
| 1605 | return NULL; |
| 1606 | |
| 1607 | /* |
| 1608 | Allocate memory for new query string: original string |
| 1609 | from SHOW statement and version-specific comments. |
| 1610 | */ |
| 1611 | query_str= alloc_query_str(stmt_length + 23); |
| 1612 | |
| 1613 | query_ptr= strnmov(query_str, stmt_str, definer_begin - stmt_str); |
| 1614 | query_ptr= strnmov(query_ptr, C_STRING_WITH_LEN("*/ /*!" )); |
| 1615 | query_ptr= strnmov(query_ptr, definer_version_str, definer_version_length); |
| 1616 | query_ptr= strnmov(query_ptr, definer_begin, definer_end - definer_begin); |
| 1617 | query_ptr= strnmov(query_ptr, C_STRING_WITH_LEN("*/ /*!" )); |
| 1618 | query_ptr= strnmov(query_ptr, stmt_version_str, stmt_version_length); |
| 1619 | query_ptr= strxmov(query_ptr, definer_end, NullS); |
| 1620 | |
| 1621 | return query_str; |
| 1622 | } |
| 1623 | |
| 1624 | /* |
| 1625 | Open a new .sql file to dump the table or view into |
| 1626 | |
| 1627 | SYNOPSIS |
| 1628 | open_sql_file_for_table |
| 1629 | name name of the table or view |
| 1630 | flags flags (as per "man 2 open") |
| 1631 | |
| 1632 | RETURN VALUES |
| 1633 | 0 Failed to open file |
| 1634 | > 0 Handle of the open file |
| 1635 | */ |
| 1636 | static FILE* open_sql_file_for_table(const char* table, int flags) |
| 1637 | { |
| 1638 | FILE* res; |
| 1639 | char filename[FN_REFLEN], tmp_path[FN_REFLEN]; |
| 1640 | convert_dirname(tmp_path,path,NullS); |
| 1641 | res= my_fopen(fn_format(filename, table, tmp_path, ".sql" , 4), |
| 1642 | flags, MYF(MY_WME)); |
| 1643 | return res; |
| 1644 | } |
| 1645 | |
| 1646 | |
| 1647 | static void free_resources() |
| 1648 | { |
| 1649 | if (md_result_file && md_result_file != stdout) |
| 1650 | my_fclose(md_result_file, MYF(0)); |
| 1651 | if (get_table_name_result) |
| 1652 | mysql_free_result(get_table_name_result); |
| 1653 | if (routine_res) |
| 1654 | mysql_free_result(routine_res); |
| 1655 | if (routine_list_res) |
| 1656 | mysql_free_result(routine_list_res); |
| 1657 | if (mysql) |
| 1658 | { |
| 1659 | mysql_close(mysql); |
| 1660 | mysql= 0; |
| 1661 | } |
| 1662 | my_free(order_by); |
| 1663 | my_free(opt_password); |
| 1664 | my_free(current_host); |
| 1665 | free_root(&glob_root, MYF(0)); |
| 1666 | if (my_hash_inited(&ignore_database)) |
| 1667 | my_hash_free(&ignore_database); |
| 1668 | if (my_hash_inited(&ignore_table)) |
| 1669 | my_hash_free(&ignore_table); |
| 1670 | dynstr_free(&extended_row); |
| 1671 | dynstr_free(&dynamic_where); |
| 1672 | dynstr_free(&insert_pat); |
| 1673 | dynstr_free(&select_field_names); |
| 1674 | if (defaults_argv) |
| 1675 | free_defaults(defaults_argv); |
| 1676 | mysql_library_end(); |
| 1677 | my_end(my_end_arg); |
| 1678 | } |
| 1679 | |
| 1680 | |
| 1681 | static void maybe_exit(int error) |
| 1682 | { |
| 1683 | if (!first_error) |
| 1684 | first_error= error; |
| 1685 | if (ignore_errors) |
| 1686 | return; |
| 1687 | ignore_errors= 1; /* don't want to recurse, if something fails below */ |
| 1688 | if (opt_slave_data) |
| 1689 | do_start_slave_sql(mysql); |
| 1690 | free_resources(); |
| 1691 | exit(error); |
| 1692 | } |
| 1693 | |
| 1694 | |
| 1695 | /* |
| 1696 | db_connect -- connects to the host and selects DB. |
| 1697 | */ |
| 1698 | |
| 1699 | static int connect_to_db(char *host, char *user,char *passwd) |
| 1700 | { |
| 1701 | char buff[20+FN_REFLEN]; |
| 1702 | my_bool reconnect; |
| 1703 | DBUG_ENTER("connect_to_db" ); |
| 1704 | |
| 1705 | verbose_msg("-- Connecting to %s...\n" , host ? host : "localhost" ); |
| 1706 | mysql_init(&mysql_connection); |
| 1707 | if (opt_compress) |
| 1708 | mysql_options(&mysql_connection,MYSQL_OPT_COMPRESS,NullS); |
| 1709 | #ifdef HAVE_OPENSSL |
| 1710 | if (opt_use_ssl) |
| 1711 | { |
| 1712 | mysql_ssl_set(&mysql_connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, |
| 1713 | opt_ssl_capath, opt_ssl_cipher); |
| 1714 | mysql_options(&mysql_connection, MYSQL_OPT_SSL_CRL, opt_ssl_crl); |
| 1715 | mysql_options(&mysql_connection, MYSQL_OPT_SSL_CRLPATH, opt_ssl_crlpath); |
| 1716 | } |
| 1717 | mysql_options(&mysql_connection,MYSQL_OPT_SSL_VERIFY_SERVER_CERT, |
| 1718 | (char*)&opt_ssl_verify_server_cert); |
| 1719 | #endif |
| 1720 | if (opt_protocol) |
| 1721 | mysql_options(&mysql_connection,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol); |
| 1722 | #ifdef HAVE_SMEM |
| 1723 | if (shared_memory_base_name) |
| 1724 | mysql_options(&mysql_connection,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name); |
| 1725 | #endif |
| 1726 | mysql_options(&mysql_connection, MYSQL_SET_CHARSET_NAME, default_charset); |
| 1727 | |
| 1728 | if (opt_plugin_dir && *opt_plugin_dir) |
| 1729 | mysql_options(&mysql_connection, MYSQL_PLUGIN_DIR, opt_plugin_dir); |
| 1730 | |
| 1731 | if (opt_default_auth && *opt_default_auth) |
| 1732 | mysql_options(&mysql_connection, MYSQL_DEFAULT_AUTH, opt_default_auth); |
| 1733 | |
| 1734 | mysql_options(&mysql_connection, MYSQL_OPT_CONNECT_ATTR_RESET, 0); |
| 1735 | mysql_options4(&mysql_connection, MYSQL_OPT_CONNECT_ATTR_ADD, |
| 1736 | "program_name" , "mysqldump" ); |
| 1737 | mysql= &mysql_connection; /* So we can mysql_close() it properly */ |
| 1738 | if (!mysql_real_connect(&mysql_connection,host,user,passwd, |
| 1739 | NULL,opt_mysql_port,opt_mysql_unix_port, 0)) |
| 1740 | { |
| 1741 | DB_error(&mysql_connection, "when trying to connect" ); |
| 1742 | DBUG_RETURN(1); |
| 1743 | } |
| 1744 | if ((mysql_get_server_version(&mysql_connection) < 40100) || |
| 1745 | (opt_compatible_mode & 3)) |
| 1746 | { |
| 1747 | /* Don't dump SET NAMES with a pre-4.1 server (bug#7997). */ |
| 1748 | opt_set_charset= 0; |
| 1749 | |
| 1750 | /* Don't switch charsets for 4.1 and earlier. (bug#34192). */ |
| 1751 | server_supports_switching_charsets= FALSE; |
| 1752 | } |
| 1753 | /* |
| 1754 | As we're going to set SQL_MODE, it would be lost on reconnect, so we |
| 1755 | cannot reconnect. |
| 1756 | */ |
| 1757 | reconnect= 0; |
| 1758 | mysql_options(&mysql_connection, MYSQL_OPT_RECONNECT, &reconnect); |
| 1759 | my_snprintf(buff, sizeof(buff), "/*!40100 SET @@SQL_MODE='%s' */" , |
| 1760 | compatible_mode_normal_str); |
| 1761 | if (mysql_query_with_error_report(mysql, 0, buff)) |
| 1762 | DBUG_RETURN(1); |
| 1763 | /* |
| 1764 | set time_zone to UTC to allow dumping date types between servers with |
| 1765 | different time zone settings |
| 1766 | */ |
| 1767 | if (opt_tz_utc) |
| 1768 | { |
| 1769 | my_snprintf(buff, sizeof(buff), "/*!40103 SET TIME_ZONE='+00:00' */" ); |
| 1770 | if (mysql_query_with_error_report(mysql, 0, buff)) |
| 1771 | DBUG_RETURN(1); |
| 1772 | } |
| 1773 | DBUG_RETURN(0); |
| 1774 | } /* connect_to_db */ |
| 1775 | |
| 1776 | |
| 1777 | /* |
| 1778 | ** dbDisconnect -- disconnects from the host. |
| 1779 | */ |
| 1780 | static void dbDisconnect(char *host) |
| 1781 | { |
| 1782 | verbose_msg("-- Disconnecting from %s...\n" , host ? host : "localhost" ); |
| 1783 | mysql_close(mysql); |
| 1784 | mysql= 0; |
| 1785 | } /* dbDisconnect */ |
| 1786 | |
| 1787 | |
| 1788 | static void unescape(FILE *file,char *pos, size_t length) |
| 1789 | { |
| 1790 | char *tmp; |
| 1791 | DBUG_ENTER("unescape" ); |
| 1792 | if (!(tmp=(char*) my_malloc(length*2+1, MYF(MY_WME)))) |
| 1793 | die(EX_MYSQLERR, "Couldn't allocate memory" ); |
| 1794 | |
| 1795 | mysql_real_escape_string(&mysql_connection, tmp, pos, (ulong)length); |
| 1796 | fputc('\'', file); |
| 1797 | fputs(tmp, file); |
| 1798 | fputc('\'', file); |
| 1799 | check_io(file); |
| 1800 | my_free(tmp); |
| 1801 | DBUG_VOID_RETURN; |
| 1802 | } /* unescape */ |
| 1803 | |
| 1804 | |
| 1805 | static my_bool test_if_special_chars(const char *str) |
| 1806 | { |
| 1807 | #if MYSQL_VERSION_ID >= 32300 |
| 1808 | for ( ; *str ; str++) |
| 1809 | if (!my_isvar(charset_info,*str) && *str != '$') |
| 1810 | return 1; |
| 1811 | #endif |
| 1812 | return 0; |
| 1813 | } /* test_if_special_chars */ |
| 1814 | |
| 1815 | |
| 1816 | /* |
| 1817 | quote_name(name, buff, force) |
| 1818 | |
| 1819 | Quotes a string, if it requires quoting. To force quoting regardless |
| 1820 | of the characters within the string, the force flag can be set to true. |
| 1821 | |
| 1822 | Args |
| 1823 | |
| 1824 | name Unquoted string containing that which will be quoted |
| 1825 | buff The buffer that contains the quoted value, also returned |
| 1826 | force Flag to make it ignore 'test_if_special_chars' |
| 1827 | |
| 1828 | Returns |
| 1829 | A pointer to the quoted string, or the original string if nothing has |
| 1830 | changed. |
| 1831 | |
| 1832 | */ |
| 1833 | static char *quote_name(const char *name, char *buff, my_bool force) |
| 1834 | { |
| 1835 | char *to= buff; |
| 1836 | char qtype= (opt_compatible_mode & MASK_ANSI_QUOTES) ? '\"' : '`'; |
| 1837 | |
| 1838 | if (!force && !opt_quoted && !test_if_special_chars(name)) |
| 1839 | return (char*) name; |
| 1840 | *to++= qtype; |
| 1841 | while (*name) |
| 1842 | { |
| 1843 | if (*name == qtype) |
| 1844 | *to++= qtype; |
| 1845 | *to++= *name++; |
| 1846 | } |
| 1847 | to[0]= qtype; |
| 1848 | to[1]= 0; |
| 1849 | return buff; |
| 1850 | } /* quote_name */ |
| 1851 | |
| 1852 | |
| 1853 | /* |
| 1854 | Quote a table name so it can be used in "SHOW TABLES LIKE <tabname>" |
| 1855 | |
| 1856 | SYNOPSIS |
| 1857 | quote_for_like() |
| 1858 | name name of the table |
| 1859 | buff quoted name of the table |
| 1860 | |
| 1861 | DESCRIPTION |
| 1862 | Quote \, _, ' and % characters |
| 1863 | |
| 1864 | Note: Because MySQL uses the C escape syntax in strings |
| 1865 | (for example, '\n' to represent newline), you must double |
| 1866 | any '\' that you use in your LIKE strings. For example, to |
| 1867 | search for '\n', specify it as '\\n'. To search for '\', specify |
| 1868 | it as '\\\\' (the backslashes are stripped once by the parser |
| 1869 | and another time when the pattern match is done, leaving a |
| 1870 | single backslash to be matched). |
| 1871 | |
| 1872 | Example: "t\1" => "t\\\\1" |
| 1873 | |
| 1874 | */ |
| 1875 | static char *quote_for_like(const char *name, char *buff) |
| 1876 | { |
| 1877 | char *to= buff; |
| 1878 | *to++= '\''; |
| 1879 | while (*name) |
| 1880 | { |
| 1881 | if (*name == '\\') |
| 1882 | { |
| 1883 | *to++='\\'; |
| 1884 | *to++='\\'; |
| 1885 | *to++='\\'; |
| 1886 | } |
| 1887 | else if (*name == '\'' || *name == '_' || *name == '%') |
| 1888 | *to++= '\\'; |
| 1889 | *to++= *name++; |
| 1890 | } |
| 1891 | to[0]= '\''; |
| 1892 | to[1]= 0; |
| 1893 | return buff; |
| 1894 | } |
| 1895 | |
| 1896 | static char *quote_for_equal(const char *name, char *buff) |
| 1897 | { |
| 1898 | char *to= buff; |
| 1899 | *to++= '\''; |
| 1900 | while (*name) |
| 1901 | { |
| 1902 | if (*name == '\\') |
| 1903 | { |
| 1904 | *to++='\\'; |
| 1905 | } |
| 1906 | if (*name == '\'') |
| 1907 | *to++= '\\'; |
| 1908 | *to++= *name++; |
| 1909 | } |
| 1910 | to[0]= '\''; |
| 1911 | to[1]= 0; |
| 1912 | return buff; |
| 1913 | |
| 1914 | } |
| 1915 | |
| 1916 | |
| 1917 | /** |
| 1918 | Quote and print a string. |
| 1919 | |
| 1920 | @param xml_file - Output file. |
| 1921 | @param str - String to print. |
| 1922 | @param len - Its length. |
| 1923 | @param is_attribute_name - A check for attribute name or value. |
| 1924 | |
| 1925 | @description |
| 1926 | Quote '<' '>' '&' '\"' chars and print a string to the xml_file. |
| 1927 | */ |
| 1928 | |
| 1929 | static void print_quoted_xml(FILE *xml_file, const char *str, size_t len, |
| 1930 | my_bool is_attribute_name) |
| 1931 | { |
| 1932 | const char *end; |
| 1933 | |
| 1934 | for (end= str + len; str != end; str++) |
| 1935 | { |
| 1936 | switch (*str) { |
| 1937 | case '<': |
| 1938 | fputs("<" , xml_file); |
| 1939 | break; |
| 1940 | case '>': |
| 1941 | fputs(">" , xml_file); |
| 1942 | break; |
| 1943 | case '&': |
| 1944 | fputs("&" , xml_file); |
| 1945 | break; |
| 1946 | case '\"': |
| 1947 | fputs(""" , xml_file); |
| 1948 | break; |
| 1949 | case ' ': |
| 1950 | /* Attribute names cannot contain spaces. */ |
| 1951 | if (is_attribute_name) |
| 1952 | { |
| 1953 | fputs("_" , xml_file); |
| 1954 | break; |
| 1955 | } |
| 1956 | /* fall through */ |
| 1957 | default: |
| 1958 | fputc(*str, xml_file); |
| 1959 | break; |
| 1960 | } |
| 1961 | } |
| 1962 | check_io(xml_file); |
| 1963 | } |
| 1964 | |
| 1965 | |
| 1966 | /* |
| 1967 | Print xml tag. Optionally add attribute(s). |
| 1968 | |
| 1969 | SYNOPSIS |
| 1970 | print_xml_tag(xml_file, sbeg, send, tag_name, first_attribute_name, |
| 1971 | ..., attribute_name_n, attribute_value_n, NullS) |
| 1972 | xml_file - output file |
| 1973 | sbeg - line beginning |
| 1974 | line_end - line ending |
| 1975 | tag_name - XML tag name. |
| 1976 | first_attribute_name - tag and first attribute |
| 1977 | first_attribute_value - (Implied) value of first attribute |
| 1978 | attribute_name_n - attribute n |
| 1979 | attribute_value_n - value of attribute n |
| 1980 | |
| 1981 | DESCRIPTION |
| 1982 | Print XML tag with any number of attribute="value" pairs to the xml_file. |
| 1983 | |
| 1984 | Format is: |
| 1985 | sbeg<tag_name first_attribute_name="first_attribute_value" ... |
| 1986 | attribute_name_n="attribute_value_n">send |
| 1987 | NOTE |
| 1988 | Additional arguments must be present in attribute/value pairs. |
| 1989 | The last argument should be the null character pointer. |
| 1990 | All attribute_value arguments MUST be NULL terminated strings. |
| 1991 | All attribute_value arguments will be quoted before output. |
| 1992 | */ |
| 1993 | |
| 1994 | static void print_xml_tag(FILE * xml_file, const char* sbeg, |
| 1995 | const char* line_end, |
| 1996 | const char* tag_name, |
| 1997 | const char* first_attribute_name, ...) |
| 1998 | { |
| 1999 | va_list arg_list; |
| 2000 | const char *attribute_name, *attribute_value; |
| 2001 | |
| 2002 | fputs(sbeg, xml_file); |
| 2003 | fputc('<', xml_file); |
| 2004 | fputs(tag_name, xml_file); |
| 2005 | |
| 2006 | va_start(arg_list, first_attribute_name); |
| 2007 | attribute_name= first_attribute_name; |
| 2008 | while (attribute_name != NullS) |
| 2009 | { |
| 2010 | attribute_value= va_arg(arg_list, char *); |
| 2011 | DBUG_ASSERT(attribute_value != NullS); |
| 2012 | |
| 2013 | fputc(' ', xml_file); |
| 2014 | fputs(attribute_name, xml_file); |
| 2015 | fputc('\"', xml_file); |
| 2016 | |
| 2017 | print_quoted_xml(xml_file, attribute_value, strlen(attribute_value), 0); |
| 2018 | fputc('\"', xml_file); |
| 2019 | |
| 2020 | attribute_name= va_arg(arg_list, char *); |
| 2021 | } |
| 2022 | va_end(arg_list); |
| 2023 | |
| 2024 | fputc('>', xml_file); |
| 2025 | fputs(line_end, xml_file); |
| 2026 | check_io(xml_file); |
| 2027 | } |
| 2028 | |
| 2029 | |
| 2030 | /* |
| 2031 | Print xml tag with for a field that is null |
| 2032 | |
| 2033 | SYNOPSIS |
| 2034 | print_xml_null_tag() |
| 2035 | xml_file - output file |
| 2036 | sbeg - line beginning |
| 2037 | stag_atr - tag and attribute |
| 2038 | sval - value of attribute |
| 2039 | line_end - line ending |
| 2040 | |
| 2041 | DESCRIPTION |
| 2042 | Print tag with one attribute to the xml_file. Format is: |
| 2043 | <stag_atr="sval" xsi:nil="true"/> |
| 2044 | NOTE |
| 2045 | sval MUST be a NULL terminated string. |
| 2046 | sval string will be qouted before output. |
| 2047 | */ |
| 2048 | |
| 2049 | static void print_xml_null_tag(FILE * xml_file, const char* sbeg, |
| 2050 | const char* stag_atr, const char* sval, |
| 2051 | const char* line_end) |
| 2052 | { |
| 2053 | fputs(sbeg, xml_file); |
| 2054 | fputs("<" , xml_file); |
| 2055 | fputs(stag_atr, xml_file); |
| 2056 | fputs("\"" , xml_file); |
| 2057 | print_quoted_xml(xml_file, sval, strlen(sval), 0); |
| 2058 | fputs("\" xsi:nil=\"true\" />" , xml_file); |
| 2059 | fputs(line_end, xml_file); |
| 2060 | check_io(xml_file); |
| 2061 | } |
| 2062 | |
| 2063 | |
| 2064 | /** |
| 2065 | Print xml CDATA section. |
| 2066 | |
| 2067 | @param xml_file - output file |
| 2068 | @param str - string to print |
| 2069 | @param len - length of the string |
| 2070 | |
| 2071 | @note |
| 2072 | This function also takes care of the presence of '[[>' |
| 2073 | string in the str. If found, the CDATA section is broken |
| 2074 | into two CDATA sections, <![CDATA[]]]]> and <![CDATA[>]]. |
| 2075 | */ |
| 2076 | |
| 2077 | static void print_xml_cdata(FILE *xml_file, const char *str, ulong len) |
| 2078 | { |
| 2079 | const char *end; |
| 2080 | |
| 2081 | fputs("<![CDATA[\n" , xml_file); |
| 2082 | for (end= str + len; str != end; str++) |
| 2083 | { |
| 2084 | switch(*str) { |
| 2085 | case ']': |
| 2086 | if ((*(str + 1) == ']') && (*(str + 2) =='>')) |
| 2087 | { |
| 2088 | fputs("]]]]><![CDATA[>" , xml_file); |
| 2089 | str += 2; |
| 2090 | continue; |
| 2091 | } |
| 2092 | /* fall through */ |
| 2093 | default: |
| 2094 | fputc(*str, xml_file); |
| 2095 | break; |
| 2096 | } |
| 2097 | } |
| 2098 | fputs("\n]]>\n" , xml_file); |
| 2099 | check_io(xml_file); |
| 2100 | } |
| 2101 | |
| 2102 | |
| 2103 | /* |
| 2104 | Print xml tag with many attributes. |
| 2105 | |
| 2106 | SYNOPSIS |
| 2107 | print_xml_row() |
| 2108 | xml_file - output file |
| 2109 | row_name - xml tag name |
| 2110 | tableRes - query result |
| 2111 | row - result row |
| 2112 | str_create - create statement header string |
| 2113 | |
| 2114 | DESCRIPTION |
| 2115 | Print tag with many attribute to the xml_file. Format is: |
| 2116 | \t\t<row_name Atr1="Val1" Atr2="Val2"... /> |
| 2117 | NOTE |
| 2118 | All atributes and values will be quoted before output. |
| 2119 | */ |
| 2120 | |
| 2121 | static void print_xml_row(FILE *xml_file, const char *row_name, |
| 2122 | MYSQL_RES *tableRes, MYSQL_ROW *row, |
| 2123 | const char *str_create) |
| 2124 | { |
| 2125 | uint i; |
| 2126 | my_bool body_found __attribute__((unused)) = 0; |
| 2127 | char *create_stmt_ptr= NULL; |
| 2128 | ulong create_stmt_len= 0; |
| 2129 | MYSQL_FIELD *field; |
| 2130 | ulong *lengths= mysql_fetch_lengths(tableRes); |
| 2131 | |
| 2132 | fprintf(xml_file, "\t\t<%s" , row_name); |
| 2133 | check_io(xml_file); |
| 2134 | mysql_field_seek(tableRes, 0); |
| 2135 | for (i= 0; (field= mysql_fetch_field(tableRes)); i++) |
| 2136 | { |
| 2137 | if ((*row)[i]) |
| 2138 | { |
| 2139 | /* For 'create' statements, dump using CDATA. */ |
| 2140 | if ((str_create) && (strcmp(str_create, field->name) == 0)) |
| 2141 | { |
| 2142 | create_stmt_ptr= (*row)[i]; |
| 2143 | create_stmt_len= lengths[i]; |
| 2144 | #ifndef DBUG_OFF |
| 2145 | body_found= 1; |
| 2146 | #endif |
| 2147 | } |
| 2148 | else |
| 2149 | { |
| 2150 | fputc(' ', xml_file); |
| 2151 | print_quoted_xml(xml_file, field->name, field->name_length, 1); |
| 2152 | fputs("=\"" , xml_file); |
| 2153 | print_quoted_xml(xml_file, (*row)[i], lengths[i], 0); |
| 2154 | fputc('"', xml_file); |
| 2155 | check_io(xml_file); |
| 2156 | } |
| 2157 | } |
| 2158 | } |
| 2159 | |
| 2160 | if (create_stmt_len) |
| 2161 | { |
| 2162 | DBUG_ASSERT(body_found); |
| 2163 | fputs(">\n" , xml_file); |
| 2164 | print_xml_cdata(xml_file, create_stmt_ptr, create_stmt_len); |
| 2165 | fprintf(xml_file, "\t\t</%s>\n" , row_name); |
| 2166 | } |
| 2167 | else |
| 2168 | fputs(" />\n" , xml_file); |
| 2169 | |
| 2170 | check_io(xml_file); |
| 2171 | } |
| 2172 | |
| 2173 | |
| 2174 | /** |
| 2175 | Print xml comments. |
| 2176 | |
| 2177 | @param xml_file - output file |
| 2178 | @param len - length of comment message |
| 2179 | @param comment_string - comment message |
| 2180 | |
| 2181 | @description |
| 2182 | Print the comment message in the format: |
| 2183 | "<!-- \n comment string \n -->\n" |
| 2184 | |
| 2185 | @note |
| 2186 | Any occurrence of continuous hyphens will be |
| 2187 | squeezed to a single hyphen. |
| 2188 | */ |
| 2189 | |
| 2190 | static void (FILE *xml_file, size_t len, |
| 2191 | const char *) |
| 2192 | { |
| 2193 | const char* end; |
| 2194 | |
| 2195 | fputs("<!-- " , xml_file); |
| 2196 | |
| 2197 | for (end= comment_string + len; comment_string != end; comment_string++) |
| 2198 | { |
| 2199 | /* |
| 2200 | The string "--" (double-hyphen) MUST NOT occur within xml comments. |
| 2201 | */ |
| 2202 | switch (*comment_string) { |
| 2203 | case '-': |
| 2204 | if (*(comment_string + 1) == '-') /* Only one hyphen allowed. */ |
| 2205 | break; |
| 2206 | /* fall through */ |
| 2207 | default: |
| 2208 | fputc(*comment_string, xml_file); |
| 2209 | break; |
| 2210 | } |
| 2211 | } |
| 2212 | fputs(" -->\n" , xml_file); |
| 2213 | check_io(xml_file); |
| 2214 | } |
| 2215 | |
| 2216 | |
| 2217 | |
| 2218 | /* A common printing function for xml and non-xml modes. */ |
| 2219 | |
| 2220 | static void (FILE *sql_file, my_bool is_error, const char *format, |
| 2221 | ...) |
| 2222 | { |
| 2223 | static char [COMMENT_LENGTH]; |
| 2224 | va_list args; |
| 2225 | |
| 2226 | /* If its an error message, print it ignoring opt_comments. */ |
| 2227 | if (!is_error && !opt_comments) |
| 2228 | return; |
| 2229 | |
| 2230 | va_start(args, format); |
| 2231 | my_vsnprintf(comment_buff, COMMENT_LENGTH, format, args); |
| 2232 | va_end(args); |
| 2233 | |
| 2234 | if (!opt_xml) |
| 2235 | { |
| 2236 | fputs(comment_buff, sql_file); |
| 2237 | check_io(sql_file); |
| 2238 | return; |
| 2239 | } |
| 2240 | |
| 2241 | print_xml_comment(sql_file, strlen(comment_buff), comment_buff); |
| 2242 | } |
| 2243 | |
| 2244 | /* |
| 2245 | create_delimiter |
| 2246 | Generate a new (null-terminated) string that does not exist in query |
| 2247 | and is therefore suitable for use as a query delimiter. Store this |
| 2248 | delimiter in delimiter_buff . |
| 2249 | |
| 2250 | This is quite simple in that it doesn't even try to parse statements as an |
| 2251 | interpreter would. It merely returns a string that is not in the query, which |
| 2252 | is much more than adequate for constructing a delimiter. |
| 2253 | |
| 2254 | RETURN |
| 2255 | ptr to the delimiter on Success |
| 2256 | NULL on Failure |
| 2257 | */ |
| 2258 | static char *create_delimiter(char *query, char *delimiter_buff, |
| 2259 | int delimiter_max_size) |
| 2260 | { |
| 2261 | int proposed_length; |
| 2262 | char *presence; |
| 2263 | |
| 2264 | delimiter_buff[0]= ';'; /* start with one semicolon, and */ |
| 2265 | |
| 2266 | for (proposed_length= 2; proposed_length < delimiter_max_size; |
| 2267 | delimiter_max_size++) { |
| 2268 | |
| 2269 | delimiter_buff[proposed_length-1]= ';'; /* add semicolons, until */ |
| 2270 | delimiter_buff[proposed_length]= '\0'; |
| 2271 | |
| 2272 | presence = strstr(query, delimiter_buff); |
| 2273 | if (presence == NULL) { /* the proposed delimiter is not in the query. */ |
| 2274 | return delimiter_buff; |
| 2275 | } |
| 2276 | |
| 2277 | } |
| 2278 | return NULL; /* but if we run out of space, return nothing at all. */ |
| 2279 | } |
| 2280 | |
| 2281 | |
| 2282 | /* |
| 2283 | dump_events_for_db |
| 2284 | -- retrieves list of events for a given db, and prints out |
| 2285 | the CREATE EVENT statement into the output (the dump). |
| 2286 | |
| 2287 | RETURN |
| 2288 | 0 Success |
| 2289 | 1 Error |
| 2290 | */ |
| 2291 | static uint dump_events_for_db(char *db) |
| 2292 | { |
| 2293 | char query_buff[QUERY_LENGTH]; |
| 2294 | char db_name_buff[NAME_LEN*2+3], name_buff[NAME_LEN*2+3]; |
| 2295 | char *event_name; |
| 2296 | char delimiter[QUERY_LENGTH]; |
| 2297 | FILE *sql_file= md_result_file; |
| 2298 | MYSQL_RES *event_res, *event_list_res; |
| 2299 | MYSQL_ROW row, event_list_row; |
| 2300 | |
| 2301 | char db_cl_name[MY_CS_NAME_SIZE]; |
| 2302 | int db_cl_altered= FALSE; |
| 2303 | |
| 2304 | DBUG_ENTER("dump_events_for_db" ); |
| 2305 | DBUG_PRINT("enter" , ("db: '%s'" , db)); |
| 2306 | |
| 2307 | mysql_real_escape_string(mysql, db_name_buff, db, (ulong)strlen(db)); |
| 2308 | |
| 2309 | /* nice comments */ |
| 2310 | print_comment(sql_file, 0, |
| 2311 | "\n--\n-- Dumping events for database '%s'\n--\n" , |
| 2312 | fix_for_comment(db)); |
| 2313 | |
| 2314 | /* |
| 2315 | not using "mysql_query_with_error_report" because we may have not |
| 2316 | enough privileges to lock mysql.events. |
| 2317 | */ |
| 2318 | if (lock_tables) |
| 2319 | mysql_query(mysql, "LOCK TABLES mysql.event READ" ); |
| 2320 | |
| 2321 | if (mysql_query_with_error_report(mysql, &event_list_res, "show events" )) |
| 2322 | DBUG_RETURN(0); |
| 2323 | |
| 2324 | strcpy(delimiter, ";" ); |
| 2325 | if (mysql_num_rows(event_list_res) > 0) |
| 2326 | { |
| 2327 | if (opt_xml) |
| 2328 | fputs("\t<events>\n" , sql_file); |
| 2329 | else |
| 2330 | { |
| 2331 | fprintf(sql_file, "/*!50106 SET @save_time_zone= @@TIME_ZONE */ ;\n" ); |
| 2332 | |
| 2333 | /* Get database collation. */ |
| 2334 | |
| 2335 | if (fetch_db_collation(db_name_buff, db_cl_name, sizeof (db_cl_name))) |
| 2336 | DBUG_RETURN(1); |
| 2337 | } |
| 2338 | |
| 2339 | if (switch_character_set_results(mysql, "binary" )) |
| 2340 | DBUG_RETURN(1); |
| 2341 | |
| 2342 | while ((event_list_row= mysql_fetch_row(event_list_res)) != NULL) |
| 2343 | { |
| 2344 | event_name= quote_name(event_list_row[1], name_buff, 0); |
| 2345 | DBUG_PRINT("info" , ("retrieving CREATE EVENT for %s" , name_buff)); |
| 2346 | my_snprintf(query_buff, sizeof(query_buff), "SHOW CREATE EVENT %s" , |
| 2347 | event_name); |
| 2348 | |
| 2349 | if (mysql_query_with_error_report(mysql, &event_res, query_buff)) |
| 2350 | DBUG_RETURN(1); |
| 2351 | |
| 2352 | while ((row= mysql_fetch_row(event_res)) != NULL) |
| 2353 | { |
| 2354 | if (opt_xml) |
| 2355 | { |
| 2356 | print_xml_row(sql_file, "event" , event_res, &row, |
| 2357 | "Create Event" ); |
| 2358 | continue; |
| 2359 | } |
| 2360 | |
| 2361 | /* |
| 2362 | if the user has EXECUTE privilege he can see event names, but not the |
| 2363 | event body! |
| 2364 | */ |
| 2365 | if (strlen(row[3]) != 0) |
| 2366 | { |
| 2367 | char *query_str; |
| 2368 | |
| 2369 | if (opt_drop) |
| 2370 | fprintf(sql_file, "/*!50106 DROP EVENT IF EXISTS %s */%s\n" , |
| 2371 | event_name, delimiter); |
| 2372 | |
| 2373 | if (create_delimiter(row[3], delimiter, sizeof(delimiter)) == NULL) |
| 2374 | { |
| 2375 | fprintf(stderr, "%s: Warning: Can't create delimiter for event '%s'\n" , |
| 2376 | my_progname_short, event_name); |
| 2377 | DBUG_RETURN(1); |
| 2378 | } |
| 2379 | |
| 2380 | fprintf(sql_file, "DELIMITER %s\n" , delimiter); |
| 2381 | |
| 2382 | if (mysql_num_fields(event_res) >= 7) |
| 2383 | { |
| 2384 | if (switch_db_collation(sql_file, db_name_buff, delimiter, |
| 2385 | db_cl_name, row[6], &db_cl_altered)) |
| 2386 | { |
| 2387 | DBUG_RETURN(1); |
| 2388 | } |
| 2389 | |
| 2390 | switch_cs_variables(sql_file, delimiter, |
| 2391 | row[4], /* character_set_client */ |
| 2392 | row[4], /* character_set_results */ |
| 2393 | row[5]); /* collation_connection */ |
| 2394 | } |
| 2395 | else |
| 2396 | { |
| 2397 | /* |
| 2398 | mysqldump is being run against the server, that does not |
| 2399 | provide character set information in SHOW CREATE |
| 2400 | statements. |
| 2401 | |
| 2402 | NOTE: the dump may be incorrect, since character set |
| 2403 | information is required in order to restore event properly. |
| 2404 | */ |
| 2405 | |
| 2406 | fprintf(sql_file, |
| 2407 | "--\n" |
| 2408 | "-- WARNING: old server version. " |
| 2409 | "The following dump may be incomplete.\n" |
| 2410 | "--\n" ); |
| 2411 | } |
| 2412 | |
| 2413 | switch_sql_mode(sql_file, delimiter, row[1]); |
| 2414 | |
| 2415 | switch_time_zone(sql_file, delimiter, row[2]); |
| 2416 | |
| 2417 | query_str= cover_definer_clause(row[3], strlen(row[3]), |
| 2418 | C_STRING_WITH_LEN("50117" ), |
| 2419 | C_STRING_WITH_LEN("50106" ), |
| 2420 | C_STRING_WITH_LEN(" EVENT" )); |
| 2421 | |
| 2422 | fprintf(sql_file, |
| 2423 | "/*!50106 %s */ %s\n" , |
| 2424 | (const char *) (query_str != NULL ? query_str : row[3]), |
| 2425 | (const char *) delimiter); |
| 2426 | |
| 2427 | my_free(query_str); |
| 2428 | restore_time_zone(sql_file, delimiter); |
| 2429 | restore_sql_mode(sql_file, delimiter); |
| 2430 | |
| 2431 | if (mysql_num_fields(event_res) >= 7) |
| 2432 | { |
| 2433 | restore_cs_variables(sql_file, delimiter); |
| 2434 | |
| 2435 | if (db_cl_altered) |
| 2436 | { |
| 2437 | if (restore_db_collation(sql_file, db_name_buff, delimiter, |
| 2438 | db_cl_name)) |
| 2439 | DBUG_RETURN(1); |
| 2440 | } |
| 2441 | } |
| 2442 | } |
| 2443 | } /* end of event printing */ |
| 2444 | mysql_free_result(event_res); |
| 2445 | |
| 2446 | } /* end of list of events */ |
| 2447 | if (opt_xml) |
| 2448 | { |
| 2449 | fputs("\t</events>\n" , sql_file); |
| 2450 | check_io(sql_file); |
| 2451 | } |
| 2452 | else |
| 2453 | { |
| 2454 | fprintf(sql_file, "DELIMITER ;\n" ); |
| 2455 | fprintf(sql_file, "/*!50106 SET TIME_ZONE= @save_time_zone */ ;\n" ); |
| 2456 | } |
| 2457 | |
| 2458 | if (switch_character_set_results(mysql, default_charset)) |
| 2459 | DBUG_RETURN(1); |
| 2460 | } |
| 2461 | mysql_free_result(event_list_res); |
| 2462 | |
| 2463 | if (lock_tables) |
| 2464 | (void) mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES" ); |
| 2465 | DBUG_RETURN(0); |
| 2466 | } |
| 2467 | |
| 2468 | |
| 2469 | /* |
| 2470 | Print hex value for blob data. |
| 2471 | |
| 2472 | SYNOPSIS |
| 2473 | print_blob_as_hex() |
| 2474 | output_file - output file |
| 2475 | str - string to print |
| 2476 | len - its length |
| 2477 | |
| 2478 | DESCRIPTION |
| 2479 | Print hex value for blob data. |
| 2480 | */ |
| 2481 | |
| 2482 | static void print_blob_as_hex(FILE *output_file, const char *str, ulong len) |
| 2483 | { |
| 2484 | /* sakaik got the idea to to provide blob's in hex notation. */ |
| 2485 | const char *ptr= str, *end= ptr + len; |
| 2486 | for (; ptr < end ; ptr++) |
| 2487 | fprintf(output_file, "%02X" , *((uchar *)ptr)); |
| 2488 | check_io(output_file); |
| 2489 | } |
| 2490 | |
| 2491 | /* |
| 2492 | dump_routines_for_db |
| 2493 | -- retrieves list of routines for a given db, and prints out |
| 2494 | the CREATE PROCEDURE definition into the output (the dump). |
| 2495 | |
| 2496 | This function has logic to print the appropriate syntax depending on whether |
| 2497 | this is a procedure or functions |
| 2498 | |
| 2499 | RETURN |
| 2500 | 0 Success |
| 2501 | 1 Error |
| 2502 | */ |
| 2503 | |
| 2504 | static uint dump_routines_for_db(char *db) |
| 2505 | { |
| 2506 | char query_buff[QUERY_LENGTH]; |
| 2507 | const char *routine_type[]= {"FUNCTION" , |
| 2508 | "PROCEDURE" , |
| 2509 | "PACKAGE" , |
| 2510 | "PACKAGE BODY" }; |
| 2511 | const char *create_caption_xml[]= {"Create Function" , |
| 2512 | "Create Procedure" , |
| 2513 | "Create Package" , |
| 2514 | "Create Package Body" }; |
| 2515 | char db_name_buff[NAME_LEN*2+3], name_buff[NAME_LEN*2+3]; |
| 2516 | char *routine_name; |
| 2517 | uint i; |
| 2518 | FILE *sql_file= md_result_file; |
| 2519 | MYSQL_ROW row, routine_list_row; |
| 2520 | |
| 2521 | char db_cl_name[MY_CS_NAME_SIZE]; |
| 2522 | int db_cl_altered= FALSE; |
| 2523 | |
| 2524 | DBUG_ENTER("dump_routines_for_db" ); |
| 2525 | DBUG_PRINT("enter" , ("db: '%s'" , db)); |
| 2526 | |
| 2527 | mysql_real_escape_string(mysql, db_name_buff, db, (ulong)strlen(db)); |
| 2528 | |
| 2529 | /* nice comments */ |
| 2530 | print_comment(sql_file, 0, |
| 2531 | "\n--\n-- Dumping routines for database '%s'\n--\n" , |
| 2532 | fix_for_comment(db)); |
| 2533 | |
| 2534 | /* |
| 2535 | not using "mysql_query_with_error_report" because we may have not |
| 2536 | enough privileges to lock mysql.proc. |
| 2537 | */ |
| 2538 | if (lock_tables) |
| 2539 | mysql_query(mysql, "LOCK TABLES mysql.proc READ" ); |
| 2540 | |
| 2541 | /* Get database collation. */ |
| 2542 | |
| 2543 | if (fetch_db_collation(db, db_cl_name, sizeof (db_cl_name))) |
| 2544 | DBUG_RETURN(1); |
| 2545 | |
| 2546 | if (switch_character_set_results(mysql, "binary" )) |
| 2547 | DBUG_RETURN(1); |
| 2548 | |
| 2549 | if (opt_xml) |
| 2550 | fputs("\t<routines>\n" , sql_file); |
| 2551 | |
| 2552 | /* 0, retrieve and dump functions, 1, procedures, etc. */ |
| 2553 | for (i= 0; i < array_elements(routine_type); i++) |
| 2554 | { |
| 2555 | my_snprintf(query_buff, sizeof(query_buff), |
| 2556 | "SHOW %s STATUS WHERE Db = '%s'" , |
| 2557 | routine_type[i], db_name_buff); |
| 2558 | |
| 2559 | if (mysql_query_with_error_report(mysql, &routine_list_res, query_buff)) |
| 2560 | DBUG_RETURN(1); |
| 2561 | |
| 2562 | if (mysql_num_rows(routine_list_res)) |
| 2563 | { |
| 2564 | |
| 2565 | while ((routine_list_row= mysql_fetch_row(routine_list_res))) |
| 2566 | { |
| 2567 | routine_name= quote_name(routine_list_row[1], name_buff, 0); |
| 2568 | DBUG_PRINT("info" , ("retrieving CREATE %s for %s" , routine_type[i], |
| 2569 | name_buff)); |
| 2570 | my_snprintf(query_buff, sizeof(query_buff), "SHOW CREATE %s %s" , |
| 2571 | routine_type[i], routine_name); |
| 2572 | |
| 2573 | if (mysql_query_with_error_report(mysql, &routine_res, query_buff)) |
| 2574 | { |
| 2575 | mysql_free_result(routine_list_res); |
| 2576 | routine_list_res= 0; |
| 2577 | DBUG_RETURN(1); |
| 2578 | } |
| 2579 | |
| 2580 | while ((row= mysql_fetch_row(routine_res))) |
| 2581 | { |
| 2582 | /* |
| 2583 | if the user has EXECUTE privilege he see routine names, but NOT the |
| 2584 | routine body of other routines that are not the creator of! |
| 2585 | */ |
| 2586 | DBUG_PRINT("info" ,("length of body for %s row[2] '%s' is %zu" , |
| 2587 | routine_name, row[2] ? row[2] : "(null)" , |
| 2588 | row[2] ? strlen(row[2]) : 0)); |
| 2589 | if (row[2] == NULL) |
| 2590 | { |
| 2591 | print_comment(sql_file, 1, "\n-- insufficient privileges to %s\n" , |
| 2592 | query_buff); |
| 2593 | print_comment(sql_file, 1, |
| 2594 | "-- does %s have permissions on mysql.proc?\n\n" , |
| 2595 | fix_for_comment(current_user)); |
| 2596 | maybe_die(EX_MYSQLERR,"%s has insufficent privileges to %s!" , |
| 2597 | current_user, query_buff); |
| 2598 | } |
| 2599 | else if (strlen(row[2])) |
| 2600 | { |
| 2601 | if (opt_xml) |
| 2602 | { |
| 2603 | print_xml_row(sql_file, "routine" , routine_res, &row, |
| 2604 | create_caption_xml[i]); |
| 2605 | continue; |
| 2606 | } |
| 2607 | if (opt_drop) |
| 2608 | fprintf(sql_file, "/*!50003 DROP %s IF EXISTS %s */;\n" , |
| 2609 | routine_type[i], routine_name); |
| 2610 | |
| 2611 | if (mysql_num_fields(routine_res) >= 6) |
| 2612 | { |
| 2613 | if (switch_db_collation(sql_file, db, ";" , |
| 2614 | db_cl_name, row[5], &db_cl_altered)) |
| 2615 | { |
| 2616 | mysql_free_result(routine_res); |
| 2617 | mysql_free_result(routine_list_res); |
| 2618 | routine_res= routine_list_res= 0; |
| 2619 | DBUG_RETURN(1); |
| 2620 | } |
| 2621 | |
| 2622 | switch_cs_variables(sql_file, ";" , |
| 2623 | row[3], /* character_set_client */ |
| 2624 | row[3], /* character_set_results */ |
| 2625 | row[4]); /* collation_connection */ |
| 2626 | } |
| 2627 | else |
| 2628 | { |
| 2629 | /* |
| 2630 | mysqldump is being run against the server, that does not |
| 2631 | provide character set information in SHOW CREATE |
| 2632 | statements. |
| 2633 | |
| 2634 | NOTE: the dump may be incorrect, since character set |
| 2635 | information is required in order to restore stored |
| 2636 | procedure/function properly. |
| 2637 | */ |
| 2638 | |
| 2639 | fprintf(sql_file, |
| 2640 | "--\n" |
| 2641 | "-- WARNING: old server version. " |
| 2642 | "The following dump may be incomplete.\n" |
| 2643 | "--\n" ); |
| 2644 | } |
| 2645 | |
| 2646 | |
| 2647 | switch_sql_mode(sql_file, ";" , row[1]); |
| 2648 | |
| 2649 | fprintf(sql_file, |
| 2650 | "DELIMITER ;;\n" |
| 2651 | "%s ;;\n" |
| 2652 | "DELIMITER ;\n" , |
| 2653 | (const char *) row[2]); |
| 2654 | |
| 2655 | restore_sql_mode(sql_file, ";" ); |
| 2656 | |
| 2657 | if (mysql_num_fields(routine_res) >= 6) |
| 2658 | { |
| 2659 | restore_cs_variables(sql_file, ";" ); |
| 2660 | |
| 2661 | if (db_cl_altered) |
| 2662 | { |
| 2663 | if (restore_db_collation(sql_file, db, ";" , db_cl_name)) |
| 2664 | { |
| 2665 | mysql_free_result(routine_res); |
| 2666 | mysql_free_result(routine_list_res); |
| 2667 | routine_res= routine_list_res= 0; |
| 2668 | DBUG_RETURN(1); |
| 2669 | } |
| 2670 | } |
| 2671 | } |
| 2672 | |
| 2673 | } |
| 2674 | } /* end of routine printing */ |
| 2675 | mysql_free_result(routine_res); |
| 2676 | routine_res= 0; |
| 2677 | |
| 2678 | } /* end of list of routines */ |
| 2679 | } |
| 2680 | mysql_free_result(routine_list_res); |
| 2681 | routine_list_res= 0; |
| 2682 | } /* end of for i (0 .. 1) */ |
| 2683 | |
| 2684 | if (opt_xml) |
| 2685 | { |
| 2686 | fputs("\t</routines>\n" , sql_file); |
| 2687 | check_io(sql_file); |
| 2688 | } |
| 2689 | |
| 2690 | if (switch_character_set_results(mysql, default_charset)) |
| 2691 | DBUG_RETURN(1); |
| 2692 | |
| 2693 | if (lock_tables) |
| 2694 | (void) mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES" ); |
| 2695 | DBUG_RETURN(0); |
| 2696 | } |
| 2697 | |
| 2698 | /* general_log or slow_log tables under mysql database */ |
| 2699 | static inline my_bool general_log_or_slow_log_tables(const char *db, |
| 2700 | const char *table) |
| 2701 | { |
| 2702 | return (!my_strcasecmp(charset_info, db, "mysql" )) && |
| 2703 | (!my_strcasecmp(charset_info, table, "general_log" ) || |
| 2704 | !my_strcasecmp(charset_info, table, "slow_log" ) || |
| 2705 | !my_strcasecmp(charset_info, table, "transaction_registry" )); |
| 2706 | } |
| 2707 | |
| 2708 | /* |
| 2709 | get_table_structure -- retrievs database structure, prints out corresponding |
| 2710 | CREATE statement and fills out insert_pat if the table is the type we will |
| 2711 | be dumping. |
| 2712 | |
| 2713 | ARGS |
| 2714 | table - table name |
| 2715 | db - db name |
| 2716 | table_type - table type, e.g. "MyISAM" or "InnoDB", but also "VIEW" |
| 2717 | ignore_flag - what we must particularly ignore - see IGNORE_ defines above |
| 2718 | |
| 2719 | RETURN |
| 2720 | number of fields in table, 0 if error |
| 2721 | */ |
| 2722 | |
| 2723 | static uint get_table_structure(char *table, char *db, char *table_type, |
| 2724 | char *ignore_flag) |
| 2725 | { |
| 2726 | my_bool init=0, delayed, write_data, complete_insert; |
| 2727 | my_ulonglong num_fields; |
| 2728 | char *result_table, *opt_quoted_table; |
| 2729 | const char *insert_option; |
| 2730 | char name_buff[NAME_LEN+3],table_buff[NAME_LEN*2+3]; |
| 2731 | char table_buff2[NAME_LEN*2+3], query_buff[QUERY_LENGTH]; |
| 2732 | char temp_buff[NAME_LEN*2 + 3], temp_buff2[NAME_LEN*2 + 3]; |
| 2733 | const char *show_fields_stmt= "SELECT `COLUMN_NAME` AS `Field`, " |
| 2734 | "`COLUMN_TYPE` AS `Type`, " |
| 2735 | "`IS_NULLABLE` AS `Null`, " |
| 2736 | "`COLUMN_KEY` AS `Key`, " |
| 2737 | "`COLUMN_DEFAULT` AS `Default`, " |
| 2738 | "`EXTRA` AS `Extra`, " |
| 2739 | "`COLUMN_COMMENT` AS `Comment` " |
| 2740 | "FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE " |
| 2741 | "TABLE_SCHEMA = %s AND TABLE_NAME = %s" ; |
| 2742 | FILE *sql_file= md_result_file; |
| 2743 | size_t len; |
| 2744 | my_bool is_log_table; |
| 2745 | MYSQL_RES *result; |
| 2746 | MYSQL_ROW row; |
| 2747 | DBUG_ENTER("get_table_structure" ); |
| 2748 | DBUG_PRINT("enter" , ("db: %s table: %s" , db, table)); |
| 2749 | |
| 2750 | *ignore_flag= check_if_ignore_table(table, table_type); |
| 2751 | |
| 2752 | delayed= opt_delayed; |
| 2753 | if (delayed && (*ignore_flag & IGNORE_INSERT_DELAYED)) |
| 2754 | { |
| 2755 | delayed= 0; |
| 2756 | verbose_msg("-- Warning: Unable to use delayed inserts for table '%s' " |
| 2757 | "because it's of type %s\n" , table, table_type); |
| 2758 | } |
| 2759 | |
| 2760 | complete_insert= 0; |
| 2761 | if ((write_data= !(*ignore_flag & IGNORE_DATA))) |
| 2762 | { |
| 2763 | complete_insert= opt_complete_insert; |
| 2764 | if (!insert_pat_inited) |
| 2765 | { |
| 2766 | insert_pat_inited= 1; |
| 2767 | init_dynamic_string_checked(&insert_pat, "" , 1024, 1024); |
| 2768 | } |
| 2769 | else |
| 2770 | dynstr_set_checked(&insert_pat, "" ); |
| 2771 | } |
| 2772 | if (!select_field_names_inited) |
| 2773 | { |
| 2774 | select_field_names_inited= 1; |
| 2775 | init_dynamic_string_checked(&select_field_names, "" , 1024, 1024); |
| 2776 | } |
| 2777 | else |
| 2778 | dynstr_set_checked(&select_field_names, "" ); |
| 2779 | insert_option= ((delayed && opt_ignore) ? " DELAYED IGNORE " : |
| 2780 | delayed ? " DELAYED " : opt_ignore ? " IGNORE " : "" ); |
| 2781 | |
| 2782 | verbose_msg("-- Retrieving table structure for table %s...\n" , table); |
| 2783 | |
| 2784 | len= my_snprintf(query_buff, sizeof(query_buff), |
| 2785 | "SET SQL_QUOTE_SHOW_CREATE=%d" , |
| 2786 | (opt_quoted || opt_keywords)); |
| 2787 | if (!create_options) |
| 2788 | strmov(query_buff+len, |
| 2789 | "/*!40102 ,SQL_MODE=concat(@@sql_mode, _utf8 ',NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS') */" ); |
| 2790 | |
| 2791 | result_table= quote_name(table, table_buff, 1); |
| 2792 | opt_quoted_table= quote_name(table, table_buff2, 0); |
| 2793 | |
| 2794 | if (opt_order_by_primary) |
| 2795 | order_by= primary_key_fields(result_table); |
| 2796 | |
| 2797 | if (!opt_xml && !mysql_query_with_error_report(mysql, 0, query_buff)) |
| 2798 | { |
| 2799 | /* using SHOW CREATE statement */ |
| 2800 | if (!opt_no_create_info) |
| 2801 | { |
| 2802 | /* Make an sql-file, if path was given iow. option -T was given */ |
| 2803 | char buff[20+FN_REFLEN]; |
| 2804 | MYSQL_FIELD *field; |
| 2805 | |
| 2806 | my_snprintf(buff, sizeof(buff), "show create table %s" , result_table); |
| 2807 | |
| 2808 | if (switch_character_set_results(mysql, "binary" ) || |
| 2809 | mysql_query_with_error_report(mysql, &result, buff) || |
| 2810 | switch_character_set_results(mysql, default_charset)) |
| 2811 | { |
| 2812 | my_free(order_by); |
| 2813 | order_by= 0; |
| 2814 | DBUG_RETURN(0); |
| 2815 | } |
| 2816 | |
| 2817 | if (path) |
| 2818 | { |
| 2819 | if (!(sql_file= open_sql_file_for_table(table, O_WRONLY))) |
| 2820 | { |
| 2821 | my_free(order_by); |
| 2822 | order_by= 0; |
| 2823 | DBUG_RETURN(0); |
| 2824 | } |
| 2825 | write_header(sql_file, db); |
| 2826 | } |
| 2827 | |
| 2828 | if (strcmp (table_type, "VIEW" ) == 0) /* view */ |
| 2829 | print_comment(sql_file, 0, |
| 2830 | "\n--\n-- Temporary table structure for view %s\n--\n\n" , |
| 2831 | fix_for_comment(result_table)); |
| 2832 | else |
| 2833 | print_comment(sql_file, 0, |
| 2834 | "\n--\n-- Table structure for table %s\n--\n\n" , |
| 2835 | fix_for_comment(result_table)); |
| 2836 | |
| 2837 | if (opt_drop) |
| 2838 | { |
| 2839 | /* |
| 2840 | Even if the "table" is a view, we do a DROP TABLE here. The |
| 2841 | view-specific code below fills in the DROP VIEW. |
| 2842 | We will skip the DROP TABLE for general_log and slow_log, since |
| 2843 | those stmts will fail, in case we apply dump by enabling logging. |
| 2844 | */ |
| 2845 | if (!general_log_or_slow_log_tables(db, table)) |
| 2846 | fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n" , |
| 2847 | opt_quoted_table); |
| 2848 | check_io(sql_file); |
| 2849 | } |
| 2850 | |
| 2851 | field= mysql_fetch_field_direct(result, 0); |
| 2852 | if (strcmp(field->name, "View" ) == 0) |
| 2853 | { |
| 2854 | char *scv_buff= NULL; |
| 2855 | my_ulonglong n_cols; |
| 2856 | |
| 2857 | verbose_msg("-- It's a view, create dummy table for view\n" ); |
| 2858 | |
| 2859 | /* save "show create" statement for later */ |
| 2860 | if ((row= mysql_fetch_row(result)) && (scv_buff=row[1])) |
| 2861 | scv_buff= my_strdup(scv_buff, MYF(0)); |
| 2862 | |
| 2863 | mysql_free_result(result); |
| 2864 | |
| 2865 | /* |
| 2866 | Create a table with the same name as the view and with columns of |
| 2867 | the same name in order to satisfy views that depend on this view. |
| 2868 | The table will be removed when the actual view is created. |
| 2869 | |
| 2870 | The properties of each column, are not preserved in this temporary |
| 2871 | table, because they are not necessary. |
| 2872 | |
| 2873 | This will not be necessary once we can determine dependencies |
| 2874 | between views and can simply dump them in the appropriate order. |
| 2875 | */ |
| 2876 | my_snprintf(query_buff, sizeof(query_buff), |
| 2877 | "SHOW FIELDS FROM %s" , result_table); |
| 2878 | if (switch_character_set_results(mysql, "binary" ) || |
| 2879 | mysql_query_with_error_report(mysql, &result, query_buff) || |
| 2880 | switch_character_set_results(mysql, default_charset)) |
| 2881 | { |
| 2882 | /* |
| 2883 | View references invalid or privileged table/col/fun (err 1356), |
| 2884 | so we cannot create a stand-in table. Be defensive and dump |
| 2885 | a comment with the view's 'show create' statement. (Bug #17371) |
| 2886 | */ |
| 2887 | |
| 2888 | if (mysql_errno(mysql) == ER_VIEW_INVALID) |
| 2889 | fprintf(sql_file, "\n-- failed on view %s: %s\n\n" , result_table, scv_buff ? scv_buff : "" ); |
| 2890 | |
| 2891 | my_free(scv_buff); |
| 2892 | |
| 2893 | if (path) |
| 2894 | my_fclose(sql_file, MYF(MY_WME)); |
| 2895 | DBUG_RETURN(0); |
| 2896 | } |
| 2897 | else |
| 2898 | my_free(scv_buff); |
| 2899 | |
| 2900 | n_cols= mysql_num_rows(result); |
| 2901 | if (0 != n_cols) |
| 2902 | { |
| 2903 | |
| 2904 | /* |
| 2905 | The actual formula is based on the column names and how the .FRM |
| 2906 | files are stored and is too volatile to be repeated here. |
| 2907 | Thus we simply warn the user if the columns exceed a limit we |
| 2908 | know works most of the time. |
| 2909 | */ |
| 2910 | if (n_cols >= 1000) |
| 2911 | fprintf(stderr, |
| 2912 | "-- Warning: Creating a stand-in table for view %s may" |
| 2913 | " fail when replaying the dump file produced because " |
| 2914 | "of the number of columns exceeding 1000. Exercise " |
| 2915 | "caution when replaying the produced dump file.\n" , |
| 2916 | table); |
| 2917 | if (opt_drop) |
| 2918 | { |
| 2919 | /* |
| 2920 | We have already dropped any table of the same name above, so |
| 2921 | here we just drop the view. |
| 2922 | */ |
| 2923 | |
| 2924 | fprintf(sql_file, "/*!50001 DROP VIEW IF EXISTS %s*/;\n" , |
| 2925 | opt_quoted_table); |
| 2926 | check_io(sql_file); |
| 2927 | } |
| 2928 | |
| 2929 | fprintf(sql_file, |
| 2930 | "SET @saved_cs_client = @@character_set_client;\n" |
| 2931 | "SET character_set_client = utf8;\n" |
| 2932 | "/*!50001 CREATE TABLE %s (\n" , |
| 2933 | result_table); |
| 2934 | |
| 2935 | /* |
| 2936 | Get first row, following loop will prepend comma - keeps from |
| 2937 | having to know if the row being printed is last to determine if |
| 2938 | there should be a _trailing_ comma. |
| 2939 | */ |
| 2940 | |
| 2941 | row= mysql_fetch_row(result); |
| 2942 | |
| 2943 | /* |
| 2944 | The actual column type doesn't matter anyway, since the table will |
| 2945 | be dropped at run time. |
| 2946 | We do tinyint to avoid hitting the row size limit. |
| 2947 | */ |
| 2948 | fprintf(sql_file, " %s tinyint NOT NULL" , |
| 2949 | quote_name(row[0], name_buff, 0)); |
| 2950 | |
| 2951 | while((row= mysql_fetch_row(result))) |
| 2952 | { |
| 2953 | /* col name, col type */ |
| 2954 | fprintf(sql_file, ",\n %s tinyint NOT NULL" , |
| 2955 | quote_name(row[0], name_buff, 0)); |
| 2956 | } |
| 2957 | |
| 2958 | /* |
| 2959 | Stand-in tables are always MyISAM tables as the default |
| 2960 | engine might have a column-limit that's lower than the |
| 2961 | number of columns in the view, and MyISAM support is |
| 2962 | guaranteed to be in the server anyway. |
| 2963 | */ |
| 2964 | fprintf(sql_file, |
| 2965 | "\n) ENGINE=MyISAM */;\n" |
| 2966 | "SET character_set_client = @saved_cs_client;\n" ); |
| 2967 | |
| 2968 | check_io(sql_file); |
| 2969 | } |
| 2970 | |
| 2971 | mysql_free_result(result); |
| 2972 | |
| 2973 | if (path) |
| 2974 | my_fclose(sql_file, MYF(MY_WME)); |
| 2975 | |
| 2976 | seen_views= 1; |
| 2977 | DBUG_RETURN(0); |
| 2978 | } |
| 2979 | |
| 2980 | row= mysql_fetch_row(result); |
| 2981 | |
| 2982 | is_log_table= general_log_or_slow_log_tables(db, table); |
| 2983 | if (is_log_table) |
| 2984 | row[1]+= 13; /* strlen("CREATE TABLE ")= 13 */ |
| 2985 | if (opt_compatible_mode & 3) |
| 2986 | { |
| 2987 | fprintf(sql_file, |
| 2988 | is_log_table ? "CREATE TABLE IF NOT EXISTS %s;\n" : "%s;\n" , |
| 2989 | row[1]); |
| 2990 | } |
| 2991 | else |
| 2992 | { |
| 2993 | fprintf(sql_file, |
| 2994 | "/*!40101 SET @saved_cs_client = @@character_set_client */;\n" |
| 2995 | "/*!40101 SET character_set_client = utf8 */;\n" |
| 2996 | "%s%s;\n" |
| 2997 | "/*!40101 SET character_set_client = @saved_cs_client */;\n" , |
| 2998 | is_log_table ? "CREATE TABLE IF NOT EXISTS " : "" , |
| 2999 | row[1]); |
| 3000 | } |
| 3001 | |
| 3002 | check_io(sql_file); |
| 3003 | mysql_free_result(result); |
| 3004 | } |
| 3005 | my_snprintf(query_buff, sizeof(query_buff), "show fields from %s" , |
| 3006 | result_table); |
| 3007 | if (mysql_query_with_error_report(mysql, &result, query_buff)) |
| 3008 | { |
| 3009 | if (path) |
| 3010 | my_fclose(sql_file, MYF(MY_WME)); |
| 3011 | DBUG_RETURN(0); |
| 3012 | } |
| 3013 | |
| 3014 | while ((row= mysql_fetch_row(result))) |
| 3015 | { |
| 3016 | if (strlen(row[SHOW_EXTRA]) && strstr(row[SHOW_EXTRA],"INVISIBLE" )) |
| 3017 | complete_insert= 1; |
| 3018 | if (init) |
| 3019 | { |
| 3020 | dynstr_append_checked(&select_field_names, ", " ); |
| 3021 | } |
| 3022 | init=1; |
| 3023 | dynstr_append_checked(&select_field_names, |
| 3024 | quote_name(row[SHOW_FIELDNAME], name_buff, 0)); |
| 3025 | } |
| 3026 | init=0; |
| 3027 | /* |
| 3028 | If write_data is true, then we build up insert statements for |
| 3029 | the table's data. Note: in subsequent lines of code, this test |
| 3030 | will have to be performed each time we are appending to |
| 3031 | insert_pat. |
| 3032 | */ |
| 3033 | if (write_data) |
| 3034 | { |
| 3035 | if (opt_replace_into) |
| 3036 | dynstr_append_checked(&insert_pat, "REPLACE " ); |
| 3037 | else |
| 3038 | dynstr_append_checked(&insert_pat, "INSERT " ); |
| 3039 | dynstr_append_checked(&insert_pat, insert_option); |
| 3040 | dynstr_append_checked(&insert_pat, "INTO " ); |
| 3041 | dynstr_append_checked(&insert_pat, opt_quoted_table); |
| 3042 | if (complete_insert) |
| 3043 | { |
| 3044 | dynstr_append_checked(&insert_pat, " (" ); |
| 3045 | } |
| 3046 | else |
| 3047 | { |
| 3048 | dynstr_append_checked(&insert_pat, " VALUES " ); |
| 3049 | if (!extended_insert) |
| 3050 | dynstr_append_checked(&insert_pat, "(" ); |
| 3051 | } |
| 3052 | } |
| 3053 | |
| 3054 | if (complete_insert) |
| 3055 | dynstr_append_checked(&insert_pat, select_field_names.str); |
| 3056 | num_fields= mysql_num_rows(result); |
| 3057 | mysql_free_result(result); |
| 3058 | } |
| 3059 | else |
| 3060 | { |
| 3061 | verbose_msg("%s: Warning: Can't set SQL_QUOTE_SHOW_CREATE option (%s)\n" , |
| 3062 | my_progname_short, mysql_error(mysql)); |
| 3063 | |
| 3064 | my_snprintf(query_buff, sizeof(query_buff), show_fields_stmt, |
| 3065 | quote_for_equal(db, temp_buff), |
| 3066 | quote_for_equal(table, temp_buff2)); |
| 3067 | |
| 3068 | if (mysql_query_with_error_report(mysql, &result, query_buff)) |
| 3069 | DBUG_RETURN(0); |
| 3070 | |
| 3071 | /* Make an sql-file, if path was given iow. option -T was given */ |
| 3072 | if (!opt_no_create_info) |
| 3073 | { |
| 3074 | if (path) |
| 3075 | { |
| 3076 | if (!(sql_file= open_sql_file_for_table(table, O_WRONLY))) |
| 3077 | DBUG_RETURN(0); |
| 3078 | write_header(sql_file, db); |
| 3079 | } |
| 3080 | |
| 3081 | print_comment(sql_file, 0, |
| 3082 | "\n--\n-- Table structure for table %s\n--\n\n" , |
| 3083 | fix_for_comment(result_table)); |
| 3084 | if (opt_drop) |
| 3085 | fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n" , result_table); |
| 3086 | if (!opt_xml) |
| 3087 | fprintf(sql_file, "CREATE TABLE %s (\n" , result_table); |
| 3088 | else |
| 3089 | print_xml_tag(sql_file, "\t" , "\n" , "table_structure" , "name=" , table, |
| 3090 | NullS); |
| 3091 | check_io(sql_file); |
| 3092 | } |
| 3093 | |
| 3094 | if (write_data) |
| 3095 | { |
| 3096 | if (opt_replace_into) |
| 3097 | dynstr_append_checked(&insert_pat, "REPLACE " ); |
| 3098 | else |
| 3099 | dynstr_append_checked(&insert_pat, "INSERT " ); |
| 3100 | dynstr_append_checked(&insert_pat, insert_option); |
| 3101 | dynstr_append_checked(&insert_pat, "INTO " ); |
| 3102 | dynstr_append_checked(&insert_pat, result_table); |
| 3103 | if (complete_insert) |
| 3104 | dynstr_append_checked(&insert_pat, " (" ); |
| 3105 | else |
| 3106 | { |
| 3107 | dynstr_append_checked(&insert_pat, " VALUES " ); |
| 3108 | if (!extended_insert) |
| 3109 | dynstr_append_checked(&insert_pat, "(" ); |
| 3110 | } |
| 3111 | } |
| 3112 | |
| 3113 | while ((row= mysql_fetch_row(result))) |
| 3114 | { |
| 3115 | if (strlen(row[SHOW_EXTRA]) && strstr(row[SHOW_EXTRA],"INVISIBLE" )) |
| 3116 | complete_insert= 1; |
| 3117 | if (init) |
| 3118 | { |
| 3119 | dynstr_append_checked(&select_field_names, ", " ); |
| 3120 | } |
| 3121 | dynstr_append_checked(&select_field_names, |
| 3122 | quote_name(row[SHOW_FIELDNAME], name_buff, 0)); |
| 3123 | init=1; |
| 3124 | } |
| 3125 | init=0; |
| 3126 | mysql_data_seek(result, 0); |
| 3127 | |
| 3128 | while ((row= mysql_fetch_row(result))) |
| 3129 | { |
| 3130 | ulong *lengths= mysql_fetch_lengths(result); |
| 3131 | if (init) |
| 3132 | { |
| 3133 | if (!opt_xml && !opt_no_create_info) |
| 3134 | { |
| 3135 | fputs(",\n" ,sql_file); |
| 3136 | check_io(sql_file); |
| 3137 | } |
| 3138 | if (complete_insert) |
| 3139 | dynstr_append_checked(&insert_pat, ", " ); |
| 3140 | } |
| 3141 | init=1; |
| 3142 | if (complete_insert) |
| 3143 | dynstr_append_checked(&insert_pat, |
| 3144 | quote_name(row[SHOW_FIELDNAME], name_buff, 0)); |
| 3145 | if (!opt_no_create_info) |
| 3146 | { |
| 3147 | if (opt_xml) |
| 3148 | { |
| 3149 | print_xml_row(sql_file, "field" , result, &row, NullS); |
| 3150 | continue; |
| 3151 | } |
| 3152 | |
| 3153 | if (opt_keywords) |
| 3154 | fprintf(sql_file, " %s.%s %s" , result_table, |
| 3155 | quote_name(row[SHOW_FIELDNAME],name_buff, 0), |
| 3156 | row[SHOW_TYPE]); |
| 3157 | else |
| 3158 | fprintf(sql_file, " %s %s" , quote_name(row[SHOW_FIELDNAME], |
| 3159 | name_buff, 0), |
| 3160 | row[SHOW_TYPE]); |
| 3161 | if (row[SHOW_DEFAULT]) |
| 3162 | { |
| 3163 | fputs(" DEFAULT " , sql_file); |
| 3164 | unescape(sql_file, row[SHOW_DEFAULT], lengths[SHOW_DEFAULT]); |
| 3165 | } |
| 3166 | if (!row[SHOW_NULL][0]) |
| 3167 | fputs(" NOT NULL" , sql_file); |
| 3168 | if (row[SHOW_EXTRA][0]) |
| 3169 | fprintf(sql_file, " %s" ,row[SHOW_EXTRA]); |
| 3170 | check_io(sql_file); |
| 3171 | } |
| 3172 | } |
| 3173 | num_fields= mysql_num_rows(result); |
| 3174 | mysql_free_result(result); |
| 3175 | if (!opt_no_create_info) |
| 3176 | { |
| 3177 | /* Make an sql-file, if path was given iow. option -T was given */ |
| 3178 | char buff[20+FN_REFLEN]; |
| 3179 | uint keynr,primary_key; |
| 3180 | my_snprintf(buff, sizeof(buff), "show keys from %s" , result_table); |
| 3181 | if (mysql_query_with_error_report(mysql, &result, buff)) |
| 3182 | { |
| 3183 | if (mysql_errno(mysql) == ER_WRONG_OBJECT) |
| 3184 | { |
| 3185 | /* it is VIEW */ |
| 3186 | fputs("\t\t<options Comment=\"view\" />\n" , sql_file); |
| 3187 | goto continue_xml; |
| 3188 | } |
| 3189 | fprintf(stderr, "%s: Can't get keys for table %s (%s)\n" , |
| 3190 | my_progname_short, result_table, mysql_error(mysql)); |
| 3191 | if (path) |
| 3192 | my_fclose(sql_file, MYF(MY_WME)); |
| 3193 | DBUG_RETURN(0); |
| 3194 | } |
| 3195 | |
| 3196 | /* Find first which key is primary key */ |
| 3197 | keynr=0; |
| 3198 | primary_key=INT_MAX; |
| 3199 | while ((row= mysql_fetch_row(result))) |
| 3200 | { |
| 3201 | if (atoi(row[3]) == 1) |
| 3202 | { |
| 3203 | keynr++; |
| 3204 | #ifdef FORCE_PRIMARY_KEY |
| 3205 | if (atoi(row[1]) == 0 && primary_key == INT_MAX) |
| 3206 | primary_key=keynr; |
| 3207 | #endif |
| 3208 | if (!strcmp(row[2],"PRIMARY" )) |
| 3209 | { |
| 3210 | primary_key=keynr; |
| 3211 | break; |
| 3212 | } |
| 3213 | } |
| 3214 | } |
| 3215 | mysql_data_seek(result,0); |
| 3216 | keynr=0; |
| 3217 | while ((row= mysql_fetch_row(result))) |
| 3218 | { |
| 3219 | if (opt_xml) |
| 3220 | { |
| 3221 | print_xml_row(sql_file, "key" , result, &row, NullS); |
| 3222 | continue; |
| 3223 | } |
| 3224 | |
| 3225 | if (atoi(row[3]) == 1) |
| 3226 | { |
| 3227 | if (keynr++) |
| 3228 | putc(')', sql_file); |
| 3229 | if (atoi(row[1])) /* Test if duplicate key */ |
| 3230 | /* Duplicate allowed */ |
| 3231 | fprintf(sql_file, ",\n KEY %s (" ,quote_name(row[2],name_buff,0)); |
| 3232 | else if (keynr == primary_key) |
| 3233 | fputs(",\n PRIMARY KEY (" ,sql_file); /* First UNIQUE is primary */ |
| 3234 | else |
| 3235 | fprintf(sql_file, ",\n UNIQUE %s (" ,quote_name(row[2],name_buff, |
| 3236 | 0)); |
| 3237 | } |
| 3238 | else |
| 3239 | putc(',', sql_file); |
| 3240 | fputs(quote_name(row[4], name_buff, 0), sql_file); |
| 3241 | if (row[7]) |
| 3242 | fprintf(sql_file, " (%s)" ,row[7]); /* Sub key */ |
| 3243 | check_io(sql_file); |
| 3244 | } |
| 3245 | mysql_free_result(result); |
| 3246 | if (!opt_xml) |
| 3247 | { |
| 3248 | if (keynr) |
| 3249 | putc(')', sql_file); |
| 3250 | fputs("\n)" ,sql_file); |
| 3251 | check_io(sql_file); |
| 3252 | } |
| 3253 | |
| 3254 | /* Get MySQL specific create options */ |
| 3255 | if (create_options) |
| 3256 | { |
| 3257 | char show_name_buff[NAME_LEN*2+2+24]; |
| 3258 | |
| 3259 | /* Check memory for quote_for_like() */ |
| 3260 | my_snprintf(buff, sizeof(buff), "show table status like %s" , |
| 3261 | quote_for_like(table, show_name_buff)); |
| 3262 | |
| 3263 | if (mysql_query_with_error_report(mysql, &result, buff)) |
| 3264 | { |
| 3265 | if (mysql_errno(mysql) != ER_PARSE_ERROR) |
| 3266 | { /* If old MySQL version */ |
| 3267 | verbose_msg("-- Warning: Couldn't get status information for " \ |
| 3268 | "table %s (%s)\n" , result_table,mysql_error(mysql)); |
| 3269 | } |
| 3270 | } |
| 3271 | else if (!(row= mysql_fetch_row(result))) |
| 3272 | { |
| 3273 | fprintf(stderr, |
| 3274 | "Error: Couldn't read status information for table %s (%s)\n" , |
| 3275 | result_table,mysql_error(mysql)); |
| 3276 | } |
| 3277 | else |
| 3278 | { |
| 3279 | if (opt_xml) |
| 3280 | print_xml_row(sql_file, "options" , result, &row, NullS); |
| 3281 | else |
| 3282 | { |
| 3283 | fputs("/*!" ,sql_file); |
| 3284 | print_value(sql_file,result,row,"engine=" ,"Engine" ,0); |
| 3285 | print_value(sql_file,result,row,"" ,"Create_options" ,0); |
| 3286 | print_value(sql_file,result,row,"comment=" ,"Comment" ,1); |
| 3287 | fputs(" */" ,sql_file); |
| 3288 | check_io(sql_file); |
| 3289 | } |
| 3290 | } |
| 3291 | mysql_free_result(result); /* Is always safe to free */ |
| 3292 | } |
| 3293 | continue_xml: |
| 3294 | if (!opt_xml) |
| 3295 | fputs(";\n" , sql_file); |
| 3296 | else |
| 3297 | fputs("\t</table_structure>\n" , sql_file); |
| 3298 | check_io(sql_file); |
| 3299 | } |
| 3300 | } |
| 3301 | if (complete_insert) |
| 3302 | { |
| 3303 | dynstr_append_checked(&insert_pat, ") VALUES " ); |
| 3304 | if (!extended_insert) |
| 3305 | dynstr_append_checked(&insert_pat, "(" ); |
| 3306 | } |
| 3307 | if (sql_file != md_result_file) |
| 3308 | { |
| 3309 | fputs("\n" , sql_file); |
| 3310 | write_footer(sql_file); |
| 3311 | my_fclose(sql_file, MYF(MY_WME)); |
| 3312 | } |
| 3313 | DBUG_RETURN((uint) num_fields); |
| 3314 | } /* get_table_structure */ |
| 3315 | |
| 3316 | static void dump_trigger_old(FILE *sql_file, MYSQL_RES *show_triggers_rs, |
| 3317 | MYSQL_ROW *show_trigger_row, |
| 3318 | const char *table_name) |
| 3319 | { |
| 3320 | char quoted_table_name_buf[NAME_LEN * 2 + 3]; |
| 3321 | char *quoted_table_name= quote_name(table_name, quoted_table_name_buf, 1); |
| 3322 | |
| 3323 | char name_buff[NAME_LEN * 4 + 3]; |
| 3324 | const char *xml_msg= "\nWarning! mysqldump being run against old server " |
| 3325 | "that does not\nsupport 'SHOW CREATE TRIGGERS' " |
| 3326 | "statement. Skipping..\n" ; |
| 3327 | |
| 3328 | DBUG_ENTER("dump_trigger_old" ); |
| 3329 | |
| 3330 | if (opt_xml) |
| 3331 | { |
| 3332 | print_xml_comment(sql_file, strlen(xml_msg), xml_msg); |
| 3333 | check_io(sql_file); |
| 3334 | DBUG_VOID_RETURN; |
| 3335 | } |
| 3336 | |
| 3337 | fprintf(sql_file, |
| 3338 | "--\n" |
| 3339 | "-- WARNING: old server version. " |
| 3340 | "The following dump may be incomplete.\n" |
| 3341 | "--\n" ); |
| 3342 | |
| 3343 | if (opt_compact) |
| 3344 | fprintf(sql_file, "/*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/;\n" ); |
| 3345 | |
| 3346 | if (opt_drop_trigger) |
| 3347 | fprintf(sql_file, "/*!50032 DROP TRIGGER IF EXISTS %s */;\n" , |
| 3348 | (*show_trigger_row)[0]); |
| 3349 | |
| 3350 | fprintf(sql_file, |
| 3351 | "DELIMITER ;;\n" |
| 3352 | "/*!50003 SET SESSION SQL_MODE=\"%s\" */;;\n" |
| 3353 | "/*!50003 CREATE */ " , |
| 3354 | (*show_trigger_row)[6]); |
| 3355 | |
| 3356 | if (mysql_num_fields(show_triggers_rs) > 7) |
| 3357 | { |
| 3358 | /* |
| 3359 | mysqldump can be run against the server, that does not support |
| 3360 | definer in triggers (there is no DEFINER column in SHOW TRIGGERS |
| 3361 | output). So, we should check if we have this column before |
| 3362 | accessing it. |
| 3363 | */ |
| 3364 | |
| 3365 | size_t user_name_len; |
| 3366 | char user_name_str[USERNAME_LENGTH + 1]; |
| 3367 | char quoted_user_name_str[USERNAME_LENGTH * 2 + 3]; |
| 3368 | size_t host_name_len; |
| 3369 | char host_name_str[HOSTNAME_LENGTH + 1]; |
| 3370 | char quoted_host_name_str[HOSTNAME_LENGTH * 2 + 3]; |
| 3371 | |
| 3372 | parse_user((*show_trigger_row)[7], |
| 3373 | strlen((*show_trigger_row)[7]), |
| 3374 | user_name_str, &user_name_len, |
| 3375 | host_name_str, &host_name_len); |
| 3376 | |
| 3377 | fprintf(sql_file, |
| 3378 | "/*!50017 DEFINER=%s@%s */ " , |
| 3379 | quote_name(user_name_str, quoted_user_name_str, FALSE), |
| 3380 | quote_name(host_name_str, quoted_host_name_str, FALSE)); |
| 3381 | } |
| 3382 | |
| 3383 | fprintf(sql_file, |
| 3384 | "/*!50003 TRIGGER %s %s %s ON %s FOR EACH ROW%s%s */;;\n" |
| 3385 | "DELIMITER ;\n" , |
| 3386 | quote_name((*show_trigger_row)[0], name_buff, 0), /* Trigger */ |
| 3387 | (*show_trigger_row)[4], /* Timing */ |
| 3388 | (*show_trigger_row)[1], /* Event */ |
| 3389 | quoted_table_name, |
| 3390 | (strchr(" \t\n\r" , *((*show_trigger_row)[3]))) ? "" : " " , |
| 3391 | (*show_trigger_row)[3] /* Statement */); |
| 3392 | |
| 3393 | if (opt_compact) |
| 3394 | fprintf(sql_file, "/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE */;\n" ); |
| 3395 | |
| 3396 | DBUG_VOID_RETURN; |
| 3397 | } |
| 3398 | |
| 3399 | static int dump_trigger(FILE *sql_file, MYSQL_RES *show_create_trigger_rs, |
| 3400 | const char *db_name, |
| 3401 | const char *db_cl_name) |
| 3402 | { |
| 3403 | MYSQL_ROW row; |
| 3404 | char *query_str; |
| 3405 | int db_cl_altered= FALSE; |
| 3406 | |
| 3407 | DBUG_ENTER("dump_trigger" ); |
| 3408 | |
| 3409 | while ((row= mysql_fetch_row(show_create_trigger_rs))) |
| 3410 | { |
| 3411 | if (opt_xml) |
| 3412 | { |
| 3413 | print_xml_row(sql_file, "trigger" , show_create_trigger_rs, &row, |
| 3414 | "SQL Original Statement" ); |
| 3415 | check_io(sql_file); |
| 3416 | continue; |
| 3417 | } |
| 3418 | |
| 3419 | if (switch_db_collation(sql_file, db_name, ";" , |
| 3420 | db_cl_name, row[5], &db_cl_altered)) |
| 3421 | DBUG_RETURN(TRUE); |
| 3422 | |
| 3423 | switch_cs_variables(sql_file, ";" , |
| 3424 | row[3], /* character_set_client */ |
| 3425 | row[3], /* character_set_results */ |
| 3426 | row[4]); /* collation_connection */ |
| 3427 | |
| 3428 | switch_sql_mode(sql_file, ";" , row[1]); |
| 3429 | |
| 3430 | if (opt_drop_trigger) |
| 3431 | fprintf(sql_file, "/*!50032 DROP TRIGGER IF EXISTS %s */;\n" , |
| 3432 | row[0]); |
| 3433 | |
| 3434 | query_str= cover_definer_clause(row[2], strlen(row[2]), |
| 3435 | C_STRING_WITH_LEN("50017" ), |
| 3436 | C_STRING_WITH_LEN("50003" ), |
| 3437 | C_STRING_WITH_LEN(" TRIGGER" )); |
| 3438 | fprintf(sql_file, |
| 3439 | "DELIMITER ;;\n" |
| 3440 | "/*!50003 %s */;;\n" |
| 3441 | "DELIMITER ;\n" , |
| 3442 | (const char *) (query_str != NULL ? query_str : row[2])); |
| 3443 | |
| 3444 | my_free(query_str); |
| 3445 | |
| 3446 | restore_sql_mode(sql_file, ";" ); |
| 3447 | restore_cs_variables(sql_file, ";" ); |
| 3448 | |
| 3449 | if (db_cl_altered) |
| 3450 | { |
| 3451 | if (restore_db_collation(sql_file, db_name, ";" , db_cl_name)) |
| 3452 | DBUG_RETURN(TRUE); |
| 3453 | } |
| 3454 | } |
| 3455 | |
| 3456 | DBUG_RETURN(FALSE); |
| 3457 | } |
| 3458 | |
| 3459 | /** |
| 3460 | Dump the triggers for a given table. |
| 3461 | |
| 3462 | This should be called after the tables have been dumped in case a trigger |
| 3463 | depends on the existence of a table. |
| 3464 | |
| 3465 | @param[in] table_name |
| 3466 | @param[in] db_name |
| 3467 | |
| 3468 | @return Error status. |
| 3469 | @retval TRUE error has occurred. |
| 3470 | @retval FALSE operation succeed. |
| 3471 | */ |
| 3472 | |
| 3473 | static int dump_triggers_for_table(char *table_name, char *db_name) |
| 3474 | { |
| 3475 | char name_buff[NAME_LEN*4+3]; |
| 3476 | char query_buff[QUERY_LENGTH]; |
| 3477 | uint old_opt_compatible_mode= opt_compatible_mode; |
| 3478 | MYSQL_RES *show_triggers_rs; |
| 3479 | MYSQL_ROW row; |
| 3480 | FILE *sql_file= md_result_file; |
| 3481 | |
| 3482 | char db_cl_name[MY_CS_NAME_SIZE]; |
| 3483 | int ret= TRUE; |
| 3484 | |
| 3485 | DBUG_ENTER("dump_triggers_for_table" ); |
| 3486 | DBUG_PRINT("enter" , ("db: %s, table_name: %s" , db_name, table_name)); |
| 3487 | |
| 3488 | if (path && !(sql_file= open_sql_file_for_table(table_name, |
| 3489 | O_WRONLY | O_APPEND))) |
| 3490 | DBUG_RETURN(1); |
| 3491 | |
| 3492 | /* Do not use ANSI_QUOTES on triggers in dump */ |
| 3493 | opt_compatible_mode&= ~MASK_ANSI_QUOTES; |
| 3494 | |
| 3495 | /* Get database collation. */ |
| 3496 | |
| 3497 | if (switch_character_set_results(mysql, "binary" )) |
| 3498 | goto done; |
| 3499 | |
| 3500 | if (fetch_db_collation(db_name, db_cl_name, sizeof (db_cl_name))) |
| 3501 | goto done; |
| 3502 | |
| 3503 | /* Get list of triggers. */ |
| 3504 | |
| 3505 | my_snprintf(query_buff, sizeof(query_buff), |
| 3506 | "SELECT TRIGGER_NAME FROM INFORMATION_SCHEMA.TRIGGERS " |
| 3507 | "WHERE EVENT_OBJECT_SCHEMA = DATABASE() AND " |
| 3508 | "EVENT_OBJECT_TABLE = %s" , |
| 3509 | quote_for_equal(table_name, name_buff)); |
| 3510 | |
| 3511 | if (mysql_query_with_error_report(mysql, &show_triggers_rs, query_buff)) |
| 3512 | goto done; |
| 3513 | |
| 3514 | /* Dump triggers. */ |
| 3515 | |
| 3516 | if (! mysql_num_rows(show_triggers_rs)) |
| 3517 | goto skip; |
| 3518 | |
| 3519 | if (opt_xml) |
| 3520 | print_xml_tag(sql_file, "\t" , "\n" , "triggers" , "name=" , |
| 3521 | table_name, NullS); |
| 3522 | |
| 3523 | while ((row= mysql_fetch_row(show_triggers_rs))) |
| 3524 | { |
| 3525 | |
| 3526 | my_snprintf(query_buff, sizeof (query_buff), |
| 3527 | "SHOW CREATE TRIGGER %s" , |
| 3528 | quote_name(row[0], name_buff, TRUE)); |
| 3529 | |
| 3530 | if (mysql_query(mysql, query_buff)) |
| 3531 | { |
| 3532 | /* |
| 3533 | mysqldump is being run against old server, that does not support |
| 3534 | SHOW CREATE TRIGGER statement. We should use SHOW TRIGGERS output. |
| 3535 | |
| 3536 | NOTE: the dump may be incorrect, as old SHOW TRIGGERS does not |
| 3537 | provide all the necessary information to restore trigger properly. |
| 3538 | */ |
| 3539 | |
| 3540 | dump_trigger_old(sql_file, show_triggers_rs, &row, table_name); |
| 3541 | } |
| 3542 | else |
| 3543 | { |
| 3544 | MYSQL_RES *show_create_trigger_rs= mysql_store_result(mysql); |
| 3545 | |
| 3546 | int error= (!show_create_trigger_rs || |
| 3547 | dump_trigger(sql_file, show_create_trigger_rs, db_name, |
| 3548 | db_cl_name)); |
| 3549 | mysql_free_result(show_create_trigger_rs); |
| 3550 | if (error) |
| 3551 | goto done; |
| 3552 | } |
| 3553 | |
| 3554 | } |
| 3555 | |
| 3556 | if (opt_xml) |
| 3557 | { |
| 3558 | fputs("\t</triggers>\n" , sql_file); |
| 3559 | check_io(sql_file); |
| 3560 | } |
| 3561 | |
| 3562 | skip: |
| 3563 | mysql_free_result(show_triggers_rs); |
| 3564 | |
| 3565 | if (switch_character_set_results(mysql, default_charset)) |
| 3566 | goto done; |
| 3567 | |
| 3568 | /* |
| 3569 | make sure to set back opt_compatible mode to |
| 3570 | original value |
| 3571 | */ |
| 3572 | opt_compatible_mode=old_opt_compatible_mode; |
| 3573 | |
| 3574 | ret= FALSE; |
| 3575 | |
| 3576 | done: |
| 3577 | if (path) |
| 3578 | my_fclose(sql_file, MYF(0)); |
| 3579 | |
| 3580 | DBUG_RETURN(ret); |
| 3581 | } |
| 3582 | |
| 3583 | static void add_load_option(DYNAMIC_STRING *str, const char *option, |
| 3584 | const char *option_value) |
| 3585 | { |
| 3586 | if (!option_value) |
| 3587 | { |
| 3588 | /* Null value means we don't add this option. */ |
| 3589 | return; |
| 3590 | } |
| 3591 | |
| 3592 | dynstr_append_checked(str, option); |
| 3593 | |
| 3594 | if (strncmp(option_value, "0x" , sizeof("0x" )-1) == 0) |
| 3595 | { |
| 3596 | /* It's a hex constant, don't escape */ |
| 3597 | dynstr_append_checked(str, option_value); |
| 3598 | } |
| 3599 | else |
| 3600 | { |
| 3601 | /* char constant; escape */ |
| 3602 | field_escape(str, option_value); |
| 3603 | } |
| 3604 | } |
| 3605 | |
| 3606 | |
| 3607 | /* |
| 3608 | Allow the user to specify field terminator strings like: |
| 3609 | "'", "\", "\\" (escaped backslash), "\t" (tab), "\n" (newline) |
| 3610 | This is done by doubling ' and add a end -\ if needed to avoid |
| 3611 | syntax errors from the SQL parser. |
| 3612 | */ |
| 3613 | |
| 3614 | static void field_escape(DYNAMIC_STRING* in, const char *from) |
| 3615 | { |
| 3616 | uint end_backslashes= 0; |
| 3617 | |
| 3618 | dynstr_append_checked(in, "'" ); |
| 3619 | |
| 3620 | while (*from) |
| 3621 | { |
| 3622 | dynstr_append_mem_checked(in, from, 1); |
| 3623 | |
| 3624 | if (*from == '\\') |
| 3625 | end_backslashes^=1; /* find odd number of backslashes */ |
| 3626 | else |
| 3627 | { |
| 3628 | if (*from == '\'' && !end_backslashes) |
| 3629 | { |
| 3630 | /* We want a duplicate of "'" for MySQL */ |
| 3631 | dynstr_append_checked(in, "\'" ); |
| 3632 | } |
| 3633 | end_backslashes=0; |
| 3634 | } |
| 3635 | from++; |
| 3636 | } |
| 3637 | /* Add missing backslashes if user has specified odd number of backs.*/ |
| 3638 | if (end_backslashes) |
| 3639 | dynstr_append_checked(in, "\\" ); |
| 3640 | |
| 3641 | dynstr_append_checked(in, "'" ); |
| 3642 | } |
| 3643 | |
| 3644 | |
| 3645 | |
| 3646 | static char *alloc_query_str(size_t size) |
| 3647 | { |
| 3648 | char *query; |
| 3649 | |
| 3650 | if (!(query= (char*) my_malloc(size, MYF(MY_WME)))) |
| 3651 | die(EX_MYSQLERR, "Couldn't allocate a query string." ); |
| 3652 | |
| 3653 | return query; |
| 3654 | } |
| 3655 | |
| 3656 | |
| 3657 | /* |
| 3658 | |
| 3659 | SYNOPSIS |
| 3660 | dump_table() |
| 3661 | |
| 3662 | dump_table saves database contents as a series of INSERT statements. |
| 3663 | |
| 3664 | ARGS |
| 3665 | table - table name |
| 3666 | db - db name |
| 3667 | |
| 3668 | RETURNS |
| 3669 | void |
| 3670 | */ |
| 3671 | |
| 3672 | |
| 3673 | static void dump_table(char *table, char *db) |
| 3674 | { |
| 3675 | char ignore_flag; |
| 3676 | char buf[200], table_buff[NAME_LEN+3]; |
| 3677 | DYNAMIC_STRING query_string; |
| 3678 | char table_type[NAME_LEN]; |
| 3679 | char *result_table, table_buff2[NAME_LEN*2+3], *opt_quoted_table; |
| 3680 | int error= 0; |
| 3681 | ulong rownr, row_break; |
| 3682 | uint num_fields; |
| 3683 | size_t total_length, init_length; |
| 3684 | |
| 3685 | MYSQL_RES *res; |
| 3686 | MYSQL_FIELD *field; |
| 3687 | MYSQL_ROW row; |
| 3688 | DBUG_ENTER("dump_table" ); |
| 3689 | |
| 3690 | /* |
| 3691 | Make sure you get the create table info before the following check for |
| 3692 | --no-data flag below. Otherwise, the create table info won't be printed. |
| 3693 | */ |
| 3694 | num_fields= get_table_structure(table, db, table_type, &ignore_flag); |
| 3695 | |
| 3696 | /* |
| 3697 | The "table" could be a view. If so, we don't do anything here. |
| 3698 | */ |
| 3699 | if (strcmp(table_type, "VIEW" ) == 0) |
| 3700 | DBUG_VOID_RETURN; |
| 3701 | |
| 3702 | /* Check --no-data flag */ |
| 3703 | if (opt_no_data) |
| 3704 | { |
| 3705 | verbose_msg("-- Skipping dump data for table '%s', --no-data was used\n" , |
| 3706 | table); |
| 3707 | DBUG_VOID_RETURN; |
| 3708 | } |
| 3709 | |
| 3710 | DBUG_PRINT("info" , |
| 3711 | ("ignore_flag: %x num_fields: %d" , (int) ignore_flag, |
| 3712 | num_fields)); |
| 3713 | /* |
| 3714 | If the table type is a merge table or any type that has to be |
| 3715 | _completely_ ignored and no data dumped |
| 3716 | */ |
| 3717 | if (ignore_flag & IGNORE_DATA) |
| 3718 | { |
| 3719 | verbose_msg("-- Warning: Skipping data for table '%s' because " \ |
| 3720 | "it's of type %s\n" , table, table_type); |
| 3721 | DBUG_VOID_RETURN; |
| 3722 | } |
| 3723 | /* Check that there are any fields in the table */ |
| 3724 | if (num_fields == 0) |
| 3725 | { |
| 3726 | verbose_msg("-- Skipping dump data for table '%s', it has no fields\n" , |
| 3727 | table); |
| 3728 | DBUG_VOID_RETURN; |
| 3729 | } |
| 3730 | |
| 3731 | /* |
| 3732 | Check --skip-events flag: it is not enough to skip creation of events |
| 3733 | discarding SHOW CREATE EVENT statements generation. The myslq.event |
| 3734 | table data should be skipped too. |
| 3735 | */ |
| 3736 | if (!opt_events && !my_strcasecmp(&my_charset_latin1, db, "mysql" ) && |
| 3737 | !my_strcasecmp(&my_charset_latin1, table, "event" )) |
| 3738 | { |
| 3739 | verbose_msg("-- Skipping data table mysql.event, --skip-events was used\n" ); |
| 3740 | DBUG_VOID_RETURN; |
| 3741 | } |
| 3742 | |
| 3743 | result_table= quote_name(table,table_buff, 1); |
| 3744 | opt_quoted_table= quote_name(table, table_buff2, 0); |
| 3745 | |
| 3746 | verbose_msg("-- Sending SELECT query...\n" ); |
| 3747 | |
| 3748 | init_dynamic_string_checked(&query_string, "" , 1024, 1024); |
| 3749 | |
| 3750 | if (path) |
| 3751 | { |
| 3752 | char filename[FN_REFLEN], tmp_path[FN_REFLEN]; |
| 3753 | |
| 3754 | /* |
| 3755 | Convert the path to native os format |
| 3756 | and resolve to the full filepath. |
| 3757 | */ |
| 3758 | convert_dirname(tmp_path,path,NullS); |
| 3759 | my_load_path(tmp_path, tmp_path, NULL); |
| 3760 | fn_format(filename, table, tmp_path, ".txt" , MYF(MY_UNPACK_FILENAME)); |
| 3761 | |
| 3762 | /* Must delete the file that 'INTO OUTFILE' will write to */ |
| 3763 | my_delete(filename, MYF(0)); |
| 3764 | |
| 3765 | /* convert to a unix path name to stick into the query */ |
| 3766 | to_unix_path(filename); |
| 3767 | |
| 3768 | /* now build the query string */ |
| 3769 | |
| 3770 | dynstr_append_checked(&query_string, "SELECT /*!40001 SQL_NO_CACHE */ " ); |
| 3771 | dynstr_append_checked(&query_string, select_field_names.str); |
| 3772 | dynstr_append_checked(&query_string, " INTO OUTFILE '" ); |
| 3773 | dynstr_append_checked(&query_string, filename); |
| 3774 | dynstr_append_checked(&query_string, "'" ); |
| 3775 | |
| 3776 | dynstr_append_checked(&query_string, " /*!50138 CHARACTER SET " ); |
| 3777 | dynstr_append_checked(&query_string, default_charset == mysql_universal_client_charset ? |
| 3778 | my_charset_bin.name : /* backward compatibility */ |
| 3779 | default_charset); |
| 3780 | dynstr_append_checked(&query_string, " */" ); |
| 3781 | |
| 3782 | if (fields_terminated || enclosed || opt_enclosed || escaped) |
| 3783 | dynstr_append_checked(&query_string, " FIELDS" ); |
| 3784 | |
| 3785 | add_load_option(&query_string, " TERMINATED BY " , fields_terminated); |
| 3786 | add_load_option(&query_string, " ENCLOSED BY " , enclosed); |
| 3787 | add_load_option(&query_string, " OPTIONALLY ENCLOSED BY " , opt_enclosed); |
| 3788 | add_load_option(&query_string, " ESCAPED BY " , escaped); |
| 3789 | add_load_option(&query_string, " LINES TERMINATED BY " , lines_terminated); |
| 3790 | |
| 3791 | dynstr_append_checked(&query_string, " FROM " ); |
| 3792 | dynstr_append_checked(&query_string, result_table); |
| 3793 | |
| 3794 | if (where) |
| 3795 | { |
| 3796 | dynstr_append_checked(&query_string, " WHERE " ); |
| 3797 | dynstr_append_checked(&query_string, where); |
| 3798 | } |
| 3799 | |
| 3800 | if (order_by) |
| 3801 | { |
| 3802 | dynstr_append_checked(&query_string, " ORDER BY " ); |
| 3803 | dynstr_append_checked(&query_string, order_by); |
| 3804 | my_free(order_by); |
| 3805 | order_by= 0; |
| 3806 | } |
| 3807 | |
| 3808 | if (mysql_real_query(mysql, query_string.str, (ulong)query_string.length)) |
| 3809 | { |
| 3810 | dynstr_free(&query_string); |
| 3811 | DB_error(mysql, "when executing 'SELECT INTO OUTFILE'" ); |
| 3812 | DBUG_VOID_RETURN; |
| 3813 | } |
| 3814 | } |
| 3815 | else |
| 3816 | { |
| 3817 | print_comment(md_result_file, 0, |
| 3818 | "\n--\n-- Dumping data for table %s\n--\n" , |
| 3819 | fix_for_comment(result_table)); |
| 3820 | |
| 3821 | dynstr_append_checked(&query_string, "SELECT /*!40001 SQL_NO_CACHE */ " ); |
| 3822 | dynstr_append_checked(&query_string, select_field_names.str); |
| 3823 | dynstr_append_checked(&query_string, " FROM " ); |
| 3824 | dynstr_append_checked(&query_string, result_table); |
| 3825 | |
| 3826 | if (where) |
| 3827 | { |
| 3828 | print_comment(md_result_file, 0, "-- WHERE: %s\n" , fix_for_comment(where)); |
| 3829 | |
| 3830 | dynstr_append_checked(&query_string, " WHERE " ); |
| 3831 | dynstr_append_checked(&query_string, where); |
| 3832 | } |
| 3833 | if (order_by) |
| 3834 | { |
| 3835 | print_comment(md_result_file, 0, "-- ORDER BY: %s\n" , fix_for_comment(order_by)); |
| 3836 | |
| 3837 | dynstr_append_checked(&query_string, " ORDER BY " ); |
| 3838 | dynstr_append_checked(&query_string, order_by); |
| 3839 | my_free(order_by); |
| 3840 | order_by= 0; |
| 3841 | } |
| 3842 | |
| 3843 | if (!opt_xml && !opt_compact) |
| 3844 | { |
| 3845 | fputs("\n" , md_result_file); |
| 3846 | check_io(md_result_file); |
| 3847 | } |
| 3848 | if (mysql_query_with_error_report(mysql, 0, query_string.str)) |
| 3849 | { |
| 3850 | dynstr_free(&query_string); |
| 3851 | DB_error(mysql, "when retrieving data from server" ); |
| 3852 | goto err; |
| 3853 | } |
| 3854 | if (quick) |
| 3855 | res=mysql_use_result(mysql); |
| 3856 | else |
| 3857 | res=mysql_store_result(mysql); |
| 3858 | if (!res) |
| 3859 | { |
| 3860 | dynstr_free(&query_string); |
| 3861 | DB_error(mysql, "when retrieving data from server" ); |
| 3862 | goto err; |
| 3863 | } |
| 3864 | |
| 3865 | verbose_msg("-- Retrieving rows...\n" ); |
| 3866 | if (mysql_num_fields(res) != num_fields) |
| 3867 | { |
| 3868 | fprintf(stderr,"%s: Error in field count for table: %s ! Aborting.\n" , |
| 3869 | my_progname_short, result_table); |
| 3870 | error= EX_CONSCHECK; |
| 3871 | goto err; |
| 3872 | } |
| 3873 | |
| 3874 | if (opt_lock) |
| 3875 | { |
| 3876 | fprintf(md_result_file,"LOCK TABLES %s WRITE;\n" , opt_quoted_table); |
| 3877 | check_io(md_result_file); |
| 3878 | } |
| 3879 | /* Moved disable keys to after lock per bug 15977 */ |
| 3880 | if (opt_disable_keys) |
| 3881 | { |
| 3882 | fprintf(md_result_file, "/*!40000 ALTER TABLE %s DISABLE KEYS */;\n" , |
| 3883 | opt_quoted_table); |
| 3884 | check_io(md_result_file); |
| 3885 | } |
| 3886 | |
| 3887 | total_length= opt_net_buffer_length; /* Force row break */ |
| 3888 | row_break=0; |
| 3889 | rownr=0; |
| 3890 | init_length=(uint) insert_pat.length+4; |
| 3891 | if (opt_xml) |
| 3892 | print_xml_tag(md_result_file, "\t" , "\n" , "table_data" , "name=" , table, |
| 3893 | NullS); |
| 3894 | if (opt_autocommit) |
| 3895 | { |
| 3896 | fprintf(md_result_file, "set autocommit=0;\n" ); |
| 3897 | check_io(md_result_file); |
| 3898 | } |
| 3899 | |
| 3900 | while ((row= mysql_fetch_row(res))) |
| 3901 | { |
| 3902 | uint i; |
| 3903 | ulong *lengths= mysql_fetch_lengths(res); |
| 3904 | rownr++; |
| 3905 | if (!extended_insert && !opt_xml) |
| 3906 | { |
| 3907 | fputs(insert_pat.str,md_result_file); |
| 3908 | check_io(md_result_file); |
| 3909 | } |
| 3910 | mysql_field_seek(res,0); |
| 3911 | |
| 3912 | if (opt_xml) |
| 3913 | { |
| 3914 | fputs("\t<row>\n" , md_result_file); |
| 3915 | check_io(md_result_file); |
| 3916 | } |
| 3917 | |
| 3918 | for (i= 0; i < mysql_num_fields(res); i++) |
| 3919 | { |
| 3920 | int is_blob; |
| 3921 | ulong length= lengths[i]; |
| 3922 | |
| 3923 | if (!(field= mysql_fetch_field(res))) |
| 3924 | die(EX_CONSCHECK, |
| 3925 | "Not enough fields from table %s! Aborting.\n" , |
| 3926 | result_table); |
| 3927 | |
| 3928 | /* |
| 3929 | 63 is my_charset_bin. If charsetnr is not 63, |
| 3930 | we have not a BLOB but a TEXT column. |
| 3931 | we'll dump in hex only BLOB columns. |
| 3932 | */ |
| 3933 | is_blob= (opt_hex_blob && field->charsetnr == 63 && |
| 3934 | (field->type == MYSQL_TYPE_BIT || |
| 3935 | field->type == MYSQL_TYPE_STRING || |
| 3936 | field->type == MYSQL_TYPE_VAR_STRING || |
| 3937 | field->type == MYSQL_TYPE_VARCHAR || |
| 3938 | field->type == MYSQL_TYPE_BLOB || |
| 3939 | field->type == MYSQL_TYPE_LONG_BLOB || |
| 3940 | field->type == MYSQL_TYPE_MEDIUM_BLOB || |
| 3941 | field->type == MYSQL_TYPE_TINY_BLOB || |
| 3942 | field->type == MYSQL_TYPE_GEOMETRY)) ? 1 : 0; |
| 3943 | if (extended_insert && !opt_xml) |
| 3944 | { |
| 3945 | if (i == 0) |
| 3946 | dynstr_set_checked(&extended_row,"(" ); |
| 3947 | else |
| 3948 | dynstr_append_checked(&extended_row,"," ); |
| 3949 | |
| 3950 | if (row[i]) |
| 3951 | { |
| 3952 | if (length) |
| 3953 | { |
| 3954 | if (!(field->flags & NUM_FLAG)) |
| 3955 | { |
| 3956 | /* |
| 3957 | "length * 2 + 2" is OK for both HEX and non-HEX modes: |
| 3958 | - In HEX mode we need exactly 2 bytes per character |
| 3959 | plus 2 bytes for '0x' prefix. |
| 3960 | - In non-HEX mode we need up to 2 bytes per character, |
| 3961 | plus 2 bytes for leading and trailing '\'' characters. |
| 3962 | Also we need to reserve 1 byte for terminating '\0'. |
| 3963 | */ |
| 3964 | dynstr_realloc_checked(&extended_row,length * 2 + 2 + 1); |
| 3965 | if (opt_hex_blob && is_blob) |
| 3966 | { |
| 3967 | dynstr_append_checked(&extended_row, "0x" ); |
| 3968 | extended_row.length+= mysql_hex_string(extended_row.str + |
| 3969 | extended_row.length, |
| 3970 | row[i], length); |
| 3971 | DBUG_ASSERT(extended_row.length+1 <= extended_row.max_length); |
| 3972 | /* mysql_hex_string() already terminated string by '\0' */ |
| 3973 | DBUG_ASSERT(extended_row.str[extended_row.length] == '\0'); |
| 3974 | } |
| 3975 | else |
| 3976 | { |
| 3977 | dynstr_append_checked(&extended_row,"'" ); |
| 3978 | extended_row.length += |
| 3979 | mysql_real_escape_string(&mysql_connection, |
| 3980 | &extended_row.str[extended_row.length], |
| 3981 | row[i],length); |
| 3982 | extended_row.str[extended_row.length]='\0'; |
| 3983 | dynstr_append_checked(&extended_row,"'" ); |
| 3984 | } |
| 3985 | } |
| 3986 | else |
| 3987 | { |
| 3988 | /* change any strings ("inf", "-inf", "nan") into NULL */ |
| 3989 | char *ptr= row[i]; |
| 3990 | if (my_isalpha(charset_info, *ptr) || (*ptr == '-' && |
| 3991 | my_isalpha(charset_info, ptr[1]))) |
| 3992 | dynstr_append_checked(&extended_row, "NULL" ); |
| 3993 | else |
| 3994 | { |
| 3995 | if (field->type == MYSQL_TYPE_DECIMAL) |
| 3996 | { |
| 3997 | /* add " signs around */ |
| 3998 | dynstr_append_checked(&extended_row, "'" ); |
| 3999 | dynstr_append_checked(&extended_row, ptr); |
| 4000 | dynstr_append_checked(&extended_row, "'" ); |
| 4001 | } |
| 4002 | else |
| 4003 | dynstr_append_checked(&extended_row, ptr); |
| 4004 | } |
| 4005 | } |
| 4006 | } |
| 4007 | else |
| 4008 | dynstr_append_checked(&extended_row,"''" ); |
| 4009 | } |
| 4010 | else |
| 4011 | dynstr_append_checked(&extended_row,"NULL" ); |
| 4012 | } |
| 4013 | else |
| 4014 | { |
| 4015 | if (i && !opt_xml) |
| 4016 | { |
| 4017 | fputc(',', md_result_file); |
| 4018 | check_io(md_result_file); |
| 4019 | } |
| 4020 | if (row[i]) |
| 4021 | { |
| 4022 | if (!(field->flags & NUM_FLAG)) |
| 4023 | { |
| 4024 | if (opt_xml) |
| 4025 | { |
| 4026 | if (opt_hex_blob && is_blob && length) |
| 4027 | { |
| 4028 | /* Define xsi:type="xs:hexBinary" for hex encoded data */ |
| 4029 | print_xml_tag(md_result_file, "\t\t" , "" , "field" , "name=" , |
| 4030 | field->name, "xsi:type=" , "xs:hexBinary" , NullS); |
| 4031 | print_blob_as_hex(md_result_file, row[i], length); |
| 4032 | } |
| 4033 | else |
| 4034 | { |
| 4035 | print_xml_tag(md_result_file, "\t\t" , "" , "field" , "name=" , |
| 4036 | field->name, NullS); |
| 4037 | print_quoted_xml(md_result_file, row[i], length, 0); |
| 4038 | } |
| 4039 | fputs("</field>\n" , md_result_file); |
| 4040 | } |
| 4041 | else if (opt_hex_blob && is_blob && length) |
| 4042 | { |
| 4043 | fputs("0x" , md_result_file); |
| 4044 | print_blob_as_hex(md_result_file, row[i], length); |
| 4045 | } |
| 4046 | else |
| 4047 | unescape(md_result_file, row[i], length); |
| 4048 | } |
| 4049 | else |
| 4050 | { |
| 4051 | /* change any strings ("inf", "-inf", "nan") into NULL */ |
| 4052 | char *ptr= row[i]; |
| 4053 | if (opt_xml) |
| 4054 | { |
| 4055 | print_xml_tag(md_result_file, "\t\t" , "" , "field" , "name=" , |
| 4056 | field->name, NullS); |
| 4057 | fputs(!my_isalpha(charset_info, *ptr) ? ptr: "NULL" , |
| 4058 | md_result_file); |
| 4059 | fputs("</field>\n" , md_result_file); |
| 4060 | } |
| 4061 | else if (my_isalpha(charset_info, *ptr) || |
| 4062 | (*ptr == '-' && my_isalpha(charset_info, ptr[1]))) |
| 4063 | fputs("NULL" , md_result_file); |
| 4064 | else if (field->type == MYSQL_TYPE_DECIMAL) |
| 4065 | { |
| 4066 | /* add " signs around */ |
| 4067 | fputc('\'', md_result_file); |
| 4068 | fputs(ptr, md_result_file); |
| 4069 | fputc('\'', md_result_file); |
| 4070 | } |
| 4071 | else |
| 4072 | fputs(ptr, md_result_file); |
| 4073 | } |
| 4074 | } |
| 4075 | else |
| 4076 | { |
| 4077 | /* The field value is NULL */ |
| 4078 | if (!opt_xml) |
| 4079 | fputs("NULL" , md_result_file); |
| 4080 | else |
| 4081 | print_xml_null_tag(md_result_file, "\t\t" , "field name=" , |
| 4082 | field->name, "\n" ); |
| 4083 | } |
| 4084 | check_io(md_result_file); |
| 4085 | } |
| 4086 | } |
| 4087 | |
| 4088 | if (opt_xml) |
| 4089 | { |
| 4090 | fputs("\t</row>\n" , md_result_file); |
| 4091 | check_io(md_result_file); |
| 4092 | } |
| 4093 | |
| 4094 | if (extended_insert) |
| 4095 | { |
| 4096 | size_t row_length; |
| 4097 | dynstr_append_checked(&extended_row,")" ); |
| 4098 | row_length= 2 + extended_row.length; |
| 4099 | if (total_length + row_length < opt_net_buffer_length) |
| 4100 | { |
| 4101 | total_length+= row_length; |
| 4102 | fputc(',',md_result_file); /* Always row break */ |
| 4103 | fputs(extended_row.str,md_result_file); |
| 4104 | } |
| 4105 | else |
| 4106 | { |
| 4107 | if (row_break) |
| 4108 | fputs(";\n" , md_result_file); |
| 4109 | row_break=1; /* This is first row */ |
| 4110 | |
| 4111 | fputs(insert_pat.str,md_result_file); |
| 4112 | fputs(extended_row.str,md_result_file); |
| 4113 | total_length= row_length+init_length; |
| 4114 | } |
| 4115 | check_io(md_result_file); |
| 4116 | } |
| 4117 | else if (!opt_xml) |
| 4118 | { |
| 4119 | fputs(");\n" , md_result_file); |
| 4120 | check_io(md_result_file); |
| 4121 | } |
| 4122 | } |
| 4123 | |
| 4124 | /* XML - close table tag and supress regular output */ |
| 4125 | if (opt_xml) |
| 4126 | fputs("\t</table_data>\n" , md_result_file); |
| 4127 | else if (extended_insert && row_break) |
| 4128 | fputs(";\n" , md_result_file); /* If not empty table */ |
| 4129 | fflush(md_result_file); |
| 4130 | check_io(md_result_file); |
| 4131 | if (mysql_errno(mysql)) |
| 4132 | { |
| 4133 | my_snprintf(buf, sizeof(buf), |
| 4134 | "%s: Error %d: %s when dumping table %s at row: %ld\n" , |
| 4135 | my_progname_short, |
| 4136 | mysql_errno(mysql), |
| 4137 | mysql_error(mysql), |
| 4138 | result_table, |
| 4139 | rownr); |
| 4140 | fputs(buf,stderr); |
| 4141 | error= EX_CONSCHECK; |
| 4142 | goto err; |
| 4143 | } |
| 4144 | |
| 4145 | /* Moved enable keys to before unlock per bug 15977 */ |
| 4146 | if (opt_disable_keys) |
| 4147 | { |
| 4148 | fprintf(md_result_file,"/*!40000 ALTER TABLE %s ENABLE KEYS */;\n" , |
| 4149 | opt_quoted_table); |
| 4150 | check_io(md_result_file); |
| 4151 | } |
| 4152 | if (opt_lock) |
| 4153 | { |
| 4154 | fputs("UNLOCK TABLES;\n" , md_result_file); |
| 4155 | check_io(md_result_file); |
| 4156 | } |
| 4157 | if (opt_autocommit) |
| 4158 | { |
| 4159 | fprintf(md_result_file, "commit;\n" ); |
| 4160 | check_io(md_result_file); |
| 4161 | } |
| 4162 | mysql_free_result(res); |
| 4163 | } |
| 4164 | dynstr_free(&query_string); |
| 4165 | DBUG_VOID_RETURN; |
| 4166 | |
| 4167 | err: |
| 4168 | dynstr_free(&query_string); |
| 4169 | maybe_exit(error); |
| 4170 | DBUG_VOID_RETURN; |
| 4171 | } /* dump_table */ |
| 4172 | |
| 4173 | |
| 4174 | static char *getTableName(int reset) |
| 4175 | { |
| 4176 | MYSQL_ROW row; |
| 4177 | |
| 4178 | if (!get_table_name_result) |
| 4179 | { |
| 4180 | if (!(get_table_name_result= mysql_list_tables(mysql,NullS))) |
| 4181 | return(NULL); |
| 4182 | } |
| 4183 | if ((row= mysql_fetch_row(get_table_name_result))) |
| 4184 | return((char*) row[0]); |
| 4185 | |
| 4186 | if (reset) |
| 4187 | mysql_data_seek(get_table_name_result,0); /* We want to read again */ |
| 4188 | else |
| 4189 | { |
| 4190 | mysql_free_result(get_table_name_result); |
| 4191 | get_table_name_result= NULL; |
| 4192 | } |
| 4193 | return(NULL); |
| 4194 | } /* getTableName */ |
| 4195 | |
| 4196 | |
| 4197 | /* |
| 4198 | dump all logfile groups and tablespaces |
| 4199 | */ |
| 4200 | |
| 4201 | static int dump_all_tablespaces() |
| 4202 | { |
| 4203 | return dump_tablespaces(NULL); |
| 4204 | } |
| 4205 | |
| 4206 | static int dump_tablespaces_for_tables(char *db, char **table_names, int tables) |
| 4207 | { |
| 4208 | int r; |
| 4209 | int i; |
| 4210 | char name_buff[NAME_LEN*2+3]; |
| 4211 | |
| 4212 | mysql_real_escape_string(mysql, name_buff, db, (ulong)strlen(db)); |
| 4213 | |
| 4214 | init_dynamic_string_checked(&dynamic_where, " AND TABLESPACE_NAME IN (" |
| 4215 | "SELECT DISTINCT TABLESPACE_NAME FROM" |
| 4216 | " INFORMATION_SCHEMA.PARTITIONS" |
| 4217 | " WHERE" |
| 4218 | " TABLE_SCHEMA='" , 256, 1024); |
| 4219 | dynstr_append_checked(&dynamic_where, name_buff); |
| 4220 | dynstr_append_checked(&dynamic_where, "' AND TABLE_NAME IN (" ); |
| 4221 | |
| 4222 | for (i=0 ; i<tables ; i++) |
| 4223 | { |
| 4224 | mysql_real_escape_string(mysql, name_buff, |
| 4225 | table_names[i], (ulong)strlen(table_names[i])); |
| 4226 | |
| 4227 | dynstr_append_checked(&dynamic_where, "'" ); |
| 4228 | dynstr_append_checked(&dynamic_where, name_buff); |
| 4229 | dynstr_append_checked(&dynamic_where, "'," ); |
| 4230 | } |
| 4231 | dynstr_trunc(&dynamic_where, 1); |
| 4232 | dynstr_append_checked(&dynamic_where,"))" ); |
| 4233 | |
| 4234 | DBUG_PRINT("info" ,("Dump TS for Tables where: %s" ,dynamic_where.str)); |
| 4235 | r= dump_tablespaces(dynamic_where.str); |
| 4236 | dynstr_free(&dynamic_where); |
| 4237 | return r; |
| 4238 | } |
| 4239 | |
| 4240 | |
| 4241 | static int dump_tablespaces_for_databases(char** databases) |
| 4242 | { |
| 4243 | int r; |
| 4244 | int i; |
| 4245 | |
| 4246 | init_dynamic_string_checked(&dynamic_where, " AND TABLESPACE_NAME IN (" |
| 4247 | "SELECT DISTINCT TABLESPACE_NAME FROM" |
| 4248 | " INFORMATION_SCHEMA.PARTITIONS" |
| 4249 | " WHERE" |
| 4250 | " TABLE_SCHEMA IN (" , 256, 1024); |
| 4251 | |
| 4252 | for (i=0 ; databases[i]!=NULL ; i++) |
| 4253 | { |
| 4254 | char db_name_buff[NAME_LEN*2+3]; |
| 4255 | mysql_real_escape_string(mysql, db_name_buff, |
| 4256 | databases[i], (ulong)strlen(databases[i])); |
| 4257 | dynstr_append_checked(&dynamic_where, "'" ); |
| 4258 | dynstr_append_checked(&dynamic_where, db_name_buff); |
| 4259 | dynstr_append_checked(&dynamic_where, "'," ); |
| 4260 | } |
| 4261 | dynstr_trunc(&dynamic_where, 1); |
| 4262 | dynstr_append_checked(&dynamic_where,"))" ); |
| 4263 | |
| 4264 | DBUG_PRINT("info" ,("Dump TS for DBs where: %s" ,dynamic_where.str)); |
| 4265 | r= dump_tablespaces(dynamic_where.str); |
| 4266 | dynstr_free(&dynamic_where); |
| 4267 | return r; |
| 4268 | } |
| 4269 | |
| 4270 | |
| 4271 | static int dump_tablespaces(char* ts_where) |
| 4272 | { |
| 4273 | MYSQL_ROW row; |
| 4274 | MYSQL_RES *tableres; |
| 4275 | char buf[FN_REFLEN]; |
| 4276 | DYNAMIC_STRING sqlbuf; |
| 4277 | int first= 0; |
| 4278 | /* |
| 4279 | The following are used for parsing the EXTRA field |
| 4280 | */ |
| 4281 | char []= "UNDO_BUFFER_SIZE=" ; |
| 4282 | char *ubs; |
| 4283 | char *endsemi; |
| 4284 | DBUG_ENTER("dump_tablespaces" ); |
| 4285 | |
| 4286 | /* |
| 4287 | Try to turn off semi-join optimization (if that fails, this is a |
| 4288 | pre-optimizer_switch server, and the old query plan is ok for us. |
| 4289 | */ |
| 4290 | mysql_query(mysql, "set optimizer_switch='semijoin=off'" ); |
| 4291 | |
| 4292 | init_dynamic_string_checked(&sqlbuf, |
| 4293 | "SELECT LOGFILE_GROUP_NAME," |
| 4294 | " FILE_NAME," |
| 4295 | " TOTAL_EXTENTS," |
| 4296 | " INITIAL_SIZE," |
| 4297 | " ENGINE," |
| 4298 | " EXTRA" |
| 4299 | " FROM INFORMATION_SCHEMA.FILES" |
| 4300 | " WHERE FILE_TYPE = 'UNDO LOG'" |
| 4301 | " AND FILE_NAME IS NOT NULL" , |
| 4302 | 256, 1024); |
| 4303 | if(ts_where) |
| 4304 | { |
| 4305 | dynstr_append_checked(&sqlbuf, |
| 4306 | " AND LOGFILE_GROUP_NAME IN (" |
| 4307 | "SELECT DISTINCT LOGFILE_GROUP_NAME" |
| 4308 | " FROM INFORMATION_SCHEMA.FILES" |
| 4309 | " WHERE FILE_TYPE = 'DATAFILE'" |
| 4310 | ); |
| 4311 | dynstr_append_checked(&sqlbuf, ts_where); |
| 4312 | dynstr_append_checked(&sqlbuf, ")" ); |
| 4313 | } |
| 4314 | dynstr_append_checked(&sqlbuf, |
| 4315 | " GROUP BY LOGFILE_GROUP_NAME, FILE_NAME" |
| 4316 | ", ENGINE" |
| 4317 | " ORDER BY LOGFILE_GROUP_NAME" ); |
| 4318 | |
| 4319 | if (mysql_query(mysql, sqlbuf.str) || |
| 4320 | !(tableres = mysql_store_result(mysql))) |
| 4321 | { |
| 4322 | dynstr_free(&sqlbuf); |
| 4323 | if (mysql_errno(mysql) == ER_BAD_TABLE_ERROR || |
| 4324 | mysql_errno(mysql) == ER_BAD_DB_ERROR || |
| 4325 | mysql_errno(mysql) == ER_UNKNOWN_TABLE) |
| 4326 | { |
| 4327 | fprintf(md_result_file, |
| 4328 | "\n--\n-- Not dumping tablespaces as no INFORMATION_SCHEMA.FILES" |
| 4329 | " table on this server\n--\n" ); |
| 4330 | check_io(md_result_file); |
| 4331 | DBUG_RETURN(0); |
| 4332 | } |
| 4333 | |
| 4334 | fprintf(stderr, "%s: Error: '%s' when trying to dump tablespaces\n" , |
| 4335 | my_progname_short, mysql_error(mysql)); |
| 4336 | DBUG_RETURN(1); |
| 4337 | } |
| 4338 | |
| 4339 | buf[0]= 0; |
| 4340 | while ((row= mysql_fetch_row(tableres))) |
| 4341 | { |
| 4342 | if (strcmp(buf, row[0]) != 0) |
| 4343 | first= 1; |
| 4344 | if (first) |
| 4345 | { |
| 4346 | print_comment(md_result_file, 0, "\n--\n-- Logfile group: %s\n--\n" , |
| 4347 | fix_for_comment(row[0])); |
| 4348 | |
| 4349 | fprintf(md_result_file, "\nCREATE" ); |
| 4350 | } |
| 4351 | else |
| 4352 | { |
| 4353 | fprintf(md_result_file, "\nALTER" ); |
| 4354 | } |
| 4355 | fprintf(md_result_file, |
| 4356 | " LOGFILE GROUP %s\n" |
| 4357 | " ADD UNDOFILE '%s'\n" , |
| 4358 | row[0], |
| 4359 | row[1]); |
| 4360 | if (first) |
| 4361 | { |
| 4362 | ubs= strstr(row[5],extra_format); |
| 4363 | if(!ubs) |
| 4364 | break; |
| 4365 | ubs+= strlen(extra_format); |
| 4366 | endsemi= strstr(ubs,";" ); |
| 4367 | if(endsemi) |
| 4368 | endsemi[0]= '\0'; |
| 4369 | fprintf(md_result_file, |
| 4370 | " UNDO_BUFFER_SIZE %s\n" , |
| 4371 | ubs); |
| 4372 | } |
| 4373 | fprintf(md_result_file, |
| 4374 | " INITIAL_SIZE %s\n" |
| 4375 | " ENGINE=%s;\n" , |
| 4376 | row[3], |
| 4377 | row[4]); |
| 4378 | check_io(md_result_file); |
| 4379 | if (first) |
| 4380 | { |
| 4381 | first= 0; |
| 4382 | strxmov(buf, row[0], NullS); |
| 4383 | } |
| 4384 | } |
| 4385 | dynstr_free(&sqlbuf); |
| 4386 | mysql_free_result(tableres); |
| 4387 | init_dynamic_string_checked(&sqlbuf, |
| 4388 | "SELECT DISTINCT TABLESPACE_NAME," |
| 4389 | " FILE_NAME," |
| 4390 | " LOGFILE_GROUP_NAME," |
| 4391 | " EXTENT_SIZE," |
| 4392 | " INITIAL_SIZE," |
| 4393 | " ENGINE" |
| 4394 | " FROM INFORMATION_SCHEMA.FILES" |
| 4395 | " WHERE FILE_TYPE = 'DATAFILE'" , |
| 4396 | 256, 1024); |
| 4397 | |
| 4398 | if(ts_where) |
| 4399 | dynstr_append_checked(&sqlbuf, ts_where); |
| 4400 | |
| 4401 | dynstr_append_checked(&sqlbuf, " ORDER BY TABLESPACE_NAME, LOGFILE_GROUP_NAME" ); |
| 4402 | |
| 4403 | if (mysql_query_with_error_report(mysql, &tableres, sqlbuf.str)) |
| 4404 | { |
| 4405 | dynstr_free(&sqlbuf); |
| 4406 | DBUG_RETURN(1); |
| 4407 | } |
| 4408 | |
| 4409 | buf[0]= 0; |
| 4410 | while ((row= mysql_fetch_row(tableres))) |
| 4411 | { |
| 4412 | if (strcmp(buf, row[0]) != 0) |
| 4413 | first= 1; |
| 4414 | if (first) |
| 4415 | { |
| 4416 | print_comment(md_result_file, 0, "\n--\n-- Tablespace: %s\n--\n" , |
| 4417 | fix_for_comment(row[0])); |
| 4418 | fprintf(md_result_file, "\nCREATE" ); |
| 4419 | } |
| 4420 | else |
| 4421 | { |
| 4422 | fprintf(md_result_file, "\nALTER" ); |
| 4423 | } |
| 4424 | fprintf(md_result_file, |
| 4425 | " TABLESPACE %s\n" |
| 4426 | " ADD DATAFILE '%s'\n" , |
| 4427 | row[0], |
| 4428 | row[1]); |
| 4429 | if (first) |
| 4430 | { |
| 4431 | fprintf(md_result_file, |
| 4432 | " USE LOGFILE GROUP %s\n" |
| 4433 | " EXTENT_SIZE %s\n" , |
| 4434 | row[2], |
| 4435 | row[3]); |
| 4436 | } |
| 4437 | fprintf(md_result_file, |
| 4438 | " INITIAL_SIZE %s\n" |
| 4439 | " ENGINE=%s;\n" , |
| 4440 | row[4], |
| 4441 | row[5]); |
| 4442 | check_io(md_result_file); |
| 4443 | if (first) |
| 4444 | { |
| 4445 | first= 0; |
| 4446 | strxmov(buf, row[0], NullS); |
| 4447 | } |
| 4448 | } |
| 4449 | |
| 4450 | mysql_free_result(tableres); |
| 4451 | dynstr_free(&sqlbuf); |
| 4452 | mysql_query(mysql, "set optimizer_switch=default" ); |
| 4453 | |
| 4454 | DBUG_RETURN(0); |
| 4455 | } |
| 4456 | |
| 4457 | |
| 4458 | /* Return 1 if we should copy the database */ |
| 4459 | static my_bool include_database(const char *hash_key) |
| 4460 | { |
| 4461 | return !my_hash_search(&ignore_database, (uchar*) hash_key, strlen(hash_key)); |
| 4462 | } |
| 4463 | |
| 4464 | |
| 4465 | static int dump_all_databases() |
| 4466 | { |
| 4467 | MYSQL_ROW row; |
| 4468 | MYSQL_RES *tableres; |
| 4469 | int result=0; |
| 4470 | |
| 4471 | if (mysql_query_with_error_report(mysql, &tableres, "SHOW DATABASES" )) |
| 4472 | return 1; |
| 4473 | while ((row= mysql_fetch_row(tableres))) |
| 4474 | { |
| 4475 | if (mysql_get_server_version(mysql) >= FIRST_INFORMATION_SCHEMA_VERSION && |
| 4476 | !my_strcasecmp(&my_charset_latin1, row[0], INFORMATION_SCHEMA_DB_NAME)) |
| 4477 | continue; |
| 4478 | |
| 4479 | if (mysql_get_server_version(mysql) >= FIRST_PERFORMANCE_SCHEMA_VERSION && |
| 4480 | !my_strcasecmp(&my_charset_latin1, row[0], PERFORMANCE_SCHEMA_DB_NAME)) |
| 4481 | continue; |
| 4482 | |
| 4483 | if (include_database(row[0])) |
| 4484 | if (dump_all_tables_in_db(row[0])) |
| 4485 | result=1; |
| 4486 | } |
| 4487 | mysql_free_result(tableres); |
| 4488 | if (seen_views) |
| 4489 | { |
| 4490 | if (mysql_query(mysql, "SHOW DATABASES" ) || |
| 4491 | !(tableres= mysql_store_result(mysql))) |
| 4492 | { |
| 4493 | fprintf(stderr, "%s: Error: Couldn't execute 'SHOW DATABASES': %s\n" , |
| 4494 | my_progname_short, mysql_error(mysql)); |
| 4495 | return 1; |
| 4496 | } |
| 4497 | while ((row= mysql_fetch_row(tableres))) |
| 4498 | { |
| 4499 | if (mysql_get_server_version(mysql) >= FIRST_INFORMATION_SCHEMA_VERSION && |
| 4500 | !my_strcasecmp(&my_charset_latin1, row[0], INFORMATION_SCHEMA_DB_NAME)) |
| 4501 | continue; |
| 4502 | |
| 4503 | if (mysql_get_server_version(mysql) >= FIRST_PERFORMANCE_SCHEMA_VERSION && |
| 4504 | !my_strcasecmp(&my_charset_latin1, row[0], PERFORMANCE_SCHEMA_DB_NAME)) |
| 4505 | continue; |
| 4506 | |
| 4507 | if (include_database(row[0])) |
| 4508 | if (dump_all_views_in_db(row[0])) |
| 4509 | result=1; |
| 4510 | } |
| 4511 | mysql_free_result(tableres); |
| 4512 | } |
| 4513 | return result; |
| 4514 | } |
| 4515 | /* dump_all_databases */ |
| 4516 | |
| 4517 | |
| 4518 | static int dump_databases(char **db_names) |
| 4519 | { |
| 4520 | int result=0; |
| 4521 | char **db; |
| 4522 | DBUG_ENTER("dump_databases" ); |
| 4523 | |
| 4524 | for (db= db_names ; *db ; db++) |
| 4525 | { |
| 4526 | if (dump_all_tables_in_db(*db)) |
| 4527 | result=1; |
| 4528 | } |
| 4529 | if (!result && seen_views) |
| 4530 | { |
| 4531 | for (db= db_names ; *db ; db++) |
| 4532 | { |
| 4533 | if (dump_all_views_in_db(*db)) |
| 4534 | result=1; |
| 4535 | } |
| 4536 | } |
| 4537 | DBUG_RETURN(result); |
| 4538 | } /* dump_databases */ |
| 4539 | |
| 4540 | |
| 4541 | /* |
| 4542 | View Specific database initalization. |
| 4543 | |
| 4544 | SYNOPSIS |
| 4545 | init_dumping_views |
| 4546 | qdatabase quoted name of the database |
| 4547 | |
| 4548 | RETURN VALUES |
| 4549 | 0 Success. |
| 4550 | 1 Failure. |
| 4551 | */ |
| 4552 | int init_dumping_views(char *qdatabase __attribute__((unused))) |
| 4553 | { |
| 4554 | return 0; |
| 4555 | } /* init_dumping_views */ |
| 4556 | |
| 4557 | |
| 4558 | /* |
| 4559 | Table Specific database initalization. |
| 4560 | |
| 4561 | SYNOPSIS |
| 4562 | init_dumping_tables |
| 4563 | qdatabase quoted name of the database |
| 4564 | |
| 4565 | RETURN VALUES |
| 4566 | 0 Success. |
| 4567 | 1 Failure. |
| 4568 | */ |
| 4569 | |
| 4570 | int init_dumping_tables(char *qdatabase) |
| 4571 | { |
| 4572 | DBUG_ENTER("init_dumping_tables" ); |
| 4573 | |
| 4574 | if (!opt_create_db) |
| 4575 | { |
| 4576 | char qbuf[256]; |
| 4577 | MYSQL_ROW row; |
| 4578 | MYSQL_RES *dbinfo; |
| 4579 | |
| 4580 | my_snprintf(qbuf, sizeof(qbuf), |
| 4581 | "SHOW CREATE DATABASE IF NOT EXISTS %s" , |
| 4582 | qdatabase); |
| 4583 | |
| 4584 | if (mysql_query(mysql, qbuf) || !(dbinfo = mysql_store_result(mysql))) |
| 4585 | { |
| 4586 | /* Old server version, dump generic CREATE DATABASE */ |
| 4587 | if (opt_drop_database) |
| 4588 | fprintf(md_result_file, |
| 4589 | "\n/*!40000 DROP DATABASE IF EXISTS %s*/;\n" , |
| 4590 | qdatabase); |
| 4591 | fprintf(md_result_file, |
| 4592 | "\nCREATE DATABASE /*!32312 IF NOT EXISTS*/ %s;\n" , |
| 4593 | qdatabase); |
| 4594 | } |
| 4595 | else |
| 4596 | { |
| 4597 | if (opt_drop_database) |
| 4598 | fprintf(md_result_file, |
| 4599 | "\n/*!40000 DROP DATABASE IF EXISTS %s*/;\n" , |
| 4600 | qdatabase); |
| 4601 | row = mysql_fetch_row(dbinfo); |
| 4602 | if (row[1]) |
| 4603 | { |
| 4604 | fprintf(md_result_file,"\n%s;\n" ,row[1]); |
| 4605 | } |
| 4606 | mysql_free_result(dbinfo); |
| 4607 | } |
| 4608 | } |
| 4609 | DBUG_RETURN(0); |
| 4610 | } /* init_dumping_tables */ |
| 4611 | |
| 4612 | |
| 4613 | static int init_dumping(char *database, int init_func(char*)) |
| 4614 | { |
| 4615 | if (mysql_select_db(mysql, database)) |
| 4616 | { |
| 4617 | DB_error(mysql, "when selecting the database" ); |
| 4618 | return 1; /* If --force */ |
| 4619 | } |
| 4620 | if (!path && !opt_xml) |
| 4621 | { |
| 4622 | if (opt_databases || opt_alldbs) |
| 4623 | { |
| 4624 | /* |
| 4625 | length of table name * 2 (if name contains quotes), 2 quotes and 0 |
| 4626 | */ |
| 4627 | char quoted_database_buf[NAME_LEN*2+3]; |
| 4628 | char *qdatabase= quote_name(database,quoted_database_buf,opt_quoted); |
| 4629 | |
| 4630 | print_comment(md_result_file, 0, |
| 4631 | "\n--\n-- Current Database: %s\n--\n" , |
| 4632 | fix_for_comment(qdatabase)); |
| 4633 | |
| 4634 | /* Call the view or table specific function */ |
| 4635 | init_func(qdatabase); |
| 4636 | |
| 4637 | fprintf(md_result_file,"\nUSE %s;\n" , qdatabase); |
| 4638 | check_io(md_result_file); |
| 4639 | } |
| 4640 | } |
| 4641 | return 0; |
| 4642 | } /* init_dumping */ |
| 4643 | |
| 4644 | |
| 4645 | /* Return 1 if we should copy the table */ |
| 4646 | |
| 4647 | my_bool include_table(const uchar *hash_key, size_t len) |
| 4648 | { |
| 4649 | return ! my_hash_search(&ignore_table, hash_key, len); |
| 4650 | } |
| 4651 | |
| 4652 | |
| 4653 | static int dump_all_tables_in_db(char *database) |
| 4654 | { |
| 4655 | char *table; |
| 4656 | uint numrows; |
| 4657 | char table_buff[NAME_LEN*2+3]; |
| 4658 | char hash_key[2*NAME_LEN+2]; /* "db.tablename" */ |
| 4659 | char *afterdot; |
| 4660 | my_bool general_log_table_exists= 0, slow_log_table_exists=0; |
| 4661 | my_bool transaction_registry_table_exists= 0; |
| 4662 | int using_mysql_db= !my_strcasecmp(charset_info, database, "mysql" ); |
| 4663 | DBUG_ENTER("dump_all_tables_in_db" ); |
| 4664 | |
| 4665 | afterdot= strmov(hash_key, database); |
| 4666 | *afterdot++= '.'; |
| 4667 | |
| 4668 | if (init_dumping(database, init_dumping_tables)) |
| 4669 | DBUG_RETURN(1); |
| 4670 | if (opt_xml) |
| 4671 | print_xml_tag(md_result_file, "" , "\n" , "database" , "name=" , database, NullS); |
| 4672 | |
| 4673 | if (lock_tables) |
| 4674 | { |
| 4675 | DYNAMIC_STRING query; |
| 4676 | init_dynamic_string_checked(&query, "LOCK TABLES " , 256, 1024); |
| 4677 | for (numrows= 0 ; (table= getTableName(1)) ; ) |
| 4678 | { |
| 4679 | char *end= strmov(afterdot, table); |
| 4680 | if (include_table((uchar*) hash_key,end - hash_key)) |
| 4681 | { |
| 4682 | numrows++; |
| 4683 | dynstr_append_checked(&query, quote_name(table, table_buff, 1)); |
| 4684 | dynstr_append_checked(&query, " READ /*!32311 LOCAL */," ); |
| 4685 | } |
| 4686 | } |
| 4687 | if (numrows && mysql_real_query(mysql, query.str, (ulong)query.length-1)) |
| 4688 | { |
| 4689 | dynstr_free(&query); |
| 4690 | DB_error(mysql, "when using LOCK TABLES" ); |
| 4691 | /* We shall continue here, if --force was given */ |
| 4692 | } |
| 4693 | dynstr_free(&query); /* Safe to call twice */ |
| 4694 | } |
| 4695 | if (flush_logs) |
| 4696 | { |
| 4697 | if (mysql_refresh(mysql, REFRESH_LOG)) |
| 4698 | DB_error(mysql, "when doing refresh" ); |
| 4699 | /* We shall continue here, if --force was given */ |
| 4700 | else |
| 4701 | verbose_msg("-- dump_all_tables_in_db : logs flushed successfully!\n" ); |
| 4702 | } |
| 4703 | if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500) |
| 4704 | { |
| 4705 | verbose_msg("-- Setting savepoint...\n" ); |
| 4706 | if (mysql_query_with_error_report(mysql, 0, "SAVEPOINT sp" )) |
| 4707 | { |
| 4708 | DBUG_RETURN(1); |
| 4709 | } |
| 4710 | } |
| 4711 | while ((table= getTableName(0))) |
| 4712 | { |
| 4713 | char *end= strmov(afterdot, table); |
| 4714 | if (include_table((uchar*) hash_key, end - hash_key)) |
| 4715 | { |
| 4716 | dump_table(table,database); |
| 4717 | my_free(order_by); |
| 4718 | order_by= 0; |
| 4719 | if (opt_dump_triggers && mysql_get_server_version(mysql) >= 50009) |
| 4720 | { |
| 4721 | if (dump_triggers_for_table(table, database)) |
| 4722 | { |
| 4723 | if (path) |
| 4724 | my_fclose(md_result_file, MYF(MY_WME)); |
| 4725 | maybe_exit(EX_MYSQLERR); |
| 4726 | } |
| 4727 | } |
| 4728 | |
| 4729 | /** |
| 4730 | ROLLBACK TO SAVEPOINT in --single-transaction mode to release metadata |
| 4731 | lock on table which was already dumped. This allows to avoid blocking |
| 4732 | concurrent DDL on this table without sacrificing correctness, as we |
| 4733 | won't access table second time and dumps created by --single-transaction |
| 4734 | mode have validity point at the start of transaction anyway. |
| 4735 | Note that this doesn't make --single-transaction mode with concurrent |
| 4736 | DDL safe in general case. It just improves situation for people for whom |
| 4737 | it might be working. |
| 4738 | */ |
| 4739 | if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500) |
| 4740 | { |
| 4741 | verbose_msg("-- Rolling back to savepoint sp...\n" ); |
| 4742 | if (mysql_query_with_error_report(mysql, 0, "ROLLBACK TO SAVEPOINT sp" )) |
| 4743 | maybe_exit(EX_MYSQLERR); |
| 4744 | } |
| 4745 | } |
| 4746 | else |
| 4747 | { |
| 4748 | /* |
| 4749 | If general_log and slow_log exists in the 'mysql' database, |
| 4750 | we should dump the table structure. But we cannot |
| 4751 | call get_table_structure() here as 'LOCK TABLES' query got executed |
| 4752 | above on the session and that 'LOCK TABLES' query does not contain |
| 4753 | 'general_log' and 'slow_log' tables. (you cannot acquire lock |
| 4754 | on log tables). Hence mark the existence of these log tables here and |
| 4755 | after 'UNLOCK TABLES' query is executed on the session, get the table |
| 4756 | structure from server and dump it in the file. |
| 4757 | */ |
| 4758 | if (using_mysql_db) |
| 4759 | { |
| 4760 | if (!my_strcasecmp(charset_info, table, "general_log" )) |
| 4761 | general_log_table_exists= 1; |
| 4762 | else if (!my_strcasecmp(charset_info, table, "slow_log" )) |
| 4763 | slow_log_table_exists= 1; |
| 4764 | else if (!my_strcasecmp(charset_info, table, "transaction_registry" )) |
| 4765 | transaction_registry_table_exists= 1; |
| 4766 | } |
| 4767 | } |
| 4768 | } |
| 4769 | |
| 4770 | if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500) |
| 4771 | { |
| 4772 | verbose_msg("-- Releasing savepoint...\n" ); |
| 4773 | if (mysql_query_with_error_report(mysql, 0, "RELEASE SAVEPOINT sp" )) |
| 4774 | DBUG_RETURN(1); |
| 4775 | } |
| 4776 | |
| 4777 | if (opt_events && mysql_get_server_version(mysql) >= 50106) |
| 4778 | { |
| 4779 | DBUG_PRINT("info" , ("Dumping events for database %s" , database)); |
| 4780 | dump_events_for_db(database); |
| 4781 | } |
| 4782 | if (opt_routines && mysql_get_server_version(mysql) >= 50009) |
| 4783 | { |
| 4784 | DBUG_PRINT("info" , ("Dumping routines for database %s" , database)); |
| 4785 | dump_routines_for_db(database); |
| 4786 | } |
| 4787 | if (opt_xml) |
| 4788 | { |
| 4789 | fputs("</database>\n" , md_result_file); |
| 4790 | check_io(md_result_file); |
| 4791 | } |
| 4792 | if (lock_tables) |
| 4793 | (void) mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES" ); |
| 4794 | if (using_mysql_db) |
| 4795 | { |
| 4796 | char table_type[NAME_LEN]; |
| 4797 | char ignore_flag; |
| 4798 | if (general_log_table_exists) |
| 4799 | { |
| 4800 | if (!get_table_structure((char *) "general_log" , |
| 4801 | database, table_type, &ignore_flag) ) |
| 4802 | verbose_msg("-- Warning: get_table_structure() failed with some internal " |
| 4803 | "error for 'general_log' table\n" ); |
| 4804 | } |
| 4805 | if (slow_log_table_exists) |
| 4806 | { |
| 4807 | if (!get_table_structure((char *) "slow_log" , |
| 4808 | database, table_type, &ignore_flag) ) |
| 4809 | verbose_msg("-- Warning: get_table_structure() failed with some internal " |
| 4810 | "error for 'slow_log' table\n" ); |
| 4811 | } |
| 4812 | if (transaction_registry_table_exists) |
| 4813 | { |
| 4814 | if (!get_table_structure((char *) "transaction_registry" , |
| 4815 | database, table_type, &ignore_flag) ) |
| 4816 | verbose_msg("-- Warning: get_table_structure() failed with some internal " |
| 4817 | "error for 'transaction_registry' table\n" ); |
| 4818 | } |
| 4819 | } |
| 4820 | if (flush_privileges && using_mysql_db) |
| 4821 | { |
| 4822 | fprintf(md_result_file,"\n--\n-- Flush Grant Tables \n--\n" ); |
| 4823 | fprintf(md_result_file,"\n/*! FLUSH PRIVILEGES */;\n" ); |
| 4824 | } |
| 4825 | DBUG_RETURN(0); |
| 4826 | } /* dump_all_tables_in_db */ |
| 4827 | |
| 4828 | |
| 4829 | /* |
| 4830 | dump structure of views of database |
| 4831 | |
| 4832 | SYNOPSIS |
| 4833 | dump_all_views_in_db() |
| 4834 | database database name |
| 4835 | |
| 4836 | RETURN |
| 4837 | 0 OK |
| 4838 | 1 ERROR |
| 4839 | */ |
| 4840 | |
| 4841 | static my_bool dump_all_views_in_db(char *database) |
| 4842 | { |
| 4843 | char *table; |
| 4844 | uint numrows; |
| 4845 | char table_buff[NAME_LEN*2+3]; |
| 4846 | char hash_key[2*NAME_LEN+2]; /* "db.tablename" */ |
| 4847 | char *afterdot; |
| 4848 | |
| 4849 | afterdot= strmov(hash_key, database); |
| 4850 | *afterdot++= '.'; |
| 4851 | |
| 4852 | if (init_dumping(database, init_dumping_views)) |
| 4853 | return 1; |
| 4854 | if (opt_xml) |
| 4855 | print_xml_tag(md_result_file, "" , "\n" , "database" , "name=" , database, NullS); |
| 4856 | if (lock_tables) |
| 4857 | { |
| 4858 | DYNAMIC_STRING query; |
| 4859 | init_dynamic_string_checked(&query, "LOCK TABLES " , 256, 1024); |
| 4860 | for (numrows= 0 ; (table= getTableName(1)); ) |
| 4861 | { |
| 4862 | char *end= strmov(afterdot, table); |
| 4863 | if (include_table((uchar*) hash_key,end - hash_key)) |
| 4864 | { |
| 4865 | numrows++; |
| 4866 | dynstr_append_checked(&query, quote_name(table, table_buff, 1)); |
| 4867 | dynstr_append_checked(&query, " READ /*!32311 LOCAL */," ); |
| 4868 | } |
| 4869 | } |
| 4870 | if (numrows && mysql_real_query(mysql, query.str, (ulong)query.length-1)) |
| 4871 | DB_error(mysql, "when using LOCK TABLES" ); |
| 4872 | /* We shall continue here, if --force was given */ |
| 4873 | dynstr_free(&query); |
| 4874 | } |
| 4875 | if (flush_logs) |
| 4876 | { |
| 4877 | if (mysql_refresh(mysql, REFRESH_LOG)) |
| 4878 | DB_error(mysql, "when doing refresh" ); |
| 4879 | /* We shall continue here, if --force was given */ |
| 4880 | else |
| 4881 | verbose_msg("-- dump_all_views_in_db : logs flushed successfully!\n" ); |
| 4882 | } |
| 4883 | while ((table= getTableName(0))) |
| 4884 | { |
| 4885 | char *end= strmov(afterdot, table); |
| 4886 | if (include_table((uchar*) hash_key, end - hash_key)) |
| 4887 | get_view_structure(table, database); |
| 4888 | } |
| 4889 | if (opt_xml) |
| 4890 | { |
| 4891 | fputs("</database>\n" , md_result_file); |
| 4892 | check_io(md_result_file); |
| 4893 | } |
| 4894 | if (lock_tables) |
| 4895 | (void) mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES" ); |
| 4896 | return 0; |
| 4897 | } /* dump_all_tables_in_db */ |
| 4898 | |
| 4899 | |
| 4900 | /* |
| 4901 | See get_actual_table_name. Used to retrieve the correct table name |
| 4902 | from the database schema. |
| 4903 | */ |
| 4904 | static char *get_actual_table_name_helper(const char *old_table_name, |
| 4905 | my_bool case_sensitive, |
| 4906 | MEM_ROOT *root) |
| 4907 | { |
| 4908 | char *name= 0; |
| 4909 | MYSQL_RES *table_res; |
| 4910 | MYSQL_ROW row; |
| 4911 | char query[50 + 2*NAME_LEN]; |
| 4912 | char show_name_buff[FN_REFLEN]; |
| 4913 | DBUG_ENTER("get_actual_table_name_helper" ); |
| 4914 | |
| 4915 | /* Check memory for quote_for_like() */ |
| 4916 | DBUG_ASSERT(2*sizeof(old_table_name) < sizeof(show_name_buff)); |
| 4917 | |
| 4918 | if (case_sensitive) |
| 4919 | { |
| 4920 | DBUG_PRINT("info" , ("case sensitive search" )); |
| 4921 | my_snprintf(query, sizeof(query), |
| 4922 | "SELECT table_name FROM INFORMATION_SCHEMA.TABLES " |
| 4923 | "WHERE table_schema = DATABASE() AND table_name = %s" , |
| 4924 | quote_for_equal(old_table_name, show_name_buff)); |
| 4925 | } |
| 4926 | else |
| 4927 | { |
| 4928 | DBUG_PRINT("info" , ("case insensitive search" )); |
| 4929 | my_snprintf(query, sizeof(query), "SHOW TABLES LIKE %s" , |
| 4930 | quote_for_like(old_table_name, show_name_buff)); |
| 4931 | } |
| 4932 | |
| 4933 | if (mysql_query_with_error_report(mysql, 0, query)) |
| 4934 | return NullS; |
| 4935 | |
| 4936 | if ((table_res= mysql_store_result(mysql))) |
| 4937 | { |
| 4938 | my_ulonglong num_rows= mysql_num_rows(table_res); |
| 4939 | if (num_rows > 0) |
| 4940 | { |
| 4941 | ulong *lengths; |
| 4942 | /* |
| 4943 | Return first row |
| 4944 | TODO: Return all matching rows |
| 4945 | */ |
| 4946 | row= mysql_fetch_row(table_res); |
| 4947 | lengths= mysql_fetch_lengths(table_res); |
| 4948 | name= strmake_root(root, row[0], lengths[0]); |
| 4949 | } |
| 4950 | mysql_free_result(table_res); |
| 4951 | } |
| 4952 | DBUG_PRINT("exit" , ("new_table_name: %s" , name)); |
| 4953 | DBUG_RETURN(name); |
| 4954 | } |
| 4955 | |
| 4956 | /* |
| 4957 | get_actual_table_name -- executes a SELECT .. FROM I_S.tables to check |
| 4958 | if the table name given on the command line matches the one in the database. |
| 4959 | If the table is not found, it falls back to a slower SHOW TABLES LIKE '%s' to |
| 4960 | get the actual table name from the server. |
| 4961 | |
| 4962 | We do this because the table name given on the command line may be a |
| 4963 | different case (e.g. T1 vs t1), but checking this takes a long time |
| 4964 | when there are many tables present. |
| 4965 | |
| 4966 | RETURN |
| 4967 | pointer to the table name |
| 4968 | 0 if error |
| 4969 | */ |
| 4970 | |
| 4971 | static char *get_actual_table_name(const char *old_table_name, |
| 4972 | int lower_case_table_names, |
| 4973 | MEM_ROOT *root) |
| 4974 | { |
| 4975 | char *name= 0; |
| 4976 | DBUG_ENTER("get_actual_table_name" ); |
| 4977 | |
| 4978 | name= get_actual_table_name_helper(old_table_name, TRUE, root); |
| 4979 | if (!name && !lower_case_table_names) |
| 4980 | name= get_actual_table_name_helper(old_table_name, FALSE, root); |
| 4981 | DBUG_RETURN(name); |
| 4982 | } |
| 4983 | |
| 4984 | /* |
| 4985 | Retrieve the value for the server system variable lower_case_table_names. |
| 4986 | |
| 4987 | RETURN |
| 4988 | 0 case sensitive. |
| 4989 | > 0 case insensitive |
| 4990 | */ |
| 4991 | static int get_sys_var_lower_case_table_names() |
| 4992 | { |
| 4993 | int lower_case_table_names = 0; |
| 4994 | MYSQL_RES *table_res; |
| 4995 | MYSQL_ROW row; |
| 4996 | const char *show_var_query = "SHOW VARIABLES LIKE 'lower_case_table_names'" ; |
| 4997 | if (mysql_query_with_error_report(mysql, &table_res, show_var_query)) |
| 4998 | return 0; /* In case of error, assume default value of 0 */ |
| 4999 | |
| 5000 | if ((row= mysql_fetch_row(table_res))) |
| 5001 | { |
| 5002 | lower_case_table_names= atoi(row[1]); |
| 5003 | mysql_free_result(table_res); |
| 5004 | } |
| 5005 | |
| 5006 | return lower_case_table_names; |
| 5007 | } |
| 5008 | |
| 5009 | |
| 5010 | |
| 5011 | static int dump_selected_tables(char *db, char **table_names, int tables) |
| 5012 | { |
| 5013 | char table_buff[NAME_LEN*2+3]; |
| 5014 | DYNAMIC_STRING lock_tables_query; |
| 5015 | char **dump_tables, **pos, **end; |
| 5016 | int lower_case_table_names; |
| 5017 | DBUG_ENTER("dump_selected_tables" ); |
| 5018 | |
| 5019 | if (init_dumping(db, init_dumping_tables)) |
| 5020 | DBUG_RETURN(1); |
| 5021 | |
| 5022 | init_alloc_root(&glob_root, "glob_root" , 8192, 0, MYF(0)); |
| 5023 | if (!(dump_tables= pos= (char**) alloc_root(&glob_root, |
| 5024 | tables * sizeof(char *)))) |
| 5025 | die(EX_EOM, "alloc_root failure." ); |
| 5026 | |
| 5027 | /* Figure out how to compare table names. */ |
| 5028 | lower_case_table_names = get_sys_var_lower_case_table_names(); |
| 5029 | |
| 5030 | init_dynamic_string_checked(&lock_tables_query, "LOCK TABLES " , 256, 1024); |
| 5031 | for (; tables > 0 ; tables-- , table_names++) |
| 5032 | { |
| 5033 | /* the table name passed on commandline may be wrong case */ |
| 5034 | if ((*pos= get_actual_table_name(*table_names, lower_case_table_names, |
| 5035 | &glob_root))) |
| 5036 | { |
| 5037 | /* Add found table name to lock_tables_query */ |
| 5038 | if (lock_tables) |
| 5039 | { |
| 5040 | dynstr_append_checked(&lock_tables_query, quote_name(*pos, table_buff, 1)); |
| 5041 | dynstr_append_checked(&lock_tables_query, " READ /*!32311 LOCAL */," ); |
| 5042 | } |
| 5043 | pos++; |
| 5044 | } |
| 5045 | else |
| 5046 | { |
| 5047 | if (!ignore_errors) |
| 5048 | { |
| 5049 | dynstr_free(&lock_tables_query); |
| 5050 | free_root(&glob_root, MYF(0)); |
| 5051 | } |
| 5052 | maybe_die(EX_ILLEGAL_TABLE, "Couldn't find table: \"%s\"" , *table_names); |
| 5053 | /* We shall countinue here, if --force was given */ |
| 5054 | } |
| 5055 | } |
| 5056 | end= pos; |
| 5057 | |
| 5058 | /* Can't LOCK TABLES in I_S / P_S, so don't try. */ |
| 5059 | if (lock_tables && |
| 5060 | !(mysql_get_server_version(mysql) >= FIRST_INFORMATION_SCHEMA_VERSION && |
| 5061 | !my_strcasecmp(&my_charset_latin1, db, INFORMATION_SCHEMA_DB_NAME)) && |
| 5062 | !(mysql_get_server_version(mysql) >= FIRST_PERFORMANCE_SCHEMA_VERSION && |
| 5063 | !my_strcasecmp(&my_charset_latin1, db, PERFORMANCE_SCHEMA_DB_NAME))) |
| 5064 | { |
| 5065 | if (mysql_real_query(mysql, lock_tables_query.str, |
| 5066 | (ulong)lock_tables_query.length-1)) |
| 5067 | { |
| 5068 | if (!ignore_errors) |
| 5069 | { |
| 5070 | dynstr_free(&lock_tables_query); |
| 5071 | free_root(&glob_root, MYF(0)); |
| 5072 | } |
| 5073 | DB_error(mysql, "when doing LOCK TABLES" ); |
| 5074 | /* We shall countinue here, if --force was given */ |
| 5075 | } |
| 5076 | } |
| 5077 | dynstr_free(&lock_tables_query); |
| 5078 | if (flush_logs) |
| 5079 | { |
| 5080 | if (mysql_refresh(mysql, REFRESH_LOG)) |
| 5081 | { |
| 5082 | if (!ignore_errors) |
| 5083 | free_root(&glob_root, MYF(0)); |
| 5084 | DB_error(mysql, "when doing refresh" ); |
| 5085 | } |
| 5086 | /* We shall countinue here, if --force was given */ |
| 5087 | else |
| 5088 | verbose_msg("-- dump_selected_tables : logs flushed successfully!\n" ); |
| 5089 | } |
| 5090 | if (opt_xml) |
| 5091 | print_xml_tag(md_result_file, "" , "\n" , "database" , "name=" , db, NullS); |
| 5092 | |
| 5093 | if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500) |
| 5094 | { |
| 5095 | verbose_msg("-- Setting savepoint...\n" ); |
| 5096 | if (mysql_query_with_error_report(mysql, 0, "SAVEPOINT sp" )) |
| 5097 | { |
| 5098 | free_root(&glob_root, MYF(0)); |
| 5099 | DBUG_RETURN(1); |
| 5100 | } |
| 5101 | } |
| 5102 | |
| 5103 | /* Dump each selected table */ |
| 5104 | for (pos= dump_tables; pos < end; pos++) |
| 5105 | { |
| 5106 | DBUG_PRINT("info" ,("Dumping table %s" , *pos)); |
| 5107 | dump_table(*pos, db); |
| 5108 | if (opt_dump_triggers && |
| 5109 | mysql_get_server_version(mysql) >= 50009) |
| 5110 | { |
| 5111 | if (dump_triggers_for_table(*pos, db)) |
| 5112 | { |
| 5113 | if (path) |
| 5114 | my_fclose(md_result_file, MYF(MY_WME)); |
| 5115 | if (!ignore_errors) |
| 5116 | free_root(&glob_root, MYF(0)); |
| 5117 | maybe_exit(EX_MYSQLERR); |
| 5118 | } |
| 5119 | } |
| 5120 | |
| 5121 | /** |
| 5122 | ROLLBACK TO SAVEPOINT in --single-transaction mode to release metadata |
| 5123 | lock on table which was already dumped. This allows to avoid blocking |
| 5124 | concurrent DDL on this table without sacrificing correctness, as we |
| 5125 | won't access table second time and dumps created by --single-transaction |
| 5126 | mode have validity point at the start of transaction anyway. |
| 5127 | Note that this doesn't make --single-transaction mode with concurrent |
| 5128 | DDL safe in general case. It just improves situation for people for whom |
| 5129 | it might be working. |
| 5130 | */ |
| 5131 | if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500) |
| 5132 | { |
| 5133 | verbose_msg("-- Rolling back to savepoint sp...\n" ); |
| 5134 | if (mysql_query_with_error_report(mysql, 0, "ROLLBACK TO SAVEPOINT sp" )) |
| 5135 | { |
| 5136 | if (!ignore_errors) |
| 5137 | free_root(&glob_root, MYF(0)); |
| 5138 | maybe_exit(EX_MYSQLERR); |
| 5139 | } |
| 5140 | } |
| 5141 | } |
| 5142 | |
| 5143 | if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500) |
| 5144 | { |
| 5145 | verbose_msg("-- Releasing savepoint...\n" ); |
| 5146 | if (mysql_query_with_error_report(mysql, 0, "RELEASE SAVEPOINT sp" )) |
| 5147 | { |
| 5148 | free_root(&glob_root, MYF(0)); |
| 5149 | DBUG_RETURN(1); |
| 5150 | } |
| 5151 | } |
| 5152 | |
| 5153 | /* Dump each selected view */ |
| 5154 | if (seen_views) |
| 5155 | { |
| 5156 | for (pos= dump_tables; pos < end; pos++) |
| 5157 | get_view_structure(*pos, db); |
| 5158 | } |
| 5159 | if (opt_events && mysql_get_server_version(mysql) >= 50106) |
| 5160 | { |
| 5161 | DBUG_PRINT("info" , ("Dumping events for database %s" , db)); |
| 5162 | dump_events_for_db(db); |
| 5163 | } |
| 5164 | /* obtain dump of routines (procs/functions) */ |
| 5165 | if (opt_routines && mysql_get_server_version(mysql) >= 50009) |
| 5166 | { |
| 5167 | DBUG_PRINT("info" , ("Dumping routines for database %s" , db)); |
| 5168 | dump_routines_for_db(db); |
| 5169 | } |
| 5170 | free_root(&glob_root, MYF(0)); |
| 5171 | if (opt_xml) |
| 5172 | { |
| 5173 | fputs("</database>\n" , md_result_file); |
| 5174 | check_io(md_result_file); |
| 5175 | } |
| 5176 | if (lock_tables) |
| 5177 | (void) mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES" ); |
| 5178 | DBUG_RETURN(0); |
| 5179 | } /* dump_selected_tables */ |
| 5180 | |
| 5181 | |
| 5182 | static int do_show_master_status(MYSQL *mysql_con, int consistent_binlog_pos, |
| 5183 | int have_mariadb_gtid, int use_gtid) |
| 5184 | { |
| 5185 | MYSQL_ROW row; |
| 5186 | MYSQL_RES *UNINIT_VAR(master); |
| 5187 | char binlog_pos_file[FN_REFLEN]; |
| 5188 | char binlog_pos_offset[LONGLONG_LEN+1]; |
| 5189 | char gtid_pos[MAX_GTID_LENGTH]; |
| 5190 | char *file, *offset; |
| 5191 | const char *= |
| 5192 | (opt_master_data == MYSQL_OPT_MASTER_DATA_COMMENTED_SQL) ? "-- " : "" ; |
| 5193 | |
| 5194 | if (consistent_binlog_pos) |
| 5195 | { |
| 5196 | if(!check_consistent_binlog_pos(binlog_pos_file, binlog_pos_offset)) |
| 5197 | return 1; |
| 5198 | file= binlog_pos_file; |
| 5199 | offset= binlog_pos_offset; |
| 5200 | if (have_mariadb_gtid && |
| 5201 | get_binlog_gtid_pos(binlog_pos_file, binlog_pos_offset, gtid_pos)) |
| 5202 | return 1; |
| 5203 | } |
| 5204 | else |
| 5205 | { |
| 5206 | if (mysql_query_with_error_report(mysql_con, &master, |
| 5207 | "SHOW MASTER STATUS" )) |
| 5208 | return 1; |
| 5209 | |
| 5210 | row= mysql_fetch_row(master); |
| 5211 | if (row && row[0] && row[1]) |
| 5212 | { |
| 5213 | file= row[0]; |
| 5214 | offset= row[1]; |
| 5215 | } |
| 5216 | else |
| 5217 | { |
| 5218 | mysql_free_result(master); |
| 5219 | if (!ignore_errors) |
| 5220 | { |
| 5221 | /* SHOW MASTER STATUS reports nothing and --force is not enabled */ |
| 5222 | fprintf(stderr, "%s: Error: Binlogging on server not active\n" , |
| 5223 | my_progname_short); |
| 5224 | maybe_exit(EX_MYSQLERR); |
| 5225 | return 1; |
| 5226 | } |
| 5227 | else |
| 5228 | { |
| 5229 | return 0; |
| 5230 | } |
| 5231 | } |
| 5232 | |
| 5233 | if (have_mariadb_gtid && get_gtid_pos(gtid_pos, 1)) |
| 5234 | return 1; |
| 5235 | } |
| 5236 | |
| 5237 | /* SHOW MASTER STATUS reports file and position */ |
| 5238 | print_comment(md_result_file, 0, |
| 5239 | "\n--\n-- Position to start replication or point-in-time " |
| 5240 | "recovery from\n--\n\n" ); |
| 5241 | fprintf(md_result_file, |
| 5242 | "%sCHANGE MASTER TO MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n" , |
| 5243 | (use_gtid ? "-- " : comment_prefix), file, offset); |
| 5244 | if (have_mariadb_gtid) |
| 5245 | { |
| 5246 | print_comment(md_result_file, 0, |
| 5247 | "\n--\n-- GTID to start replication from\n--\n\n" ); |
| 5248 | if (use_gtid) |
| 5249 | fprintf(md_result_file, |
| 5250 | "%sCHANGE MASTER TO MASTER_USE_GTID=slave_pos;\n" , |
| 5251 | comment_prefix); |
| 5252 | fprintf(md_result_file, |
| 5253 | "%sSET GLOBAL gtid_slave_pos='%s';\n" , |
| 5254 | (!use_gtid ? "-- " : comment_prefix), gtid_pos); |
| 5255 | } |
| 5256 | check_io(md_result_file); |
| 5257 | |
| 5258 | if (!consistent_binlog_pos) |
| 5259 | mysql_free_result(master); |
| 5260 | |
| 5261 | return 0; |
| 5262 | } |
| 5263 | |
| 5264 | static int do_stop_slave_sql(MYSQL *mysql_con) |
| 5265 | { |
| 5266 | MYSQL_RES *slave; |
| 5267 | MYSQL_ROW row; |
| 5268 | |
| 5269 | if (mysql_query_with_error_report(mysql_con, &slave, |
| 5270 | multi_source ? |
| 5271 | "SHOW ALL SLAVES STATUS" : |
| 5272 | "SHOW SLAVE STATUS" )) |
| 5273 | return(1); |
| 5274 | |
| 5275 | /* Loop over all slaves */ |
| 5276 | while ((row= mysql_fetch_row(slave))) |
| 5277 | { |
| 5278 | if (row[11 + multi_source]) |
| 5279 | { |
| 5280 | /* if SLAVE SQL is not running, we don't stop it */ |
| 5281 | if (strcmp(row[11 + multi_source], "No" )) |
| 5282 | { |
| 5283 | char query[160]; |
| 5284 | if (multi_source) |
| 5285 | sprintf(query, "STOP SLAVE '%.80s' SQL_THREAD" , row[0]); |
| 5286 | else |
| 5287 | strmov(query, "STOP SLAVE SQL_THREAD" ); |
| 5288 | |
| 5289 | if (mysql_query_with_error_report(mysql_con, 0, query)) |
| 5290 | { |
| 5291 | mysql_free_result(slave); |
| 5292 | return 1; |
| 5293 | } |
| 5294 | } |
| 5295 | } |
| 5296 | } |
| 5297 | mysql_free_result(slave); |
| 5298 | return(0); |
| 5299 | } |
| 5300 | |
| 5301 | static int add_stop_slave(void) |
| 5302 | { |
| 5303 | if (opt_comments) |
| 5304 | fprintf(md_result_file, |
| 5305 | "\n--\n-- stop slave statement to make a recovery dump)\n--\n\n" ); |
| 5306 | if (multi_source) |
| 5307 | fprintf(md_result_file, "STOP ALL SLAVES;\n" ); |
| 5308 | else |
| 5309 | fprintf(md_result_file, "STOP SLAVE;\n" ); |
| 5310 | return(0); |
| 5311 | } |
| 5312 | |
| 5313 | static int add_slave_statements(void) |
| 5314 | { |
| 5315 | if (opt_comments) |
| 5316 | fprintf(md_result_file, |
| 5317 | "\n--\n-- start slave statement to make a recovery dump)\n--\n\n" ); |
| 5318 | if (multi_source) |
| 5319 | fprintf(md_result_file, "START ALL SLAVES;\n" ); |
| 5320 | else |
| 5321 | fprintf(md_result_file, "START SLAVE;\n" ); |
| 5322 | return(0); |
| 5323 | } |
| 5324 | |
| 5325 | static int do_show_slave_status(MYSQL *mysql_con, int use_gtid, |
| 5326 | int have_mariadb_gtid) |
| 5327 | { |
| 5328 | MYSQL_RES *UNINIT_VAR(slave); |
| 5329 | MYSQL_ROW row; |
| 5330 | const char *= |
| 5331 | (opt_slave_data == MYSQL_OPT_SLAVE_DATA_COMMENTED_SQL) ? "-- " : "" ; |
| 5332 | const char *= (use_gtid ? comment_prefix : "-- " ); |
| 5333 | const char *= (!use_gtid ? comment_prefix : "-- " ); |
| 5334 | int set_gtid_done= 0; |
| 5335 | |
| 5336 | if (mysql_query_with_error_report(mysql_con, &slave, |
| 5337 | multi_source ? |
| 5338 | "SHOW ALL SLAVES STATUS" : |
| 5339 | "SHOW SLAVE STATUS" )) |
| 5340 | { |
| 5341 | if (!ignore_errors) |
| 5342 | { |
| 5343 | /* SHOW SLAVE STATUS reports nothing and --force is not enabled */ |
| 5344 | fprintf(stderr, "%s: Error: Slave not set up\n" , my_progname_short); |
| 5345 | } |
| 5346 | mysql_free_result(slave); |
| 5347 | return 1; |
| 5348 | } |
| 5349 | |
| 5350 | while ((row= mysql_fetch_row(slave))) |
| 5351 | { |
| 5352 | if (multi_source && !set_gtid_done) |
| 5353 | { |
| 5354 | char gtid_pos[MAX_GTID_LENGTH]; |
| 5355 | if (have_mariadb_gtid && get_gtid_pos(gtid_pos, 0)) |
| 5356 | return 1; |
| 5357 | if (opt_comments) |
| 5358 | fprintf(md_result_file, "\n--\n-- Gtid position to start replication " |
| 5359 | "from\n--\n\n" ); |
| 5360 | fprintf(md_result_file, "%sSET GLOBAL gtid_slave_pos='%s';\n" , |
| 5361 | gtid_comment_prefix, gtid_pos); |
| 5362 | set_gtid_done= 1; |
| 5363 | } |
| 5364 | if (row[9 + multi_source] && row[21 + multi_source]) |
| 5365 | { |
| 5366 | if (use_gtid) |
| 5367 | { |
| 5368 | if (multi_source) |
| 5369 | fprintf(md_result_file, "%sCHANGE MASTER '%.80s' TO " |
| 5370 | "MASTER_USE_GTID=slave_pos;\n" , gtid_comment_prefix, row[0]); |
| 5371 | else |
| 5372 | fprintf(md_result_file, "%sCHANGE MASTER TO " |
| 5373 | "MASTER_USE_GTID=slave_pos;\n" , gtid_comment_prefix); |
| 5374 | } |
| 5375 | |
| 5376 | /* SHOW MASTER STATUS reports file and position */ |
| 5377 | if (opt_comments) |
| 5378 | fprintf(md_result_file, |
| 5379 | "\n--\n-- Position to start replication or point-in-time " |
| 5380 | "recovery from (the master of this slave)\n--\n\n" ); |
| 5381 | |
| 5382 | if (multi_source) |
| 5383 | fprintf(md_result_file, "%sCHANGE MASTER '%.80s' TO " , |
| 5384 | nogtid_comment_prefix, row[0]); |
| 5385 | else |
| 5386 | fprintf(md_result_file, "%sCHANGE MASTER TO " , nogtid_comment_prefix); |
| 5387 | |
| 5388 | if (opt_include_master_host_port) |
| 5389 | { |
| 5390 | if (row[1 + multi_source]) |
| 5391 | fprintf(md_result_file, "MASTER_HOST='%s', " , row[1 + multi_source]); |
| 5392 | if (row[3]) |
| 5393 | fprintf(md_result_file, "MASTER_PORT=%s, " , row[3 + multi_source]); |
| 5394 | } |
| 5395 | fprintf(md_result_file, |
| 5396 | "MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n" , |
| 5397 | row[9 + multi_source], row[21 + multi_source]); |
| 5398 | |
| 5399 | check_io(md_result_file); |
| 5400 | } |
| 5401 | } |
| 5402 | mysql_free_result(slave); |
| 5403 | return 0; |
| 5404 | } |
| 5405 | |
| 5406 | static int do_start_slave_sql(MYSQL *mysql_con) |
| 5407 | { |
| 5408 | MYSQL_RES *slave; |
| 5409 | MYSQL_ROW row; |
| 5410 | int error= 0; |
| 5411 | DBUG_ENTER("do_start_slave_sql" ); |
| 5412 | |
| 5413 | /* We need to check if the slave sql is stopped in the first place */ |
| 5414 | if (mysql_query_with_error_report(mysql_con, &slave, |
| 5415 | multi_source ? |
| 5416 | "SHOW ALL SLAVES STATUS" : |
| 5417 | "SHOW SLAVE STATUS" )) |
| 5418 | DBUG_RETURN(1); |
| 5419 | |
| 5420 | while ((row= mysql_fetch_row(slave))) |
| 5421 | { |
| 5422 | DBUG_PRINT("info" , ("Connection: '%s' status: '%s'" , |
| 5423 | multi_source ? row[0] : "" , row[11 + multi_source])); |
| 5424 | if (row[11 + multi_source]) |
| 5425 | { |
| 5426 | /* if SLAVE SQL is not running, we don't start it */ |
| 5427 | if (strcmp(row[11 + multi_source], "Yes" )) |
| 5428 | { |
| 5429 | char query[160]; |
| 5430 | if (multi_source) |
| 5431 | sprintf(query, "START SLAVE '%.80s'" , row[0]); |
| 5432 | else |
| 5433 | strmov(query, "START SLAVE" ); |
| 5434 | |
| 5435 | if (mysql_query_with_error_report(mysql_con, 0, query)) |
| 5436 | { |
| 5437 | fprintf(stderr, "%s: Error: Unable to start slave '%s'\n" , |
| 5438 | my_progname_short, multi_source ? row[0] : "" ); |
| 5439 | error= 1; |
| 5440 | } |
| 5441 | } |
| 5442 | } |
| 5443 | } |
| 5444 | mysql_free_result(slave); |
| 5445 | DBUG_RETURN(error); |
| 5446 | } |
| 5447 | |
| 5448 | |
| 5449 | |
| 5450 | static int do_flush_tables_read_lock(MYSQL *mysql_con) |
| 5451 | { |
| 5452 | /* |
| 5453 | We do first a FLUSH TABLES. If a long update is running, the FLUSH TABLES |
| 5454 | will wait but will not stall the whole mysqld, and when the long update is |
| 5455 | done the FLUSH TABLES WITH READ LOCK will start and succeed quickly. So, |
| 5456 | FLUSH TABLES is to lower the probability of a stage where both mysqldump |
| 5457 | and most client connections are stalled. Of course, if a second long |
| 5458 | update starts between the two FLUSHes, we have that bad stall. |
| 5459 | |
| 5460 | We use the LOCAL option, as we do not want the FLUSH TABLES replicated to |
| 5461 | other servers. |
| 5462 | */ |
| 5463 | return |
| 5464 | ( mysql_query_with_error_report(mysql_con, 0, |
| 5465 | "FLUSH /*!40101 LOCAL */ TABLES" ) || |
| 5466 | mysql_query_with_error_report(mysql_con, 0, |
| 5467 | "FLUSH TABLES WITH READ LOCK" ) ); |
| 5468 | } |
| 5469 | |
| 5470 | |
| 5471 | static int do_unlock_tables(MYSQL *mysql_con) |
| 5472 | { |
| 5473 | return mysql_query_with_error_report(mysql_con, 0, "UNLOCK TABLES" ); |
| 5474 | } |
| 5475 | |
| 5476 | static int get_bin_log_name(MYSQL *mysql_con, |
| 5477 | char* buff_log_name, uint buff_len) |
| 5478 | { |
| 5479 | MYSQL_RES *res; |
| 5480 | MYSQL_ROW row; |
| 5481 | |
| 5482 | if (mysql_query(mysql_con, "SHOW MASTER STATUS" ) || |
| 5483 | !(res= mysql_store_result(mysql))) |
| 5484 | return 1; |
| 5485 | |
| 5486 | if (!(row= mysql_fetch_row(res))) |
| 5487 | { |
| 5488 | mysql_free_result(res); |
| 5489 | return 1; |
| 5490 | } |
| 5491 | /* |
| 5492 | Only one row is returned, and the first column is the name of the |
| 5493 | active log. |
| 5494 | */ |
| 5495 | strmake(buff_log_name, row[0], buff_len - 1); |
| 5496 | |
| 5497 | mysql_free_result(res); |
| 5498 | return 0; |
| 5499 | } |
| 5500 | |
| 5501 | static int purge_bin_logs_to(MYSQL *mysql_con, char* log_name) |
| 5502 | { |
| 5503 | DYNAMIC_STRING str; |
| 5504 | int err; |
| 5505 | init_dynamic_string_checked(&str, "PURGE BINARY LOGS TO '" , 1024, 1024); |
| 5506 | dynstr_append_checked(&str, log_name); |
| 5507 | dynstr_append_checked(&str, "'" ); |
| 5508 | err = mysql_query_with_error_report(mysql_con, 0, str.str); |
| 5509 | dynstr_free(&str); |
| 5510 | return err; |
| 5511 | } |
| 5512 | |
| 5513 | |
| 5514 | static int start_transaction(MYSQL *mysql_con) |
| 5515 | { |
| 5516 | verbose_msg("-- Starting transaction...\n" ); |
| 5517 | /* |
| 5518 | We use BEGIN for old servers. --single-transaction --master-data will fail |
| 5519 | on old servers, but that's ok as it was already silently broken (it didn't |
| 5520 | do a consistent read, so better tell people frankly, with the error). |
| 5521 | |
| 5522 | We want the first consistent read to be used for all tables to dump so we |
| 5523 | need the REPEATABLE READ level (not anything lower, for example READ |
| 5524 | COMMITTED would give one new consistent read per dumped table). |
| 5525 | */ |
| 5526 | if ((mysql_get_server_version(mysql_con) < 40100) && opt_master_data) |
| 5527 | { |
| 5528 | fprintf(stderr, "-- %s: the combination of --single-transaction and " |
| 5529 | "--master-data requires a MySQL server version of at least 4.1 " |
| 5530 | "(current server's version is %s). %s\n" , |
| 5531 | ignore_errors ? "Warning" : "Error" , |
| 5532 | mysql_con->server_version ? mysql_con->server_version : "unknown" , |
| 5533 | ignore_errors ? "Continuing due to --force, backup may not be consistent across all tables!" : "Aborting." ); |
| 5534 | if (!ignore_errors) |
| 5535 | exit(EX_MYSQLERR); |
| 5536 | } |
| 5537 | |
| 5538 | return (mysql_query_with_error_report(mysql_con, 0, |
| 5539 | "SET SESSION TRANSACTION ISOLATION " |
| 5540 | "LEVEL REPEATABLE READ" ) || |
| 5541 | mysql_query_with_error_report(mysql_con, 0, |
| 5542 | "START TRANSACTION " |
| 5543 | "/*!40100 WITH CONSISTENT SNAPSHOT */" )); |
| 5544 | } |
| 5545 | |
| 5546 | |
| 5547 | static ulong find_set(TYPELIB *lib, const char *x, size_t length, |
| 5548 | char **err_pos, uint *err_len) |
| 5549 | { |
| 5550 | const char *end= x + length; |
| 5551 | ulong found= 0; |
| 5552 | uint find; |
| 5553 | char buff[255]; |
| 5554 | |
| 5555 | *err_pos= 0; /* No error yet */ |
| 5556 | while (end > x && my_isspace(charset_info, end[-1])) |
| 5557 | end--; |
| 5558 | |
| 5559 | *err_len= 0; |
| 5560 | if (x != end) |
| 5561 | { |
| 5562 | const char *start= x; |
| 5563 | for (;;) |
| 5564 | { |
| 5565 | const char *pos= start; |
| 5566 | uint var_len; |
| 5567 | |
| 5568 | for (; pos != end && *pos != ','; pos++) ; |
| 5569 | var_len= (uint) (pos - start); |
| 5570 | strmake(buff, start, MY_MIN(sizeof(buff) - 1, var_len)); |
| 5571 | find= find_type(buff, lib, FIND_TYPE_BASIC); |
| 5572 | if (find <= 0) |
| 5573 | { |
| 5574 | *err_pos= (char*) start; |
| 5575 | *err_len= var_len; |
| 5576 | } |
| 5577 | else |
| 5578 | found|= 1UL << (find - 1); |
| 5579 | if (pos == end) |
| 5580 | break; |
| 5581 | start= pos + 1; |
| 5582 | } |
| 5583 | } |
| 5584 | return found; |
| 5585 | } |
| 5586 | |
| 5587 | |
| 5588 | /* Print a value with a prefix on file */ |
| 5589 | static void print_value(FILE *file, MYSQL_RES *result, MYSQL_ROW row, |
| 5590 | const char *prefix, const char *name, |
| 5591 | int string_value) |
| 5592 | { |
| 5593 | MYSQL_FIELD *field; |
| 5594 | mysql_field_seek(result, 0); |
| 5595 | |
| 5596 | for ( ; (field= mysql_fetch_field(result)) ; row++) |
| 5597 | { |
| 5598 | if (!strcmp(field->name,name)) |
| 5599 | { |
| 5600 | if (row[0] && row[0][0] && strcmp(row[0],"0" )) /* Skip default */ |
| 5601 | { |
| 5602 | fputc(' ',file); |
| 5603 | fputs(prefix, file); |
| 5604 | if (string_value) |
| 5605 | unescape(file,row[0], strlen(row[0])); |
| 5606 | else |
| 5607 | fputs(row[0], file); |
| 5608 | check_io(file); |
| 5609 | return; |
| 5610 | } |
| 5611 | } |
| 5612 | } |
| 5613 | return; /* This shouldn't happen */ |
| 5614 | } /* print_value */ |
| 5615 | |
| 5616 | |
| 5617 | /* |
| 5618 | SYNOPSIS |
| 5619 | |
| 5620 | Check if we the table is one of the table types that should be ignored: |
| 5621 | MRG_ISAM, MRG_MYISAM, if opt_delayed, if that table supports delayed inserts. |
| 5622 | If the table should be altogether ignored, it returns a TRUE, FALSE if it |
| 5623 | should not be ignored. If the user has selected to use INSERT DELAYED, it |
| 5624 | sets the value of the bool pointer supports_delayed_inserts to 0 if not |
| 5625 | supported, 1 if it is supported. |
| 5626 | |
| 5627 | ARGS |
| 5628 | |
| 5629 | check_if_ignore_table() |
| 5630 | table_name Table name to check |
| 5631 | table_type Type of table |
| 5632 | |
| 5633 | GLOBAL VARIABLES |
| 5634 | mysql MySQL connection |
| 5635 | verbose Write warning messages |
| 5636 | |
| 5637 | RETURN |
| 5638 | char (bit value) See IGNORE_ values at top |
| 5639 | */ |
| 5640 | |
| 5641 | char check_if_ignore_table(const char *table_name, char *table_type) |
| 5642 | { |
| 5643 | char result= IGNORE_NONE; |
| 5644 | char buff[FN_REFLEN+80], show_name_buff[FN_REFLEN]; |
| 5645 | MYSQL_RES *res= NULL; |
| 5646 | MYSQL_ROW row; |
| 5647 | DBUG_ENTER("check_if_ignore_table" ); |
| 5648 | |
| 5649 | /* Check memory for quote_for_like() */ |
| 5650 | DBUG_ASSERT(2*sizeof(table_name) < sizeof(show_name_buff)); |
| 5651 | my_snprintf(buff, sizeof(buff), |
| 5652 | "SELECT engine FROM INFORMATION_SCHEMA.TABLES " |
| 5653 | "WHERE table_schema = DATABASE() AND table_name = %s" , |
| 5654 | quote_for_equal(table_name, show_name_buff)); |
| 5655 | if (mysql_query_with_error_report(mysql, &res, buff)) |
| 5656 | { |
| 5657 | if (mysql_errno(mysql) != ER_PARSE_ERROR) |
| 5658 | { /* If old MySQL version */ |
| 5659 | verbose_msg("-- Warning: Couldn't get status information for " |
| 5660 | "table %s (%s)\n" , table_name, mysql_error(mysql)); |
| 5661 | DBUG_RETURN(result); /* assume table is ok */ |
| 5662 | } |
| 5663 | } |
| 5664 | if (!(row= mysql_fetch_row(res))) |
| 5665 | { |
| 5666 | fprintf(stderr, |
| 5667 | "Error: Couldn't read status information for table %s (%s)\n" , |
| 5668 | table_name, mysql_error(mysql)); |
| 5669 | mysql_free_result(res); |
| 5670 | DBUG_RETURN(result); /* assume table is ok */ |
| 5671 | } |
| 5672 | if (!(row[0])) |
| 5673 | strmake(table_type, "VIEW" , NAME_LEN-1); |
| 5674 | else |
| 5675 | { |
| 5676 | /* |
| 5677 | If the table type matches any of these, we do support delayed inserts. |
| 5678 | Note: we do not want to skip dumping this table if if is not one of |
| 5679 | these types, but we do want to use delayed inserts in the dump if |
| 5680 | the table type is _NOT_ one of these types |
| 5681 | */ |
| 5682 | strmake(table_type, row[0], NAME_LEN-1); |
| 5683 | if (opt_delayed) |
| 5684 | { |
| 5685 | if (strcmp(table_type,"MyISAM" ) && |
| 5686 | strcmp(table_type,"ISAM" ) && |
| 5687 | strcmp(table_type,"ARCHIVE" ) && |
| 5688 | strcmp(table_type,"HEAP" ) && |
| 5689 | strcmp(table_type,"MEMORY" )) |
| 5690 | result= IGNORE_INSERT_DELAYED; |
| 5691 | } |
| 5692 | |
| 5693 | /* |
| 5694 | If these two types, we do want to skip dumping the table |
| 5695 | */ |
| 5696 | if (!opt_no_data && opt_no_data_med) |
| 5697 | { |
| 5698 | const char *found= strstr(" " MED_ENGINES "," , table_type); |
| 5699 | if (found && found[-1] == ' ' && found[strlen(table_type)] == ',') |
| 5700 | result= IGNORE_DATA; |
| 5701 | } |
| 5702 | } |
| 5703 | mysql_free_result(res); |
| 5704 | DBUG_RETURN(result); |
| 5705 | } |
| 5706 | |
| 5707 | |
| 5708 | /* |
| 5709 | Get string of comma-separated primary key field names |
| 5710 | |
| 5711 | SYNOPSIS |
| 5712 | char *primary_key_fields(const char *table_name) |
| 5713 | RETURNS pointer to allocated buffer (must be freed by caller) |
| 5714 | table_name quoted table name |
| 5715 | |
| 5716 | DESCRIPTION |
| 5717 | Use SHOW KEYS FROM table_name, allocate a buffer to hold the |
| 5718 | field names, and then build that string and return the pointer |
| 5719 | to that buffer. |
| 5720 | |
| 5721 | Returns NULL if there is no PRIMARY or UNIQUE key on the table, |
| 5722 | or if there is some failure. It is better to continue to dump |
| 5723 | the table unsorted, rather than exit without dumping the data. |
| 5724 | */ |
| 5725 | |
| 5726 | static char *primary_key_fields(const char *table_name) |
| 5727 | { |
| 5728 | MYSQL_RES *res= NULL; |
| 5729 | MYSQL_ROW row; |
| 5730 | /* SHOW KEYS FROM + table name * 2 (escaped) + 2 quotes + \0 */ |
| 5731 | char show_keys_buff[15 + NAME_LEN * 2 + 3]; |
| 5732 | size_t result_length= 0; |
| 5733 | char *result= 0; |
| 5734 | char buff[NAME_LEN * 2 + 3]; |
| 5735 | char *quoted_field; |
| 5736 | |
| 5737 | my_snprintf(show_keys_buff, sizeof(show_keys_buff), |
| 5738 | "SHOW KEYS FROM %s" , table_name); |
| 5739 | if (mysql_query(mysql, show_keys_buff) || |
| 5740 | !(res= mysql_store_result(mysql))) |
| 5741 | { |
| 5742 | fprintf(stderr, "Warning: Couldn't read keys from table %s;" |
| 5743 | " records are NOT sorted (%s)\n" , |
| 5744 | table_name, mysql_error(mysql)); |
| 5745 | /* Don't exit, because it's better to print out unsorted records */ |
| 5746 | goto cleanup; |
| 5747 | } |
| 5748 | |
| 5749 | /* |
| 5750 | * Figure out the length of the ORDER BY clause result. |
| 5751 | * Note that SHOW KEYS is ordered: a PRIMARY key is always the first |
| 5752 | * row, and UNIQUE keys come before others. So we only need to check |
| 5753 | * the first key, not all keys. |
| 5754 | */ |
| 5755 | if ((row= mysql_fetch_row(res)) && atoi(row[1]) == 0) |
| 5756 | { |
| 5757 | /* Key is unique */ |
| 5758 | do |
| 5759 | { |
| 5760 | quoted_field= quote_name(row[4], buff, 0); |
| 5761 | result_length+= strlen(quoted_field) + 1; /* + 1 for ',' or \0 */ |
| 5762 | } while ((row= mysql_fetch_row(res)) && atoi(row[3]) > 1); |
| 5763 | } |
| 5764 | |
| 5765 | /* Build the ORDER BY clause result */ |
| 5766 | if (result_length) |
| 5767 | { |
| 5768 | char *end; |
| 5769 | /* result (terminating \0 is already in result_length) */ |
| 5770 | result= my_malloc(result_length + 10, MYF(MY_WME)); |
| 5771 | if (!result) |
| 5772 | { |
| 5773 | fprintf(stderr, "Error: Not enough memory to store ORDER BY clause\n" ); |
| 5774 | goto cleanup; |
| 5775 | } |
| 5776 | mysql_data_seek(res, 0); |
| 5777 | row= mysql_fetch_row(res); |
| 5778 | quoted_field= quote_name(row[4], buff, 0); |
| 5779 | end= strmov(result, quoted_field); |
| 5780 | while ((row= mysql_fetch_row(res)) && atoi(row[3]) > 1) |
| 5781 | { |
| 5782 | quoted_field= quote_name(row[4], buff, 0); |
| 5783 | end= strxmov(end, "," , quoted_field, NullS); |
| 5784 | } |
| 5785 | } |
| 5786 | |
| 5787 | cleanup: |
| 5788 | if (res) |
| 5789 | mysql_free_result(res); |
| 5790 | |
| 5791 | return result; |
| 5792 | } |
| 5793 | |
| 5794 | |
| 5795 | /* |
| 5796 | Replace a substring |
| 5797 | |
| 5798 | SYNOPSIS |
| 5799 | replace |
| 5800 | ds_str The string to search and perform the replace in |
| 5801 | search_str The string to search for |
| 5802 | search_len Length of the string to search for |
| 5803 | replace_str The string to replace with |
| 5804 | replace_len Length of the string to replace with |
| 5805 | |
| 5806 | RETURN |
| 5807 | 0 String replaced |
| 5808 | 1 Could not find search_str in str |
| 5809 | */ |
| 5810 | |
| 5811 | static int replace(DYNAMIC_STRING *ds_str, |
| 5812 | const char *search_str, ulong search_len, |
| 5813 | const char *replace_str, ulong replace_len) |
| 5814 | { |
| 5815 | DYNAMIC_STRING ds_tmp; |
| 5816 | const char *start= strstr(ds_str->str, search_str); |
| 5817 | if (!start) |
| 5818 | return 1; |
| 5819 | init_dynamic_string_checked(&ds_tmp, "" , |
| 5820 | ds_str->length + replace_len, 256); |
| 5821 | dynstr_append_mem_checked(&ds_tmp, ds_str->str, (uint)(start - ds_str->str)); |
| 5822 | dynstr_append_mem_checked(&ds_tmp, replace_str, replace_len); |
| 5823 | dynstr_append_checked(&ds_tmp, start + search_len); |
| 5824 | dynstr_set_checked(ds_str, ds_tmp.str); |
| 5825 | dynstr_free(&ds_tmp); |
| 5826 | return 0; |
| 5827 | } |
| 5828 | |
| 5829 | |
| 5830 | /* |
| 5831 | Getting VIEW structure |
| 5832 | |
| 5833 | SYNOPSIS |
| 5834 | get_view_structure() |
| 5835 | table view name |
| 5836 | db db name |
| 5837 | |
| 5838 | RETURN |
| 5839 | 0 OK |
| 5840 | 1 ERROR |
| 5841 | */ |
| 5842 | |
| 5843 | static my_bool get_view_structure(char *table, char* db) |
| 5844 | { |
| 5845 | MYSQL_RES *table_res; |
| 5846 | MYSQL_ROW row; |
| 5847 | MYSQL_FIELD *field; |
| 5848 | char *result_table, *opt_quoted_table; |
| 5849 | char table_buff[NAME_LEN*2+3]; |
| 5850 | char table_buff2[NAME_LEN*2+3]; |
| 5851 | char query[QUERY_LENGTH]; |
| 5852 | FILE *sql_file= md_result_file; |
| 5853 | DBUG_ENTER("get_view_structure" ); |
| 5854 | |
| 5855 | if (opt_no_create_info) /* Don't write table creation info */ |
| 5856 | DBUG_RETURN(0); |
| 5857 | |
| 5858 | verbose_msg("-- Retrieving view structure for table %s...\n" , table); |
| 5859 | |
| 5860 | #ifdef NOT_REALLY_USED_YET |
| 5861 | dynstr_append_checked(&insert_pat, "SET SQL_QUOTE_SHOW_CREATE=" ); |
| 5862 | dynstr_append_checked(&insert_pat, (opt_quoted || opt_keywords)? "1" :"0" ); |
| 5863 | #endif |
| 5864 | |
| 5865 | result_table= quote_name(table, table_buff, 1); |
| 5866 | opt_quoted_table= quote_name(table, table_buff2, 0); |
| 5867 | |
| 5868 | if (switch_character_set_results(mysql, "binary" )) |
| 5869 | DBUG_RETURN(1); |
| 5870 | |
| 5871 | my_snprintf(query, sizeof(query), "SHOW CREATE TABLE %s" , result_table); |
| 5872 | |
| 5873 | if (mysql_query_with_error_report(mysql, &table_res, query)) |
| 5874 | { |
| 5875 | switch_character_set_results(mysql, default_charset); |
| 5876 | DBUG_RETURN(0); |
| 5877 | } |
| 5878 | |
| 5879 | /* Check if this is a view */ |
| 5880 | field= mysql_fetch_field_direct(table_res, 0); |
| 5881 | if (strcmp(field->name, "View" ) != 0) |
| 5882 | { |
| 5883 | mysql_free_result(table_res); |
| 5884 | switch_character_set_results(mysql, default_charset); |
| 5885 | verbose_msg("-- It's base table, skipped\n" ); |
| 5886 | DBUG_RETURN(0); |
| 5887 | } |
| 5888 | |
| 5889 | /* If requested, open separate .sql file for this view */ |
| 5890 | if (path) |
| 5891 | { |
| 5892 | if (!(sql_file= open_sql_file_for_table(table, O_WRONLY))) |
| 5893 | { |
| 5894 | mysql_free_result(table_res); |
| 5895 | DBUG_RETURN(1); |
| 5896 | } |
| 5897 | write_header(sql_file, db); |
| 5898 | } |
| 5899 | |
| 5900 | print_comment(sql_file, 0, |
| 5901 | "\n--\n-- Final view structure for view %s\n--\n\n" , |
| 5902 | fix_for_comment(result_table)); |
| 5903 | |
| 5904 | /* Table might not exist if this view was dumped with --tab. */ |
| 5905 | fprintf(sql_file, "/*!50001 DROP TABLE IF EXISTS %s*/;\n" , opt_quoted_table); |
| 5906 | if (opt_drop) |
| 5907 | { |
| 5908 | fprintf(sql_file, "/*!50001 DROP VIEW IF EXISTS %s*/;\n" , |
| 5909 | opt_quoted_table); |
| 5910 | check_io(sql_file); |
| 5911 | } |
| 5912 | |
| 5913 | |
| 5914 | my_snprintf(query, sizeof(query), |
| 5915 | "SELECT CHECK_OPTION, DEFINER, SECURITY_TYPE, " |
| 5916 | " CHARACTER_SET_CLIENT, COLLATION_CONNECTION " |
| 5917 | "FROM information_schema.views " |
| 5918 | "WHERE table_name=\"%s\" AND table_schema=\"%s\"" , table, db); |
| 5919 | |
| 5920 | if (mysql_query(mysql, query)) |
| 5921 | { |
| 5922 | /* |
| 5923 | Use the raw output from SHOW CREATE TABLE if |
| 5924 | information_schema query fails. |
| 5925 | */ |
| 5926 | row= mysql_fetch_row(table_res); |
| 5927 | fprintf(sql_file, "/*!50001 %s */;\n" , row[1]); |
| 5928 | check_io(sql_file); |
| 5929 | mysql_free_result(table_res); |
| 5930 | } |
| 5931 | else |
| 5932 | { |
| 5933 | char *ptr; |
| 5934 | ulong *lengths; |
| 5935 | char search_buf[256], replace_buf[256]; |
| 5936 | ulong search_len, replace_len; |
| 5937 | DYNAMIC_STRING ds_view; |
| 5938 | |
| 5939 | /* Save the result of SHOW CREATE TABLE in ds_view */ |
| 5940 | row= mysql_fetch_row(table_res); |
| 5941 | lengths= mysql_fetch_lengths(table_res); |
| 5942 | init_dynamic_string_checked(&ds_view, row[1], lengths[1] + 1, 1024); |
| 5943 | mysql_free_result(table_res); |
| 5944 | |
| 5945 | /* Get the result from "select ... information_schema" */ |
| 5946 | if (!(table_res= mysql_store_result(mysql)) || |
| 5947 | !(row= mysql_fetch_row(table_res))) |
| 5948 | { |
| 5949 | if (table_res) |
| 5950 | mysql_free_result(table_res); |
| 5951 | dynstr_free(&ds_view); |
| 5952 | DB_error(mysql, "when trying to save the result of SHOW CREATE TABLE in ds_view." ); |
| 5953 | DBUG_RETURN(1); |
| 5954 | } |
| 5955 | |
| 5956 | lengths= mysql_fetch_lengths(table_res); |
| 5957 | |
| 5958 | /* |
| 5959 | "WITH %s CHECK OPTION" is available from 5.0.2 |
| 5960 | Surround it with !50002 comments |
| 5961 | */ |
| 5962 | if (strcmp(row[0], "NONE" )) |
| 5963 | { |
| 5964 | |
| 5965 | ptr= search_buf; |
| 5966 | search_len= (ulong)(strxmov(ptr, "WITH " , row[0], |
| 5967 | " CHECK OPTION" , NullS) - ptr); |
| 5968 | ptr= replace_buf; |
| 5969 | replace_len=(ulong)(strxmov(ptr, "*/\n/*!50002 WITH " , row[0], |
| 5970 | " CHECK OPTION" , NullS) - ptr); |
| 5971 | replace(&ds_view, search_buf, search_len, replace_buf, replace_len); |
| 5972 | } |
| 5973 | |
| 5974 | /* |
| 5975 | "DEFINER=%s SQL SECURITY %s" is available from 5.0.13 |
| 5976 | Surround it with !50013 comments |
| 5977 | */ |
| 5978 | { |
| 5979 | size_t user_name_len; |
| 5980 | char user_name_str[USERNAME_LENGTH + 1]; |
| 5981 | char quoted_user_name_str[USERNAME_LENGTH * 2 + 3]; |
| 5982 | size_t host_name_len; |
| 5983 | char host_name_str[HOSTNAME_LENGTH + 1]; |
| 5984 | char quoted_host_name_str[HOSTNAME_LENGTH * 2 + 3]; |
| 5985 | |
| 5986 | parse_user(row[1], lengths[1], user_name_str, &user_name_len, |
| 5987 | host_name_str, &host_name_len); |
| 5988 | |
| 5989 | ptr= search_buf; |
| 5990 | search_len= |
| 5991 | (ulong)(strxmov(ptr, "DEFINER=" , |
| 5992 | quote_name(user_name_str, quoted_user_name_str, FALSE), |
| 5993 | "@" , |
| 5994 | quote_name(host_name_str, quoted_host_name_str, FALSE), |
| 5995 | " SQL SECURITY " , row[2], NullS) - ptr); |
| 5996 | ptr= replace_buf; |
| 5997 | replace_len= |
| 5998 | (ulong)(strxmov(ptr, "*/\n/*!50013 DEFINER=" , |
| 5999 | quote_name(user_name_str, quoted_user_name_str, FALSE), |
| 6000 | "@" , |
| 6001 | quote_name(host_name_str, quoted_host_name_str, FALSE), |
| 6002 | " SQL SECURITY " , row[2], |
| 6003 | " */\n/*!50001" , NullS) - ptr); |
| 6004 | replace(&ds_view, search_buf, search_len, replace_buf, replace_len); |
| 6005 | } |
| 6006 | |
| 6007 | /* Dump view structure to file */ |
| 6008 | |
| 6009 | fprintf(sql_file, |
| 6010 | "/*!50001 SET @saved_cs_client = @@character_set_client */;\n" |
| 6011 | "/*!50001 SET @saved_cs_results = @@character_set_results */;\n" |
| 6012 | "/*!50001 SET @saved_col_connection = @@collation_connection */;\n" |
| 6013 | "/*!50001 SET character_set_client = %s */;\n" |
| 6014 | "/*!50001 SET character_set_results = %s */;\n" |
| 6015 | "/*!50001 SET collation_connection = %s */;\n" |
| 6016 | "/*!50001 %s */;\n" |
| 6017 | "/*!50001 SET character_set_client = @saved_cs_client */;\n" |
| 6018 | "/*!50001 SET character_set_results = @saved_cs_results */;\n" |
| 6019 | "/*!50001 SET collation_connection = @saved_col_connection */;\n" , |
| 6020 | (const char *) row[3], |
| 6021 | (const char *) row[3], |
| 6022 | (const char *) row[4], |
| 6023 | (const char *) ds_view.str); |
| 6024 | |
| 6025 | check_io(sql_file); |
| 6026 | mysql_free_result(table_res); |
| 6027 | dynstr_free(&ds_view); |
| 6028 | } |
| 6029 | |
| 6030 | switch_character_set_results(mysql, default_charset); |
| 6031 | |
| 6032 | /* If a separate .sql file was opened, close it now */ |
| 6033 | if (sql_file != md_result_file) |
| 6034 | { |
| 6035 | fputs("\n" , sql_file); |
| 6036 | write_footer(sql_file); |
| 6037 | my_fclose(sql_file, MYF(MY_WME)); |
| 6038 | } |
| 6039 | DBUG_RETURN(0); |
| 6040 | } |
| 6041 | |
| 6042 | /* |
| 6043 | The following functions are wrappers for the dynamic string functions |
| 6044 | and if they fail, the wrappers will terminate the current process. |
| 6045 | */ |
| 6046 | |
| 6047 | #define DYNAMIC_STR_ERROR_MSG "Couldn't perform DYNAMIC_STRING operation" |
| 6048 | |
| 6049 | static void init_dynamic_string_checked(DYNAMIC_STRING *str, const char *init_str, |
| 6050 | size_t init_alloc, size_t alloc_increment) |
| 6051 | { |
| 6052 | if (init_dynamic_string(str, init_str, init_alloc, alloc_increment)) |
| 6053 | die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG); |
| 6054 | } |
| 6055 | |
| 6056 | static void dynstr_append_checked(DYNAMIC_STRING* dest, const char* src) |
| 6057 | { |
| 6058 | if (dynstr_append(dest, src)) |
| 6059 | die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG); |
| 6060 | } |
| 6061 | |
| 6062 | static void dynstr_set_checked(DYNAMIC_STRING *str, const char *init_str) |
| 6063 | { |
| 6064 | if (dynstr_set(str, init_str)) |
| 6065 | die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG); |
| 6066 | } |
| 6067 | |
| 6068 | static void dynstr_append_mem_checked(DYNAMIC_STRING *str, const char *append, |
| 6069 | uint length) |
| 6070 | { |
| 6071 | if (dynstr_append_mem(str, append, length)) |
| 6072 | die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG); |
| 6073 | } |
| 6074 | |
| 6075 | static void dynstr_realloc_checked(DYNAMIC_STRING *str, ulong additional_size) |
| 6076 | { |
| 6077 | if (dynstr_realloc(str, additional_size)) |
| 6078 | die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG); |
| 6079 | } |
| 6080 | |
| 6081 | |
| 6082 | int main(int argc, char **argv) |
| 6083 | { |
| 6084 | char bin_log_name[FN_REFLEN]; |
| 6085 | int exit_code; |
| 6086 | int consistent_binlog_pos= 0; |
| 6087 | int have_mariadb_gtid= 0; |
| 6088 | MY_INIT(argv[0]); |
| 6089 | |
| 6090 | sf_leaking_memory=1; /* don't report memory leaks on early exits */ |
| 6091 | compatible_mode_normal_str[0]= 0; |
| 6092 | default_charset= (char *)mysql_universal_client_charset; |
| 6093 | |
| 6094 | exit_code= get_options(&argc, &argv); |
| 6095 | if (exit_code) |
| 6096 | { |
| 6097 | free_resources(); |
| 6098 | exit(exit_code); |
| 6099 | } |
| 6100 | sf_leaking_memory=0; /* from now on we cleanup properly */ |
| 6101 | |
| 6102 | /* |
| 6103 | Disable comments in xml mode if 'comments' option is not explicitly used. |
| 6104 | */ |
| 6105 | if (opt_xml && !opt_comments_used) |
| 6106 | opt_comments= 0; |
| 6107 | |
| 6108 | if (log_error_file) |
| 6109 | { |
| 6110 | if(!(stderror_file= freopen(log_error_file, "a+" , stderr))) |
| 6111 | { |
| 6112 | free_resources(); |
| 6113 | exit(EX_MYSQLERR); |
| 6114 | } |
| 6115 | } |
| 6116 | |
| 6117 | if (connect_to_db(current_host, current_user, opt_password)) |
| 6118 | { |
| 6119 | free_resources(); |
| 6120 | exit(EX_MYSQLERR); |
| 6121 | } |
| 6122 | if (!path) |
| 6123 | write_header(md_result_file, *argv); |
| 6124 | |
| 6125 | /* Check if the server support multi source */ |
| 6126 | if (mysql_get_server_version(mysql) >= 100000) |
| 6127 | { |
| 6128 | multi_source= 2; |
| 6129 | have_mariadb_gtid= 1; |
| 6130 | } |
| 6131 | |
| 6132 | if (opt_slave_data && do_stop_slave_sql(mysql)) |
| 6133 | goto err; |
| 6134 | |
| 6135 | if (opt_single_transaction && opt_master_data) |
| 6136 | { |
| 6137 | /* See if we can avoid FLUSH TABLES WITH READ LOCK (MariaDB 5.3+). */ |
| 6138 | consistent_binlog_pos= check_consistent_binlog_pos(NULL, NULL); |
| 6139 | } |
| 6140 | |
| 6141 | if ((opt_lock_all_tables || (opt_master_data && !consistent_binlog_pos) || |
| 6142 | (opt_single_transaction && flush_logs)) && |
| 6143 | do_flush_tables_read_lock(mysql)) |
| 6144 | goto err; |
| 6145 | |
| 6146 | /* |
| 6147 | Flush logs before starting transaction since |
| 6148 | this causes implicit commit starting mysql-5.5. |
| 6149 | */ |
| 6150 | if (opt_lock_all_tables || opt_master_data || |
| 6151 | (opt_single_transaction && flush_logs) || |
| 6152 | opt_delete_master_logs) |
| 6153 | { |
| 6154 | if (flush_logs || opt_delete_master_logs) |
| 6155 | { |
| 6156 | if (mysql_refresh(mysql, REFRESH_LOG)) |
| 6157 | goto err; |
| 6158 | verbose_msg("-- main : logs flushed successfully!\n" ); |
| 6159 | } |
| 6160 | |
| 6161 | /* Not anymore! That would not be sensible. */ |
| 6162 | flush_logs= 0; |
| 6163 | } |
| 6164 | |
| 6165 | if (opt_delete_master_logs) |
| 6166 | { |
| 6167 | if (get_bin_log_name(mysql, bin_log_name, sizeof(bin_log_name))) |
| 6168 | goto err; |
| 6169 | } |
| 6170 | |
| 6171 | if (opt_single_transaction && start_transaction(mysql)) |
| 6172 | goto err; |
| 6173 | |
| 6174 | /* Add 'STOP SLAVE to beginning of dump */ |
| 6175 | if (opt_slave_apply && add_stop_slave()) |
| 6176 | goto err; |
| 6177 | |
| 6178 | if (opt_master_data && do_show_master_status(mysql, consistent_binlog_pos, |
| 6179 | have_mariadb_gtid, opt_use_gtid)) |
| 6180 | goto err; |
| 6181 | if (opt_slave_data && do_show_slave_status(mysql, opt_use_gtid, |
| 6182 | have_mariadb_gtid)) |
| 6183 | goto err; |
| 6184 | if (opt_single_transaction && do_unlock_tables(mysql)) /* unlock but no commit! */ |
| 6185 | goto err; |
| 6186 | |
| 6187 | if (opt_alltspcs) |
| 6188 | dump_all_tablespaces(); |
| 6189 | |
| 6190 | if (extended_insert) |
| 6191 | init_dynamic_string_checked(&extended_row, "" , 1024, 1024); |
| 6192 | |
| 6193 | if (opt_alldbs) |
| 6194 | { |
| 6195 | if (!opt_alltspcs && !opt_notspcs) |
| 6196 | dump_all_tablespaces(); |
| 6197 | dump_all_databases(); |
| 6198 | } |
| 6199 | else |
| 6200 | { |
| 6201 | // Check all arguments meet length condition. Currently database and table |
| 6202 | // names are limited to NAME_LEN bytes and stack-based buffers assumes |
| 6203 | // that escaped name will be not longer than NAME_LEN*2 + 2 bytes long. |
| 6204 | int argument; |
| 6205 | for (argument= 0; argument < argc; argument++) |
| 6206 | { |
| 6207 | size_t argument_length= strlen(argv[argument]); |
| 6208 | if (argument_length > NAME_LEN) |
| 6209 | { |
| 6210 | die(EX_CONSCHECK, "[ERROR] Argument '%s' is too long, it cannot be " |
| 6211 | "name for any table or database.\n" , argv[argument]); |
| 6212 | } |
| 6213 | } |
| 6214 | |
| 6215 | if (argc > 1 && !opt_databases) |
| 6216 | { |
| 6217 | /* Only one database and selected table(s) */ |
| 6218 | if (!opt_alltspcs && !opt_notspcs) |
| 6219 | dump_tablespaces_for_tables(*argv, (argv + 1), (argc - 1)); |
| 6220 | dump_selected_tables(*argv, (argv + 1), (argc - 1)); |
| 6221 | } |
| 6222 | else |
| 6223 | { |
| 6224 | /* One or more databases, all tables */ |
| 6225 | if (!opt_alltspcs && !opt_notspcs) |
| 6226 | dump_tablespaces_for_databases(argv); |
| 6227 | dump_databases(argv); |
| 6228 | } |
| 6229 | } |
| 6230 | |
| 6231 | /* add 'START SLAVE' to end of dump */ |
| 6232 | if (opt_slave_apply && add_slave_statements()) |
| 6233 | goto err; |
| 6234 | |
| 6235 | /* ensure dumped data flushed */ |
| 6236 | if (md_result_file && fflush(md_result_file)) |
| 6237 | { |
| 6238 | if (!first_error) |
| 6239 | first_error= EX_MYSQLERR; |
| 6240 | goto err; |
| 6241 | } |
| 6242 | /* everything successful, purge the old logs files */ |
| 6243 | if (opt_delete_master_logs && purge_bin_logs_to(mysql, bin_log_name)) |
| 6244 | goto err; |
| 6245 | |
| 6246 | /* |
| 6247 | No reason to explicitly COMMIT the transaction, neither to explicitly |
| 6248 | UNLOCK TABLES: these will be automatically be done by the server when we |
| 6249 | disconnect now. Saves some code here, some network trips, adds nothing to |
| 6250 | server. |
| 6251 | */ |
| 6252 | err: |
| 6253 | /* if --dump-slave , start the slave sql thread */ |
| 6254 | if (opt_slave_data) |
| 6255 | do_start_slave_sql(mysql); |
| 6256 | |
| 6257 | #ifdef HAVE_SMEM |
| 6258 | my_free(shared_memory_base_name); |
| 6259 | #endif |
| 6260 | |
| 6261 | dbDisconnect(current_host); |
| 6262 | if (!path) |
| 6263 | write_footer(md_result_file); |
| 6264 | free_resources(); |
| 6265 | |
| 6266 | if (stderror_file) |
| 6267 | fclose(stderror_file); |
| 6268 | |
| 6269 | return(first_error); |
| 6270 | } /* main */ |
| 6271 | |