~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2000-2006 MySQL AB
2
3
   This program is free software; you can redistribute it and/or modify
4
   it under the terms of the GNU General Public License as published by
5
   the Free Software Foundation; version 2 of the License.
6
7
   This program is distributed in the hope that it will be useful,
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
   GNU General Public License for more details.
11
12
   You should have received a copy of the GNU General Public License
13
   along with this program; if not, write to the Free Software
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
16
/*
17
**	   mysqlimport.c  - Imports all given files
18
**			    into a table(s).
19
**
20
**			   *************************
21
**			   *			   *
22
**			   * AUTHOR: Monty & Jani  *
23
**			   * DATE:   June 24, 1997 *
24
**			   *			   *
25
**			   *************************
26
*/
27
#define IMPORT_VERSION "3.7"
28
29
#include "client_priv.h"
77.1.39 by Monty Taylor
More mysql->drizzle renaming.
30
#include "drizzle_version.h"
1 by brian
clean slate
31
#ifdef HAVE_LIBPTHREAD
32
#include <my_pthread.h>
33
#endif
34
35
36
/* Global Thread counter */
37
uint counter;
38
#ifdef HAVE_LIBPTHREAD
39
pthread_mutex_t counter_mutex;
40
pthread_cond_t count_threshhold;
41
#endif
42
43
static void db_error_with_table(MYSQL *mysql, char *table);
44
static void db_error(MYSQL *mysql);
45
static char *field_escape(char *to,const char *from,uint length);
46
static char *add_load_option(char *ptr,const char *object,
47
			     const char *statement);
48
143 by Brian Aker
Bool cleanup.
49
static bool	verbose=0,lock_tables=0,ignore_errors=0,opt_delete=0,
1 by brian
clean slate
50
		replace=0,silent=0,ignore=0,opt_compress=0,
51
                opt_low_priority= 0, tty_password= 0;
143 by Brian Aker
Bool cleanup.
52
static bool debug_info_flag= 0, debug_check_flag= 0;
1 by brian
clean slate
53
static uint opt_use_threads=0, opt_local_file=0, my_end_arg= 0;
54
static char	*opt_password=0, *current_user=0,
55
		*current_host=0, *current_db=0, *fields_terminated=0,
56
		*lines_terminated=0, *enclosed=0, *opt_enclosed=0,
57
		*escaped=0, *opt_columns=0, 
58
		*default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME;
