~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to client/mysqlimport.c

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

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