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