~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to client/drizzleimport.cc

Merge Stewart.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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"
 
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"
21
29
 
22
30
#include "client_priv.h"
23
31
#include <string>
24
32
#include <sstream>
25
 
#include <iostream>
26
 
#include <fstream>
27
 
#include <boost/program_options.hpp>
 
33
 
28
34
#include <pthread.h>
29
35
 
30
36
/* Added this for string translation. */
31
37
#include <drizzled/gettext.h>
32
 
#include <drizzled/configmake.h>
33
38
 
34
 
namespace po= boost::program_options;
35
39
using namespace std;
36
40
using namespace drizzled;
37
41
 
39
43
 
40
44
int exitcode= 0;
41
45
 
42
 
const char *program_name= "drizzleimport";
43
 
 
44
46
/* Global Thread counter */
45
47
uint32_t counter;
46
48
pthread_mutex_t counter_mutex;
52
54
static char *add_load_option(char *ptr,const char *object,
53
55
           const char *statement);
54
56
 
55
 
static bool verbose= false, ignore_errors= false,
 
57
static bool verbose= false, lock_tables= false, ignore_errors= false,
56
58
            opt_delete= false, opt_replace= false, silent= false,
57
59
            ignore_unique= false, opt_low_priority= false,
58
 
            use_drizzle_protocol= false, opt_local_file;
 
60
            tty_password= false, opt_mysql= false;
59
61
 
60
 
static uint32_t opt_use_threads;
 
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;
61
67
static uint32_t opt_drizzle_port= 0;
62
68
static int64_t opt_ignore_lines= -1;
63
69
 
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())
 
70
static struct my_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, 0, 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 bool get_one_option(int optid, const struct my_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
      exit(1);
 
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
      exit(1);
 
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
        exit(ENOMEM);
 
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)
82
248
  {
83
249
    fprintf(stderr, "You can't use ..enclosed.. and ..optionally-enclosed.. at the same time.\n");
84
250
    return(1);
88
254
    fprintf(stderr, "You can't use --ignore_unique (-i) and --replace (-r) at the same time.\n");
89
255
    return(1);
90
256
  }
91
 
 
 
257
  if (*argc < 2)
 
258
  {
 
259
    usage();
 
260
    return 1;
 
261
  }
 
262
  current_db= *((*argv)++);
 
263
  (*argc)--;
92
264
  if (tty_password)
93
265
    opt_password=client_get_tty_password(NULL);
94
266
  return(0);
104
276
  drizzle_return_t ret;
105
277
 
106
278
  internal::fn_format(tablename, filename, "", "", 1 | 2); /* removes path & ext. */
107
 
  if (not opt_local_file)
 
279
  if (!opt_local_file)
108
280
    strcpy(hard_path,filename);
109
281
  else
110
282
    internal::my_load_path(hard_path, filename, NULL); /* filename includes the path */
114
286
    if (verbose)
115
287
      fprintf(stdout, "Deleting the old data from table %s\n", tablename);
116
288
#ifdef HAVE_SNPRINTF
117
 
    snprintf(sql_statement, sizeof(sql_statement), "DELETE FROM %s", tablename);
 
289
    snprintf(sql_statement, FN_REFLEN*16+256, "DELETE FROM %s", tablename);
118
290
#else
119
 
    snprintf(sql_statement, sizeof(sql_statement), "DELETE FROM %s", tablename);
 
291
    sprintf(sql_statement, "DELETE FROM %s", tablename);
120
292
#endif
121
293
    if (drizzle_query_str(con, &result, sql_statement, &ret) == NULL ||
122
294
        ret != DRIZZLE_RETURN_OK)
135
307
      fprintf(stdout, "Loading data from SERVER file: %s into %s\n",
136
308
        hard_path, tablename);
137
309
  }
