~drizzle-trunk/drizzle/development

1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
 *
4
 *  Copyright (C) 2010 Andrew Hutchings
5
 *
6
 *  This program is free software; you can redistribute it and/or modify
7
 *  it under the terms of the GNU General Public License as published by
8
 *  the Free Software Foundation; version 2 of the License.
9
 *
10
 *  This program is distributed in the hope that it will be useful,
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 *  GNU General Public License for more details.
14
 *
15
 *  You should have received a copy of the GNU General Public License
16
 *  along with this program; if not, write to the Free Software
17
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
 */
19
20
#include "drizzledump_data.h"
21
#include "client_priv.h"
22
#include <drizzled/gettext.h>
23
#include <string>
24
#include <iostream>
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
25
#include <boost/regex.hpp>
1751.4.24 by Andrew Hutchings
Fix ignore tables
26
#include <boost/unordered_set.hpp>
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
27
1751.4.25 by Andrew Hutchings
Fix error handling
28
#define EX_DRIZZLEERR 2
29
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
30
extern bool opt_no_create_info;
31
extern bool opt_no_data;
32
extern bool opt_create_db;
33
extern bool opt_disable_keys;
34
extern bool extended_insert;
35
extern bool opt_replace_into;
1751.4.25 by Andrew Hutchings
Fix error handling
36
extern bool opt_drop;
37
extern bool verbose;
38
extern bool opt_databases;
39
extern bool opt_alldbs;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
40
extern uint32_t show_progress_size;
1751.4.26 by Andrew Hutchings
Fix up for the drizzledump test cases
41
extern bool opt_ignore;
1799.7.2 by Andrew Hutchings
Clean up some drizzledump options
42
extern bool opt_compress;
43
extern bool opt_drop_database;
44
extern bool opt_autocommit;
1799.7.4 by Andrew Hutchings
Fix up some more options and the docs
45
extern bool ignore_errors;
1862.2.1 by Andrew Hutchings
Link up --destination-database
46
extern std::string opt_destination_database;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
47
1751.4.24 by Andrew Hutchings
Fix ignore tables
48
extern boost::unordered_set<std::string> ignore_table;
1751.4.25 by Andrew Hutchings
Fix error handling
49
extern void maybe_exit(int error);
1751.4.24 by Andrew Hutchings
Fix ignore tables
50
1751.4.23 by Andrew Hutchings
Fix various bugs
51
enum destinations {
52
  DESTINATION_DB,
53
  DESTINATION_FILES,
54
  DESTINATION_STDOUT
55
};
56
57
extern int opt_destination;
58
1751.4.24 by Andrew Hutchings
Fix ignore tables
59
/* returns true on keep, false on ignore */
60
bool DrizzleDumpDatabase::ignoreTable(std::string tableName)
61
{
62
  std::string dbTable(databaseName);
63
  dbTable.append(".");
64
  dbTable.append(tableName);
65
66
  boost::unordered_set<std::string>::iterator iter= ignore_table.find(dbTable);
67
  return (iter == ignore_table.end());
68
}
69
1751.4.25 by Andrew Hutchings
Fix error handling
70
void DrizzleDumpDatabase::cleanTableName(std::string &tableName)
71
{
72
  std::string replace("``");
73
  std::string find("`");
74
  size_t j = 0;
75
  for (;(j = tableName.find(find, j)) != std::string::npos;)
76
  {
77
    tableName.replace(j, find.length(), replace);
78
    j+= replace.length();
79
  }
80
81
}
82
1810.6.4 by Andrew Hutchings
Add foreign keys to Drizzle server
83
std::ostream& operator <<(std::ostream &os, const DrizzleDumpForeignKey &obj)
84
{
85
  os << "  CONSTRAINT `" << obj.constraintName << "` FOREIGN KEY ("
86
    << obj.parentColumns << ") REFERENCES `" << obj.childTable << "` ("
87
    << obj.childColumns << ")";
88
89
  if (not obj.deleteRule.empty())
90
    os << " ON DELETE " << obj.deleteRule;
91
92
  if (not obj.updateRule.empty())
93
    os << " ON UPDATE " << obj.updateRule;
94
95
  return os;
96
}
97
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
98
std::ostream& operator <<(std::ostream &os, const DrizzleDumpIndex &obj)
99
{
100
  if (obj.isPrimary)
101
  {
102
    os << "  PRIMARY KEY ";
103
  }
104
  else if (obj.isUnique)
105
  {
106
    os << "  UNIQUE KEY `" << obj.indexName << "` ";
107
  }
108
  else
109
  {
110
    os << "  KEY `" << obj.indexName << "` ";
111
  }
112
113
  os << "(";
114
  
115
  std::vector<std::string>::iterator i;
116
  std::vector<std::string> fields = obj.columns;
117
  for (i= fields.begin(); i != fields.end(); ++i)
118
  {
119
    if (i != fields.begin())
120
      os << ",";
121
    std::string field= *i;
122
    os << "`" << field << "`";
1802.2.1 by Andrew Hutchings
Fix index lengths not shown for part-indexed columns.
123
    if (obj.length > 0)
124
      os << "(" << obj.length << ")";
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
125
  }
126
127
  os << ")";
128
129
  return os;
130
}
131
132
std::ostream& operator <<(std::ostream &os, const DrizzleDumpField &obj)
133
{
134
  os << "  `" << obj.fieldName << "` ";
135
  os << obj.type;
136
  if (((obj.type.compare("VARCHAR") == 0) or
137
   (obj.type.compare("VARBINARY") == 0)) and
138
   (obj.length > 0))
139
  {
140
    os << "(" << obj.length << ")";
141
  }
1751.4.26 by Andrew Hutchings
Fix up for the drizzledump test cases
142
  else if (((obj.type.compare("DECIMAL") == 0) or
143
    (obj.type.compare("DOUBLE") == 0)) and
144
    ((obj.decimalPrecision + obj.decimalScale) > 0))
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
145
  {
146
    os << "(" << obj.decimalPrecision << "," << obj.decimalScale << ")";
147
  }
148
  else if (obj.type.compare("ENUM") == 0)
149
  {
150
    os << "(" << obj.enumValues << ")";
151
  }
152
153
  if (not obj.isNull)
154
  {
155
    os << " NOT NULL";
156
  }
157
158
  if ((not obj.collation.empty()) and (obj.collation.compare("binary") != 0))
159
  {
160
    os << " COLLATE " << obj.collation;
161
  }
162
163
  if (obj.isAutoIncrement)
164
    os << " AUTO_INCREMENT";
165
166
  if (not obj.defaultValue.empty())
167
  {
168
    if (obj.defaultValue.compare("CURRENT_TIMESTAMP") != 0)
1971.5.2 by Andrew Hutchings
Add BIT support when converting MySQL. We convert this to a varbinary and covert the bit length to a byte length.
169
    {
170
      if (obj.defaultValue.compare(0, 2, "b'") == 0)
171
      {
172
        os << " DEFAULT " << obj.defaultValue;
173
      }
174
      else
175
      {
176
        os << " DEFAULT '" << obj.defaultValue << "'";
177
      }
178
    }
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
179
    else
1971.5.2 by Andrew Hutchings
Add BIT support when converting MySQL. We convert this to a varbinary and covert the bit length to a byte length.
180
    {
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
181
     os << " DEFAULT CURRENT_TIMESTAMP";
1971.5.2 by Andrew Hutchings
Add BIT support when converting MySQL. We convert this to a varbinary and covert the bit length to a byte length.
182
    }
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
183
  }
1751.4.26 by Andrew Hutchings
Fix up for the drizzledump test cases
184
  else if ((obj.defaultIsNull))
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
185
  {
186
    os << " DEFAULT NULL";
187
  }
188
1976.4.3 by Andrew Hutchings
Add field level comments back in to drizzledump
189
  if (not obj.comment.empty())
190
  {
191
    os << " COMMENT '" << DrizzleDumpData::escape(obj.comment.c_str(), obj.comment.length()) << "'";
192
  }
193
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
194
  return os;
195
}
196
197
std::ostream& operator <<(std::ostream &os, const DrizzleDumpDatabase &obj)
198
{
1751.4.23 by Andrew Hutchings
Fix various bugs
199
  if ((opt_destination == DESTINATION_DB) or opt_databases or opt_alldbs)
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
200
  {
1751.4.26 by Andrew Hutchings
Fix up for the drizzledump test cases
201
    if (verbose)
202
    {
203
      std::cerr << "--" << std::endl
204
        << "-- Current Database: `" << obj.databaseName << "`" << std::endl
205
        << "--" << std::endl << std::endl;
206
    }
1751.4.23 by Andrew Hutchings
Fix various bugs
207
208
    /* Love that this variable is the opposite of its name */
209
    if (not opt_create_db)
210
    {
1799.7.2 by Andrew Hutchings
Clean up some drizzledump options
211
      if (opt_drop_database)
1862.2.1 by Andrew Hutchings
Link up --destination-database
212
      {
213
        os << "DROP DATABASE IF EXISTS `"
214
          << ((opt_destination_database.empty()) ? obj.databaseName
215
          : opt_destination_database) << "`" << std::endl;
216
      }
1799.7.2 by Andrew Hutchings
Clean up some drizzledump options
217
1862.2.1 by Andrew Hutchings
Link up --destination-database
218
      os << "CREATE DATABASE IF NOT EXISTS `"
219
        << ((opt_destination_database.empty()) ? obj.databaseName
220
        : opt_destination_database) << "`";
1751.4.23 by Andrew Hutchings
Fix various bugs
221
      if (not obj.collate.empty())
222
       os << " COLLATE = " << obj.collate;
223
224
      os << ";" << std::endl << std::endl;
225
    }
1862.2.1 by Andrew Hutchings
Link up --destination-database
226
    os << "USE `" << ((opt_destination_database.empty()) ? obj.databaseName
227
      : opt_destination_database) << "`;" << std::endl << std::endl;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
228
  }
229
230
  std::vector<DrizzleDumpTable*>::iterator i;
231
  std::vector<DrizzleDumpTable*> output_tables = obj.tables;
232
  for (i= output_tables.begin(); i != output_tables.end(); ++i)
233
  {
234
    DrizzleDumpTable *table= *i;
235
    if (not opt_no_create_info)
236
      os << *table;
237
    if (not opt_no_data)
238
    {
1751.4.21 by Andrew Hutchings
Add database destination settings and connect it all up
239
      obj.dcon->setDB(obj.databaseName);
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
240
      DrizzleDumpData *data= table->getData();
1751.4.25 by Andrew Hutchings
Fix error handling
241
      if (data == NULL)
242
      {
243
        std::cerr << "Error: Could not get data for table " << table->displayName << std::endl;
1799.7.4 by Andrew Hutchings
Fix up some more options and the docs
244
        if (not ignore_errors)
245
          maybe_exit(EX_DRIZZLEERR);
246
        else
247
          continue;
1751.4.25 by Andrew Hutchings
Fix error handling
248
      }
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
249
      os << *data;
250
      delete data;
251
    }
252
  }
253
254
  return os;
255
}
256
257
258
std::ostream& operator <<(std::ostream &os, const DrizzleDumpData &obj)
259
{
260
  bool new_insert= true;
261
  bool first= true;
262
  uint64_t rownr= 0;
1855.1.1 by Andrew Hutchings
Fix several bugs dumping tables with many rows
263
  size_t byte_counter= 0;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
264
265
  drizzle_row_t row;
266
1751.4.23 by Andrew Hutchings
Fix various bugs
267
  if (verbose)
1751.4.25 by Andrew Hutchings
Fix error handling
268
    std::cerr << _("-- Retrieving data for ") << obj.table->displayName << "..." << std::endl;
1751.4.23 by Andrew Hutchings
Fix various bugs
269
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
270
  if (drizzle_result_row_count(obj.result) < 1)
271
  {
1751.4.26 by Andrew Hutchings
Fix up for the drizzledump test cases
272
    if (verbose)
273
    {
274
      std::cerr << "--" << std::endl
275
        << "-- No data to dump for table `" << obj.table->displayName << "`"
276
        << std::endl << "--" << std::endl << std::endl;
277
    }
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
278
    return os;
279
  }
1751.4.26 by Andrew Hutchings
Fix up for the drizzledump test cases
280
  else if (verbose)
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
281
  {
1751.4.26 by Andrew Hutchings
Fix up for the drizzledump test cases
282
    std::cerr << "--" << std::endl
283
      << "-- Dumping data for table `" << obj.table->displayName << "`"
284
      << std::endl << "--" << std::endl << std::endl;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
285
  }
286
  if (opt_disable_keys)
1751.4.25 by Andrew Hutchings
Fix error handling
287
    os << "ALTER TABLE `" << obj.table->displayName << "` DISABLE KEYS;" << std::endl;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
288
1799.7.2 by Andrew Hutchings
Clean up some drizzledump options
289
  /* Another option that does the opposite of its name, makes me sad :( */
290
  if (opt_autocommit)
291
    os << "START TRANSACTION;" << std::endl;
292
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
293
  std::streampos out_position= os.tellp();
294
295
  while((row= drizzle_row_next(obj.result)))
296
  {
297
    rownr++;
1855.1.1 by Andrew Hutchings
Fix several bugs dumping tables with many rows
298
    if (verbose and (rownr % show_progress_size) == 0)
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
299
    {
1802.11.1 by Andrew Hutchings
1. date regex was broken
300
      std::cerr << "-- " << rownr << _(" rows dumped for table ") << obj.table->displayName << std::endl;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
301
    }
302
303
    size_t* row_sizes= drizzle_row_field_sizes(obj.result);
1855.1.1 by Andrew Hutchings
Fix several bugs dumping tables with many rows
304
    for (uint32_t i= 0; i < drizzle_result_column_count(obj.result); i++)
305
      byte_counter+= row_sizes[i];
306
307
    if (not first and not new_insert)
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
308
    {
309
      if (extended_insert)
310
        os << "),(";
311
      else
312
        os << ");" << std::endl;
1855.1.1 by Andrew Hutchings
Fix several bugs dumping tables with many rows
313
      byte_counter+= 3;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
314
    }
315
    else
316
      first= false;
317
318
    if (new_insert)
319
    {
320
      if (opt_replace_into)
321
        os << "REPLACE ";
322
      else
1751.4.26 by Andrew Hutchings
Fix up for the drizzledump test cases
323
      {
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
324
        os << "INSERT ";
1751.4.26 by Andrew Hutchings
Fix up for the drizzledump test cases
325
        if (opt_ignore)
326
          os << "IGNORE ";
327
      }
1751.4.25 by Andrew Hutchings
Fix error handling
328
      os << "INTO `" << obj.table->displayName << "` VALUES (";
1855.1.1 by Andrew Hutchings
Fix several bugs dumping tables with many rows
329
      byte_counter+= 28 + obj.table->displayName.length();
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
330
      if (extended_insert)
331
        new_insert= false;
332
    }
333
    for (uint32_t i= 0; i < drizzle_result_column_count(obj.result); i++)
334
    {
335
      if (not row[i])
336
      {
337
        os << "NULL";
1971.5.3 by Andrew Hutchings
If migrating a BIGINT UNISIGNED value > BIGINT signed max value, error. We cannot store it.
338
        if (i != obj.table->fields.size() - 1)
339
          os << ",";
340
        continue;
341
      }
342
1971.5.6 by Andrew Hutchings
Make BIGINT range check only happen on MySQL BIGINT UNSIGNED as it is tripping up on negative BIGINT values.
343
      if ((obj.table->fields[i]->rangeCheck) and
344
        (obj.table->fields[i]->type.compare("BIGINT") == 0) and
345
        (boost::lexical_cast<uint64_t>(row[i]) > INT64_MAX))
1971.5.3 by Andrew Hutchings
If migrating a BIGINT UNISIGNED value > BIGINT signed max value, error. We cannot store it.
346
      {
347
        std::cerr << "Error: Data for column " << obj.table->fields[i]->fieldName << " is greater than max BIGINT, cannot migrate automatically" << std::endl;
348
        if (not ignore_errors)
349
          maybe_exit(EX_DRIZZLEERR);
350
        else
351
          continue;
352
      }
353
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
354
      /* time/date conversion for MySQL connections */
355
      else if (obj.table->fields[i]->convertDateTime)
356
      {
1802.11.1 by Andrew Hutchings
1. date regex was broken
357
        os << obj.checkDateTime(row[i], i);
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
358
      }
359
      else
360
      {
1971.5.6 by Andrew Hutchings
Make BIGINT range check only happen on MySQL BIGINT UNSIGNED as it is tripping up on negative BIGINT values.
361
        if ((obj.table->fields[i]->type.compare("INT") != 0) and
362
          (obj.table->fields[i]->type.compare("BIGINT") != 0))
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
363
        {
364
          /* Hex blob processing or escape text */
365
          if (((obj.table->fields[i]->type.compare("BLOB") == 0) or
366
            (obj.table->fields[i]->type.compare("VARBINARY") == 0)))
1855.1.1 by Andrew Hutchings
Fix several bugs dumping tables with many rows
367
          {
1751.4.26 by Andrew Hutchings
Fix up for the drizzledump test cases
368
            os << obj.convertHex((unsigned char*)row[i], row_sizes[i]);
1855.1.1 by Andrew Hutchings
Fix several bugs dumping tables with many rows
369
            byte_counter+= row_sizes[i];
370
          }
1882.2.1 by Andrew Hutchings
MySQL can contain '' as an ENUM value which is not valid in Drizzle. Convert this to NULL.
371
          else if ((obj.table->fields[i]->type.compare("ENUM") == 0) and
372
            (strcmp(row[i], "") == 0))
373
          {
374
            os << "NULL";
375
          }
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
376
          else
1810.1.1 by Andrew Hutchings
Add table comments
377
            os << "'" << DrizzleDumpData::escape(row[i], row_sizes[i]) << "'";
1855.1.1 by Andrew Hutchings
Fix several bugs dumping tables with many rows
378
          byte_counter+= 3;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
379
        }
380
        else
381
          os << row[i];
382
      }
383
      if (i != obj.table->fields.size() - 1)
384
        os << ",";
385
    }
386
    /* Break insert up if it is too long */
1865.2.1 by Andrew Hutchings
Fix drizzledump --skip-extended-insert
387
    if ((extended_insert and
388
      (byte_counter >= DRIZZLE_MAX_LINE_LENGTH)) or (not extended_insert))
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
389
    {
390
      os << ");" << std::endl;
391
      new_insert= true;
1855.1.1 by Andrew Hutchings
Fix several bugs dumping tables with many rows
392
      byte_counter= 0;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
393
    }
394
  }
1865.2.2 by Andrew Hutchings
Fix possibility of double ");" at end of data dump
395
  if (not new_insert)
396
    os << ");" << std::endl;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
397
1799.7.2 by Andrew Hutchings
Clean up some drizzledump options
398
  if (opt_autocommit)
399
    os << "COMMIT;" << std::endl;
400
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
401
  if (opt_disable_keys)
402
    os << "ALTER TABLE `" << obj.table->tableName << "` ENABLE KEYS;" << std::endl;
403
404
  os << std::endl;
405
406
  return os;
407
}
408
1751.4.26 by Andrew Hutchings
Fix up for the drizzledump test cases
409
std::string DrizzleDumpData::convertHex(const unsigned char* from, size_t from_size) const
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
410
{
411
  std::ostringstream output;
412
  if (from_size > 0)
413
    output << "0x";
1897.3.1 by Andrew Hutchings
drizzledump MySQL migration fixes:
414
  else
415
    output << "''";
416
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
417
  while (from_size > 0)
418
  {
1751.4.26 by Andrew Hutchings
Fix up for the drizzledump test cases
419
    /* Would be nice if std::hex liked uint8_t, ah well */
420
    output << std::uppercase << std::hex << std::setw(2) << std::setfill('0') << (unsigned short)(*from);
1831.1.1 by Andrew Hutchings
Fix new warnings in GCC 4.5
421
    (void) *from++;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
422
    from_size--;
423
  }
424
425
  return output.str();
426
}
427
428
/* Ripped out of libdrizzle, hopefully a little safer */
1810.1.1 by Andrew Hutchings
Add table comments
429
std::string DrizzleDumpData::escape(const char* from, size_t from_size)
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
430
{
431
  std::string output;
432
433
  while (from_size > 0)
434
  {
435
    if (!(*from & 0x80))
436
    {
437
      switch (*from)
438
      {
439
         case 0:
1855.2.1 by Andrew Hutchings
The escape function is a clone of libdrizzle's but C++'ified. Unfortunately libdrizzle's is broken. Fixed it here, will fix it in libdrizzle at a later date.
440
           output.append("\\0");
441
           break;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
442
         case '\n':
1855.2.1 by Andrew Hutchings
The escape function is a clone of libdrizzle's but C++'ified. Unfortunately libdrizzle's is broken. Fixed it here, will fix it in libdrizzle at a later date.
443
           output.append("\\n");
444
           break;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
445
         case '\r':
1855.2.1 by Andrew Hutchings
The escape function is a clone of libdrizzle's but C++'ified. Unfortunately libdrizzle's is broken. Fixed it here, will fix it in libdrizzle at a later date.
446
           output.append("\\r");
447
           break;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
448
         case '\\':
1855.2.1 by Andrew Hutchings
The escape function is a clone of libdrizzle's but C++'ified. Unfortunately libdrizzle's is broken. Fixed it here, will fix it in libdrizzle at a later date.
449
           output.append("\\\\");
450
           break;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
451
         case '\'':
1855.2.1 by Andrew Hutchings
The escape function is a clone of libdrizzle's but C++'ified. Unfortunately libdrizzle's is broken. Fixed it here, will fix it in libdrizzle at a later date.
452
           output.append("\\'");
453
           break;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
454
         case '"':
1855.2.1 by Andrew Hutchings
The escape function is a clone of libdrizzle's but C++'ified. Unfortunately libdrizzle's is broken. Fixed it here, will fix it in libdrizzle at a later date.
455
           output.append("\\\"");
456
           break;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
457
         case '\032':
1855.2.1 by Andrew Hutchings
The escape function is a clone of libdrizzle's but C++'ified. Unfortunately libdrizzle's is broken. Fixed it here, will fix it in libdrizzle at a later date.
458
           output.append("\\Z");
459
           break;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
460
         default:
1855.2.1 by Andrew Hutchings
The escape function is a clone of libdrizzle's but C++'ified. Unfortunately libdrizzle's is broken. Fixed it here, will fix it in libdrizzle at a later date.
461
           output.push_back(*from);
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
462
           break;
463
       }
464
    }
1855.2.1 by Andrew Hutchings
The escape function is a clone of libdrizzle's but C++'ified. Unfortunately libdrizzle's is broken. Fixed it here, will fix it in libdrizzle at a later date.
465
    else
466
      output.push_back(*from);
1831.1.1 by Andrew Hutchings
Fix new warnings in GCC 4.5
467
    (void) *from++;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
468
    from_size--;
469
  }
470
471
  return output;
472
}
473
474
std::ostream& operator <<(std::ostream &os, const DrizzleDumpTable &obj)
475
{
1751.4.26 by Andrew Hutchings
Fix up for the drizzledump test cases
476
  if (verbose)
477
  {
478
    std::cerr << "--" << std::endl
479
      << "-- Table structure for table `" << obj.displayName << "`" << std::endl
480
      << "--" << std::endl << std::endl;
481
  }
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
482
483
  if (opt_drop)
1751.4.25 by Andrew Hutchings
Fix error handling
484
    os << "DROP TABLE IF EXISTS `" << obj.displayName <<  "`;" << std::endl;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
485
1751.4.25 by Andrew Hutchings
Fix error handling
486
  os << "CREATE TABLE `" << obj.displayName << "` (" << std::endl;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
487
  std::vector<DrizzleDumpField*>::iterator i;
488
  std::vector<DrizzleDumpField*> output_fields = obj.fields;
489
  for (i= output_fields.begin(); i != output_fields.end(); ++i)
490
  {
491
    if (i != output_fields.begin())
492
      os << "," << std::endl;
493
    DrizzleDumpField *field= *i;
494
    os << *field;
495
  }
496
497
  std::vector<DrizzleDumpIndex*>::iterator j;
498
  std::vector<DrizzleDumpIndex*> output_indexes = obj.indexes;
499
  for (j= output_indexes.begin(); j != output_indexes.end(); ++j)
500
  {
1810.6.4 by Andrew Hutchings
Add foreign keys to Drizzle server
501
    os << "," << std::endl;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
502
    DrizzleDumpIndex *index= *j;
503
    os << *index;
504
  }
1810.6.4 by Andrew Hutchings
Add foreign keys to Drizzle server
505
506
  std::vector<DrizzleDumpForeignKey*>::iterator k;
507
  std::vector<DrizzleDumpForeignKey*> output_fkeys = obj.fkeys;
508
  for (k= output_fkeys.begin(); k != output_fkeys.end(); ++k)
509
  {
510
    os << "," << std::endl;
511
    DrizzleDumpForeignKey *fkey= *k;
512
    os << *fkey;
513
  }
514
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
515
  os << std::endl;
1880.2.1 by Andrew Hutchings
Add quoting to the end of the table definition
516
  os << ") ENGINE='" << obj.engineName << "' ";
1802.5.1 by Andrew Hutchings
Adds auto_increment to data_dictionary.tables and drizzledump (when connecting to a Drizzle server)
517
  if (obj.autoIncrement > 0)
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
518
  {
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
519
    os << "AUTO_INCREMENT=" << obj.autoIncrement << " ";
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
520
  }
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
521
1880.2.1 by Andrew Hutchings
Add quoting to the end of the table definition
522
  os << "COLLATE='" << obj.collate << "'";
1810.1.1 by Andrew Hutchings
Add table comments
523
524
  if (not obj.comment.empty())
525
  {
1880.2.1 by Andrew Hutchings
Add quoting to the end of the table definition
526
    os << " COMMENT='" << obj.comment << "'";
1810.1.1 by Andrew Hutchings
Add table comments
527
  }
528
529
  os << ";" << std::endl << std::endl;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
530
531
  return os;
532
}
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
533
534
DrizzleDumpConnection::DrizzleDumpConnection(std::string &host, uint16_t port, 
535
  std::string &username, std::string &password, bool drizzle_protocol) :
