1 /*
2 Copyright (c) 2000, 2021, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 /*
26 ** mysqlimport.c - Imports all given files
27 ** into a table(s).
28 */
29
30 #define IMPORT_VERSION "3.7"
31
32 #include "client_priv.h"
33 #include "my_default.h"
34 #include "mysql_version.h"
35
36 #include <welcome_copyright_notice.h> /* ORACLE_WELCOME_COPYRIGHT_NOTICE */
37
38
39 /* Global Thread counter */
40 uint counter;
41 native_mutex_t init_mutex;
42 native_mutex_t counter_mutex;
43 native_cond_t count_threshold;
44
45 static void db_error_with_table(MYSQL *mysql, char *table);
46 static void db_error(MYSQL *mysql);
47 static char *field_escape(char *to,const char *from,uint length);
48 static char *add_load_option(char *ptr,const char *object,
49 const char *statement);
50
51 static my_bool verbose=0,lock_tables=0,ignore_errors=0,opt_delete=0,
52 replace=0,silent=0,ignore=0,opt_compress=0,
53 opt_low_priority= 0, tty_password= 0, opt_secure_auth= TRUE;
54 static my_bool debug_info_flag= 0, debug_check_flag= 0;
55 static uint opt_use_threads=0, opt_local_file=0, my_end_arg= 0;
56 static char *opt_password=0, *current_user=0,
57 *current_host=0, *current_db=0, *fields_terminated=0,
58 *lines_terminated=0, *enclosed=0, *opt_enclosed=0,
59 *escaped=0, *opt_columns=0,
60 *default_charset= (char*) MYSQL_AUTODETECT_CHARSET_NAME;
61 static uint opt_enable_cleartext_plugin= 0;
62 static my_bool using_opt_enable_cleartext_plugin= 0;
63 static uint opt_mysql_port= 0, opt_protocol= 0;
64 static char *opt_bind_addr = NULL;
65 static char * opt_mysql_unix_port=0;
66 static char *opt_plugin_dir= 0, *opt_default_auth= 0;
67 static longlong opt_ignore_lines= -1;
68 #include <sslopt-vars.h>
69 #include <caching_sha2_passwordopt-vars.h>
70
71 #if defined (_WIN32) && !defined (EMBEDDED_LIBRARY)
72 static char *shared_memory_base_name=0;
73 #endif
74
75 static struct my_option my_long_options[] =
76 {
77 {"bind-address", 0, "IP address to bind to.",
78 (uchar**) &opt_bind_addr, (uchar**) &opt_bind_addr, 0, GET_STR,
79 REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
80 {"character-sets-dir", OPT_CHARSETS_DIR,
81 "Directory for character set files.", &charsets_dir,
82 &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
83 {"default-character-set", OPT_DEFAULT_CHARSET,
84 "Set the default character set.", &default_charset,
85 &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
86 {"columns", 'c',
87 "Use only these columns to import the data to. Give the column names in a comma separated list. This is same as giving columns to LOAD DATA INFILE.",
88 &opt_columns, &opt_columns, 0, GET_STR, REQUIRED_ARG, 0, 0, 0,
89 0, 0, 0},
90 {"compress", 'C', "Use compression in server/client protocol.",
91 &opt_compress, &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
92 0, 0, 0},
93 #ifdef NDEBUG
94 {"debug", '#', "This is a non-debug version. Catch this and exit.",
95 0, 0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
96 {"debug-check", OPT_DEBUG_CHECK, "This is a non-debug version. Catch this and exit.",
97 0, 0, 0,
98 GET_DISABLED, NO_ARG, 0, 0, 0, 0, 0, 0},
99 {"debug-info", OPT_DEBUG_INFO, "This is a non-debug version. Catch this and exit.", 0,
100 0, 0, GET_DISABLED, NO_ARG, 0, 0, 0, 0, 0, 0},
101 #else
102 {"debug",'#', "Output debug log. Often this is 'd:t:o,filename'.", 0, 0, 0,
103 GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
104 {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
105 &debug_check_flag, &debug_check_flag, 0,
106 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
107 {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
108 &debug_info_flag, &debug_info_flag,
109 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
110 #endif
111 {"default_auth", OPT_DEFAULT_AUTH,
112 "Default authentication client-side plugin to use.",
113 &opt_default_auth, &opt_default_auth, 0,
114 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
115 {"delete", 'd', "First delete all rows from table.", &opt_delete,
116 &opt_delete, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
117 {"enable_cleartext_plugin", OPT_ENABLE_CLEARTEXT_PLUGIN,
118 "Enable/disable the clear text authentication plugin.",
119 &opt_enable_cleartext_plugin, &opt_enable_cleartext_plugin,
120 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0},
121 {"fields-terminated-by", OPT_FTB,
122 "Fields in the input file are terminated by the given string.",
123 &fields_terminated, &fields_terminated, 0,
124 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
125 {"fields-enclosed-by", OPT_ENC,
126 "Fields in the import file are enclosed by the given character.",
127 &enclosed, &enclosed, 0,
128 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
129 {"fields-optionally-enclosed-by", OPT_O_ENC,
130 "Fields in the input file are optionally enclosed by the given character.",
131 &opt_enclosed, &opt_enclosed, 0,
132 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
133 {"fields-escaped-by", OPT_ESC,
134 "Fields in the input file are escaped by the given character.",
135 &escaped, &escaped, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0,
136 0, 0},
137 {"force", 'f', "Continue even if we get an SQL error.",
138 &ignore_errors, &ignore_errors, 0, GET_BOOL, NO_ARG, 0, 0,
139 0, 0, 0, 0},
140 {"help", '?', "Displays this help and exits.", 0, 0, 0, GET_NO_ARG, NO_ARG,
141 0, 0, 0, 0, 0, 0},
142 {"host", 'h', "Connect to host.", ¤t_host,
143 ¤t_host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
144 {"ignore", 'i', "If duplicate unique key was found, keep old row.",
145 &ignore, &ignore, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
146 {"ignore-lines", OPT_IGN_LINES, "Ignore first n lines of data infile.",
147 &opt_ignore_lines, &opt_ignore_lines, 0, GET_LL,
148 REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
149 {"lines-terminated-by", OPT_LTB,
150 "Lines in the input file are terminated by the given string.",
151 &lines_terminated, &lines_terminated, 0, GET_STR,
152 REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
153 {"local", 'L', "Read all files through the client.", &opt_local_file,
154 &opt_local_file, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
155 {"lock-tables", 'l', "Lock all tables for write (this disables threads).",
156 &lock_tables, &lock_tables, 0, GET_BOOL, NO_ARG,
157 0, 0, 0, 0, 0, 0},
158 {"low-priority", OPT_LOW_PRIORITY,
159 "Use LOW_PRIORITY when updating the table.", &opt_low_priority,
160 &opt_low_priority, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
161 {"password", 'p',
162 "Password to use when connecting to server. If password is not given it's asked from the tty.",
163 0, 0, 0, GET_PASSWORD, OPT_ARG, 0, 0, 0, 0, 0, 0},
164 #ifdef _WIN32
165 {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG,
166 NO_ARG, 0, 0, 0, 0, 0, 0},
167 #endif
168 {"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.",
169 &opt_plugin_dir, &opt_plugin_dir, 0,
170 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
171 {"port", 'P', "Port number to use for connection or 0 for default to, in "
172 "order of preference, my.cnf, $MYSQL_TCP_PORT, "
173 #if MYSQL_PORT_DEFAULT == 0
174 "/etc/services, "
175 #endif
176 "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
177 &opt_mysql_port,
178 &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0,
179 0},
180 {"protocol", OPT_MYSQL_PROTOCOL, "The protocol to use for connection (tcp, socket, pipe, memory).",
181 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
182 {"replace", 'r', "If duplicate unique key was found, replace old row.",
183 &replace, &replace, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
184 {"secure-auth", OPT_SECURE_AUTH, "Refuse client connecting to server if it"
185 " uses old (pre-4.1.1) protocol. Deprecated. Always TRUE",
186 &opt_secure_auth, &opt_secure_auth, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
187 #if defined (_WIN32) && !defined (EMBEDDED_LIBRARY)
188 {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
189 "Base name of shared memory.", &shared_memory_base_name, &shared_memory_base_name,
190 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
191 #endif
192 {"silent", 's', "Be more silent.", &silent, &silent, 0,
193 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
194 {"socket", 'S', "The socket file to use for connection.",
195 &opt_mysql_unix_port, &opt_mysql_unix_port, 0, GET_STR,
196 REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
197 #include <sslopt-longopts.h>
198 #include <caching_sha2_passwordopt-longopts.h>
199 {"use-threads", OPT_USE_THREADS,
200 "Load files in parallel. The argument is the number "
201 "of threads to use for loading data.",
202 &opt_use_threads, &opt_use_threads, 0,
203 GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
204 {"user", 'u', "User for login if not current user.", ¤t_user,
205 ¤t_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
206 {"verbose", 'v', "Print info about the various stages.", &verbose,
207 &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
208 {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
209 NO_ARG, 0, 0, 0, 0, 0, 0},
210 { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
211 };
212
213
214 static const char *load_default_groups[]= { "mysqlimport","client",0 };
215
216
print_version(void)217 static void print_version(void)
218 {
219 printf("%s Ver %s Distrib %s, for %s (%s)\n" ,my_progname,
220 IMPORT_VERSION, MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
221 }
222
223
usage(void)224 static void usage(void)
225 {
226 struct my_option *optp;
227 print_version();
228 puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000"));
229 printf("\
230 Loads tables from text files in various formats. The base name of the\n\
231 text file must be the name of the table that should be used.\n\
232 If one uses sockets to connect to the MySQL server, the server will open and\n\
233 read the text file directly. In other cases the client will open the text\n\
234 file. The SQL command 'LOAD DATA INFILE' is used to import the rows.\n");
235
236 printf("\nUsage: %s [OPTIONS] database textfile...",my_progname);
237 print_defaults("my",load_default_groups);
238 /*
239 Turn default for zombies off so that the help on how to
240 turn them off text won't show up.
241 This is safe to do since it's followed by a call to exit().
242 */
243 for (optp= my_long_options; optp->name; optp++)
244 {
245 if (optp->id == OPT_SECURE_AUTH)
246 {
247 optp->def_value= 0;
248 break;
249 }
250 }
251 my_print_help(my_long_options);
252 my_print_variables(my_long_options);
253 }
254
255
256 static my_bool
get_one_option(int optid,const struct my_option * opt MY_ATTRIBUTE ((unused)),char * argument)257 get_one_option(int optid, const struct my_option *opt MY_ATTRIBUTE((unused)),
258 char *argument)
259 {
260 switch(optid) {
261 case 'p':
262 if (argument == disabled_my_option)
263 argument= (char*) ""; /* Don't require password */
264 if (argument)
265 {
266 char *start=argument;
267 my_free(opt_password);
268 opt_password=my_strdup(PSI_NOT_INSTRUMENTED,
269 argument,MYF(MY_FAE));
270 while (*argument) *argument++= 'x'; /* Destroy argument */
271 if (*start)
272 start[1]=0; /* Cut length of argument */
273 tty_password= 0;
274 }
275 else
276 tty_password= 1;
277 break;
278 #ifdef _WIN32
279 case 'W':
280 opt_protocol = MYSQL_PROTOCOL_PIPE;
281 opt_local_file=1;
282 break;
283 #endif
284 case OPT_ENABLE_CLEARTEXT_PLUGIN:
285 using_opt_enable_cleartext_plugin= TRUE;
286 break;
287 case OPT_MYSQL_PROTOCOL:
288 opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib,
289 opt->name);
290 break;
291 case '#':
292 DBUG_PUSH(argument ? argument : "d:t:o");
293 debug_check_flag= 1;
294 break;
295 #include <sslopt-case.h>
296 case 'V': print_version(); exit(0);
297 case 'I':
298 case '?':
299 usage();
300 exit(0);
301 case OPT_SECURE_AUTH:
302 /* --secure-auth is a zombie option. */
303 if (!opt_secure_auth)
304 {
305 fprintf(stderr, "mysqlimport: [ERROR] --skip-secure-auth is not supported.\n");
306 exit(1);
307 }
308 else
309 CLIENT_WARN_DEPRECATED_NO_REPLACEMENT("--secure-auth");
310 break;
311 }
312 return 0;
313 }
314
315
get_options(int * argc,char *** argv)316 static int get_options(int *argc, char ***argv)
317 {
318 int ho_error;
319
320 if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
321 exit(ho_error);
322 if (debug_info_flag)
323 my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
324 if (debug_check_flag)
325 my_end_arg= MY_CHECK_ERROR;
326
327 if (enclosed && opt_enclosed)
328 {
329 fprintf(stderr, "You can't use ..enclosed.. and ..optionally-enclosed.. at the same time.\n");
330 return(1);
331 }
332 if (replace && ignore)
333 {
334 fprintf(stderr, "You can't use --ignore (-i) and --replace (-r) at the same time.\n");
335 return(1);
336 }
337 if (*argc < 2)
338 {
339 usage();
340 return 1;
341 }
342 current_db= *((*argv)++);
343 (*argc)--;
344 if (tty_password)
345 opt_password=get_tty_password(NullS);
346 return(0);
347 }
348
349
350
write_to_table(char * filename,MYSQL * mysql)351 static int write_to_table(char *filename, MYSQL *mysql)
352 {
353 char tablename[FN_REFLEN], hard_path[FN_REFLEN],
354 escaped_name[FN_REFLEN * 2 + 1],
355 sql_statement[FN_REFLEN*16+256], *end, *pos;
356 DBUG_ENTER("write_to_table");
357 DBUG_PRINT("enter",("filename: %s",filename));
358
359 fn_format(tablename, filename, "", "", 1 | 2); /* removes path & ext. */
360 if (!opt_local_file)
361 my_stpcpy(hard_path,filename);
362 else
363 my_load_path(hard_path, filename, NULL); /* filename includes the path */
364
365 if (opt_delete)
366 {
367 if (verbose)
368 fprintf(stdout, "Deleting the old data from table %s\n", tablename);
369 my_snprintf(sql_statement, FN_REFLEN*16+256, "DELETE FROM %s", tablename);
370 if (mysql_query(mysql, sql_statement))
371 {
372 db_error_with_table(mysql, tablename);
373 DBUG_RETURN(1);
374 }
375 }
376 to_unix_path(hard_path);
377 if (verbose)
378 {
379 if (opt_local_file)
380 fprintf(stdout, "Loading data from LOCAL file: %s into %s\n",
381 hard_path, tablename);
382 else
383 fprintf(stdout, "Loading data from SERVER file: %s into %s\n",
384 hard_path, tablename);
385 }
386 mysql_real_escape_string_quote(mysql, escaped_name, hard_path,
387 (unsigned long) strlen(hard_path), '\'');
388 sprintf(sql_statement, "LOAD DATA %s %s INFILE '%s'",
389 opt_low_priority ? "LOW_PRIORITY" : "",
390 opt_local_file ? "LOCAL" : "", escaped_name);
391 end= strend(sql_statement);
392 if (replace)
393 end= my_stpcpy(end, " REPLACE");
394 if (ignore)
395 end= my_stpcpy(end, " IGNORE");
396 end= my_stpcpy(end, " INTO TABLE `");
397 /* Turn any ` into `` in table name. */
398 for (pos= tablename; *pos; pos++)
399 {
400 if (*pos == '`')
401 *end++= '`';
402 *end++= *pos;
403 }
404 end= my_stpcpy(end, "`");
405
406 if (fields_terminated || enclosed || opt_enclosed || escaped)
407 end= my_stpcpy(end, " FIELDS");
408 end= add_load_option(end, fields_terminated, " TERMINATED BY");
409 end= add_load_option(end, enclosed, " ENCLOSED BY");
410 end= add_load_option(end, opt_enclosed,
411 " OPTIONALLY ENCLOSED BY");
412 end= add_load_option(end, escaped, " ESCAPED BY");
413 end= add_load_option(end, lines_terminated, " LINES TERMINATED BY");
414 if (opt_ignore_lines >= 0)
415 end= my_stpcpy(longlong10_to_str(opt_ignore_lines,
416 my_stpcpy(end, " IGNORE "),10), " LINES");
417 if (opt_columns)
418 end= my_stpcpy(my_stpcpy(my_stpcpy(end, " ("), opt_columns), ")");
419 *end= '\0';
420
421 if (mysql_query(mysql, sql_statement))
422 {
423 db_error_with_table(mysql, tablename);
424 DBUG_RETURN(1);
425 }
426 if (!silent)
427 {
428 if (mysql_info(mysql)) /* If NULL-pointer, print nothing */
429 {
430 fprintf(stdout, "%s.%s: %s\n", current_db, tablename,
431 mysql_info(mysql));
432 }
433 }
434 DBUG_RETURN(0);
435 }
436
437
438
lock_table(MYSQL * mysql,int tablecount,char ** raw_tablename)439 static void lock_table(MYSQL *mysql, int tablecount, char **raw_tablename)
440 {
441 DYNAMIC_STRING query;
442 int i;
443 char tablename[FN_REFLEN];
444
445 if (verbose)
446 fprintf(stdout, "Locking tables for write\n");
447 init_dynamic_string(&query, "LOCK TABLES ", 256, 1024);
448 for (i=0 ; i < tablecount ; i++)
449 {
450 fn_format(tablename, raw_tablename[i], "", "", 1 | 2);
451 dynstr_append(&query, tablename);
452 dynstr_append(&query, " WRITE,");
453 }
454 if (mysql_real_query(mysql, query.str, (ulong)(query.length-1)))
455 db_error(mysql); /* We shall countinue here, if --force was given */
456 }
457
458
459
460
db_connect(char * host,char * database,char * user,char * passwd)461 static MYSQL *db_connect(char *host, char *database,
462 char *user, char *passwd)
463 {
464 MYSQL *mysql;
465 if (verbose)
466 fprintf(stdout, "Connecting to %s\n", host ? host : "localhost");
467 if (opt_use_threads && !lock_tables)
468 {
469 native_mutex_lock(&init_mutex);
470 if (!(mysql= mysql_init(NULL)))
471 {
472 native_mutex_unlock(&init_mutex);
473 return 0;
474 }
475 native_mutex_unlock(&init_mutex);
476 }
477 else
478 if (!(mysql= mysql_init(NULL)))
479 return 0;
480 if (opt_compress)
481 mysql_options(mysql,MYSQL_OPT_COMPRESS,NullS);
482 if (opt_local_file)
483 mysql_options(mysql,MYSQL_OPT_LOCAL_INFILE,
484 (char*) &opt_local_file);
485 SSL_SET_OPTIONS(mysql);
486 if (opt_protocol)
487 mysql_options(mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
488 if (opt_bind_addr)
489 mysql_options(mysql,MYSQL_OPT_BIND,opt_bind_addr);
490 #if defined (_WIN32) && !defined (EMBEDDED_LIBRARY)
491 if (shared_memory_base_name)
492 mysql_options(mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
493 #endif
494
495 if (opt_plugin_dir && *opt_plugin_dir)
496 mysql_options(mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir);
497
498 if (opt_default_auth && *opt_default_auth)
499 mysql_options(mysql, MYSQL_DEFAULT_AUTH, opt_default_auth);
500
501 if (using_opt_enable_cleartext_plugin)
502 mysql_options(mysql, MYSQL_ENABLE_CLEARTEXT_PLUGIN,
503 (char*)&opt_enable_cleartext_plugin);
504
505 mysql_options(mysql, MYSQL_SET_CHARSET_NAME, default_charset);
506 mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
507 mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
508 "program_name", "mysqlimport");
509
510 set_server_public_key(mysql);
511 set_get_server_public_key_option(mysql);
512
513 if (!(mysql_real_connect(mysql,host,user,passwd,
514 database,opt_mysql_port,opt_mysql_unix_port,
515 0)))
516 {
517 ignore_errors=0; /* NO RETURN FROM db_error */
518 db_error(mysql);
519 }
520 mysql->reconnect= 0;
521 if (verbose)
522 fprintf(stdout, "Selecting database %s\n", database);
523 if (mysql_select_db(mysql, database))
524 {
525 ignore_errors=0;
526 db_error(mysql);
527 }
528 return mysql;
529 }
530
531
532
db_disconnect(char * host,MYSQL * mysql)533 static void db_disconnect(char *host, MYSQL *mysql)
534 {
535 if (verbose)
536 fprintf(stdout, "Disconnecting from %s\n", host ? host : "localhost");
537 mysql_close(mysql);
538 }
539
540
541
safe_exit(int error,MYSQL * mysql)542 static void safe_exit(int error, MYSQL *mysql)
543 {
544 if (ignore_errors)
545 return;
546 if (mysql)
547 mysql_close(mysql);
548 exit(error);
549 }
550
551
552
db_error_with_table(MYSQL * mysql,char * table)553 static void db_error_with_table(MYSQL *mysql, char *table)
554 {
555 my_printf_error(0,"Error: %d, %s, when using table: %s",
556 MYF(0), mysql_errno(mysql), mysql_error(mysql), table);
557 safe_exit(1, mysql);
558 }
559
560
561
db_error(MYSQL * mysql)562 static void db_error(MYSQL *mysql)
563 {
564 my_printf_error(0,"Error: %d %s", MYF(0), mysql_errno(mysql), mysql_error(mysql));
565 safe_exit(1, mysql);
566 }
567
568
add_load_option(char * ptr,const char * object,const char * statement)569 static char *add_load_option(char *ptr, const char *object,
570 const char *statement)
571 {
572 if (object)
573 {
574 /* Don't escape hex constants */
575 if (object[0] == '0' && (object[1] == 'x' || object[1] == 'X'))
576 ptr= strxmov(ptr," ",statement," ",object,NullS);
577 else
578 {
579 /* char constant; escape */
580 ptr= strxmov(ptr," ",statement," '",NullS);
581 ptr= field_escape(ptr,object,(uint) strlen(object));
582 *ptr++= '\'';
583 }
584 }
585 return ptr;
586 }
587
588 /*
589 ** Allow the user to specify field terminator strings like:
590 ** "'", "\", "\\" (escaped backslash), "\t" (tab), "\n" (newline)
591 ** This is done by doubleing ' and add a end -\ if needed to avoid
592 ** syntax errors from the SQL parser.
593 */
594
field_escape(char * to,const char * from,uint length)595 static char *field_escape(char *to,const char *from,uint length)
596 {
597 const char *end;
598 uint end_backslashes=0;
599
600 for (end= from+length; from != end; from++)
601 {
602 *to++= *from;
603 if (*from == '\\')
604 end_backslashes^=1; /* find odd number of backslashes */
605 else
606 {
607 if (*from == '\'' && !end_backslashes)
608 *to++= *from; /* We want a dublicate of "'" for MySQL */
609 end_backslashes=0;
610 }
611 }
612 /* Add missing backslashes if user has specified odd number of backs.*/
613 if (end_backslashes)
614 *to++= '\\';
615 return to;
616 }
617
618 int exitcode= 0;
619
worker_thread(void * arg)620 void *worker_thread(void *arg)
621 {
622 int error;
623 char *raw_table_name= (char *)arg;
624 MYSQL *mysql= 0;
625
626 if (mysql_thread_init())
627 goto error;
628
629 if (!(mysql= db_connect(current_host,current_db,current_user,opt_password)))
630 {
631 goto error;
632 }
633
634 if (mysql_query(mysql, "/*!40101 set @@character_set_database=binary */;"))
635 {
636 db_error(mysql); /* We shall countinue here, if --force was given */
637 goto error;
638 }
639
640 /*
641 We are not currently catching the error here.
642 */
643 if((error= write_to_table(raw_table_name, mysql)))
644 if (exitcode == 0)
645 exitcode= error;
646
647 error:
648 if (mysql)
649 db_disconnect(current_host, mysql);
650
651 native_mutex_lock(&counter_mutex);
652 counter--;
653 native_cond_signal(&count_threshold);
654 native_mutex_unlock(&counter_mutex);
655 mysql_thread_end();
656 my_thread_exit(0);
657 return 0;
658 }
659
660
main(int argc,char ** argv)661 int main(int argc, char **argv)
662 {
663 int error=0;
664 char **argv_to_free;
665 MY_INIT(argv[0]);
666
667 my_getopt_use_args_separator= TRUE;
668 if (load_defaults("my",load_default_groups,&argc,&argv))
669 return 1;
670 my_getopt_use_args_separator= FALSE;
671
672 /* argv is changed in the program */
673 argv_to_free= argv;
674 if (get_options(&argc, &argv))
675 {
676 free_defaults(argv_to_free);
677 return(1);
678 }
679
680 if (opt_use_threads && !lock_tables)
681 {
682 char **save_argv;
683 uint worker_thread_count= 0, table_count= 0, i= 0;
684 my_thread_handle *worker_threads; /* Thread descriptor */
685 my_thread_attr_t attr; /* Thread attributes */
686 my_thread_attr_init(&attr);
687 my_thread_attr_setdetachstate(&attr, MY_THREAD_CREATE_JOINABLE);
688
689 native_mutex_init(&init_mutex, NULL);
690 native_mutex_init(&counter_mutex, NULL);
691 native_cond_init(&count_threshold);
692
693 /* Count the number of tables. This number denotes the total number
694 of threads spawn.
695 */
696 save_argv= argv;
697 for (table_count= 0; *argv != NULL; argv++)
698 table_count++;
699 argv= save_argv;
700
701 if (!(worker_threads= (my_thread_handle*) my_malloc(PSI_NOT_INSTRUMENTED,
702 table_count *
703 sizeof(*worker_threads),
704 MYF(0))))
705 return -2;
706
707 for (counter= 0; *argv != NULL; argv++) /* Loop through tables */
708 {
709 native_mutex_lock(&counter_mutex);
710 while (counter == opt_use_threads)
711 {
712 struct timespec abstime;
713
714 set_timespec(&abstime, 3);
715 native_cond_timedwait(&count_threshold, &counter_mutex, &abstime);
716 }
717 /* Before exiting the lock we set ourselves up for the next thread */
718 counter++;
719 native_mutex_unlock(&counter_mutex);
720 /* now create the thread */
721 if (my_thread_create(&worker_threads[worker_thread_count], &attr,
722 worker_thread, (void *)*argv) != 0)
723 {
724 native_mutex_lock(&counter_mutex);
725 counter--;
726 native_mutex_unlock(&counter_mutex);
727 fprintf(stderr,"%s: Could not create thread\n", my_progname);
728 continue;
729 }
730 worker_thread_count++;
731 }
732
733 /*
734 We loop until we know that all children have cleaned up.
735 */
736 native_mutex_lock(&counter_mutex);
737 while (counter)
738 {
739 struct timespec abstime;
740
741 set_timespec(&abstime, 3);
742 native_cond_timedwait(&count_threshold, &counter_mutex, &abstime);
743 }
744 native_mutex_unlock(&counter_mutex);
745 native_mutex_destroy(&init_mutex);
746 native_mutex_destroy(&counter_mutex);
747 native_cond_destroy(&count_threshold);
748 my_thread_attr_destroy(&attr);
749
750 for(i= 0; i < worker_thread_count; i++)
751 {
752 if (my_thread_join(&worker_threads[i], NULL))
753 fprintf(stderr,"%s: Could not join worker thread.\n", my_progname);
754 }
755
756 my_free(worker_threads);
757 }
758 else
759 {
760 MYSQL *mysql= 0;
761 if (!(mysql= db_connect(current_host,current_db,current_user,opt_password)))
762 {
763 free_defaults(argv_to_free);
764 return(1); /* purecov: deadcode */
765 }
766
767 if (mysql_query(mysql, "/*!40101 set @@character_set_database=binary */;"))
768 {
769 db_error(mysql); /* We shall countinue here, if --force was given */
770 return(1);
771 }
772
773 if (lock_tables)
774 lock_table(mysql, argc, argv);
775 for (; *argv != NULL; argv++)
776 if ((error= write_to_table(*argv, mysql)))
777 if (exitcode == 0)
778 exitcode= error;
779 db_disconnect(current_host, mysql);
780 }
781 my_free(opt_password);
782 #if defined (_WIN32) && !defined (EMBEDDED_LIBRARY)
783 my_free(shared_memory_base_name);
784 #endif
785 free_defaults(argv_to_free);
786 my_end(my_end_arg);
787 return(exitcode);
788 }
789