138
 
  snprintf(sql_statement, sizeof(sql_statement), "LOAD DATA %s %s INFILE '%s'",
 
310
  sprintf(sql_statement, "LOAD DATA %s %s INFILE '%s'",
139
311
    opt_low_priority ? "LOW_PRIORITY" : "",
140
312
    opt_local_file ? "LOCAL" : "", hard_path);
141
313
  end= strchr(sql_statement, '\0');
146
318
 
147
319
  end+= sprintf(end, " INTO TABLE %s", tablename);
148
320
 
149
 
  if (! fields_terminated.empty() || ! enclosed.empty() || ! opt_enclosed.empty() || ! escaped.empty())
 
321
  if (fields_terminated || enclosed || opt_enclosed || escaped)
150
322
      end= strcpy(end, " FIELDS")+7;
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(),
 
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,
154
326
           " OPTIONALLY ENCLOSED 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");
 
327
  end= add_load_option(end, escaped, " ESCAPED BY");
 
328
  end= add_load_option(end, lines_terminated, " LINES TERMINATED BY");
157
329
  if (opt_ignore_lines >= 0)
158
330
  {
159
331
    end= strcpy(end, " IGNORE ")+8;
162
334
    end= strcpy(end, buffer.str().c_str())+ buffer.str().size();
163
335
    end= strcpy(end, " LINES")+6;
164
336
  }
165
 
  if (! opt_columns.empty())
 
337
  if (opt_columns)
166
338
  {
167
339
    end= strcpy(end, " (")+2;
168
 
    end= strcpy(end, (char *)opt_columns.c_str()+opt_columns.length());
 
340
    end= strcpy(end, opt_columns)+strlen(opt_columns);
169
341
    end= strcpy(end, ")")+1;
170
342
  }
171
343
  *end= '\0';
180
352
  {
181
353
    if (strcmp(drizzle_result_info(&result), ""))
182
354
    {
183
 
      fprintf(stdout, "%s.%s: %s\n", current_db.c_str(), tablename,
 
355
      fprintf(stdout, "%s.%s: %s\n", current_db, tablename,
184
356
        drizzle_result_info(&result));
185
357
    }
186
358
  }
189
361
}
190
362
 
191
363
 
192
 
static drizzle_con_st *db_connect(const string host, const string database,
193
 
                                  const string user, const string passwd)
 
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)
194
395
{
195
396
  drizzle_st *drizzle;
196
397
  drizzle_con_st *con;
197
398
  drizzle_return_t ret;
198
399
 
199
400
  if (verbose)
200
 
    fprintf(stdout, "Connecting to %s, using protocol %s...\n", ! host.empty() ? host.c_str() : "localhost", opt_protocol.c_str());
 
401
    fprintf(stdout, "Connecting to %s\n", host ? host : "localhost");
201
402
  if (!(drizzle= drizzle_create(NULL)))
202
403
    return 0;
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)))
 
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)))
205
406
  {
206
407
    return 0;
207
408
  }
213
414
  }
214
415
 
215
416
  if (verbose)
216
 
    fprintf(stdout, "Selecting database %s\n", database.c_str());
 
417
    fprintf(stdout, "Selecting database %s\n", database);
217
418
 
218
419
  return con;
219
420
}
220
421
 
221
422
 
222
423
 
223
 
static void db_disconnect(const string host, drizzle_con_st *con)
 
424
static void db_disconnect(char *host, drizzle_con_st *con)
224
425
{
225
426
  if (verbose)
226
 
    fprintf(stdout, "Disconnecting from %s\n", ! host.empty() ? host.c_str() : "localhost");
 
427
    fprintf(stdout, "Disconnecting from %s\n", host ? host : "localhost");
227
428
  drizzle_free(drizzle_con_drizzle(con));
228
429
}
229
430
 
245
446
{
246
447
  if (ret == DRIZZLE_RETURN_ERROR_CODE)
247
448
  {
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 : "");
 
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 : "");
252
453
    drizzle_result_free(result);
253
454
  }
254
455
  else
255
456
  {
256
 
    fprintf(stdout, "Error: %d, %s%s%s", ret, drizzle_con_error(con),
257
 
            table ? ", when using table: " : "", table ? table : "");
 
457
    my_printf_error(0,"Error: %d, %s%s%s", MYF(0), ret, drizzle_con_error(con),
 
458
                    table ? ", when using table: " : "", table ? table : "");
258
459
  }