536
  hostName(host),
537
  drizzleProtocol(drizzle_protocol)
538
{
539
  drizzle_return_t ret;
540
541
  if (host.empty())
542
    host= "localhost";
543
544
  std::string protocol= (drizzle_protocol) ? "Drizzle" : "MySQL";
1751.4.23 by Andrew Hutchings
Fix various bugs
545
  if (verbose)
546
  {
547
    std::cerr << _("-- Connecting to ") << host  << _(" using protocol ")
548
      << protocol << "..." << std::endl;
549
  }
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
550
  drizzle_create(&drizzle);
551
  drizzle_con_create(&drizzle, &connection);
552
  drizzle_con_set_tcp(&connection, (char *)host.c_str(), port);
553
  drizzle_con_set_auth(&connection, (char *)username.c_str(),
554
    (char *)password.c_str());
555
  drizzle_con_add_options(&connection, 
556
    drizzle_protocol ? DRIZZLE_CON_EXPERIMENTAL : DRIZZLE_CON_MYSQL);
557
  ret= drizzle_con_connect(&connection);
558
  if (ret != DRIZZLE_RETURN_OK)
559
  {
560
    errorHandler(NULL, ret, "when trying to connect");
1966.3.1 by Monty Taylor
Use std::exception instead of catch(...)
561
    throw std::exception();
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
562
  }
563
564
  boost::match_flag_type flags = boost::match_default; 
565
566
  boost::regex mysql_regex("(5\\.[0-9]+\\.[0-9]+)");
567
  boost::regex drizzle_regex("(20[0-9]{2}\\.(0[1-9]|1[012])\\.[0-9]+)");
568
569
  std::string version(getServerVersion());
570
571
  if (regex_search(version, mysql_regex, flags))
572
    serverType= SERVER_MYSQL_FOUND;
1751.4.21 by Andrew Hutchings
Add database destination settings and connect it all up
573
  else if (regex_search(version, drizzle_regex, flags))
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
574
    serverType= SERVER_DRIZZLE_FOUND;
1751.4.21 by Andrew Hutchings
Add database destination settings and connect it all up
575
  else
576
    serverType= SERVER_UNKNOWN_FOUND;
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
577
}
578
579
drizzle_result_st* DrizzleDumpConnection::query(std::string &str_query)
580
{
581
  drizzle_return_t ret;
582
  drizzle_result_st* result= new drizzle_result_st;
583
  if (drizzle_query_str(&connection, result, str_query.c_str(), &ret) == NULL ||
584
      ret != DRIZZLE_RETURN_OK)
585
  {
586
    if (ret == DRIZZLE_RETURN_ERROR_CODE)
587
    {
588
      std::cerr << _("Error executing query: ") <<
1751.4.23 by Andrew Hutchings
Fix various bugs
589
        drizzle_result_error(result) << std::endl;
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
590
      drizzle_result_free(result);
591
    }
592
    else
593
    {
594
      std::cerr << _("Error executing query: ") <<
1751.4.23 by Andrew Hutchings
Fix various bugs
595
        drizzle_con_error(&connection) << std::endl;
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
596
    }
597
    return NULL;
598
  }
599
600
  if (drizzle_result_buffer(result) != DRIZZLE_RETURN_OK)
601
  {
602
    std::cerr << _("Could not buffer result: ") <<
1751.4.23 by Andrew Hutchings
Fix various bugs
603
        drizzle_con_error(&connection) << std::endl;
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
604
    return NULL;
605
  }
606
  return result;
607
}
608
609
void DrizzleDumpConnection::freeResult(drizzle_result_st* result)
610
{
611
  drizzle_result_free(result);
612
  delete result;
613
}
614
615
bool DrizzleDumpConnection::queryNoResult(std::string &str_query)
616
{
617
  drizzle_return_t ret;
618
  drizzle_result_st result;
619
620
  if (drizzle_query_str(&connection, &result, str_query.c_str(), &ret) == NULL ||
621
      ret != DRIZZLE_RETURN_OK)
622
  {
623
    if (ret == DRIZZLE_RETURN_ERROR_CODE)
624
    {
625
      std::cerr << _("Error executing query: ") <<
1751.4.23 by Andrew Hutchings
Fix various bugs
626
        drizzle_result_error(&result) << std::endl;
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
627
      drizzle_result_free(&result);
628
    }
629
    else
630
    {
631
      std::cerr << _("Error executing query: ") <<
1751.4.23 by Andrew Hutchings
Fix various bugs
632
        drizzle_con_error(&connection) << std::endl;
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
633
    }
634
    return false;
635
  }
636
637
  drizzle_result_free(&result);
638
  return true;
639
}
640
641
bool DrizzleDumpConnection::setDB(std::string databaseName)
642
{
643
  drizzle_return_t ret;
644
  drizzle_result_st result;
645
  if (drizzle_select_db(&connection, &result, databaseName.c_str(), &ret) == 
646
    NULL || ret != DRIZZLE_RETURN_OK)
647
  {
1751.4.25 by Andrew Hutchings
Fix error handling
648
    std::cerr << _("Error: Could not set db '") << databaseName << "'" << std::endl;
649
    if (ret == DRIZZLE_RETURN_ERROR_CODE)
650
      drizzle_result_free(&result);
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
651
    return false;
652
  }
653
  drizzle_result_free(&result);
654
  return true;
655
}
656
1799.7.2 by Andrew Hutchings
Clean up some drizzledump options
657
void DrizzleDumpConnection::errorHandler(drizzle_result_st *res,
658
  drizzle_return_t ret, const char *when)
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
659
{
1802.6.1 by Andrew Hutchings
Add better error handling and exception handling for database connect
660
  if (res == NULL)
661
  {
662
    std::cerr << _("Got error: ") << drizzle_con_error(&connection) << " "
663
      << when << std::endl;
664
  }
665
  else if (ret == DRIZZLE_RETURN_ERROR_CODE)
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
666
  {
667
    std::cerr << _("Got error: ") << drizzle_result_error(res)
668
      << " (" << drizzle_result_error_code(res) << ") " << when << std::endl;
669
    drizzle_result_free(res);
670
  }
671
  else
672
  {
673
    std::cerr << _("Got error: ") << ret << " " << when << std::endl;
674
  }
675
676
  return;
677
}
678
679
DrizzleDumpConnection::~DrizzleDumpConnection()
680
{
1751.4.23 by Andrew Hutchings
Fix various bugs
681
  if (verbose)
682
    std::cerr << _("-- Disconnecting from ") << hostName << "..." << std::endl;
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
683
  drizzle_con_free(&connection);
684
  drizzle_free(&drizzle);
685
}