59
static uint     opt_mysql_port= 0, opt_protocol= 0;
60
static char * opt_mysql_unix_port=0;
152 by Brian Aker
longlong replacement
61
static int64_t opt_ignore_lines= -1;
1 by brian
clean slate
62
static CHARSET_INFO *charset_info= &my_charset_latin1;
63
64
#ifdef HAVE_SMEM
65
static char *shared_memory_base_name=0;
66
#endif
67
68
static struct my_option my_long_options[] =
69
{
70
  {"character-sets-dir", OPT_CHARSETS_DIR,
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
71
   "Directory where character sets are.", (char**) &charsets_dir,
72
   (char**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1 by brian
clean slate
73
  {"default-character-set", OPT_DEFAULT_CHARSET,
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
74
   "Set the default character set.", (char**) &default_charset,
75
   (char**) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1 by brian
clean slate
76
  {"columns", 'c',
77
   "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.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
78
   (char**) &opt_columns, (char**) &opt_columns, 0, GET_STR, REQUIRED_ARG, 0, 0, 0,
1 by brian
clean slate
79
   0, 0, 0},
80
  {"compress", 'C', "Use compression in server/client protocol.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
81
   (char**) &opt_compress, (char**) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
1 by brian
clean slate
82
   0, 0, 0},
83
  {"debug",'#', "Output debug log. Often this is 'd:t:o,filename'.", 0, 0, 0,
84
   GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
85
  {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
86
   (char**) &debug_check_flag, (char**) &debug_check_flag, 0,
1 by brian
clean slate
87
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
88
  {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
89
   (char**) &debug_info_flag, (char**) &debug_info_flag,
1 by brian
clean slate
90
   0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
91
  {"delete", 'd', "First delete all rows from table.", (char**) &opt_delete,
92
   (char**) &opt_delete, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1 by brian
clean slate
93
  {"fields-terminated-by", OPT_FTB,
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
94
   "Fields in the textfile are terminated by ...", (char**) &fields_terminated,
95
   (char**) &fields_terminated, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1 by brian
clean slate
96
  {"fields-enclosed-by", OPT_ENC,
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
97
   "Fields in the importfile are enclosed by ...", (char**) &enclosed,
98
   (char**) &enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1 by brian
clean slate
99
  {"fields-optionally-enclosed-by", OPT_O_ENC,
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
100
   "Fields in the i.file are opt. enclosed by ...", (char**) &opt_enclosed,
101
   (char**) &opt_enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1 by brian
clean slate
102
  {"fields-escaped-by", OPT_ESC, "Fields in the i.file are escaped by ...",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
103
   (char**) &escaped, (char**) &escaped, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0,
1 by brian
clean slate
104
   0, 0},
105
  {"force", 'f', "Continue even if we get an sql-error.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
106
   (char**) &ignore_errors, (char**) &ignore_errors, 0, GET_BOOL, NO_ARG, 0, 0,
1 by brian
clean slate
107
   0, 0, 0, 0},
108
  {"help", '?', "Displays this help and exits.", 0, 0, 0, GET_NO_ARG, NO_ARG,
109
   0, 0, 0, 0, 0, 0},
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
110
  {"host", 'h', "Connect to host.", (char**) &current_host,
111
   (char**) &current_host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1 by brian
clean slate
112
  {"ignore", 'i', "If duplicate unique key was found, keep old row.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
113
   (char**) &ignore, (char**) &ignore, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1 by brian
clean slate
114
  {"ignore-lines", OPT_IGN_LINES, "Ignore first n lines of data infile.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
115
   (char**) &opt_ignore_lines, (char**) &opt_ignore_lines, 0, GET_LL,
1 by brian
clean slate
116
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
117
  {"lines-terminated-by", OPT_LTB, "Lines in the i.file are terminated by ...",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
118
   (char**) &lines_terminated, (char**) &lines_terminated, 0, GET_STR,
1 by brian
clean slate
119
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
120
  {"local", 'L', "Read all files through the client.", (char**) &opt_local_file,
121
   (char**) &opt_local_file, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1 by brian
clean slate
122
  {"lock-tables", 'l', "Lock all tables for write (this disables threads).",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
123
    (char**) &lock_tables, (char**) &lock_tables, 0, GET_BOOL, NO_ARG, 
1 by brian
clean slate
124
    0, 0, 0, 0, 0, 0},
125
  {"low-priority", OPT_LOW_PRIORITY,
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
126
   "Use LOW_PRIORITY when updating the table.", (char**) &opt_low_priority,
127
   (char**) &opt_low_priority, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1 by brian
clean slate
128
  {"password", 'p',
129
   "Password to use when connecting to server. If password is not given it's asked from the tty.",
130
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
131
  {"port", 'P', "Port number to use for connection or 0 for default to, in "
132
   "order of preference, my.cnf, $MYSQL_TCP_PORT, "
133
#if MYSQL_PORT_DEFAULT == 0
134
   "/etc/services, "
135
#endif
136
   "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
137
   (char**) &opt_mysql_port,
138
   (char**) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0,
1 by brian
clean slate
139
   0},
140
  {"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).",
141
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
142
  {"replace", 'r', "If duplicate unique key was found, replace old row.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
143
   (char**) &replace, (char**) &replace, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1 by brian
clean slate
144
#ifdef HAVE_SMEM
145
  {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
146
   "Base name of shared memory.", (char**) &shared_memory_base_name, (char**) &shared_memory_base_name,
1 by brian
clean slate
147
   0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
148
#endif
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
149
  {"silent", 's', "Be more silent.", (char**) &silent, (char**) &silent, 0,
1 by brian
clean slate
150
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
151
  {"socket", 'S', "Socket file to use for connection.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
152
   (char**) &opt_mysql_unix_port, (char**) &opt_mysql_unix_port, 0, GET_STR,
1 by brian
clean slate
153
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
154
  {"use-threads", OPT_USE_THREADS,
155
   "Load files in parallel. The argument is the number "
156
   "of threads to use for loading data.",
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
157
   (char**) &opt_use_threads, (char**) &opt_use_threads, 0, 
1 by brian
clean slate
158
   GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
159
#ifndef DONT_ALLOW_USER_CHANGE
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
160
  {"user", 'u', "User for login if not current user.", (char**) &current_user,
161
   (char**) &current_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1 by brian
clean slate
162
#endif
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
163
  {"verbose", 'v', "Print info about the various stages.", (char**) &verbose,
164
   (char**) &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1 by brian
clean slate
165
  {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
166
   NO_ARG, 0, 0, 0, 0, 0, 0},
167
  { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
168
};
169
170
171
static const char *load_default_groups[]= { "mysqlimport","client",0 };
172
173
#include <help_start.h>
174
175
static void print_version(void)
176
{
177
  printf("%s  Ver %s Distrib %s, for %s (%s)\n" ,my_progname,
178
	  IMPORT_VERSION, MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
179
}
180
181
182
static void usage(void)
183
{
184
  print_version();
185
  puts("Copyright (C) 2000-2006 MySQL AB");
186
  puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n");
187
  printf("\
188
Loads tables from text files in various formats.  The base name of the\n\
189
text file must be the name of the table that should be used.\n\
190
If one uses sockets to connect to the MySQL server, the server will open and\n\
191
read the text file directly. In other cases the client will open the text\n\
192
file. The SQL command 'LOAD DATA INFILE' is used to import the rows.\n");
193
194
  printf("\nUsage: %s [OPTIONS] database textfile...",my_progname);
195
  print_defaults("my",load_default_groups);
196
  my_print_help(my_long_options);
197
  my_print_variables(my_long_options);
198
}
199
200
#include <help_end.h>
201
143 by Brian Aker
Bool cleanup.
202
static bool
1 by brian
clean slate
203
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
204
	       char *argument)
205
{
206
  switch(optid) {
207
  case 'p':
208
    if (argument)
209
    {
210
      char *start=argument;
211
      my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
212
      opt_password=my_strdup(argument,MYF(MY_FAE));
213
      while (*argument) *argument++= 'x';		/* Destroy argument */
214
      if (*start)
215
	start[1]=0;				/* Cut length of argument */
216
      tty_password= 0;
217
    }
218
    else
219
      tty_password= 1;
220
    break;
221
  case OPT_MYSQL_PROTOCOL:
222
    opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib,
223
                                    opt->name);
224
    break;
225
  case 'V': print_version(); exit(0);
226
  case 'I':
227
  case '?':
228
    usage();
229
    exit(0);
230
  }
231
  return 0;
232
}
233
234
235
static int get_options(int *argc, char ***argv)
236
{
237
  int ho_error;
238
239
  if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
240
    exit(ho_error);
241
  if (debug_info_flag)
242
    my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
243
  if (debug_check_flag)
244
    my_end_arg= MY_CHECK_ERROR;
245
246
  if (enclosed && opt_enclosed)
247
  {
248
    fprintf(stderr, "You can't use ..enclosed.. and ..optionally-enclosed.. at the same time.\n");
249
    return(1);
250
  }
251
  if (replace && ignore)
252
  {
253
    fprintf(stderr, "You can't use --ignore (-i) and --replace (-r) at the same time.\n");
254
    return(1);
255
  }
256
  if (strcmp(default_charset, charset_info->csname) &&
257
      !(charset_info= get_charset_by_csname(default_charset,
258
  					    MY_CS_PRIMARY, MYF(MY_WME))))
259
    exit(1);
260
  if (*argc < 2)
261
  {
262
    usage();
263
    return 1;
264
  }
265
  current_db= *((*argv)++);
266
  (*argc)--;
267
  if (tty_password)
268
    opt_password=get_tty_password(NullS);
269
  return(0);
270
}
271
272
273
274
static int write_to_table(char *filename, MYSQL *mysql)
275
{
276
  char tablename[FN_REFLEN], hard_path[FN_REFLEN],
277
       sql_statement[FN_REFLEN*16+256], *end;
278
279
  fn_format(tablename, filename, "", "", 1 | 2); /* removes path & ext. */
280
  if (!opt_local_file)
281
    strmov(hard_path,filename);
282
  else
283
    my_load_path(hard_path, filename, NULL); /* filename includes the path */
284
285
  if (opt_delete)
286
  {
287
    if (verbose)
288
      fprintf(stdout, "Deleting the old data from table %s\n", tablename);
289
#ifdef HAVE_SNPRINTF
290
    snprintf(sql_statement, FN_REFLEN*16+256, "DELETE FROM %s", tablename);
291
#else
292
    sprintf(sql_statement, "DELETE FROM %s", tablename);
293
#endif
294
    if (mysql_query(mysql, sql_statement))
295
    {
296
      db_error_with_table(mysql, tablename);
142.1.2 by Patrick
All DBUG_x removed from client/
297
      return(1);
1 by brian
clean slate
298
    }
299
  }
300
  to_unix_path(hard_path);
301
  if (verbose)
302
  {
303
    if (opt_local_file)
304
      fprintf(stdout, "Loading data from LOCAL file: %s into %s\n",
305
	      hard_path, tablename);
306
    else
307
      fprintf(stdout, "Loading data from SERVER file: %s into %s\n",
308
	      hard_path, tablename);
309
  }
310
  sprintf(sql_statement, "LOAD DATA %s %s INFILE '%s'",
311
	  opt_low_priority ? "LOW_PRIORITY" : "",
312
	  opt_local_file ? "LOCAL" : "", hard_path);
313
  end= strend(sql_statement);
314
  if (replace)
315
    end= strmov(end, " REPLACE");
316
  if (ignore)
317
    end= strmov(end, " IGNORE");
318
  end= strmov(strmov(end, " INTO TABLE "), tablename);
319
320
  if (fields_terminated || enclosed || opt_enclosed || escaped)
321
      end= strmov(end, " FIELDS");
322
  end= add_load_option(end, fields_terminated, " TERMINATED BY");
323
  end= add_load_option(end, enclosed, " ENCLOSED BY");
324
  end= add_load_option(end, opt_enclosed,
325
		       " OPTIONALLY ENCLOSED BY");
326
  end= add_load_option(end, escaped, " ESCAPED BY");
327
  end= add_load_option(end, lines_terminated, " LINES TERMINATED BY");
328
  if (opt_ignore_lines >= 0)
152 by Brian Aker
longlong replacement
329
    end= strmov(int64_t10_to_str(opt_ignore_lines, 
1 by brian
clean slate
330
				  strmov(end, " IGNORE "),10), " LINES");
331
  if (opt_columns)
332
    end= strmov(strmov(strmov(end, " ("), opt_columns), ")");
333
  *end= '\0';
334
335
  if (mysql_query(mysql, sql_statement))
336
  {
337
    db_error_with_table(mysql, tablename);
142.1.2 by Patrick
All DBUG_x removed from client/
338
    return(1);
1 by brian
clean slate
339
  }
340
  if (!silent)
341
  {
342
    if (mysql_info(mysql)) /* If NULL-pointer, print nothing */
343
    {
344
      fprintf(stdout, "%s.%s: %s\n", current_db, tablename,
345
	      mysql_info(mysql));
346
    }
347
  }
142.1.2 by Patrick
All DBUG_x removed from client/
348
  return(0);
1 by brian
clean slate
349
}
350
351
352
353
static void lock_table(MYSQL *mysql, int tablecount, char **raw_tablename)
354
{
355
  DYNAMIC_STRING query;
356
  int i;
357
  char tablename[FN_REFLEN];
358
359
  if (verbose)
360
    fprintf(stdout, "Locking tables for write\n");
361
  init_dynamic_string(&query, "LOCK TABLES ", 256, 1024);
362
  for (i=0 ; i < tablecount ; i++)
363
  {
364
    fn_format(tablename, raw_tablename[i], "", "", 1 | 2);
365
    dynstr_append(&query, tablename);
366
    dynstr_append(&query, " WRITE,");
367
  }
368
  if (mysql_real_query(mysql, query.str, query.length-1))
369
    db_error(mysql); /* We shall countinue here, if --force was given */
370
}
371
372
373
374
375
static MYSQL *db_connect(char *host, char *database,
376
                         char *user, char *passwd)
377
{
378
  MYSQL *mysql;
379
  if (verbose)
380
    fprintf(stdout, "Connecting to %s\n", host ? host : "localhost");
381
  if (!(mysql= mysql_init(NULL)))
382
    return 0;
383
  if (opt_compress)
384
    mysql_options(mysql,MYSQL_OPT_COMPRESS,NullS);
385
  if (opt_local_file)
386
    mysql_options(mysql,MYSQL_OPT_LOCAL_INFILE,
387
		  (char*) &opt_local_file);
388
  if (opt_protocol)
389
    mysql_options(mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
390
#ifdef HAVE_SMEM
391
  if (shared_memory_base_name)
392
    mysql_options(mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
393
#endif
394
  if (!(mysql_real_connect(mysql,host,user,passwd,
395
                           database,opt_mysql_port,opt_mysql_unix_port,
396
                           0)))
397
  {
398
    ignore_errors=0;	  /* NO RETURN FROM db_error */
399
    db_error(mysql);
400
  }
401
  mysql->reconnect= 0;
402
  if (verbose)
403
    fprintf(stdout, "Selecting database %s\n", database);
404
  if (mysql_select_db(mysql, database))
405
  {
406
    ignore_errors=0;
407
    db_error(mysql);
408
  }
409
  return mysql;
410
}
411
412
413
414
static void db_disconnect(char *host, MYSQL *mysql)
415
{
416
  if (verbose)
417
    fprintf(stdout, "Disconnecting from %s\n", host ? host : "localhost");
418
  mysql_close(mysql);
419
}
420
421
422
423
static void safe_exit(int error, MYSQL *mysql)
424
{
425
  if (ignore_errors)
426
    return;
427
  if (mysql)
428
    mysql_close(mysql);
429
  exit(error);
430
}
431
432
433
434
static void db_error_with_table(MYSQL *mysql, char *table)
435
{
436
  my_printf_error(0,"Error: %d, %s, when using table: %s",
437
		  MYF(0), mysql_errno(mysql), mysql_error(mysql), table);
438
  safe_exit(1, mysql);
439
}
440
441
442
443
static void db_error(MYSQL *mysql)
444
{
445
  my_printf_error(0,"Error: %d %s", MYF(0), mysql_errno(mysql), mysql_error(mysql));
446
  safe_exit(1, mysql);
447
}
448
449
450
static char *add_load_option(char *ptr, const char *object,
451
			     const char *statement)
452
{
453
  if (object)
454
  {
455
    /* Don't escape hex constants */
456
    if (object[0] == '0' && (object[1] == 'x' || object[1] == 'X'))
457
      ptr= strxmov(ptr," ",statement," ",object,NullS);
458
    else
459
    {
460
      /* char constant; escape */
461
      ptr= strxmov(ptr," ",statement," '",NullS);
462
      ptr= field_escape(ptr,object,(uint) strlen(object));
463
      *ptr++= '\'';
464
    }
465
  }
466
  return ptr;
467
}
468
469
/*
470
** Allow the user to specify field terminator strings like:
471
** "'", "\", "\\" (escaped backslash), "\t" (tab), "\n" (newline)
472
** This is done by doubleing ' and add a end -\ if needed to avoid
473
** syntax errors from the SQL parser.
474
*/ 
475
476
static char *field_escape(char *to,const char *from,uint length)
477
{
478
  const char *end;
479
  uint end_backslashes=0; 
480
481
  for (end= from+length; from != end; from++)
482
  {
483
    *to++= *from;
484
    if (*from == '\\')
485
      end_backslashes^=1;    /* find odd number of backslashes */
486
    else 
487
    {
488
      if (*from == '\'' && !end_backslashes)
489
	*to++= *from;      /* We want a dublicate of "'" for MySQL */
490
      end_backslashes=0;
491
    }
492
  }
493
  /* Add missing backslashes if user has specified odd number of backs.*/
494
  if (end_backslashes)
495
    *to++= '\\';          
496
  return to;
497
}
498
499
int exitcode= 0;
500
501
#ifdef HAVE_LIBPTHREAD
53.2.4 by Monty Taylor
Changes so that client/ builds cleanly with no warnings.
502
static pthread_handler_t worker_thread(void *arg)
1 by brian
clean slate
503
{
504
  int error;
505
  char *raw_table_name= (char *)arg;
506
  MYSQL *mysql= 0;
507
508
  if (mysql_thread_init())
509
    goto error;
510
  
511
  if (!(mysql= db_connect(current_host,current_db,current_user,opt_password)))
512
  {
513
    goto error;
514
  }
515
516
  if (mysql_query(mysql, "/*!40101 set @@character_set_database=binary */;"))
517
  {
518
    db_error(mysql); /* We shall countinue here, if --force was given */
519
    goto error;
520
  }
521
522
  /*
523
    We are not currently catching the error here.
524
  */
525
  if((error= write_to_table(raw_table_name, mysql)))
526
    if (exitcode == 0)
527
      exitcode= error;
528
529
error:
530
  if (mysql)
531
    db_disconnect(current_host, mysql);
532
533
  pthread_mutex_lock(&counter_mutex);
534
  counter--;
535
  pthread_cond_signal(&count_threshhold);
536
  pthread_mutex_unlock(&counter_mutex);
537
  my_thread_end();
538
539
  return 0;
540
}
541
#endif
542
543
544
int main(int argc, char **argv)
545
{
546
  int error=0;
547
  char **argv_to_free;
548
  MY_INIT(argv[0]);
549
550
  load_defaults("my",load_default_groups,&argc,&argv);
551
  /* argv is changed in the program */
552
  argv_to_free= argv;
553
  if (get_options(&argc, &argv))
554
  {
555
    free_defaults(argv_to_free);
556
    return(1);
557
  }
558
559
#ifdef HAVE_LIBPTHREAD
560
  if (opt_use_threads && !lock_tables)
561
  {
562
    pthread_t mainthread;            /* Thread descriptor */
563
    pthread_attr_t attr;          /* Thread attributes */
564
    pthread_attr_init(&attr);
565
    pthread_attr_setdetachstate(&attr,
566
                                PTHREAD_CREATE_DETACHED);
567
568
    VOID(pthread_mutex_init(&counter_mutex, NULL));
569
    VOID(pthread_cond_init(&count_threshhold, NULL));
570
571
    for (counter= 0; *argv != NULL; argv++) /* Loop through tables */
572
    {
573
      pthread_mutex_lock(&counter_mutex);
574
      while (counter == opt_use_threads)
575
      {
576
        struct timespec abstime;
577
578
        set_timespec(abstime, 3);
579
        pthread_cond_timedwait(&count_threshhold, &counter_mutex, &abstime);
580
      }
581
      /* Before exiting the lock we set ourselves up for the next thread */
582
      counter++;
583
      pthread_mutex_unlock(&counter_mutex);
584
      /* now create the thread */
585
      if (pthread_create(&mainthread, &attr, worker_thread, 
586
                         (void *)*argv) != 0)
587
      {
588
        pthread_mutex_lock(&counter_mutex);
589
        counter--;
590
        pthread_mutex_unlock(&counter_mutex);
591
        fprintf(stderr,"%s: Could not create thread\n",
592
                my_progname);
593
      }
594
    }
595
596
    /*
597
      We loop until we know that all children have cleaned up.
598
    */
599
    pthread_mutex_lock(&counter_mutex);
600
    while (counter)
601
    {
602
      struct timespec abstime;
603
604
      set_timespec(abstime, 3);
605
      pthread_cond_timedwait(&count_threshhold, &counter_mutex, &abstime);
606
    }
607
    pthread_mutex_unlock(&counter_mutex);
608
    VOID(pthread_mutex_destroy(&counter_mutex));
609
    VOID(pthread_cond_destroy(&count_threshhold));
610
    pthread_attr_destroy(&attr);
611
  }
612
  else
613
#endif
614
  {
615
    MYSQL *mysql= 0;
616
    if (!(mysql= db_connect(current_host,current_db,current_user,opt_password)))
617
    {
618
      free_defaults(argv_to_free);
619
      return(1); /* purecov: deadcode */
620
    }
621
622
    if (mysql_query(mysql, "/*!40101 set @@character_set_database=binary */;"))
623
    {
624
      db_error(mysql); /* We shall countinue here, if --force was given */
625
      return(1);
626
    }
627
628
    if (lock_tables)
629
      lock_table(mysql, argc, argv);
630
    for (; *argv != NULL; argv++)
631
      if ((error= write_to_table(*argv, mysql)))
632
        if (exitcode == 0)
633
          exitcode= error;
634
    db_disconnect(current_host, mysql);
635
  }
636
  my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
637
#ifdef HAVE_SMEM
638
  my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR));
639
#endif
640
  free_defaults(argv_to_free);
641
  my_end(my_end_arg);
642
  return(exitcode);
643
}