259
460
 
260
461
  safe_exit(1, con);
314
515
{
315
516
  int error;
316
517
  char *raw_table_name= (char *)arg;
317
 
  drizzle_con_st *con;
 
518
  drizzle_con_st *con= NULL;
 
519
  drizzle_result_st result;
 
520
  drizzle_return_t ret;
318
521
 
319
522
  if (!(con= db_connect(current_host,current_db,current_user,opt_password)))
320
523
  {
321
 
    return 0;
 
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;
322
535
  }
323
536
 
324
537
  /*
325
538
    We are not currently catching the error here.
326
539
  */
327
 
  if ((error= write_to_table(raw_table_name, con)))
328
 
  {
 
540
  if((error= write_to_table(raw_table_name, con)))
329
541
    if (exitcode == 0)
330
 
    {
331
542
      exitcode= error;
332
 
    }
333
 
  }
334
543
 
 
544
error:
335
545
  if (con)
336
 
  {
337
546
    db_disconnect(current_host, con);
338
 
  }
339
547
 
340
548
  pthread_mutex_lock(&counter_mutex);
341
549
  counter--;
342
550
  pthread_cond_signal(&count_threshhold);
343
551
  pthread_mutex_unlock(&counter_mutex);
 
552
  internal::my_thread_end();
344
553
 
345
554
  return 0;
346
555
}
348
557
 
