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