~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to client/drizzleimport.cc

  • Committer: Monty Taylor
  • Date: 2008-09-16 00:00:48 UTC
  • mto: This revision was merged to the branch mainline in revision 391.
  • Revision ID: monty@inaugust.com-20080916000048-3rvrv3gv9l0ad3gs
Fixed copyright headers in drizzled/

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"
 
28
 
 
29
#include <string>
21
30
 
22
31
#include "client_priv.h"
23
 
#include <string>
24
 
#include <sstream>
25
 
#include <iostream>
26
 
#include <fstream>
27
 
#include <boost/program_options.hpp>
28
32
#include <pthread.h>
29
33
 
30
 
/* Added this for string translation. */
31
 
#include <drizzled/gettext.h>
32
 
#include <drizzled/configmake.h>
33
 
 
34
 
namespace po= boost::program_options;
35
34
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= "drizzleimport";
43
35
 
44
36
/* Global Thread counter */
45
 
uint32_t counter;
 
37
uint counter;
46
38
pthread_mutex_t counter_mutex;
47
39
pthread_cond_t count_threshhold;
48
40
 
49
 
static void db_error(drizzle_con_st *con, drizzle_result_st *result,
50
 
                     drizzle_return_t ret, char *table);
51
 
static char *field_escape(char *to,const char *from,uint32_t length);
 
41
static void db_error_with_table(DRIZZLE *drizzle, char *table);
 
42
static void db_error(DRIZZLE *drizzle);
 
43
static char *field_escape(char *to,const char *from,uint length);
52
44
static char *add_load_option(char *ptr,const char *object,
53
45
           const char *statement);
54
46
 
55
 
static bool verbose= false, ignore_errors= false,
56
 
            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;
61
 
static uint32_t opt_drizzle_port= 0;
 
47
static bool  verbose=0,lock_tables=0,ignore_errors=0,opt_delete=0,
 
48
  opt_replace=0,silent=0,ignore=0,opt_compress=0,
 
49
  opt_low_priority= 0, tty_password= 0;
 
50
static bool debug_info_flag= 0, debug_check_flag= 0;
 
51
static uint opt_use_threads=0, opt_local_file=0, my_end_arg= 0;
 
52
static char  *opt_password=0, *current_user=0,
 
53
    *current_host=0, *current_db=0, *fields_terminated=0,
 
54
    *lines_terminated=0, *enclosed=0, *opt_enclosed=0,
 
55
    *escaped=0, *opt_columns=0,
 
56
    *default_charset= (char*) DRIZZLE_DEFAULT_CHARSET_NAME;
 
57
static uint     opt_drizzle_port= 0, opt_protocol= 0;
 
58
static char * opt_drizzle_unix_port=0;
62
59
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())
 
60
static const CHARSET_INFO *charset_info= &my_charset_utf8_general_ci;
 
61
 
 
62
static struct my_option my_long_options[] =
 