349
558
int main(int argc, char **argv)
350
559
{
351
 
try
352
 
{
353
560
  int error=0;
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
 
  if (user_config_dir.compare(0, 2, "~/") == 0)
426
 
  {
427
 
    char *homedir;
428
 
    homedir= getenv("HOME");
429
 
    if (homedir != NULL)
430
 
      user_config_dir.replace(0, 1, homedir);
431
 
  }
432
 
 
433
 
  po::variables_map vm;
434
 
 
435
 
  // Disable allow_guessing
436
 
  int style = po::command_line_style::default_style & ~po::command_line_style::allow_guessing;
437
 
 
438
 
  po::store(po::command_line_parser(argc, argv).options(long_options).
439
 
            style(style).extra_parser(parse_password_arg).run(), vm);
440
 
 
441
 
  std::string user_config_dir_import(user_config_dir);
442
 
  user_config_dir_import.append("/drizzle/drizzleimport.cnf"); 
443
 
 
444
 
  std::string user_config_dir_client(user_config_dir);
445
 
  user_config_dir_client.append("/drizzle/client.cnf");
446
 
 
447
 
  ifstream user_import_ifs(user_config_dir_import.c_str());
448
 
  po::store(parse_config_file(user_import_ifs, import_options), vm);
449
 
 
450
 
  ifstream user_client_ifs(user_config_dir_client.c_str());
451
 
  po::store(parse_config_file(user_client_ifs, client_options), vm);
452
 
 
453
 
  ifstream system_import_ifs(system_config_dir_import.c_str());
454
 
  store(parse_config_file(system_import_ifs, import_options), vm);
455
 
 
456
 
  ifstream system_client_ifs(system_config_dir_client.c_str());
457
 
  po::store(parse_config_file(system_client_ifs, client_options), vm);
458
 
 
459
 
  po::notify(vm);
460
 
  if (vm.count("protocol"))
461
 
  {
462
 
    std::transform(opt_protocol.begin(), opt_protocol.end(),
463
 
      opt_protocol.begin(), ::tolower);
464
 
 
465
 
    if (not opt_protocol.compare("mysql"))
466
 
      use_drizzle_protocol=false;
467
 
    else if (not opt_protocol.compare("drizzle"))
468
 
      use_drizzle_protocol=true;
469
 
    else
470
 
    {
471
 
      cout << _("Error: Unknown protocol") << " '" << opt_protocol << "'" << endl;
472
 
      exit(-1);
473
 
    }
474
 
  }
475
 
 
476
 
  if (vm.count("port"))
477
 
  {
478
 
    
479
 
    /* If the port number is > 65535 it is not a valid port
480
 
       This also helps with potential data loss casting unsigned long to a
481
 
       uint32_t. */
482
 
    if (opt_drizzle_port > 65535)
483
 
    {
484
 
      fprintf(stderr, _("Value supplied for port is not valid.\n"));
485
 
      exit(EXIT_ARGUMENT_INVALID);
486
 
    }
487
 
  }
488
 
 
489
 
  if( vm.count("password") )
490
 
  {
491
 
    if (!opt_password.empty())
492
 
      opt_password.erase();
493
 
    if (password == PASSWORD_SENTINEL)
494
 
    {
495
 
      opt_password= "";
496
 
    }
497
 
    else
498
 
    {
499
 
      opt_password= password;
500
 
      tty_password= false;
501
 
    }
502
 
  }
503
 
  else
504
 
  {
505
 
      tty_password= true;
506
 
  }
507
 
 
508
 
 
509
 
  if (vm.count("version"))
510
 
  {
511
 
    printf("%s  Ver %s Distrib %s, for %s-%s (%s)\n", program_name,
512
 
    IMPORT_VERSION, drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
513
 
  }
514
 
  
515
 
  if (vm.count("help") || argc < 2)
516
 
  {
517
 
    printf("%s  Ver %s Distrib %s, for %s-%s (%s)\n", program_name,
518
 
    IMPORT_VERSION, drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
519
 
    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");
520
 
    printf("\
521
 
    Loads tables from text files in various formats.  The base name of the\n\
522
 
    text file must be the name of the table that should be used.\n\
523
 
    If one uses sockets to connect to the Drizzle server, the server will open and\n\
524
 
    read the text file directly. In other cases the client will open the text\n\
525
 
    file. The SQL command 'LOAD DATA INFILE' is used to import the rows.\n");
526
 
 
527
 
    printf("\nUsage: %s [OPTIONS] database textfile...", program_name);
528
 
    cout<<long_options;
529
 
    exit(0);
530
 
  }
531
 
 
532
 
 
533
 
  if (get_options())
534
 
  {
 
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);
535
570
    return(1);
536
571
  }
537
 
  
538
 
  current_db= (*argv)++;
539
 
  argc--;
540
572
 
541
 
  if (opt_use_threads)
 
573
#ifdef HAVE_LIBPTHREAD
 
574
  if (opt_use_threads && !lock_tables)
542
575
  {
543
576
    pthread_t mainthread;            /* Thread descriptor */
544
577
    pthread_attr_t attr;          /* Thread attributes */
569
602
        pthread_mutex_lock(&counter_mutex);
570
603
        counter--;
571
604
        pthread_mutex_unlock(&counter_mutex);
572
 
        fprintf(stderr,"%s: Could not create thread\n", program_name);
 
605
        fprintf(stderr,"%s: Could not create thread\n",
 
606
                internal::my_progname);
573
607
      }
574
608
    }
575
609
 
590
624
    pthread_attr_destroy(&attr);
591
625
  }
592
626
  else
 
627
#endif
593
628
  {
594
 
    drizzle_con_st *con;
595
 
 
 
629
    drizzle_con_st *con= 0;
 
630
    drizzle_result_st result;
 
631
    drizzle_return_t ret;
596
632
    if (!(con= db_connect(current_host,current_db,current_user,opt_password)))
597
633
    {
598
 
      return(1);
599
 
    }
600
 
 
 
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);
601
652
    for (; *argv != NULL; argv++)
602
653
      if ((error= write_to_table(*argv, con)))
603
654
        if (exitcode == 0)
604
655
          exitcode= error;
605
656
    db_disconnect(current_host, con);
606
657
  }
607
 
  opt_password.empty();
608
 
}
609
 
  catch(exception &err)
610
 
  {
611
 
    cerr<<err.what()<<endl;
612
 
  }
 
658
  free(opt_password);
 
659
  internal::free_defaults(argv_to_free);
 
660
  internal::my_end();
613
661
  return(exitcode);
614
662
}