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