~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to client/drizzleimport.cc

  • Committer: devananda
  • Date: 2009-07-01 17:38:47 UTC
  • mto: (1093.1.7 captain)
  • mto: This revision was merged to the branch mainline in revision 1095.
  • Revision ID: devananda.vdv@gmail.com-20090701173847-3n3mbtessg5ff35e
refactored function/benchmark into plugin/benchmark

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) 2008 Drizzle Open Source Development Team
 
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
**     drizzleimport.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"
21
28
 
22
29
#include "client_priv.h"
23
30
#include <string>
24
 
#include <sstream>
25
 
#include <iostream>
26
 
#include <fstream>
27
 
#include <boost/program_options.hpp>
 
31
 
28
32
#include <pthread.h>
29
33
 
30
34
/* Added this for string translation. */
31
35
#include <drizzled/gettext.h>
32
 
#include <drizzled/configmake.h>
33
36
 
34
 
namespace po= boost::program_options;
35
37
using namespace std;
36
 
using namespace drizzled;
37
 
 
38
 
extern "C" void * worker_thread(void *arg);
39
 
 
40
 
int exitcode= 0;
41
 
 
42
 
const char *program_name= "drizzlesimport";
43
38
 
44
39
/* Global Thread counter */
45
40
uint32_t counter;
52
47
static char *add_load_option(char *ptr,const char *object,
53
48
           const char *statement);
54
49
 
55
 
static bool verbose= false, ignore_errors= false,
 
50
static bool verbose= false, lock_tables= false, ignore_errors= false,
56
51
            opt_delete= false, opt_replace= false, silent= false,
57
 
            ignore_unique= false, opt_low_priority= false,
58
 
            use_drizzle_protocol= false, opt_local_file;
59
 
 
60
 
static uint32_t opt_use_threads;
 
52
            ignore_unique= false, opt_compress= false, opt_low_priority= false,
 
53
            tty_password= false;
 
54
static bool debug_info_flag= false, debug_check_flag= false;
 
55
static uint32_t opt_use_threads= 0, opt_local_file= 0, my_end_arg= 0;
 
56
static char  *opt_password= NULL, *current_user= NULL,
 
57
    *current_host= NULL, *current_db= NULL, *fields_terminated= NULL,
 
58
    *lines_terminated= NULL, *enclosed= NULL, *opt_enclosed= NULL,
 
59
    *escaped= NULL, *opt_columns= NULL,
 
60
    *default_charset= (char*) DRIZZLE_DEFAULT_CHARSET_NAME;
61
61
static uint32_t opt_drizzle_port= 0;
 
62
static char * opt_drizzle_unix_port= 0;
62
63
static int64_t opt_ignore_lines= -1;
63
 
 
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())
 
64
static const CHARSET_INFO *charset_info= &my_charset_utf8_general_ci;
 
65
 
 
66
static struct my_option my_long_options[] =
 
