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