1 /*
2    Copyright (c) 2000, 2018, 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 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 DBUG_OFF
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.", &current_host,
143    &current_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.", &current_user,
205    &current_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