67
{
 
68
  {"default-character-set", OPT_DEFAULT_CHARSET,
 
69
   "Set the default character set.", (char**) &default_charset,
 
70
   (char**) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
71
  {"columns", 'c',
 
72
   "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.",
 
73
   (char**) &opt_columns, (char**) &opt_columns, 0, GET_STR, REQUIRED_ARG, 0, 0, 0,
 
74
   0, 0, 0},
 
75
  {"compress", 'C', "Use compression in server/client protocol.",
 
76
   (char**) &opt_compress, (char**) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
 
77
   0, 0, 0},
 
78
  {"debug",'#', "Output debug log. Often this is 'd:t:o,filename'.", 0, 0, 0,
 
79
   GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
 
80
  {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
 
81
   (char**) &debug_check_flag, (char**) &debug_check_flag, 0,
 
82
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
83
  {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
 
84
   (char**) &debug_info_flag, (char**) &debug_info_flag,
 
85
   0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
86
  {"delete", 'd', "First delete all rows from table.", (char**) &opt_delete,
 
87
   (char**) &opt_delete, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
88
  {"fields-terminated-by", OPT_FTB,
 
89
   "Fields in the textfile are terminated by ...", (char**) &fields_terminated,
 
90
   (char**) &fields_terminated, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
91
  {"fields-enclosed-by", OPT_ENC,
 
92
   "Fields in the importfile are enclosed by ...", (char**) &enclosed,
 
93
   (char**) &enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
94
  {"fields-optionally-enclosed-by", OPT_O_ENC,
 
95
   "Fields in the i.file are opt. enclosed by ...", (char**) &opt_enclosed,
 
96
   (char**) &opt_enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
97
  {"fields-escaped-by", OPT_ESC, "Fields in the i.file are escaped by ...",
 
98
   (char**) &escaped, (char**) &escaped, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0,
 
99
   0, 0},
 
100
  {"force", 'f', "Continue even if we get an sql-error.",
 
101
   (char**) &ignore_errors, (char**) &ignore_errors, 0, GET_BOOL, NO_ARG, 0, 0,
 
102
   0, 0, 0, 0},
 
103
  {"help", '?', "Displays this help and exits.", 0, 0, 0, GET_NO_ARG, NO_ARG,
 
104
   0, 0, 0, 0, 0, 0},
 
105
  {"host", 'h', "Connect to host.", (char**) &current_host,
 
106
   (char**) &current_host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
107
  {"ignore", 'i', "If duplicate unique key was found, keep old row.",
 
108
   (char**) &ignore_unique, (char**) &ignore_unique, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
109
  {"ignore-lines", OPT_IGN_LINES, "Ignore first n lines of data infile.",
 
110
   (char**) &opt_ignore_lines, (char**) &opt_ignore_lines, 0, GET_LL,
 
111
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
112
  {"lines-terminated-by", OPT_LTB, "Lines in the i.file are terminated by ...",
 
113
   (char**) &lines_terminated, (char**) &lines_terminated, 0, GET_STR,
 
114
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
115
  {"local", 'L', "Read all files through the client.", (char**) &opt_local_file,
 
116
   (char**) &opt_local_file, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
117
  {"lock-tables", 'l', "Lock all tables for write (this disables threads).",
 
118
    (char**) &lock_tables, (char**) &lock_tables, 0, GET_BOOL, NO_ARG,
 
119
    0, 0, 0, 0, 0, 0},
 
120
  {"low-priority", OPT_LOW_PRIORITY,
 
121
   "Use LOW_PRIORITY when updating the table.", (char**) &opt_low_priority,
 
122
   (char**) &opt_low_priority, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
123
  {"password", 'P',
 
124
   "Password to use when connecting to server. If password is not given it's asked from the tty.",
 
125
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
 
126
  {"port", 'p', "Port number to use for connection or 0 for default to, in "
 
127
   "order of preference, drizzle.cnf, $DRIZZLE_TCP_PORT, "
 
128
   "built-in default (" STRINGIFY_ARG(DRIZZLE_PORT) ").",
 
129
   0, 0, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
130
  {"protocol", OPT_DRIZZLE_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).",
 
131
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
132
  {"replace", 'r', "If duplicate unique key was found, replace old row.",
 
133
   (char**) &opt_replace, (char**) &opt_replace, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
134
  {"silent", 's', "Be more silent.", (char**) &silent, (char**) &silent, 0,
 
135
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
136
  {"socket", 'S', "Socket file to use for connection.",
 
137
   (char**) &opt_drizzle_unix_port, (char**) &opt_drizzle_unix_port, 0, GET_STR,
 
138
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
139
  {"use-threads", OPT_USE_THREADS,
 
140
   "Load files in parallel. The argument is the number "
 
141
   "of threads to use for loading data.",
 
142
   (char**) &opt_use_threads, (char**) &opt_use_threads, 0,
 
143
   GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
144
#ifndef DONT_ALLOW_USER_CHANGE
 
145
  {"user", 'u', "User for login if not current user.", (char**) &current_user,
 
146
   (char**) &current_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
147
#endif
 
148
  {"verbose", 'v', "Print info about the various stages.", (char**) &verbose,
 
149
   (char**) &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
150
  {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
 
151
   NO_ARG, 0, 0, 0, 0, 0, 0},
 
152
  { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
 
153
};
 
154
 
 
155
 
 
156
static const char *load_default_groups[]= { "drizzleimport","client",0 };
 
157
 
 
158
static void print_version(void)
 
159
{
 
160
  printf("%s  Ver %s Distrib %s, for %s (%s)\n" ,my_progname,
 
161
    IMPORT_VERSION, drizzle_version(),SYSTEM_TYPE,MACHINE_TYPE);
 
162
}
 
163
 
 
164
 
 
165
static void usage(void)
 
166
{
 
167
  print_version();
 
168
  puts("Copyright (C) 2008 Drizzle Open Source Development Team");
 
169
  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");
 
170
  printf("\
 
171
Loads tables from text files in various formats.  The base name of the\n\
 
172
text file must be the name of the table that should be used.\n\
 
173
If one uses sockets to connect to the Drizzle server, the server will open and\n\
 
174
read the text file directly. In other cases the client will open the text\n\
 
175
file. The SQL command 'LOAD DATA INFILE' is used to import the rows.\n");
 
176
 
 
177
  printf("\nUsage: %s [OPTIONS] database textfile...",my_progname);
 
178
  print_defaults("drizzle",load_default_groups);
 
179
  my_print_help(my_long_options);
 
180
  my_print_variables(my_long_options);
 
181
}
 
182
 
 
183
extern "C"
 
184
bool get_one_option(int optid, const struct my_option *, char *argument)
 
185
{
 
186
  char *endchar= NULL;
 
187
  uint64_t temp_drizzle_port= 0;
 
188
 
 
189
  switch(optid) {
 
190
  case 'p':
 
191
    temp_drizzle_port= (uint64_t) strtoul(argument, &endchar, 10);
 
192
    /* if there is an alpha character this is not a valid port */
 
193
    if (strlen(endchar) != 0)
 
194
    {
 
195
      fprintf(stderr, _("Non-integer value supplied for port.  If you are trying to enter a password please use --password instead.\n"));
 
196
      exit(1);
 
197
    }
 
198
    /* If the port number is > 65535 it is not a valid port
 
199
       This also helps with potential data loss casting unsigned long to a
 
200
       uint32_t. */
 
201
    if ((temp_drizzle_port == 0) || (temp_drizzle_port > 65535))
 
202
    {
 
203
      fprintf(stderr, _("Value supplied for port is not valid.\n"));
 
204
      exit(1);
 
205
    }
 
206
    else
 
207
    {
 
208
      opt_drizzle_port= (uint32_t) temp_drizzle_port;
 
209
    }
 
210
    break;
 
211
  case 'P':
 
212
    if (argument)
 
213
    {
 
214
      char *start=argument;
 
215
      if (opt_password)
 
216
        free(opt_password);
 
217
      opt_password = strdup(argument);
 
218
      if (opt_password == NULL)
 
219
      {
 
220
        fprintf(stderr, "Memory allocation error while copying password. "
 
221
                        "Aborting.\n");
 
222
        exit(ENOMEM);
 
223
      }
 
224
      while (*argument)
 
225
      {
 
226
        /* Overwriting password with 'x' */
 
227
        *argument++= 'x';
 
228
      }
 
229
      if (*start)
 
230
      {
 
231
        /* Cut length of argument */
 
232
        start[1]= 0;
 
233
      }
 
234
      tty_password= 0;
 
235
    }
 
236
    else
 
237
      tty_password= 1;
 
238
    break;
 
239
  case OPT_DRIZZLE_PROTOCOL:
 
240
    break;
 
241
  case 'V': print_version(); exit(0);
 
242
  case 'I':
 
243
  case '?':
 
244
    usage();
 
245
    exit(0);
 
246
  }
 
247
  return 0;
 
248
}
 
249
 
 
250
 
 
251
static int get_options(int *argc, char ***argv)
 
252
{
 
253
  int ho_error;
 
254
 
 
255
  if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
 
256
    exit(ho_error);
 
257
  if (debug_info_flag)
 
258
    my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
 
259
  if (debug_check_flag)
 
260
    my_end_arg= MY_CHECK_ERROR;
 
261
 
 
262
  if (enclosed && opt_enclosed)
82
263
  {
83
264
    fprintf(stderr, "You can't use ..enclosed.. and ..optionally-enclosed.. at the same time.\n");
84
265
    return(1);
88
269
    fprintf(stderr, "You can't use --ignore_unique (-i) and --replace (-r) at the same time.\n");
89
270
    return(1);
90
271
  }
91
 
 
 
272
  if (strcmp(default_charset, charset_info->csname) &&
 
273
      !(charset_info= get_charset_by_csname(default_charset, MY_CS_PRIMARY)))
 
274
    exit(1);
 
275
  if (*argc < 2)
 
276
  {
 
277
    usage();
 
278
    return 1;
 
279
  }
 
280
  current_db= *((*argv)++);
 
281
  (*argc)--;
92
282
  if (tty_password)
93
283
    opt_password=client_get_tty_password(NULL);
94
284
  return(0);
103
293
  drizzle_result_st result;
104
294
  drizzle_return_t ret;
105
295
 
106
 
  internal::fn_format(tablename, filename, "", "", 1 | 2); /* removes path & ext. */
107
 
  if (not opt_local_file)
 
296
  fn_format(tablename, filename, "", "", 1 | 2); /* removes path & ext. */
 
297
  if (!opt_local_file)
108
298
    strcpy(hard_path,filename);
109
299
  else
110
 
    internal::my_load_path(hard_path, filename, NULL); /* filename includes the path */
 
300
    my_load_path(hard_path, filename, NULL); /* filename includes the path */
111
301
 
112
302
  if (opt_delete)
113
303
  {
114
304
    if (verbose)
115
305
      fprintf(stdout, "Deleting the old data from table %s\n", tablename);
116
306
#ifdef HAVE_SNPRINTF
117
 
    snprintf(sql_statement, sizeof(sql_statement), "DELETE FROM %s", tablename);
 
307
    snprintf(sql_statement, FN_REFLEN*16+256, "DELETE FROM %s", tablename);
118
308
#else
119
 
    snprintf(sql_statement, sizeof(sql_statement), "DELETE FROM %s", tablename);
 
309
    sprintf(sql_statement, "DELETE FROM %s", tablename);
120
310
#endif
121
311
    if (drizzle_query_str(con, &result, sql_statement, &ret) == NULL ||
122
312
        ret != DRIZZLE_RETURN_OK)
135
325
      fprintf(stdout, "Loading data from SERVER file: %s into %s\n",
136
326
        hard_path, tablename);
137
327
  }
138
 
  snprintf(sql_statement, sizeof(sql_statement), "LOAD DATA %s %s INFILE '%s'",
 
328
  sprintf(sql_statement, "LOAD DATA %s %s INFILE '%s'",
139
329
    opt_low_priority ? "LOW_PRIORITY" : "",
140
330
    opt_local_file ? "LOCAL" : "", hard_path);
141
331
  end= strchr(sql_statement, '\0');
146
336
 
147
337
  end+= sprintf(end, " INTO TABLE %s", tablename);
148
338
 
149
 
  if (! fields_terminated.empty() || ! enclosed.empty() || ! opt_enclosed.empty() || ! escaped.empty())
 
339
  if (fields_terminated || enclosed || opt_enclosed || escaped)
150
340
      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(),
 
341
  end= add_load_option(end, fields_terminated, " TERMINATED BY");
 
342
  end= add_load_option(end, enclosed, " ENCLOSED BY");
 
343
  end= add_load_option(end, opt_enclosed,
154
344
           " 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");
 
345
  end= add_load_option(end, escaped, " ESCAPED BY");
 
346
  end= add_load_option(end, lines_terminated, " LINES TERMINATED BY");
157
347
  if (opt_ignore_lines >= 0)
158
348
  {
159
349
    end= strcpy(end, " IGNORE ")+8;
162
352
    end= strcpy(end, buffer.str().c_str())+ buffer.str().size();
163
353
    end= strcpy(end, " LINES")+6;
164
354
  }
165
 
  if (! opt_columns.empty())
 
355
  if (opt_columns)
166
356
  {
167
357
    end= strcpy(end, " (")+2;
168
 
    end= strcpy(end, (char *)opt_columns.c_str()+opt_columns.length());
 
358
    end= strcpy(end, opt_columns)+strlen(opt_columns);
169
359
    end= strcpy(end, ")")+1;
170
360
  }
171
361
  *end= '\0';
180
370
  {
181
371
    if (strcmp(drizzle_result_info(&result), ""))
182
372
    {
183
 
      fprintf(stdout, "%s.%s: %s\n", current_db.c_str(), tablename,
 
373
      fprintf(stdout, "%s.%s: %s\n", current_db, tablename,
184
374
        drizzle_result_info(&result));
185
375
    }
186
376
  }
189
379
}
190
380
 
191
381
 
192
 
static drizzle_con_st *db_connect(const string host, const string database,
193
 
                                  const string user, const string passwd)
 
382
static void lock_table(drizzle_con_st *con, int tablecount, char **raw_tablename)
 
383
{
 
384
  string query;
 
385
  int i;
 
386
  char tablename[FN_REFLEN];
 
387
  drizzle_result_st result;
 
388
  drizzle_return_t ret;
 
389
 
 
390
  if (verbose)
 
391
    fprintf(stdout, "Locking tables for write\n");
 
392
  query.append("LOCK TABLES ");
 
393
  for (i=0 ; i < tablecount ; i++)
 
394
  {
 
395
    fn_format(tablename, raw_tablename[i], "", "", 1 | 2);
 
396
    query.append(tablename);
 
397
    query.append(" WRITE,");
 
398
  }
 
399
  if (drizzle_query(con, &result, query.c_str(), query.length()-1,
 
400
                    &ret) == NULL ||
 
401
      ret != DRIZZLE_RETURN_OK)
 
402
  {
 
403
    db_error(con, &result, ret, NULL);
 
404
    /* We shall countinue here, if --force was given */
 
405
    return;
 
406
  }
 
407
  drizzle_result_free(&result);
 
408
}
 
409
 
 
410
 
 
411
static drizzle_con_st *db_connect(char *host, char *database,
 
412
                                  char *user, char *passwd)
194
413
{
195
414
  drizzle_st *drizzle;
196
415
  drizzle_con_st *con;
197
416
  drizzle_return_t ret;
198
417
 
199
418
  if (verbose)
200
 
    fprintf(stdout, "Connecting to %s, using protocol %s...\n", ! host.empty() ? host.c_str() : "localhost", opt_protocol.c_str());
 
419
    fprintf(stdout, "Connecting to %s\n", host ? host : "localhost");
201
420
  if (!(drizzle= drizzle_create(NULL)))
202
421
    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)))
 
422
  if (!(con= drizzle_con_add_tcp(drizzle,NULL,host,opt_drizzle_port,user,passwd,
 
423
                                 database, DRIZZLE_CON_NONE)))
205
424
  {
206
425
    return 0;
207
426
  }
213
432
  }
214
433
 
215
434
  if (verbose)
216
 
    fprintf(stdout, "Selecting database %s\n", database.c_str());
 
435
    fprintf(stdout, "Selecting database %s\n", database);
217
436
 
218
437
  return con;
219
438
}
220
439
 
221
440
 
222
441
 
223
 
static void db_disconnect(const string host, drizzle_con_st *con)
 
442
static void db_disconnect(char *host, drizzle_con_st *con)
224
443
{
225
444
  if (verbose)
226
 
    fprintf(stdout, "Disconnecting from %s\n", ! host.empty() ? host.c_str() : "localhost");
 
445
    fprintf(stdout, "Disconnecting from %s\n", host ? host : "localhost");
227
446
  drizzle_free(drizzle_con_drizzle(con));
228
447
}
229
448
 
245
464
{
246
465
  if (ret == DRIZZLE_RETURN_ERROR_CODE)
247
466
  {
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 : "");
 
467
    my_printf_error(0,"Error: %d, %s%s%s", MYF(0),
 
468
                    drizzle_result_error_code(result),
 
469
                    drizzle_result_error(result),
 
470
                    table ? ", when using table: " : "", table ? table : "");
252
471
    drizzle_result_free(result);
253
472
  }
254
473
  else
255
474
  {
256
 
    fprintf(stdout, "Error: %d, %s%s%s", ret, drizzle_con_error(con),
257
 
            table ? ", when using table: " : "", table ? table : "");
 
475
    my_printf_error(0,"Error: %d, %s%s%s", MYF(0), ret, drizzle_con_error(con),
 
476
                    table ? ", when using table: " : "", table ? table : "");
258
477
  }
259
478
 
260
479
  safe_exit(1, con);
310
529
  return to;
311
530
}
312
531
 
 
532
int exitcode= 0;
 
533
 
 
534
extern "C"
313
535
void * worker_thread(void *arg)
314
536
{
315
537
  int error;
316
538
  char *raw_table_name= (char *)arg;
317
 
  drizzle_con_st *con;
 
539
  drizzle_con_st *con= NULL;
 
540
  drizzle_result_st result;
 
541
  drizzle_return_t ret;
318
542
 
319
543
  if (!(con= db_connect(current_host,current_db,current_user,opt_password)))
320
544
  {
321
 
    return 0;
 
545
    goto error;
 
546
  }
 
547
 
 
548
  if (drizzle_query_str(con, &result,
 
549
                        "/*!40101 set @@character_set_database=binary */;",
 
550
                        &ret) == NULL ||
 
551
      ret != DRIZZLE_RETURN_OK)
 
552
  {
 
553
    db_error(con, &result, ret, NULL);
 
554
    /* We shall countinue here, if --force was given */
 
555
    goto error;
322
556
  }
323
557
 
324
558
  /*
325
559
    We are not currently catching the error here.
326
560
  */
327
 
  if ((error= write_to_table(raw_table_name, con)))
328
 
  {
 
561
  if((error= write_to_table(raw_table_name, con)))
329
562
    if (exitcode == 0)
330
 
    {
331
563
      exitcode= error;
332
 
    }
333
 
  }
334
564
 
 
565
error:
335
566
  if (con)
336
 
  {
337
567
    db_disconnect(current_host, con);
338
 
  }
339
568
 
340
569
  pthread_mutex_lock(&counter_mutex);
341
570
  counter--;
342
571
  pthread_cond_signal(&count_threshhold);
343
572
  pthread_mutex_unlock(&counter_mutex);
 
573
  my_thread_end();
344
574
 
345
575
  return 0;
346
576
}
348
578
 
349
579
int main(int argc, char **argv)
350
580
{
351
 
try
352
 
{
353
581
  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
 
  {
 
582
  char **argv_to_free;
 
583
  MY_INIT(argv[0]);
 
584
 
 
585
  load_defaults("drizzle",load_default_groups,&argc,&argv);
 
586
  /* argv is changed in the program */
 
587
  argv_to_free= argv;
 
588
  if (get_options(&argc, &argv))
 
589
  {
 
590
    free_defaults(argv_to_free);
535
591
    return(1);
536
592
  }
537
 
  
538
 
  current_db= (*argv)++;
539
 
  argc--;
540
593
 
541
 
  if (opt_use_threads)
 
594
#ifdef HAVE_LIBPTHREAD
 
595
  if (opt_use_threads && !lock_tables)
542
596
  {
543
597
    pthread_t mainthread;            /* Thread descriptor */
544
598
    pthread_attr_t attr;          /* Thread attributes */
569
623
        pthread_mutex_lock(&counter_mutex);
570
624
        counter--;
571
625
        pthread_mutex_unlock(&counter_mutex);
572
 
        fprintf(stderr,"%s: Could not create thread\n", program_name);
 
626
        fprintf(stderr,"%s: Could not create thread\n",
 
627
                my_progname);
573
628
      }
574
629
    }
575
630
 
590
645
    pthread_attr_destroy(&attr);
591
646
  }
592
647
  else
 
648
#endif
593
649
  {
594
 
    drizzle_con_st *con;
595
 
 
 
650
    drizzle_con_st *con= 0;
 
651
    drizzle_result_st result;
 
652
    drizzle_return_t ret;
596
653
    if (!(con= db_connect(current_host,current_db,current_user,opt_password)))
597
654
    {
 
655
      free_defaults(argv_to_free);
 
656
      return(1); /* purecov: deadcode */
 
657
    }
 
658
 
 
659
    if (drizzle_query_str(con, &result,
 
660
                          "/*!40101 set @@character_set_database=binary */;",
 
661
                          &ret) == NULL ||
 
662
        ret != DRIZZLE_RETURN_OK)
 
663
    {
 
664
      db_error(con, &result, ret, NULL);
 
665
      /* We shall countinue here, if --force was given */
598
666
      return(1);
599
667
    }
600
668
 
 
669
    drizzle_result_free(&result);
 
670
 
 
671
    if (lock_tables)
 
672
      lock_table(con, argc, argv);
601
673
    for (; *argv != NULL; argv++)
602
674
      if ((error= write_to_table(*argv, con)))
603
675
        if (exitcode == 0)
604
676
          exitcode= error;
605
677
    db_disconnect(current_host, con);
606
678
  }
607
 
  opt_password.empty();
608
 
}
609
 
  catch(exception &err)
610
 
  {
611
 
    cerr<<err.what()<<endl;
612
 
  }
 
679
  free(opt_password);
 
680
  free_defaults(argv_to_free);
 
681
  my_end(my_end_arg);
613
682
  return(exitcode);
614
683
}