~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.24 by Andrew Hutchings
Fix ignore tables
26
#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)
27
#include <boost/lexical_cast.hpp>
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
28
1751.4.25 by Andrew Hutchings
Fix error handling
29
#define EX_DRIZZLEERR 2
30
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
31
extern bool opt_no_create_info;
32
extern bool opt_no_data;
33
extern bool opt_create_db;
34
extern bool opt_disable_keys;
35
extern bool extended_insert;
36
extern bool opt_replace_into;
1751.4.25 by Andrew Hutchings
Fix error handling
37
extern bool opt_drop;
38
extern bool verbose;
39
extern bool opt_databases;
40
extern bool opt_alldbs;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
41
extern uint32_t show_progress_size;
1751.4.26 by Andrew Hutchings
Fix up for the drizzledump test cases
42
extern bool opt_ignore;
1799.7.2 by Andrew Hutchings
Clean up some drizzledump options
43
extern bool opt_compress;
44
extern bool opt_drop_database;
45
extern bool opt_autocommit;
1799.7.4 by Andrew Hutchings
Fix up some more options and the docs
46
extern bool ignore_errors;
1862.2.1 by Andrew Hutchings
Link up --destination-database
47
extern std::string opt_destination_database;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
48
1751.4.24 by Andrew Hutchings
Fix ignore tables
49
extern boost::unordered_set<std::string> ignore_table;
1751.4.25 by Andrew Hutchings
Fix error handling
50
extern void maybe_exit(int error);
1751.4.24 by Andrew Hutchings
Fix ignore tables
51
1751.4.23 by Andrew Hutchings
Fix various bugs
52
enum destinations {
53
  DESTINATION_DB,
54
  DESTINATION_FILES,
55
  DESTINATION_STDOUT
56
};
57
58
extern int opt_destination;
59
2192.4.1 by Olaf van der Spek
Add find_ptr
60
// 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
61
bool DrizzleDumpDatabase::ignoreTable(std::string tableName)
62
{
2192.4.1 by Olaf van der Spek
Add find_ptr
63
  return ignore_table.find(databaseName + "." + tableName) == ignore_table.end();
1751.4.24 by Andrew Hutchings
Fix ignore tables
64
}
65
1751.4.25 by Andrew Hutchings
Fix error handling
66
void DrizzleDumpDatabase::cleanTableName(std::string &tableName)
67
{
68
  std::string replace("``");
69
  std::string find("`");
70
  size_t j = 0;
71
  for (;(j = tableName.find(find, j)) != std::string::npos;)
72
  {
73
    tableName.replace(j, find.length(), replace);
74
    j+= replace.length();
75
  }
76
77
}
78
1810.6.4 by Andrew Hutchings
Add foreign keys to Drizzle server
79
std::ostream& operator <<(std::ostream &os, const DrizzleDumpForeignKey &obj)
80
{
81
  os << "  CONSTRAINT `" << obj.constraintName << "` FOREIGN KEY ("
82
    << obj.parentColumns << ") REFERENCES `" << obj.childTable << "` ("
83
    << obj.childColumns << ")";
84
85
  if (not obj.deleteRule.empty())
86
    os << " ON DELETE " << obj.deleteRule;
87
88
  if (not obj.updateRule.empty())
89
    os << " ON UPDATE " << obj.updateRule;
90
91
  return os;
92
}
93
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
94
std::ostream& operator <<(std::ostream &os, const DrizzleDumpIndex &obj)
95
{
96
  if (obj.isPrimary)
97
  {
98
    os << "  PRIMARY KEY ";
99
  }
100
  else if (obj.isUnique)
101
  {
102
    os << "  UNIQUE KEY `" << obj.indexName << "` ";
103
  }
104
  else
105
  {
106
    os << "  KEY `" << obj.indexName << "` ";
107
  }
108
109
  os << "(";
110
  
2228.3.1 by Andrew Hutchings
Fix multi-part index length processing in drizzledump
111
  std::vector<DrizzleDumpIndex::columnData>::iterator i;
112
  std::vector<DrizzleDumpIndex::columnData> fields = obj.columns;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
113
  for (i= fields.begin(); i != fields.end(); ++i)
114
  {
115
    if (i != fields.begin())
116
      os << ",";
2228.3.1 by Andrew Hutchings
Fix multi-part index length processing in drizzledump
117
    os << "`" << (*i).first << "`";
118
    if ((*i).second > 0)
119
      os << "(" << (*i).second << ")";
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
120
  }
121
122
  os << ")";
123
124
  return os;
125
}
126
127
std::ostream& operator <<(std::ostream &os, const DrizzleDumpField &obj)
128
{
129
  os << "  `" << obj.fieldName << "` ";
130
  os << obj.type;
131
  if (((obj.type.compare("VARCHAR") == 0) or
132
   (obj.type.compare("VARBINARY") == 0)) and
133
   (obj.length > 0))
134
  {
135
    os << "(" << obj.length << ")";
136
  }
1751.4.26 by Andrew Hutchings
Fix up for the drizzledump test cases
137
  else if (((obj.type.compare("DECIMAL") == 0) or
138
    (obj.type.compare("DOUBLE") == 0)) and
139
    ((obj.decimalPrecision + obj.decimalScale) > 0))
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
140
  {
141
    os << "(" << obj.decimalPrecision << "," << obj.decimalScale << ")";
142
  }
143
  else if (obj.type.compare("ENUM") == 0)
144
  {
145
    os << "(" << obj.enumValues << ")";
146
  }
147
148
  if (not obj.isNull)
149
  {
150
    os << " NOT NULL";
151
  }
152
153
  if ((not obj.collation.empty()) and (obj.collation.compare("binary") != 0))
154
  {
155
    os << " COLLATE " << obj.collation;
156
  }
157
158
  if (obj.isAutoIncrement)
159
    os << " AUTO_INCREMENT";
160
161
  if (not obj.defaultValue.empty())
162
  {
163
    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.
164
    {
165
      if (obj.defaultValue.compare(0, 2, "b'") == 0)
166
      {
167
        os << " DEFAULT " << obj.defaultValue;
168
      }
169
      else
170
      {
171
        os << " DEFAULT '" << obj.defaultValue << "'";
172
      }
173
    }
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
174
    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.
175
    {
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
176
     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.
177
    }
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
178
  }
1751.4.26 by Andrew Hutchings
Fix up for the drizzledump test cases
179
  else if ((obj.defaultIsNull))
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
180
  {
181
    os << " DEFAULT NULL";
182
  }
183
1976.4.3 by Andrew Hutchings
Add field level comments back in to drizzledump
184
  if (not obj.comment.empty())
185
  {
186
    os << " COMMENT '" << DrizzleDumpData::escape(obj.comment.c_str(), obj.comment.length()) << "'";
187
  }
188
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
189
  return os;
190
}
191
192
std::ostream& operator <<(std::ostream &os, const DrizzleDumpDatabase &obj)
193
{
1751.4.23 by Andrew Hutchings
Fix various bugs
194
  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
195
  {
1751.4.26 by Andrew Hutchings
Fix up for the drizzledump test cases
196
    if (verbose)
197
    {
198
      std::cerr << "--" << std::endl
199
        << "-- Current Database: `" << obj.databaseName << "`" << std::endl
200
        << "--" << std::endl << std::endl;
201
    }
1751.4.23 by Andrew Hutchings
Fix various bugs
202
203
    /* Love that this variable is the opposite of its name */
204
    if (not opt_create_db)
205
    {
1799.7.2 by Andrew Hutchings
Clean up some drizzledump options
206
      if (opt_drop_database)
1862.2.1 by Andrew Hutchings
Link up --destination-database
207
      {
208
        os << "DROP DATABASE IF EXISTS `"
209
          << ((opt_destination_database.empty()) ? obj.databaseName
210
          : opt_destination_database) << "`" << std::endl;
211
      }
1799.7.2 by Andrew Hutchings
Clean up some drizzledump options
212
1862.2.1 by Andrew Hutchings
Link up --destination-database
213
      os << "CREATE DATABASE IF NOT EXISTS `"
214
        << ((opt_destination_database.empty()) ? obj.databaseName
215
        : opt_destination_database) << "`";
1751.4.23 by Andrew Hutchings
Fix various bugs
216
      if (not obj.collate.empty())
217
       os << " COLLATE = " << obj.collate;
218
219
      os << ";" << std::endl << std::endl;
220
    }
1862.2.1 by Andrew Hutchings
Link up --destination-database
221
    os << "USE `" << ((opt_destination_database.empty()) ? obj.databaseName
222
      : opt_destination_database) << "`;" << std::endl << std::endl;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
223
  }
224
225
  std::vector<DrizzleDumpTable*>::iterator i;
226
  std::vector<DrizzleDumpTable*> output_tables = obj.tables;
227
  for (i= output_tables.begin(); i != output_tables.end(); ++i)
228
  {
229
    DrizzleDumpTable *table= *i;
230
    if (not opt_no_create_info)
231
      os << *table;
232
    if (not opt_no_data)
233
    {
1751.4.21 by Andrew Hutchings
Add database destination settings and connect it all up
234
      obj.dcon->setDB(obj.databaseName);
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
235
      DrizzleDumpData *data= table->getData();
1751.4.25 by Andrew Hutchings
Fix error handling
236
      if (data == NULL)
237
      {
238
        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
239
        if (not ignore_errors)
240
          maybe_exit(EX_DRIZZLEERR);
241
        else
242
          continue;
1751.4.25 by Andrew Hutchings
Fix error handling
243
      }
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
244
      os << *data;
245
      delete data;
246
    }
247
  }
248
249
  return os;
250
}
251
252
253
std::ostream& operator <<(std::ostream &os, const DrizzleDumpData &obj)
254
{
255
  bool new_insert= true;
256
  bool first= true;
257
  uint64_t rownr= 0;
1855.1.1 by Andrew Hutchings
Fix several bugs dumping tables with many rows
258
  size_t byte_counter= 0;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
259
260
  drizzle_row_t row;
261
1751.4.23 by Andrew Hutchings
Fix various bugs
262
  if (verbose)
1751.4.25 by Andrew Hutchings
Fix error handling
263
    std::cerr << _("-- Retrieving data for ") << obj.table->displayName << "..." << std::endl;
1751.4.23 by Andrew Hutchings
Fix various bugs
264
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
265
  if (drizzle_result_row_count(obj.result) < 1)
266
  {
1751.4.26 by Andrew Hutchings
Fix up for the drizzledump test cases
267
    if (verbose)
268
    {
269
      std::cerr << "--" << std::endl
270
        << "-- No data to dump for table `" << obj.table->displayName << "`"
271
        << std::endl << "--" << std::endl << std::endl;
272
    }
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
273
    return os;
274
  }
1751.4.26 by Andrew Hutchings
Fix up for the drizzledump test cases
275
  else if (verbose)
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
276
  {
1751.4.26 by Andrew Hutchings
Fix up for the drizzledump test cases
277
    std::cerr << "--" << std::endl
278
      << "-- Dumping data for table `" << obj.table->displayName << "`"
279
      << std::endl << "--" << std::endl << std::endl;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
280
  }
281
  if (opt_disable_keys)
1751.4.25 by Andrew Hutchings
Fix error handling
282
    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
283
1799.7.2 by Andrew Hutchings
Clean up some drizzledump options
284
  /* Another option that does the opposite of its name, makes me sad :( */
285
  if (opt_autocommit)
286
    os << "START TRANSACTION;" << std::endl;
287
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
288
  while((row= drizzle_row_next(obj.result)))
289
  {
290
    rownr++;
1855.1.1 by Andrew Hutchings
Fix several bugs dumping tables with many rows
291
    if (verbose and (rownr % show_progress_size) == 0)
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
292
    {
1802.11.1 by Andrew Hutchings
1. date regex was broken
293
      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
294
    }
295
296
    size_t* row_sizes= drizzle_row_field_sizes(obj.result);
1855.1.1 by Andrew Hutchings
Fix several bugs dumping tables with many rows
297
    for (uint32_t i= 0; i < drizzle_result_column_count(obj.result); i++)
298
      byte_counter+= row_sizes[i];
299
300
    if (not first and not new_insert)
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
301
    {
302
      if (extended_insert)
303
        os << "),(";
304
      else
305
        os << ");" << std::endl;
1855.1.1 by Andrew Hutchings
Fix several bugs dumping tables with many rows
306
      byte_counter+= 3;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
307
    }
308
    else
309
      first= false;
310
311
    if (new_insert)
312
    {
313
      if (opt_replace_into)
314
        os << "REPLACE ";
315
      else
1751.4.26 by Andrew Hutchings
Fix up for the drizzledump test cases
316
      {
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
317
        os << "INSERT ";
1751.4.26 by Andrew Hutchings
Fix up for the drizzledump test cases
318
        if (opt_ignore)
319
          os << "IGNORE ";
320
      }
1751.4.25 by Andrew Hutchings
Fix error handling
321
      os << "INTO `" << obj.table->displayName << "` VALUES (";
1855.1.1 by Andrew Hutchings
Fix several bugs dumping tables with many rows
322
      byte_counter+= 28 + obj.table->displayName.length();
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
323
      if (extended_insert)
324
        new_insert= false;
325
    }
326
    for (uint32_t i= 0; i < drizzle_result_column_count(obj.result); i++)
327
    {
328
      if (not row[i])
329
      {
330
        os << "NULL";
1971.5.3 by Andrew Hutchings
If migrating a BIGINT UNISIGNED value > BIGINT signed max value, error. We cannot store it.
331
        if (i != obj.table->fields.size() - 1)
332
          os << ",";
333
        continue;
334
      }
335
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.
336
      if ((obj.table->fields[i]->rangeCheck) and
337
        (obj.table->fields[i]->type.compare("BIGINT") == 0) and
338
        (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.
339
      {
340
        std::cerr << "Error: Data for column " << obj.table->fields[i]->fieldName << " is greater than max BIGINT, cannot migrate automatically" << std::endl;
341
        if (not ignore_errors)
342
          maybe_exit(EX_DRIZZLEERR);
343
        else
344
          continue;
345
      }
346
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
347
      /* time/date conversion for MySQL connections */
348
      else if (obj.table->fields[i]->convertDateTime)
349
      {
1802.11.1 by Andrew Hutchings
1. date regex was broken
350
        os << obj.checkDateTime(row[i], i);
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
351
      }
352
      else
353
      {
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.
354
        if ((obj.table->fields[i]->type.compare("INT") != 0) and
355
          (obj.table->fields[i]->type.compare("BIGINT") != 0))
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
356
        {
357
          /* Hex blob processing or escape text */
358
          if (((obj.table->fields[i]->type.compare("BLOB") == 0) or
359
            (obj.table->fields[i]->type.compare("VARBINARY") == 0)))
1855.1.1 by Andrew Hutchings
Fix several bugs dumping tables with many rows
360
          {
1751.4.26 by Andrew Hutchings
Fix up for the drizzledump test cases
361
            os << obj.convertHex((unsigned char*)row[i], row_sizes[i]);
1855.1.1 by Andrew Hutchings
Fix several bugs dumping tables with many rows
362
            byte_counter+= row_sizes[i];
363
          }
1882.2.1 by Andrew Hutchings
MySQL can contain '' as an ENUM value which is not valid in Drizzle. Convert this to NULL.
364
          else if ((obj.table->fields[i]->type.compare("ENUM") == 0) and
365
            (strcmp(row[i], "") == 0))
366
          {
367
            os << "NULL";
368
          }
2187.3.3 by Andrew Hutchings
Add boolean support for drizzledump too
369
          else if (obj.table->fields[i]->type.compare("BOOLEAN") == 0)
370
          {
371
            if (strncmp(row[i], "1", 1) == 0)
372
              os << "TRUE";
373
            else
374
              os << "FALSE";
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
2228.2.1 by Andrew Hutchings
Add REPLICATE=FALSE support to drizzledump
529
  if (not obj.replicate)
530
  {
531
    os << " REPLICATE=FALSE";
532
  }
533
1810.1.1 by Andrew Hutchings
Add table comments
534
  os << ";" << std::endl << std::endl;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
535
536
  return os;
537
}
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
538
539
DrizzleDumpConnection::DrizzleDumpConnection(std::string &host, uint16_t port, 
540
  std::string &username, std::string &password, bool drizzle_protocol) :
541
  hostName(host),
542
  drizzleProtocol(drizzle_protocol)
543
{
544
  drizzle_return_t ret;
545
546
  if (host.empty())
547
    host= "localhost";
548
549
  std::string protocol= (drizzle_protocol) ? "Drizzle" : "MySQL";
1751.4.23 by Andrew Hutchings
Fix various bugs
550
  if (verbose)
551
  {
552
    std::cerr << _("-- Connecting to ") << host  << _(" using protocol ")
553
      << protocol << "..." << std::endl;
554
  }
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
555
  drizzle_create(&drizzle);
556
  drizzle_con_create(&drizzle, &connection);
557
  drizzle_con_set_tcp(&connection, (char *)host.c_str(), port);
558
  drizzle_con_set_auth(&connection, (char *)username.c_str(),
559
    (char *)password.c_str());
560
  drizzle_con_add_options(&connection, 
561
    drizzle_protocol ? DRIZZLE_CON_EXPERIMENTAL : DRIZZLE_CON_MYSQL);
562
  ret= drizzle_con_connect(&connection);
563
  if (ret != DRIZZLE_RETURN_OK)
564
  {
565
    errorHandler(NULL, ret, "when trying to connect");
1966.3.1 by Monty Taylor
Use std::exception instead of catch(...)
566
    throw std::exception();
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
567
  }
568
2187.3.2 by Andrew Hutchings
Separate the server detection functions into a .h file
569
  ServerDetect server_detect= ServerDetect(&connection);
570
571
  serverType= server_detect.getServerType();
572
  serverVersion= server_detect.getServerVersion();
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
573
}
574
575
drizzle_result_st* DrizzleDumpConnection::query(std::string &str_query)
576
{
577
  drizzle_return_t ret;
578
  drizzle_result_st* result= new drizzle_result_st;
579
  if (drizzle_query_str(&connection, result, str_query.c_str(), &ret) == NULL ||
580
      ret != DRIZZLE_RETURN_OK)
581
  {
582
    if (ret == DRIZZLE_RETURN_ERROR_CODE)
583
    {
584
      std::cerr << _("Error executing query: ") <<
1751.4.23 by Andrew Hutchings
Fix various bugs
585
        drizzle_result_error(result) << std::endl;
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
586
      drizzle_result_free(result);
587
    }
588
    else
589
    {
590
      std::cerr << _("Error executing query: ") <<
1751.4.23 by Andrew Hutchings
Fix various bugs
591
        drizzle_con_error(&connection) << std::endl;
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
592
    }
593
    return NULL;
594
  }
595
596
  if (drizzle_result_buffer(result) != DRIZZLE_RETURN_OK)
597
  {
598
    std::cerr << _("Could not buffer result: ") <<
1751.4.23 by Andrew Hutchings
Fix various bugs
599
        drizzle_con_error(&connection) << std::endl;
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
600
    return NULL;
601
  }
602
  return result;
603
}
604
605
void DrizzleDumpConnection::freeResult(drizzle_result_st* result)
606
{
607
  drizzle_result_free(result);
608
  delete result;
609
}
610
611
bool DrizzleDumpConnection::queryNoResult(std::string &str_query)
612
{
613
  drizzle_return_t ret;
614
  drizzle_result_st result;
615
616
  if (drizzle_query_str(&connection, &result, str_query.c_str(), &ret) == NULL ||
617
      ret != DRIZZLE_RETURN_OK)
618
  {
619
    if (ret == DRIZZLE_RETURN_ERROR_CODE)
620
    {
621
      std::cerr << _("Error executing query: ") <<
1751.4.23 by Andrew Hutchings
Fix various bugs
622
        drizzle_result_error(&result) << std::endl;
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
623
      drizzle_result_free(&result);
624
    }
625
    else
626
    {
627
      std::cerr << _("Error executing query: ") <<
1751.4.23 by Andrew Hutchings
Fix various bugs
628
        drizzle_con_error(&connection) << std::endl;
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
629
    }
630
    return false;
631
  }
632
633
  drizzle_result_free(&result);
634
  return true;
635
}
636
637
bool DrizzleDumpConnection::setDB(std::string databaseName)
638
{
639
  drizzle_return_t ret;
640
  drizzle_result_st result;
641
  if (drizzle_select_db(&connection, &result, databaseName.c_str(), &ret) == 
642
    NULL || ret != DRIZZLE_RETURN_OK)
643
  {
1751.4.25 by Andrew Hutchings
Fix error handling
644
    std::cerr << _("Error: Could not set db '") << databaseName << "'" << std::endl;
645
    if (ret == DRIZZLE_RETURN_ERROR_CODE)
646
      drizzle_result_free(&result);
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
647
    return false;
648
  }
649
  drizzle_result_free(&result);
650
  return true;
651
}
652
1799.7.2 by Andrew Hutchings
Clean up some drizzledump options
653
void DrizzleDumpConnection::errorHandler(drizzle_result_st *res,
654
  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
655
{
1802.6.1 by Andrew Hutchings
Add better error handling and exception handling for database connect
656
  if (res == NULL)
657
  {
658
    std::cerr << _("Got error: ") << drizzle_con_error(&connection) << " "
659
      << when << std::endl;
660
  }
661
  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
662
  {
663
    std::cerr << _("Got error: ") << drizzle_result_error(res)
664
      << " (" << drizzle_result_error_code(res) << ") " << when << std::endl;
665
    drizzle_result_free(res);
666
  }
667
  else
668
  {
669
    std::cerr << _("Got error: ") << ret << " " << when << std::endl;
670
  }
671
672
  return;
673
}
674
675
DrizzleDumpConnection::~DrizzleDumpConnection()
676
{
1751.4.23 by Andrew Hutchings
Fix various bugs
677
  if (verbose)
678
    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
679
  drizzle_con_free(&connection);
680
  drizzle_free(&drizzle);
681
}