~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to client/drizzleimport.cc

  • Committer: Brian Aker
  • Date: 2010-10-08 16:11:47 UTC
  • mto: This revision was merged to the branch mainline in revision 1834.
  • Revision ID: brian@tangent.org-20101008161147-o3us2a8itszsaycx
Typdef our lock type.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2000-2006 MySQL AB
2
 
   Copyright (C) 2008-2009 Sun Microsystems, Inc
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 as published by
6
 
   the Free Software Foundation; version 2 of the License.
7
 
 
8
 
   This program is distributed in the hope that it will be useful,
9
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 
   GNU General Public License for more details.
12
 
 
13
 
   You should have received a copy of the GNU General Public License
14
 
   along with this program; if not, write to the Free Software
15
 
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
16
 
 
17
 
/*
18
 
**     drizzleimport.c  - Imports all given files
19
 
**          into a table(s).
20
 
**
21
 
**         *************************
22
 
**         *         *
23
 
**         * AUTHOR: Monty & Jani  *
24
 
**         * DATE:   June 24, 1997 *
25
 
**         *         *
26
 
**         *************************
27
 
*/
28
 
#define IMPORT_VERSION "3.7"
 
1
/* 
 
2
  Copyright (C) 2010 Vijay Samuel
 
3
  Copyright (C) 2010 Brian Aker
 
4
  Copyright (C) 2000-2006 MySQL AB
 
5
  Copyright (C) 2008-2009 Sun Microsystems, Inc
 
6
 
 
7
  This program is free software; you can redistribute it and/or modify
 
8
  it under the terms of the GNU General Public License as published by
 
9
  the Free Software Foundation; version 2 of the License.
 
10
 
 
11
  This program is distributed in the hope that it will be useful,
 
12
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
  GNU General Public License for more details.
 
15
 
 
16
  You should have received a copy of the GNU General Public License
 
17
  along with this program; if not, write to the Free Software
 
18
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
 
19
 
 
20
#define IMPORT_VERSION "4.0"
29
21
 
30
22
#include "client_priv.h"
31
23
#include <string>
32
24
#include <sstream>
33
 
 
 
25
#include <iostream>
 
26
#include <fstream>
 
27
#include <boost/program_options.hpp>
34
28
#include <pthread.h>
35
29
 
36
30
/* Added this for string translation. */
37
31
#include <drizzled/gettext.h>
 
32
#include <drizzled/configmake.h>
38
33
 
 
34
namespace po= boost::program_options;
39
35
using namespace std;
40
36
using namespace drizzled;
41
37
 
43
39
 
44
40
int exitcode= 0;
45
41
 
 
42
const char *program_name= "drizzlesimport";
 
43
 
46
44
/* Global Thread counter */
47
45
uint32_t counter;
48
46
pthread_mutex_t counter_mutex;
54
52
static char *add_load_option(char *ptr,const char *object,
55
53
           const char *statement);
56
54
 
57
 
static bool verbose= false, lock_tables= false, ignore_errors= false,
 
55
static bool verbose= false, ignore_errors= false,
58
56
            opt_delete= false, opt_replace= false, silent= false,
59
57
            ignore_unique= false, opt_low_priority= false,
60
 
            tty_password= false, opt_mysql= false;
 
58
            use_drizzle_protocol= false, opt_local_file;
61
59
 
62
 
static uint32_t opt_use_threads= 0, opt_local_file= 0;
63
 
static char  *opt_password= NULL, *current_user= NULL,
64
 
    *current_host= NULL, *current_db= NULL, *fields_terminated= NULL,
65
 
    *lines_terminated= NULL, *enclosed= NULL, *opt_enclosed= NULL,
66
 
    *escaped= NULL, *opt_columns= NULL;
 
60
static uint32_t opt_use_threads;
67
61
static uint32_t opt_drizzle_port= 0;
68
62
static int64_t opt_ignore_lines= -1;
69
63
 
70
 
static struct option my_long_options[] =
71
 
