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