63
{
 
64
  {"character-sets-dir", OPT_CHARSETS_DIR,
 
65
   "Directory where character sets are.", (char**) &charsets_dir,
 
66
   (char**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
67
  {"default-character-set", OPT_DEFAULT_CHARSET,
 
68
   "Set the default character set.", (char**) &default_charset,
 
69
   (char**) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
70
  {"columns", 'c',
 
71
   "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.",
 
72
   (char**) &opt_columns, (char**) &opt_columns, 0, GET_STR, REQUIRED_ARG, 0, 0, 0,
 
73
   0, 0, 0},
 
74
  {"compress", 'C', "Use compression in server/client protocol.",
 
75
   (char**) &opt_compress, (char**) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
 
76
   0, 0, 0},
 
77
  {"debug",'#', "Output debug log. Often this is 'd:t:o,filename'.", 0, 0, 0,
 
78
   GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
 
79
  {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
 
80
   (char**) &debug_check_flag, (char**) &debug_check_flag, 0,
 
81
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
82
  {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
 
83
   (char**) &debug_info_flag, (char**) &debug_info_flag,
 
84
   0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
85
  {"delete", 'd', "First delete all rows from table.", (char**) &opt_delete,
 
86
   (char**) &opt_delete, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
87
  {"fields-terminated-by", OPT_FTB,
 
88
   "Fields in the textfile are terminated by ...", (char**) &fields_terminated,
 
89
   (char**) &fields_terminated, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
90
  {"fields-enclosed-by", OPT_ENC,
 
91
   "Fields in the importfile are enclosed by ...", (char**) &enclosed,
 
92
   (char**) &enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
93
  {"fields-optionally-enclosed-by", OPT_O_ENC,
 
94
   "Fields in the i.file are opt. enclosed by ...", (char**) &opt_enclosed,
 
95
   (char**) &opt_enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
96
  {"fields-escaped-by", OPT_ESC, "Fields in the i.file are escaped by ...",
 
97
   (char**) &escaped, (char**) &escaped, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0,
 
98
   0, 0},
 
99
  {"force", 'f', "Continue even if we get an sql-error.",
 
100
   (char**) &ignore_errors, (char**) &ignore_errors, 0, GET_BOOL, NO_ARG, 0, 0,
 
101
   0, 0, 0, 0},
 
102
  {"help", '?', "Displays this help and exits.", 0, 0, 0, GET_NO_ARG, NO_ARG,
 
103
   0, 0, 0, 0, 0, 0},
 
104
  {"host", 'h', "Connect to host.", (char**) &current_host,
 
105
   (char**) &current_host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
106
  {"ignore", 'i', "If duplicate unique key was found, keep old row.",
 
107
   (char**) &ignore, (char**) &ignore, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
108
  {"ignore-lines", OPT_IGN_LINES, "Ignore first n lines of data infile.",
 
109
   (char**) &opt_ignore_lines, (char**) &opt_ignore_lines, 0, GET_LL,
 
110
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
111
  {"lines-terminated-by", OPT_LTB, "Lines in the i.file are terminated by ...",
 
112
   (char**) &lines_terminated, (char**) &lines_terminated, 0, GET_STR,
 
113
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
114
  {"local", 'L', "Read all files through the client.", (char**) &opt_local_file,
 
115
   (char**) &opt_local_file, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
116
  {"lock-tables", 'l', "Lock all tables for write (this disables threads).",
 
117
    (char**) &lock_tables, (char**) &lock_tables, 0, GET_BOOL, NO_ARG,
 
118
    0, 0, 0, 0, 0, 0},
 
119
  {"low-priority", OPT_LOW_PRIORITY,
 
120
   "Use LOW_PRIORITY when updating the table.", (char**) &opt_low_priority,
 
121
   (char**) &opt_low_priority, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
122
  {"password", 'p',
 
123
   "Password to use when connecting to server. If password is not given it's asked from the tty.",
 
124
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
 
125
  {"port", 'P', "Port number to use for connection or 0 for default to, in "
 
126
   "order of preference, my.cnf, $DRIZZLE_TCP_PORT, "
 
127
   "built-in default (" STRINGIFY_ARG(DRIZZLE_PORT) ").",
 
128
   (char**) &opt_drizzle_port,
 
129
   (char**) &opt_drizzle_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0,
 
130
   0},
 
131
  {"protocol", OPT_DRIZZLE_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).",
 
132
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
133
  {"replace", 'r', "If duplicate unique key was found, replace old row.",
 
134
   (char**) &opt_replace, (char**) &opt_replace, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
135
  {"silent", 's', "Be more silent.", (char**) &silent, (char**) &silent, 0,
 
136
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
137
  {"socket", 'S', "Socket file to use for connection.",
 
138
   (char**) &opt_drizzle_unix_port, (char**) &opt_drizzle_unix_port, 0, GET_STR,
 
139
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
140
  {"use-threads", OPT_USE_THREADS,
 
141
   "Load files in parallel. The argument is the number "
 
142
   "of threads to use for loading data.",
 
143
   (char**) &opt_use_threads, (char**) &opt_use_threads, 0,
 
144
   GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
145
#ifndef DONT_ALLOW_USER_CHANGE
 
146
  {"user", 'u', "User for login if not current user.", (char**) &current_user,
 
147
   (char**) &current_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
148
#endif
 
149
  {"verbose", 'v', "Print info about the various stages.", (char**) &verbose,
 
150
   (char**) &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
151
  {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
 
152
   NO_ARG, 0, 0, 0, 0, 0, 0},
 
153
  { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
 
154
};
 
155
 
 
156
 
 
157
static const char *load_default_groups[]= { "drizzleimport","client",0 };
 
158
 
 
159
static void print_version(void)
 
160
{
 
161
  printf("%s  Ver %s Distrib %s, for %s (%s)\n" ,my_progname,
 
162
    IMPORT_VERSION, drizzle_get_client_info(),SYSTEM_TYPE,MACHINE_TYPE);
 
163
}
 
164
 
 
165
 
 
166
static void usage(void)
 
167
{
 
168
  print_version();
 
169
  puts("Copyright (C) 2008 Drizzle Open Source Development Team");
 
170
  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");
 
171
  printf("\
 
172
Loads tables from text files in various formats.  The base name of the\n\
 
173
text file must be the name of the table that should be used.\n\
 
174
If one uses sockets to connect to the Drizzle server, the server will open and\n\
 
175
read the text file directly. In other cases the client will open the text\n\
 
176
file. The SQL command 'LOAD DATA INFILE' is used to import the rows.\n");
 
177
 
 
178
  printf("\nUsage: %s [OPTIONS] database textfile...",my_progname);
 
179
  print_defaults("my",load_default_groups);
 
180
  my_print_help(my_long_options);
 
181
  my_print_variables(my_long_options);
 
182
}
 
183
 
 
184
static bool
 
185
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
 
186
         char *argument)
 
187
{
 
188
  switch(optid) {
 
189
  case 'p':
 
190
    if (argument)
 
191
    {
 
192
      char *start=argument;
 
193
      my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
 
194
      opt_password=my_strdup(argument,MYF(MY_FAE));
 
195
      while (*argument) *argument++= 'x';    /* Destroy argument */
 
196
      if (*start)
 
197
  start[1]=0;        /* Cut length of argument */
 
198
      tty_password= 0;
 
199
    }
 
200
    else
 
201
      tty_password= 1;
 
202
    break;
 
203
  case OPT_DRIZZLE_PROTOCOL:
 
204
    break;
 
205
  case 'V': print_version(); exit(0);
 
206
  case 'I':
 
207
  case '?':
 
208
    usage();
 
209
    exit(0);
 
210
  }
 
211
  return 0;
 
212
}
 
213
 
 
214
 
 
215
static int get_options(int *argc, char ***argv)
 
216
{
 
217
  int ho_error;
 
218
 
 
219
  if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
 
220
    exit(ho_error);
 
221
  if (debug_info_flag)
 
222
    my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
 
223
  if (debug_check_flag)
 
224
    my_end_arg= MY_CHECK_ERROR;
 
225
 
 
226
  if (enclosed && opt_enclosed)
82
227
  {
83
228
    fprintf(stderr, "You can't use ..enclosed.. and ..optionally-enclosed.. at the same time.\n");
84
229
    return(1);
85
230
  }
86
 
  if (opt_replace && ignore_unique)
 
231
  if (opt_replace && ignore)
87
232
  {
88
 
    fprintf(stderr, "You can't use --ignore_unique (-i) and --replace (-r) at the same time.\n");
 
233
    fprintf(stderr, "You can't use --ignore (-i) and --replace (-r) at the same time.\n");
89
234
    return(1);
90
235
  }
91
 
 
 
236
  if (strcmp(default_charset, charset_info->csname) &&
 
237
      !(charset_info= get_charset_by_csname(default_charset,
 
238
                MY_CS_PRIMARY, MYF(MY_WME))))
 
239
    exit(1);
 
240
  if (*argc < 2)
 
241
  {
 
242
    usage();
 
243
    return 1;
 
244
  }
 
245
  current_db= *((*argv)++);
 
246
  (*argc)--;
92
247
  if (tty_password)
93
 
    opt_password=client_get_tty_password(NULL);
 
248
    opt_password=get_tty_password(NullS);
94
249
  return(0);
95
250
}
96
251
 
97
252
 
98
253
 
99
 
static int write_to_table(char *filename, drizzle_con_st *con)
 
254
static int write_to_table(char *filename, DRIZZLE *drizzle)
100
255
{
101
256
  char tablename[FN_REFLEN], hard_path[FN_REFLEN],
102
257
       sql_statement[FN_REFLEN*16+256], *end;
103
 
  drizzle_result_st result;
104
 
  drizzle_return_t ret;
105
258
 
106
 
  internal::fn_format(tablename, filename, "", "", 1 | 2); /* removes path & ext. */
107
 
  if (not opt_local_file)
108
 
    strcpy(hard_path,filename);
 
259
  fn_format(tablename, filename, "", "", 1 | 2); /* removes path & ext. */
 
260
  if (!opt_local_file)
 
261
    stpcpy(hard_path,filename);
109
262
  else
110
 
    internal::my_load_path(hard_path, filename, NULL); /* filename includes the path */
 
263
    my_load_path(hard_path, filename, NULL); /* filename includes the path */
111
264
 
112
265
  if (opt_delete)
113
266
  {
114
267
    if (verbose)
115
268
      fprintf(stdout, "Deleting the old data from table %s\n", tablename);
116
269
#ifdef HAVE_SNPRINTF
117
 
    snprintf(sql_statement, sizeof(sql_statement), "DELETE FROM %s", tablename);
 
270
    snprintf(sql_statement, FN_REFLEN*16+256, "DELETE FROM %s", tablename);
118
271
#else
119
 
    snprintf(sql_statement, sizeof(sql_statement), "DELETE FROM %s", tablename);
 
272
    sprintf(sql_statement, "DELETE FROM %s", tablename);
120
273
#endif
121
 
    if (drizzle_query_str(con, &result, sql_statement, &ret) == NULL ||
122
 
        ret != DRIZZLE_RETURN_OK)
 
274
    if (drizzle_query(drizzle, sql_statement))
123
275
    {
124
 
      db_error(con, &result, ret, tablename);
 
276
      db_error_with_table(drizzle, tablename);
125
277
      return(1);
126
278
    }
127
 
    drizzle_result_free(&result);
128
279
  }
 
280
  to_unix_path(hard_path);
129
281
  if (verbose)
130
282
  {
131
283
    if (opt_local_file)
135
287
      fprintf(stdout, "Loading data from SERVER file: %s into %s\n",
136
288
        hard_path, tablename);
137
289
  }
138
 
  snprintf(sql_statement, sizeof(sql_statement), "LOAD DATA %s %s INFILE '%s'",
 
290
  sprintf(sql_statement, "LOAD DATA %s %s INFILE '%s'",
139
291
    opt_low_priority ? "LOW_PRIORITY" : "",
140
292
    opt_local_file ? "LOCAL" : "", hard_path);
141
293
  end= strchr(sql_statement, '\0');
142
294
  if (opt_replace)
143
 
    end= strcpy(end, " REPLACE")+8;
144
 
  if (ignore_unique)
145
 
    end= strcpy(end, " IGNORE")+7;
146
 
 
147
 
  end+= sprintf(end, " INTO TABLE %s", tablename);
148
 
 
149
 
  if (! fields_terminated.empty() || ! enclosed.empty() || ! opt_enclosed.empty() || ! escaped.empty())
150
 
      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(),
 
295
    end= stpcpy(end, " REPLACE");
 
296
  if (ignore)
 
297
    end= stpcpy(end, " IGNORE");
 
298
  end= stpcpy(stpcpy(end, " INTO TABLE "), tablename);
 
299
 
 
300
  if (fields_terminated || enclosed || opt_enclosed || escaped)
 
301
      end= stpcpy(end, " FIELDS");
 
302
  end= add_load_option(end, fields_terminated, " TERMINATED BY");
 
303
  end= add_load_option(end, enclosed, " ENCLOSED BY");
 
304
  end= add_load_option(end, opt_enclosed,
154
305
           " 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");
 
306
  end= add_load_option(end, escaped, " ESCAPED BY");
 
307
  end= add_load_option(end, lines_terminated, " LINES TERMINATED BY");
157
308
  if (opt_ignore_lines >= 0)
158
 
  {
159
 
    end= strcpy(end, " IGNORE ")+8;
160
 
    ostringstream buffer;
161
 
    buffer << opt_ignore_lines;
162
 
    end= strcpy(end, buffer.str().c_str())+ buffer.str().size();
163
 
    end= strcpy(end, " LINES")+6;
164
 
  }
165
 
  if (! opt_columns.empty())
166
 
  {
167
 
    end= strcpy(end, " (")+2;
168
 
    end= strcpy(end, (char *)opt_columns.c_str()+opt_columns.length());
169
 
    end= strcpy(end, ")")+1;
170
 
  }
 
309
    end= stpcpy(int64_t10_to_str(opt_ignore_lines,
 
310
          stpcpy(end, " IGNORE "),10), " LINES");
 
311
  if (opt_columns)
 
312
    end= stpcpy(stpcpy(stpcpy(end, " ("), opt_columns), ")");
171
313
  *end= '\0';
172
314
 
173
 
  if (drizzle_query_str(con, &result, sql_statement, &ret) == NULL ||
174
 
      ret != DRIZZLE_RETURN_OK)
 
315
  if (drizzle_query(drizzle, sql_statement))
175
316
  {
176
 
    db_error(con, &result, ret, tablename);
 
317
    db_error_with_table(drizzle, tablename);
177
318
    return(1);
178
319
  }
179
320
  if (!silent)
180
321
  {
181
 
    if (strcmp(drizzle_result_info(&result), ""))
 
322
    if (drizzle_info(drizzle)) /* If NULL-pointer, print nothing */
182
323
    {
183
 
      fprintf(stdout, "%s.%s: %s\n", current_db.c_str(), tablename,
184
 
        drizzle_result_info(&result));
 
324
      fprintf(stdout, "%s.%s: %s\n", current_db, tablename,
 
325
        drizzle_info(drizzle));
185
326
    }
186
327
  }
187
 
  drizzle_result_free(&result);
188
328
  return(0);
189
329
}
190
330
 
191
331
 
192
 
static drizzle_con_st *db_connect(const string host, const string database,
193
 
                                  const string user, const string passwd)
194
 
{
195
 
  drizzle_st *drizzle;
196
 
  drizzle_con_st *con;
197
 
  drizzle_return_t ret;
198
 
 
199
 
  if (verbose)
200
 
    fprintf(stdout, "Connecting to %s, using protocol %s...\n", ! host.empty() ? host.c_str() : "localhost", opt_protocol.c_str());
 
332
 
 
333
static void lock_table(DRIZZLE *drizzle, int tablecount, char **raw_tablename)
 
334
{
 
335
  string query;
 
336
  int i;
 
337
  char tablename[FN_REFLEN];
 
338
 
 
339
  if (verbose)
 
340
    fprintf(stdout, "Locking tables for write\n");
 
341
  query.append("LOCK TABLES ");
 
342
  for (i=0 ; i < tablecount ; i++)
 
343
  {
 
344
    fn_format(tablename, raw_tablename[i], "", "", 1 | 2);
 
345
    query.append(tablename);
 
346
    query.append(" WRITE,");
 
347
  }
 
348
  if (drizzle_real_query(drizzle, query.c_str(), query.length()-1))
 
349
    db_error(drizzle); /* We shall countinue here, if --force was given */
 
350
}
 
351
 
 
352
 
 
353
 
 
354
 
 
355
static DRIZZLE *db_connect(char *host, char *database,
 
356
                         char *user, char *passwd)
 
357
{
 
358
  DRIZZLE *drizzle;
 
359
  if (verbose)
 
360
    fprintf(stdout, "Connecting to %s\n", host ? host : "localhost");
201
361
  if (!(drizzle= drizzle_create(NULL)))
202
362
    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)))
205
 
  {
206
 
    return 0;
207
 
  }
208
 
 
209
 
  if ((ret= drizzle_con_connect(con)) != DRIZZLE_RETURN_OK)
 
363
  if (opt_compress)
 
364
    drizzle_options(drizzle,DRIZZLE_OPT_COMPRESS,NullS);
 
365
  if (opt_local_file)
 
366
    drizzle_options(drizzle,DRIZZLE_OPT_LOCAL_INFILE,
 
367
      (char*) &opt_local_file);
 
368
  if (opt_protocol)
 
369
    drizzle_options(drizzle,DRIZZLE_OPT_PROTOCOL,(char*)&opt_protocol);
 
370
  if (!(drizzle_connect(drizzle,host,user,passwd,
 
371
                           database,opt_drizzle_port,opt_drizzle_unix_port,
 
372
                           0)))
210
373
  {
211
374
    ignore_errors=0;    /* NO RETURN FROM db_error */
212
 
    db_error(con, NULL, ret, NULL);
 
375
    db_error(drizzle);
213
376
  }
214
 
 
 
377
  drizzle->reconnect= 0;
215
378
  if (verbose)
216
 
    fprintf(stdout, "Selecting database %s\n", database.c_str());
217
 
 
218
 
  return con;
 
379
    fprintf(stdout, "Selecting database %s\n", database);
 
380
  if (drizzle_select_db(drizzle, database))
 
381
  {
 
382
    ignore_errors=0;
 
383
    db_error(drizzle);
 
384
  }
 
385
  return drizzle;
219
386
}
220
387
 
221
388
 
222
389
 
223
 
static void db_disconnect(const string host, drizzle_con_st *con)
 
390
static void db_disconnect(char *host, DRIZZLE *drizzle)
224
391
{
225
392
  if (verbose)
226
 
    fprintf(stdout, "Disconnecting from %s\n", ! host.empty() ? host.c_str() : "localhost");
227
 
  drizzle_free(drizzle_con_drizzle(con));
 
393
    fprintf(stdout, "Disconnecting from %s\n", host ? host : "localhost");
 
394
  drizzle_close(drizzle);
228
395
}
229
396
 
230
397
 
231
398
 
232
 
static void safe_exit(int error, drizzle_con_st *con)
 
399
static void safe_exit(int error, DRIZZLE *drizzle)
233
400
{
234
401
  if (ignore_errors)
235
402
    return;
236
 
  if (con)
237
 
    drizzle_free(drizzle_con_drizzle(con));
 
403
  if (drizzle)
 
404
    drizzle_close(drizzle);
238
405
  exit(error);
239
406
}
240
407
 
241
408
 
242
409
 
243
 
static void db_error(drizzle_con_st *con, drizzle_result_st *result,
244
 
                     drizzle_return_t ret, char *table)
245
 
{
246
 
  if (ret == DRIZZLE_RETURN_ERROR_CODE)
247
 
  {
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 : "");
252
 
    drizzle_result_free(result);
253
 
  }
254
 
  else
255
 
  {
256
 
    fprintf(stdout, "Error: %d, %s%s%s", ret, drizzle_con_error(con),
257
 
            table ? ", when using table: " : "", table ? table : "");
258
 
  }
259
 
 
260
 
  safe_exit(1, con);
 
410
static void db_error_with_table(DRIZZLE *drizzle, char *table)
 
411
{
 
412
  my_printf_error(0,"Error: %d, %s, when using table: %s",
 
413
      MYF(0), drizzle_errno(drizzle), drizzle_error(drizzle), table);
 
414
  safe_exit(1, drizzle);
 
415
}
 
416
 
 
417
 
 
418
 
 
419
static void db_error(DRIZZLE *drizzle)
 
420
{
 
421
  my_printf_error(0,"Error: %d %s", MYF(0), drizzle_errno(drizzle), drizzle_error(drizzle));
 
422
  safe_exit(1, drizzle);
261
423
}
262
424
 
263
425
 
268
430
  {
269
431
    /* Don't escape hex constants */
270
432
    if (object[0] == '0' && (object[1] == 'x' || object[1] == 'X'))
271
 
      ptr+= sprintf(ptr, " %s %s", statement, object);
 
433
      ptr= strxmov(ptr," ",statement," ",object,NullS);
272
434
    else
273
435
    {
274
436
      /* char constant; escape */
275
 
      ptr+= sprintf(ptr, " %s '", statement); 
276
 
      ptr= field_escape(ptr,object,(uint32_t) strlen(object));
 
437
      ptr= strxmov(ptr," ",statement," '",NullS);
 
438
      ptr= field_escape(ptr,object,(uint) strlen(object));
277
439
      *ptr++= '\'';
278
440
    }
279
441
  }
287
449
** syntax errors from the SQL parser.
288
450
*/
289
451
 
290
 
static char *field_escape(char *to,const char *from,uint32_t length)
 
452
static char *field_escape(char *to,const char *from,uint length)
291
453
{
292
454
  const char *end;
293
 
  uint32_t end_backslashes=0;
 
455
  uint end_backslashes=0;
294
456
 
295
457
  for (end= from+length; from != end; from++)
296
458
  {
306
468
  }
307
469
  /* Add missing backslashes if user has specified odd number of backs.*/
308
470
  if (end_backslashes)
309
 
    *to++= '\\';
 
471
    *to++= '\\';         
310
472
  return to;
311
473
}
312
474
 
313
 
void * worker_thread(void *arg)
 
475
int exitcode= 0;
 
476
 
 
477
static void * worker_thread(void *arg)
314
478
{
315
479
  int error;
316
480
  char *raw_table_name= (char *)arg;
317
 
  drizzle_con_st *con;
318
 
 
319
 
  if (!(con= db_connect(current_host,current_db,current_user,opt_password)))
320
 
  {
321
 
    return 0;
 
481
  DRIZZLE *drizzle= 0;
 
482
 
 
483
  if (!(drizzle= db_connect(current_host,current_db,current_user,opt_password)))
 
484
  {
 
485
    goto error;
 
486
  }
 
487
 
 
488
  if (drizzle_query(drizzle, "/*!40101 set @@character_set_database=binary */;"))
 
489
  {
 
490
    db_error(drizzle); /* We shall countinue here, if --force was given */
 
491
    goto error;
322
492
  }
323
493
 
324
494
  /*
325
495
    We are not currently catching the error here.
326
496
  */
327
 
  if ((error= write_to_table(raw_table_name, con)))
328
 
  {
 
497
  if((error= write_to_table(raw_table_name, drizzle)))
329
498
    if (exitcode == 0)
330
 
    {
331
499
      exitcode= error;
332
 
    }
333
 
  }
334
500
 
335
 
  if (con)
336
 
  {
337
 
    db_disconnect(current_host, con);
338
 
  }
 
501
error:
 
502
  if (drizzle)
 
503
    db_disconnect(current_host, drizzle);
339
504
 
340
505
  pthread_mutex_lock(&counter_mutex);
341
506
  counter--;
342
507
  pthread_cond_signal(&count_threshhold);
343
508
  pthread_mutex_unlock(&counter_mutex);
 
509
  my_thread_end();
344
510
 
345
511
  return 0;
346
512
}
348
514
 
349
515
int main(int argc, char **argv)
350
516
{
351
 
try
352
 
{
353
517
  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
 
  {
 
518
  char **argv_to_free;
 
519
  MY_INIT(argv[0]);
 
520
 
 
521
  load_defaults("my",load_default_groups,&argc,&argv);
 
522
  /* argv is changed in the program */
 
523
  argv_to_free= argv;
 
524
  if (get_options(&argc, &argv))
 
525
  {
 
526
    free_defaults(argv_to_free);
535
527
    return(1);
536
528
  }
537
 
  
538
 
  current_db= (*argv)++;
539
 
  argc--;
540
529
 
541
 
  if (opt_use_threads)
 
530
#ifdef HAVE_LIBPTHREAD
 
531
  if (opt_use_threads && !lock_tables)
542
532
  {
543
533
    pthread_t mainthread;            /* Thread descriptor */
544
534
    pthread_attr_t attr;          /* Thread attributes */
546
536
    pthread_attr_setdetachstate(&attr,
547
537
                                PTHREAD_CREATE_DETACHED);
548
538
 
549
 
    pthread_mutex_init(&counter_mutex, NULL);
550
 
    pthread_cond_init(&count_threshhold, NULL);
 
539
    VOID(pthread_mutex_init(&counter_mutex, NULL));
 
540
    VOID(pthread_cond_init(&count_threshhold, NULL));
551
541
 
552
542
    for (counter= 0; *argv != NULL; argv++) /* Loop through tables */
553
543
    {
569
559
        pthread_mutex_lock(&counter_mutex);
570
560
        counter--;
571
561
        pthread_mutex_unlock(&counter_mutex);
572
 
        fprintf(stderr,"%s: Could not create thread\n", program_name);
 
562
        fprintf(stderr,"%s: Could not create thread\n",
 
563
                my_progname);
573
564
      }
574
565
    }
575
566
 
585
576
      pthread_cond_timedwait(&count_threshhold, &counter_mutex, &abstime);
586
577
    }
587
578
    pthread_mutex_unlock(&counter_mutex);
588
 
    pthread_mutex_destroy(&counter_mutex);
589
 
    pthread_cond_destroy(&count_threshhold);
 
579
    VOID(pthread_mutex_destroy(&counter_mutex));
 
580
    VOID(pthread_cond_destroy(&count_threshhold));
590
581
    pthread_attr_destroy(&attr);
591
582
  }
592
583
  else
 
584
#endif
593
585
  {
594
 
    drizzle_con_st *con;
 
586
    DRIZZLE *drizzle= 0;
 
587
    if (!(drizzle= db_connect(current_host,current_db,current_user,opt_password)))
 
588
    {
 
589
      free_defaults(argv_to_free);
 
590
      return(1); /* purecov: deadcode */
 
591
    }
595
592
 
596
 
    if (!(con= db_connect(current_host,current_db,current_user,opt_password)))
 
593
    if (drizzle_query(drizzle, "/*!40101 set @@character_set_database=binary */;"))
597
594
    {
 
595
      db_error(drizzle); /* We shall countinue here, if --force was given */
598
596
      return(1);
599
597
    }
600
598
 
 
599
    if (lock_tables)
 
600
      lock_table(drizzle, argc, argv);
601
601
    for (; *argv != NULL; argv++)
602
 
      if ((error= write_to_table(*argv, con)))
 
602
      if ((error= write_to_table(*argv, drizzle)))
603
603
        if (exitcode == 0)
604
604
          exitcode= error;
605
 
    db_disconnect(current_host, con);
606
 
  }
607
 
  opt_password.empty();
608
 
}
609
 
  catch(exception &err)
610
 
  {
611
 
    cerr<<err.what()<<endl;
612
 
  }
 
605
    db_disconnect(current_host, drizzle);
 
606
  }
 
607
  my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
 
608
  free_defaults(argv_to_free);
 
609
  my_end(my_end_arg);
613
610
  return(exitcode);
614
611
}