{
72
 
  {"columns", 'c',
73
 
   "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.",
74
 
   (char**) &opt_columns, (char**) &opt_columns, 0, GET_STR, REQUIRED_ARG, 0, 0, 0,
75
 
   0, 0, 0},
76
 
  {"debug",'#', "Output debug log. Often this is 'd:t:o,filename'.", 0, 0, 0,
77
 
   GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
78
 
  {"delete", 'd', "First delete all rows from table.", (char**) &opt_delete,
79
 
   (char**) &opt_delete, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
80
 
  {"fields-terminated-by", OPT_FTB,
81
 
   "Fields in the textfile are terminated by ...", (char**) &fields_terminated,
82
 
   (char**) &fields_terminated, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
83
 
  {"fields-enclosed-by", OPT_ENC,
84
 
   "Fields in the importfile are enclosed by ...", (char**) &enclosed,
85
 
   (char**) &enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
86
 
  {"fields-optionally-enclosed-by", OPT_O_ENC,
87
 
   "Fields in the i.file are opt. enclosed by ...", (char**) &opt_enclosed,
88
 
   (char**) &opt_enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
89
 
  {"fields-escaped-by", OPT_ESC, "Fields in the i.file are escaped by ...",
90
 
   (char**) &escaped, (char**) &escaped, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0,
91
 
   0, 0},
92
 
  {"force", 'f', "Continue even if we get an sql-error.",
93
 
   (char**) &ignore_errors, (char**) &ignore_errors, 0, GET_BOOL, NO_ARG, 0, 0,
94
 
   0, 0, 0, 0},
95
 
  {"help", '?', "Displays this help and exits.", 0, 0, 0, GET_NO_ARG, NO_ARG,
96
 
   0, 0, 0, 0, 0, 0},
97
 
  {"host", 'h', "Connect to host.", (char**) &current_host,
98
 
   (char**) &current_host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
99
 
  {"ignore", 'i', "If duplicate unique key was found, keep old row.",
100
 
   (char**) &ignore_unique, (char**) &ignore_unique, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
101
 
  {"ignore-lines", OPT_IGN_LINES, "Ignore first n lines of data infile.",
102
 
   (char**) &opt_ignore_lines, (char**) &opt_ignore_lines, 0, GET_LL,
103
 
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
104
 
  {"lines-terminated-by", OPT_LTB, "Lines in the i.file are terminated by ...",
105
 
   (char**) &lines_terminated, (char**) &lines_terminated, 0, GET_STR,
106
 
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
107
 
  {"local", 'L', "Read all files through the client.", (char**) &opt_local_file,
108
 
   (char**) &opt_local_file, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
109
 
  {"lock-tables", 'l', "Lock all tables for write (this disables threads).",
110
 
    (char**) &lock_tables, (char**) &lock_tables, 0, GET_BOOL, NO_ARG,
111
 
    0, 0, 0, 0, 0, 0},
112
 
  {"low-priority", OPT_LOW_PRIORITY,
113
 
   "Use LOW_PRIORITY when updating the table.", (char**) &opt_low_priority,
114
 
   (char**) &opt_low_priority, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
115
 
  {"mysql", 'm', N_("Use MySQL Protocol."),
116
 
   (char**) &opt_mysql, (char**) &opt_mysql, 0, GET_BOOL, NO_ARG, 1, 0, 0,
117
 
   0, 0, 0},
118
 
  {"password", 'P',
119
 
   "Password to use when connecting to server. If password is not given it's asked from the tty.",
120
 
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
121
 
  {"port", 'p', "Port number to use for connection or 0 for default to, in "
122
 
   "order of preference, drizzle.cnf, $DRIZZLE_TCP_PORT, "
123
 
   "built-in default (" STRINGIFY_ARG(DRIZZLE_PORT) ").",
124
 
   0, 0, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
125
 
  {"protocol", OPT_DRIZZLE_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).",
126
 
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
127
 
  {"replace", 'r', "If duplicate unique key was found, replace old row.",
128
 
   (char**) &opt_replace, (char**) &opt_replace, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
129
 
  {"silent", 's', "Be more silent.", (char**) &silent, (char**) &silent, 0,
130
 
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
131
 
  {"use-threads", OPT_USE_THREADS,
132
 
   "Load files in parallel. The argument is the number "
133
 
   "of threads to use for loading data.",
134
 
   (char**) &opt_use_threads, (char**) &opt_use_threads, 0,
135
 
   GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
136
 
  {"user", 'u', "User for login if not current user.", (char**) &current_user,
137
 
   (char**) &current_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
138
 
  {"verbose", 'v', "Print info about the various stages.", (char**) &verbose,
139
 
   (char**) &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
140
 
  {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
141
 
   NO_ARG, 0, 0, 0, 0, 0, 0},
142
 
  { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
143
 
};
144
 
 
145
 
 
146
 
static const char *load_default_groups[]= { "drizzleimport","client",0 };
147
 
 
148
 
static void print_version(void)
149
 
{
150
 
  printf("%s  Ver %s Distrib %s, for %s-%s (%s)\n" ,internal::my_progname,
151
 
    IMPORT_VERSION, drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
152
 
}
153
 
 
154
 
 
155
 
static void usage(void)
156
 
{
157
 
  print_version();
158
 
  puts("Copyright (C) 2008 Drizzle Open Source Development Team");
159
 
  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");
160
 
  printf("\
161
 
Loads tables from text files in various formats.  The base name of the\n\
162
 
text file must be the name of the table that should be used.\n\
163
 
If one uses sockets to connect to the Drizzle server, the server will open and\n\
164
 
read the text file directly. In other cases the client will open the text\n\
165
 
file. The SQL command 'LOAD DATA INFILE' is used to import the rows.\n");
166
 
 
167
 
  printf("\nUsage: %s [OPTIONS] database textfile...",internal::my_progname);
168
 
  internal::print_defaults("drizzle",load_default_groups);
169
 
  my_print_help(my_long_options);
170
 
  my_print_variables(my_long_options);
171
 
}
172
 
 
173
 
static int get_one_option(int optid, const struct option *, char *argument)
174
 
{
175
 
  char *endchar= NULL;
176
 
  uint64_t temp_drizzle_port= 0;
177
 
 
178
 
  switch(optid) {
179
 
  case 'p':
180
 
    temp_drizzle_port= (uint64_t) strtoul(argument, &endchar, 10);
181
 
    /* if there is an alpha character this is not a valid port */
182
 
    if (strlen(endchar) != 0)
183
 
    {
184
 
      fprintf(stderr, _("Non-integer value supplied for port.  If you are trying to enter a password please use --password instead.\n"));
185
 
      return EXIT_ARGUMENT_INVALID;
186
 
    }
187
 
    /* If the port number is > 65535 it is not a valid port
188
 
       This also helps with potential data loss casting unsigned long to a
189
 
       uint32_t. */
190
 
    if ((temp_drizzle_port == 0) || (temp_drizzle_port > 65535))
191
 
    {
192
 
      fprintf(stderr, _("Value supplied for port is not valid.\n"));
193
 
      return EXIT_ARGUMENT_INVALID;
194
 
    }
195
 
    else
196
 
    {
197
 
      opt_drizzle_port= (uint32_t) temp_drizzle_port;
198
 
    }
199
 
    break;
200
 
  case 'P':
201
 
    if (argument)
202
 
    {
203
 
      char *start=argument;
204
 
      if (opt_password)
205
 
        free(opt_password);
206
 
      opt_password = strdup(argument);
207
 
      if (opt_password == NULL)
208
 
      {
209
 
        fprintf(stderr, "Memory allocation error while copying password. "
210
 
                        "Aborting.\n");
211
 
        return EXIT_OUT_OF_MEMORY;
212
 
      }
213
 
      while (*argument)
214
 
      {
215
 
        /* Overwriting password with 'x' */
216
 
        *argument++= 'x';
217
 
      }
218
 
      if (*start)
219
 
      {
220
 
        /* Cut length of argument */
221
 
        start[1]= 0;
222
 
      }
223
 
      tty_password= 0;
224
 
    }
225
 
    else
226
 
      tty_password= 1;
227
 
    break;
228
 
  case OPT_DRIZZLE_PROTOCOL:
229
 
    break;
230
 
  case 'V': print_version(); exit(0);
231
 
  case 'I':
232
 
  case '?':
233
 
    usage();
234
 
    exit(0);
235
 
  }
236
 
  return 0;
237
 
}
238
 
 
239
 
 
240
 
static int get_options(int *argc, char ***argv)
241
 
{
242
 
  int ho_error;
243
 
 
244
 
  if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
245
 
    exit(ho_error);
246
 
 
247
 
  if (enclosed && opt_enclosed)
 
64
std::string opt_columns,
 
65
  opt_enclosed,
 
66
  escaped,
 
67
  password,
 
68
  current_db,
 
69
  lines_terminated,
 
70
  current_user,
 
71
  opt_password,
 
72
  enclosed,  
 
73
  current_host,
 
74
  fields_terminated,
 
75
  opt_protocol;
 
76
 
 
77
 
 
78
static int get_options(void)
 
79
{
 
80
 
 
81
  if (! enclosed.empty() && ! opt_enclosed.empty())
248
82
  {
249
83
    fprintf(stderr, "You can't use ..enclosed.. and ..optionally-enclosed.. at the same time.\n");
250
84
    return(1);
254
88
    fprintf(stderr, "You can't use --ignore_unique (-i) and --replace (-r) at the same time.\n");
255
89
    return(1);
256
90
  }
257
 
  if (*argc < 2)
258
 
  {
259
 
    usage();
260
 
    return 1;
261
 
  }
262
 
  current_db= *((*argv)++);
263
 
  (*argc)--;
 
91
 
264
92
  if (tty_password)
265
93
    opt_password=client_get_tty_password(NULL);
266
94
  return(0);
276
104
  drizzle_return_t ret;
277
105
 
278
106
  internal::fn_format(tablename, filename, "", "", 1 | 2); /* removes path & ext. */
279
 
  if (!opt_local_file)
 
107
  if (not opt_local_file)
280
108
    strcpy(hard_path,filename);
281
109
  else
282
110
    internal::my_load_path(hard_path, filename, NULL); /* filename includes the path */
318
146
 
319
147
  end+= sprintf(end, " INTO TABLE %s", tablename);
320
148
 
321
 
  if (fields_terminated || enclosed || opt_enclosed || escaped)
 
149
  if (! fields_terminated.empty() || ! enclosed.empty() || ! opt_enclosed.empty() || ! escaped.empty())
322
150
      end= strcpy(end, " FIELDS")+7;
323
 
  end= add_load_option(end, fields_terminated, " TERMINATED BY");
324
 
  end= add_load_option(end, enclosed, " ENCLOSED BY");
325
 
  end= add_load_option(end, opt_enclosed,
 
151
  end= add_load_option(end, (char *)fields_terminated.c_str(), " TERMINATED BY");
 
152
  end= add_load_option(end, (char *)enclosed.c_str(), " ENCLOSED BY");
 
153
  end= add_load_option(end, (char *)opt_enclosed.c_str(),
326
154
           " OPTIONALLY ENCLOSED BY");
327
 
  end= add_load_option(end, escaped, " ESCAPED BY");
328
 
  end= add_load_option(end, lines_terminated, " LINES TERMINATED BY");
 
155
  end= add_load_option(end, (char *)escaped.c_str(), " ESCAPED BY");
 
156
  end= add_load_option(end, (char *)lines_terminated.c_str(), " LINES TERMINATED BY");
329
157
  if (opt_ignore_lines >= 0)
330
158
  {
331
159
    end= strcpy(end, " IGNORE ")+8;
334
162
    end= strcpy(end, buffer.str().c_str())+ buffer.str().size();
335
163
    end= strcpy(end, " LINES")+6;
336
164
  }
337
 
  if (opt_columns)
 
165
  if (! opt_columns.empty())
338
166
  {
339
167
    end= strcpy(end, " (")+2;
340
 
    end= strcpy(end, opt_columns)+strlen(opt_columns);
 
168
    end= strcpy(end, (char *)opt_columns.c_str()+opt_columns.length());
341
169
    end= strcpy(end, ")")+1;
342
170
  }
343
171
  *end= '\0';
352
180
  {
353
181
    if (strcmp(drizzle_result_info(&result), ""))
354
182
    {
355
 
      fprintf(stdout, "%s.%s: %s\n", current_db, tablename,
 
183
      fprintf(stdout, "%s.%s: %s\n", current_db.c_str(), tablename,
356
184
        drizzle_result_info(&result));
357
185
    }
358
186
  }
361
189
}
362
190
 
363
191
 
364
 
static void lock_table(drizzle_con_st *con, int tablecount, char **raw_tablename)
365
 
{
366
 
  string query;
367
 
  int i;
368
 
  char tablename[FN_REFLEN];
369
 
  drizzle_result_st result;
370
 
  drizzle_return_t ret;
371
 
 
372
 
  if (verbose)
373
 
    fprintf(stdout, "Locking tables for write\n");
374
 
  query.append("LOCK TABLES ");
375
 
  for (i=0 ; i < tablecount ; i++)
376
 
  {
377
 
    internal::fn_format(tablename, raw_tablename[i], "", "", 1 | 2);
378
 
    query.append(tablename);
379
 
    query.append(" WRITE,");
380
 
  }
381
 
  if (drizzle_query(con, &result, query.c_str(), query.length()-1,
382
 
                    &ret) == NULL ||
383
 
      ret != DRIZZLE_RETURN_OK)
384
 
  {
385
 
    db_error(con, &result, ret, NULL);
386
 
    /* We shall countinue here, if --force was given */
387
 
    return;
388
 
  }
389
 
  drizzle_result_free(&result);
390
 
}
391
 
 
392
 
 
393
 
static drizzle_con_st *db_connect(char *host, char *database,
394
 
                                  char *user, char *passwd)
 
192
static drizzle_con_st *db_connect(const string host, const string database,
 
193
                                  const string user, const string passwd)
395
194
{
396
195
  drizzle_st *drizzle;
397
196
  drizzle_con_st *con;
398
197
  drizzle_return_t ret;
399
198
 
400
199
  if (verbose)
401
 
    fprintf(stdout, "Connecting to %s\n", host ? host : "localhost");
 
200
    fprintf(stdout, "Connecting to %s, using protocol %s...\n", ! host.empty() ? host.c_str() : "localhost", opt_protocol.c_str());
402
201
  if (!(drizzle= drizzle_create(NULL)))
403
202
    return 0;
404
 
  if (!(con= drizzle_con_add_tcp(drizzle,NULL,host,opt_drizzle_port,user,passwd,
405
 
                                 database, opt_mysql ? DRIZZLE_CON_MYSQL : DRIZZLE_CON_NONE)))
 
203
  if (!(con= drizzle_con_add_tcp(drizzle,NULL,(char *)host.c_str(),opt_drizzle_port,(char *)user.c_str(),(char *)passwd.c_str(),
 
204
                                 (char *)database.c_str(), use_drizzle_protocol ? DRIZZLE_CON_EXPERIMENTAL : DRIZZLE_CON_MYSQL)))
406
205
  {
407
206
    return 0;
408
207
  }
414
213
  }
415
214
 
416
215
  if (verbose)
417
 
    fprintf(stdout, "Selecting database %s\n", database);
 
216
    fprintf(stdout, "Selecting database %s\n", database.c_str());
418
217
 
419
218
  return con;
420
219
}
421
220
 
422
221
 
423
222
 
424
 
static void db_disconnect(char *host, drizzle_con_st *con)
 
223
static void db_disconnect(const string host, drizzle_con_st *con)
425
224
{
426
225
  if (verbose)
427
 
    fprintf(stdout, "Disconnecting from %s\n", host ? host : "localhost");
 
226
    fprintf(stdout, "Disconnecting from %s\n", ! host.empty() ? host.c_str() : "localhost");
428
227
  drizzle_free(drizzle_con_drizzle(con));
429
228
}
430
229
 
446
245
{
447
246
  if (ret == DRIZZLE_RETURN_ERROR_CODE)
448
247
  {
449
 
    my_printf_error(0,"Error: %d, %s%s%s", MYF(0),
450
 
                    drizzle_result_error_code(result),
451
 
                    drizzle_result_error(result),
452
 
                    table ? ", when using table: " : "", table ? table : "");
 
248
    fprintf(stdout, "Error: %d, %s%s%s",
 
249
            drizzle_result_error_code(result),
 
250
            drizzle_result_error(result),
 
251
            table ? ", when using table: " : "", table ? table : "");
453
252
    drizzle_result_free(result);
454
253
  }
455
254
  else
456
255
  {
457
 
    my_printf_error(0,"Error: %d, %s%s%s", MYF(0), ret, drizzle_con_error(con),
458
 
                    table ? ", when using table: " : "", table ? table : "");
 
256
    fprintf(stdout, "Error: %d, %s%s%s", ret, drizzle_con_error(con),
 
257
            table ? ", when using table: " : "", table ? table : "");
459
258
  }
460
259
 
461
260
  safe_exit(1, con);
515
314
{
516
315
  int error;
517
316
  char *raw_table_name= (char *)arg;
518
 
  drizzle_con_st *con= NULL;
519
 
  drizzle_result_st result;
520
 
  drizzle_return_t ret;
 
317
  drizzle_con_st *con;
521
318
 
522
319
  if (!(con= db_connect(current_host,current_db,current_user,opt_password)))
523
320
  {
524
 
    goto error;
525
 
  }
526
 
 
527
 
  if (drizzle_query_str(con, &result,
528
 
                        "/*!40101 set @@character_set_database=binary */;",
529
 
                        &ret) == NULL ||
530
 
      ret != DRIZZLE_RETURN_OK)
531
 
  {
532
 
    db_error(con, &result, ret, NULL);
533
 
    /* We shall countinue here, if --force was given */
534
 
    goto error;
 
321
    return 0;
535
322
  }
536
323
 
537
324
  /*
538
325
    We are not currently catching the error here.
539
326
  */
540
 
  if((error= write_to_table(raw_table_name, con)))
 
327
  if ((error= write_to_table(raw_table_name, con)))
 
328
  {
541
329
    if (exitcode == 0)
 
330
    {
542
331
      exitcode= error;
 
332
    }
 
333
  }
543
334
 
544
 
error:
545
335
  if (con)
 
336
  {
546
337
    db_disconnect(current_host, con);
 
338
  }
547
339
 
548
340
  pthread_mutex_lock(&counter_mutex);
549
341
  counter--;
550
342
  pthread_cond_signal(&count_threshhold);
551
343
  pthread_mutex_unlock(&counter_mutex);
552
 
  internal::my_thread_end();
553
344
 
554
345
  return 0;
555
346
}
557
348
 
558
349
int main(int argc, char **argv)
559
350
{
 
351
try
 
352
{
560
353
  int error=0;
561
 
  char **argv_to_free;
562
 
  MY_INIT(argv[0]);
563
 
 
564
 
  internal::load_defaults("drizzle",load_default_groups,&argc,&argv);
565
 
  /* argv is changed in the program */
566
 
  argv_to_free= argv;
567
 
  if (get_options(&argc, &argv))
568
 
  {
569
 
    internal::free_defaults(argv_to_free);
 
354
 
 
355
  po::options_description commandline_options("Options used only in command line");
 
356
  commandline_options.add_options()
 
357
 
 
358
  ("debug,#", po::value<string>(),
 
359
  "Output debug log. Often this is 'd:t:o,filename'.")
 
360
  ("delete,d", po::value<bool>(&opt_delete)->default_value(false)->zero_tokens(),
 
361
  "First delete all rows from table.")
 
362
  ("help,?", "Displays this help and exits.")
 
363
  ("ignore,i", po::value<bool>(&ignore_unique)->default_value(false)->zero_tokens(),
 
364
  "If duplicate unique key was found, keep old row.")
 
365
  ("low-priority", po::value<bool>(&opt_low_priority)->default_value(false)->zero_tokens(),
 
366
  "Use LOW_PRIORITY when updating the table.")
 
367
  ("replace,r", po::value<bool>(&opt_replace)->default_value(false)->zero_tokens(),
 
368
  "If duplicate unique key was found, replace old row.")
 
369
  ("verbose,v", po::value<bool>(&verbose)->default_value(false)->zero_tokens(),
 
370
  "Print info about the various stages.")
 
371
  ("version,V", "Output version information and exit.")
 
372
  ;
 
373
 
 
374
  po::options_description import_options("Options specific to the drizzleimport");
 
375
  import_options.add_options()
 
376
  ("columns,C", po::value<string>(&opt_columns)->default_value(""),
 
377
  "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.")
 
378
  ("fields-terminated-by", po::value<string>(&fields_terminated)->default_value(""),
 
379
  "Fields in the textfile are terminated by ...")
 
380
  ("fields-enclosed-by", po::value<string>(&enclosed)->default_value(""),
 
381
  "Fields in the importfile are enclosed by ...")
 
382
  ("fields-optionally-enclosed-by", po::value<string>(&opt_enclosed)->default_value(""),
 
383
  "Fields in the i.file are opt. enclosed by ...")
 
384
  ("fields-escaped-by", po::value<string>(&escaped)->default_value(""),
 
385
  "Fields in the i.file are escaped by ...")
 
386
  ("force,f", po::value<bool>(&ignore_errors)->default_value(false)->zero_tokens(),
 
387
  "Continue even if we get an sql-error.")
 
388
  ("ignore-lines", po::value<int64_t>(&opt_ignore_lines)->default_value(0),
 
389
  "Ignore first n lines of data infile.")
 
390
  ("lines-terminated-by", po::value<string>(&lines_terminated)->default_value(""),
 
391
  "Lines in the i.file are terminated by ...")
 
392
  ("local,L", po::value<bool>(&opt_local_file)->default_value(false)->zero_tokens(),
 
393
  "Read all files through the client.")
 
394
  ("silent,s", po::value<bool>(&silent)->default_value(false)->zero_tokens(),
 
395
  "Be more silent.")
 
396
  ("use-threads", po::value<uint32_t>(&opt_use_threads)->default_value(4),
 
397
  "Load files in parallel. The argument is the number of threads to use for loading data (default is 4.")
 
398
  ;
 
399
 
 
400
  po::options_description client_options("Options specific to the client");
 
401
  client_options.add_options()
 
402
  ("host,h", po::value<string>(&current_host)->default_value("localhost"),
 
403
  "Connect to host.")
 
404
  ("password,P", po::value<string>(&password),
 
405
  "Password to use when connecting to server. If password is not given it's asked from the tty." )
 
406
  ("port,p", po::value<uint32_t>(&opt_drizzle_port)->default_value(0),
 
407
  "Port number to use for connection") 
 
408
  ("protocol", po::value<string>(&opt_protocol)->default_value("mysql"),
 
409
  "The protocol of connection (mysql or drizzle).")
 
410
  ("user,u", po::value<string>(&current_user)->default_value(""),
 
411
  "User for login if not current user.")
 
412
  ;
 
413
 
 
414
  po::options_description long_options("Allowed Options");
 
415
  long_options.add(commandline_options).add(import_options).add(client_options);
 
416
 
 
417
  std::string system_config_dir_import(SYSCONFDIR); 
 
418
  system_config_dir_import.append("/drizzle/drizzleimport.cnf");
 
419
 
 
420
  std::string system_config_dir_client(SYSCONFDIR); 
 
421
  system_config_dir_client.append("/drizzle/client.cnf");
 
422
  
 
423
  std::string user_config_dir((getenv("XDG_CONFIG_HOME")? getenv("XDG_CONFIG_HOME"):"~/.config"));
 
424
 
 
425
  po::variables_map vm;
 
426
 
 
427
  // Disable allow_guessing
 
428
  int style = po::command_line_style::default_style & ~po::command_line_style::allow_guessing;
 
429
 
 
430
  po::store(po::command_line_parser(argc, argv).options(long_options).
 
431
            style(style).extra_parser(parse_password_arg).run(), vm);
 
432
 
 
433
  std::string user_config_dir_import(user_config_dir);
 
434
  user_config_dir_import.append("/drizzle/drizzleimport.cnf"); 
 
435
 
 
436
  std::string user_config_dir_client(user_config_dir);
 
437
  user_config_dir_client.append("/drizzle/client.cnf");
 
438
 
 
439
  ifstream user_import_ifs(user_config_dir_import.c_str());
 
440
  po::store(parse_config_file(user_import_ifs, import_options), vm);
 
441
 
 
442
  ifstream user_client_ifs(user_config_dir_client.c_str());
 
443
  po::store(parse_config_file(user_client_ifs, client_options), vm);
 
444
 
 
445
  ifstream system_import_ifs(system_config_dir_import.c_str());
 
446
  store(parse_config_file(system_import_ifs, import_options), vm);
 
447
 
 
448
  ifstream system_client_ifs(system_config_dir_client.c_str());
 
449
  po::store(parse_config_file(system_client_ifs, client_options), vm);
 
450
 
 
451
  po::notify(vm);
 
452
  if (vm.count("protocol"))
 
453
  {
 
454
    std::transform(opt_protocol.begin(), opt_protocol.end(),
 
455
      opt_protocol.begin(), ::tolower);
 
456
 
 
457
    if (not opt_protocol.compare("mysql"))
 
458
      use_drizzle_protocol=false;
 
459
    else if (not opt_protocol.compare("drizzle"))
 
460
      use_drizzle_protocol=true;
 
461
    else
 
462
    {
 
463
      cout << _("Error: Unknown protocol") << " '" << opt_protocol << "'" << endl;
 
464
      exit(-1);
 
465
    }
 
466
  }
 
467
 
 
468
  if (vm.count("port"))
 
469
  {
 
470
    
 
471
    /* If the port number is > 65535 it is not a valid port
 
472
       This also helps with potential data loss casting unsigned long to a
 
473
       uint32_t. */
 
474
    if (opt_drizzle_port > 65535)
 
475
    {
 
476
      fprintf(stderr, _("Value supplied for port is not valid.\n"));
 
477
      exit(EXIT_ARGUMENT_INVALID);
 
478
    }
 
479
  }
 
480
 
 
481
  if( vm.count("password") )
 
482
  {
 
483
    if (!opt_password.empty())
 
484
      opt_password.erase();
 
485
    if (password == PASSWORD_SENTINEL)
 
486
    {
 
487
      opt_password= "";
 
488
    }
 
489
    else
 
490
    {
 
491
      opt_password= password;
 
492
      tty_password= false;
 
493
    }
 
494
  }
 
495
  else
 
496
  {
 
497
      tty_password= true;
 
498
  }
 
499
 
 
500
 
 
501
  if (vm.count("version"))
 
502
  {
 
503
    printf("%s  Ver %s Distrib %s, for %s-%s (%s)\n", program_name,
 
504
    IMPORT_VERSION, drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
 
505
  }
 
506
  
 
507
  if (vm.count("help") || argc < 2)
 
508
  {
 
509
    printf("%s  Ver %s Distrib %s, for %s-%s (%s)\n", program_name,
 
510
    IMPORT_VERSION, drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
 
511
    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");
 
512
    printf("\
 
513
    Loads tables from text files in various formats.  The base name of the\n\
 
514
    text file must be the name of the table that should be used.\n\
 
515
    If one uses sockets to connect to the Drizzle server, the server will open and\n\
 
516
    read the text file directly. In other cases the client will open the text\n\
 
517
    file. The SQL command 'LOAD DATA INFILE' is used to import the rows.\n");
 
518
 
 
519
    printf("\nUsage: %s [OPTIONS] database textfile...", program_name);
 
520
    cout<<long_options;
 
521
    exit(0);
 
522
  }
 
523
 
 
524
 
 
525
  if (get_options())
 
526
  {
570
527
    return(1);
571
528
  }
 
529
  
 
530
  current_db= (*argv)++;
 
531
  argc--;
572
532
 
573
 
#ifdef HAVE_LIBPTHREAD
574
 
  if (opt_use_threads && !lock_tables)
 
533
  if (opt_use_threads)
575
534
  {
576
535
    pthread_t mainthread;            /* Thread descriptor */
577
536
    pthread_attr_t attr;          /* Thread attributes */
602
561
        pthread_mutex_lock(&counter_mutex);
603
562
        counter--;
604
563
        pthread_mutex_unlock(&counter_mutex);
605
 
        fprintf(stderr,"%s: Could not create thread\n",
606
 
                internal::my_progname);
 
564
        fprintf(stderr,"%s: Could not create thread\n", program_name);
607
565
      }
608
566
    }
609
567
 
624
582
    pthread_attr_destroy(&attr);
625
583
  }
626
584
  else
627
 
#endif
628
585
  {
629
 
    drizzle_con_st *con= 0;
630
 
    drizzle_result_st result;
631
 
    drizzle_return_t ret;
 
586
    drizzle_con_st *con;
 
587
 
632
588
    if (!(con= db_connect(current_host,current_db,current_user,opt_password)))
633
589
    {
634
 
      internal::free_defaults(argv_to_free);
635
 
      return(1);
636
 
    }
637
 
 
638
 
    if (drizzle_query_str(con, &result,
639
 
                          "/*!40101 set @@character_set_database=binary */;",
640
 
                          &ret) == NULL ||
641
 
        ret != DRIZZLE_RETURN_OK)
642
 
    {
643
 
      db_error(con, &result, ret, NULL);
644
 
      /* We shall countinue here, if --force was given */
645
 
      return(1);
646
 
    }
647
 
 
648
 
    drizzle_result_free(&result);
649
 
 
650
 
    if (lock_tables)
651
 
      lock_table(con, argc, argv);
 
590
      return(1);
 
591
    }
 
592
 
652
593
    for (; *argv != NULL; argv++)
653
594
      if ((error= write_to_table(*argv, con)))
654
595
        if (exitcode == 0)
655
596
          exitcode= error;
656
597
    db_disconnect(current_host, con);
657
598
  }
658
 
  free(opt_password);
659
 
  internal::free_defaults(argv_to_free);
660
 
  internal::my_end();
 
599
  opt_password.empty();
 
600
}
 
601
  catch(exception &err)
 
602
  {
 
603
    cerr<<err.what()<<endl;
 
604
  }
661
605
  return(exitcode);
662
606
}