~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
2192.4.1 by Olaf van der Spek
Add find_ptr
59
// 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
60
bool DrizzleDumpDatabase::ignoreTable(std::string tableName)
61
{
2192.4.1 by Olaf van der Spek
Add find_ptr
62
  return ignore_table.find(databaseName + "." + tableName) == ignore_table.end();
1751.4.24 by Andrew Hutchings
Fix ignore tables
63
}
64
1751.4.25 by Andrew Hutchings
Fix error handling
65
void DrizzleDumpDatabase::cleanTableName(std::string &tableName)
66
{
67
  std::string replace("``");
68
  std::string find("`");
69
  size_t j = 0;
70
  for (;(j = tableName.find(find, j)) != std::string::npos;)
71
  {
72
    tableName.replace(j, find.length(), replace);
73
    j+= replace.length();
74
  }
75
76
}
77
1810.6.4 by Andrew Hutchings
Add foreign keys to Drizzle server
78
std::ostream& operator <<(std::ostream &os, const DrizzleDumpForeignKey &obj)
79
{
80
  os << "  CONSTRAINT `" << obj.constraintName << "` FOREIGN KEY ("
81
    << obj.parentColumns << ") REFERENCES `" << obj.childTable << "` ("
82
    << obj.childColumns << ")";
83
84
  if (not obj.deleteRule.empty())
85
    os << " ON DELETE " << obj.deleteRule;
86
87
  if (not obj.updateRule.empty())
88
    os << " ON UPDATE " << obj.updateRule;
89
90
  return os;
91
}
92
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
93
std::ostream& operator <<(std::ostream &os, const DrizzleDumpIndex &obj)
94
{
95
  if (obj.isPrimary)
96
  {
97
    os << "  PRIMARY KEY ";
98
  }
99
  else if (obj.isUnique)
100
  {
101
    os << "  UNIQUE KEY `" << obj.indexName << "` ";
102
  }
103
  else
104
  {
105
    os << "  KEY `" << obj.indexName << "` ";
106
  }
107
108
  os << "(";
109
  
110
  std::vector<std::string>::iterator i;
111
  std::vector<std::string> fields = obj.columns;
112
  for (i= fields.begin(); i != fields.end(); ++i)
113
  {
114
    if (i != fields.begin())
115
      os << ",";
116
    std::string field= *i;
117
    os << "`" << field << "`";
1802.2.1 by Andrew Hutchings
Fix index lengths not shown for part-indexed columns.
118
    if (obj.length > 0)
119
      os << "(" << obj.length << ")";
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
  std::streampos out_position= os.tellp();
289
290
  while((row= drizzle_row_next(obj.result)))
291
  {
292
    rownr++;
1855.1.1 by Andrew Hutchings
Fix several bugs dumping tables with many rows
293
    if (verbose and (rownr % show_progress_size) == 0)
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
294
    {
1802.11.1 by Andrew Hutchings
1. date regex was broken
295
      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
296
    }
297
298
    size_t* row_sizes= drizzle_row_field_sizes(obj.result);
1855.1.1 by Andrew Hutchings
Fix several bugs dumping tables with many rows
299
    for (uint32_t i= 0; i < drizzle_result_column_count(obj.result); i++)
300
      byte_counter+= row_sizes[i];
301
302
    if (not first and not new_insert)
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
303
    {
304
      if (extended_insert)
305
        os << "),(";
306
      else
307
        os << ");" << std::endl;
1855.1.1 by Andrew Hutchings
Fix several bugs dumping tables with many rows
308
      byte_counter+= 3;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
309
    }
310
    else
311
      first= false;
312
313
    if (new_insert)
314
    {
315
      if (opt_replace_into)
316
        os << "REPLACE ";
317
      else
1751.4.26 by Andrew Hutchings
Fix up for the drizzledump test cases
318
      {
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
319
        os << "INSERT ";
1751.4.26 by Andrew Hutchings
Fix up for the drizzledump test cases
320
        if (opt_ignore)
321
          os << "IGNORE ";
322
      }
1751.4.25 by Andrew Hutchings
Fix error handling
323
      os << "INTO `" << obj.table->displayName << "` VALUES (";
1855.1.1 by Andrew Hutchings
Fix several bugs dumping tables with many rows
324
      byte_counter+= 28 + obj.table->displayName.length();
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
325
      if (extended_insert)
326
        new_insert= false;
327
    }
328
    for (uint32_t i= 0; i < drizzle_result_column_count(obj.result); i++)
329
    {
330
      if (not row[i])
331
      {
332
        os << "NULL";
1971.5.3 by Andrew Hutchings
If migrating a BIGINT UNISIGNED value > BIGINT signed max value, error. We cannot store it.
333
        if (i != obj.table->fields.size() - 1)
334
          os << ",";
335
        continue;
336
      }
337
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.
338
      if ((obj.table->fields[i]->rangeCheck) and
339
        (obj.table->fields[i]->type.compare("BIGINT") == 0) and
340
        (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.
341
      {
342
        std::cerr << "Error: Data for column " << obj.table->fields[i]->fieldName << " is greater than max BIGINT, cannot migrate automatically" << std::endl;
343
        if (not ignore_errors)
344
          maybe_exit(EX_DRIZZLEERR);
345
        else
346
          continue;
347
      }
348
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
349
      /* time/date conversion for MySQL connections */
350
      else if (obj.table->fields[i]->convertDateTime)
351
      {
1802.11.1 by Andrew Hutchings
1. date regex was broken
352
        os << obj.checkDateTime(row[i], i);
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
353
      }
354
      else
355
      {
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.
356
        if ((obj.table->fields[i]->type.compare("INT") != 0) and
357
          (obj.table->fields[i]->type.compare("BIGINT") != 0))
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
358
        {
359
          /* Hex blob processing or escape text */
360
          if (((obj.table->fields[i]->type.compare("BLOB") == 0) or
361
            (obj.table->fields[i]->type.compare("VARBINARY") == 0)))
1855.1.1 by Andrew Hutchings
Fix several bugs dumping tables with many rows
362
          {
1751.4.26 by Andrew Hutchings
Fix up for the drizzledump test cases
363
            os << obj.convertHex((unsigned char*)row[i], row_sizes[i]);
1855.1.1 by Andrew Hutchings
Fix several bugs dumping tables with many rows
364
            byte_counter+= row_sizes[i];
365
          }
1882.2.1 by Andrew Hutchings
MySQL can contain '' as an ENUM value which is not valid in Drizzle. Convert this to NULL.
366
          else if ((obj.table->fields[i]->type.compare("ENUM") == 0) and
367
            (strcmp(row[i], "") == 0))
368
          {
369
            os << "NULL";
370
          }
2187.3.3 by Andrew Hutchings
Add boolean support for drizzledump too
371
          else if (obj.table->fields[i]->type.compare("BOOLEAN") == 0)
372
          {
373
            if (strncmp(row[i], "1", 1) == 0)
374
              os << "TRUE";
375
            else
376
              os << "FALSE";
377
          }
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
378
          else
1810.1.1 by Andrew Hutchings
Add table comments
379
            os << "'" << DrizzleDumpData::escape(row[i], row_sizes[i]) << "'";
1855.1.1 by Andrew Hutchings
Fix several bugs dumping tables with many rows
380
          byte_counter+= 3;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
381
        }
382
        else
383
          os << row[i];
384
      }
385
      if (i != obj.table->fields.size() - 1)
386
        os << ",";
387
    }
388
    /* Break insert up if it is too long */
1865.2.1 by Andrew Hutchings
Fix drizzledump --skip-extended-insert
389
    if ((extended_insert and
390
      (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
391
    {
392
      os << ");" << std::endl;
393
      new_insert= true;
1855.1.1 by Andrew Hutchings
Fix several bugs dumping tables with many rows
394
      byte_counter= 0;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
395
    }
396
  }
1865.2.2 by Andrew Hutchings
Fix possibility of double ");" at end of data dump
397
  if (not new_insert)
398
    os << ");" << std::endl;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
399
1799.7.2 by Andrew Hutchings
Clean up some drizzledump options
400
  if (opt_autocommit)
401
    os << "COMMIT;" << std::endl;
402
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
403
  if (opt_disable_keys)
404
    os << "ALTER TABLE `" << obj.table->tableName << "` ENABLE KEYS;" << std::endl;
405
406
  os << std::endl;
407
408
  return os;
409
}
410
1751.4.26 by Andrew Hutchings
Fix up for the drizzledump test cases
411
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
412
{
413
  std::ostringstream output;
414
  if (from_size > 0)
415
    output << "0x";
1897.3.1 by Andrew Hutchings
drizzledump MySQL migration fixes:
416
  else
417
    output << "''";
418
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
419
  while (from_size > 0)
420
  {
1751.4.26 by Andrew Hutchings
Fix up for the drizzledump test cases
421
    /* Would be nice if std::hex liked uint8_t, ah well */
422
    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
423
    (void) *from++;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
424
    from_size--;
425
  }
426
427
  return output.str();
428
}
429
430
/* Ripped out of libdrizzle, hopefully a little safer */
1810.1.1 by Andrew Hutchings
Add table comments
431
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
432
{
433
  std::string output;
434
435
  while (from_size > 0)
436
  {
437
    if (!(*from & 0x80))
438
    {
439
      switch (*from)
440
      {
441
         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.
442
           output.append("\\0");
443
           break;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
444
         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.
445
           output.append("\\n");
446
           break;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
447
         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.
448
           output.append("\\r");
449
           break;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
450
         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.
451
           output.append("\\\\");
452
           break;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
453
         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.
454
           output.append("\\'");
455
           break;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
456
         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.
457
           output.append("\\\"");
458
           break;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
459
         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.
460
           output.append("\\Z");
461
           break;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
462
         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.
463
           output.push_back(*from);
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
464
           break;
465
       }
466
    }
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.
467
    else
468
      output.push_back(*from);
1831.1.1 by Andrew Hutchings
Fix new warnings in GCC 4.5
469
    (void) *from++;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
470
    from_size--;
471
  }
472
473
  return output;
474
}
475
476
std::ostream& operator <<(std::ostream &os, const DrizzleDumpTable &obj)
477
{
1751.4.26 by Andrew Hutchings
Fix up for the drizzledump test cases
478
  if (verbose)
479
  {
480
    std::cerr << "--" << std::endl
481
      << "-- Table structure for table `" << obj.displayName << "`" << std::endl
482
      << "--" << std::endl << std::endl;
483
  }
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
484
485
  if (opt_drop)
1751.4.25 by Andrew Hutchings
Fix error handling
486
    os << "DROP TABLE IF EXISTS `" << obj.displayName <<  "`;" << std::endl;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
487
1751.4.25 by Andrew Hutchings
Fix error handling
488
  os << "CREATE TABLE `" << obj.displayName << "` (" << std::endl;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
489
  std::vector<DrizzleDumpField*>::iterator i;
490
  std::vector<DrizzleDumpField*> output_fields = obj.fields;
491
  for (i= output_fields.begin(); i != output_fields.end(); ++i)
492
  {
493
    if (i != output_fields.begin())
494
      os << "," << std::endl;
495
    DrizzleDumpField *field= *i;
496
    os << *field;
497
  }
498
499
  std::vector<DrizzleDumpIndex*>::iterator j;
500
  std::vector<DrizzleDumpIndex*> output_indexes = obj.indexes;
501
  for (j= output_indexes.begin(); j != output_indexes.end(); ++j)
502
  {
1810.6.4 by Andrew Hutchings
Add foreign keys to Drizzle server
503
    os << "," << std::endl;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
504
    DrizzleDumpIndex *index= *j;
505
    os << *index;
506
  }
1810.6.4 by Andrew Hutchings
Add foreign keys to Drizzle server
507
508
  std::vector<DrizzleDumpForeignKey*>::iterator k;
509
  std::vector<DrizzleDumpForeignKey*> output_fkeys = obj.fkeys;
510
  for (k= output_fkeys.begin(); k != output_fkeys.end(); ++k)
511
  {
512
    os << "," << std::endl;
513
    DrizzleDumpForeignKey *fkey= *k;
514
    os << *fkey;
515
  }
516
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
517
  os << std::endl;
1880.2.1 by Andrew Hutchings
Add quoting to the end of the table definition
518
  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)
519
  if (obj.autoIncrement > 0)
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
    os << "AUTO_INCREMENT=" << obj.autoIncrement << " ";
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
522
  }
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
523
1880.2.1 by Andrew Hutchings
Add quoting to the end of the table definition
524
  os << "COLLATE='" << obj.collate << "'";
1810.1.1 by Andrew Hutchings
Add table comments
525
526
  if (not obj.comment.empty())
527
  {
1880.2.1 by Andrew Hutchings
Add quoting to the end of the table definition
528
    os << " COMMENT='" << obj.comment << "'";
1810.1.1 by Andrew Hutchings
Add table comments
529
  }
530
531
  os << ";" << std::endl << std::endl;
1751.4.19 by Andrew Hutchings
Put drizzle and mysql processes in seperate classes/files
532
533
  return os;
534
}
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
535
536
DrizzleDumpConnection::DrizzleDumpConnection(std::string &host, uint16_t port, 
537
  std::string &username, std::string &password, bool drizzle_protocol) :
538
  hostName(host),
539
  drizzleProtocol(drizzle_protocol)
540
{
541
  drizzle_return_t ret;
542
543
  if (host.empty())
544
    host= "localhost";
545
546
  std::string protocol= (drizzle_protocol) ? "Drizzle" : "MySQL";
1751.4.23 by Andrew Hutchings
Fix various bugs
547
  if (verbose)
548
  {
549
    std::cerr << _("-- Connecting to ") << host  << _(" using protocol ")
550
      << protocol << "..." << std::endl;
551
  }
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
552
  drizzle_create(&drizzle);
553
  drizzle_con_create(&drizzle, &connection);
554
  drizzle_con_set_tcp(&connection, (char *)host.c_str(), port);
555
  drizzle_con_set_auth(&connection, (char *)username.c_str(),
556
    (char *)password.c_str());
557
  drizzle_con_add_options(&connection, 
558
    drizzle_protocol ? DRIZZLE_CON_EXPERIMENTAL : DRIZZLE_CON_MYSQL);
559
  ret= drizzle_con_connect(&connection);
560
  if (ret != DRIZZLE_RETURN_OK)
561
  {
562
    errorHandler(NULL, ret, "when trying to connect");
1966.3.1 by Monty Taylor
Use std::exception instead of catch(...)
563
    throw std::exception();
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
564
  }
565
2187.3.2 by Andrew Hutchings
Separate the server detection functions into a .h file
566
  ServerDetect server_detect= ServerDetect(&connection);
567
568
  serverType= server_detect.getServerType();
569
  serverVersion= server_detect.getServerVersion();
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
570
}
571
572
drizzle_result_st* DrizzleDumpConnection::query(std::string &str_query)
573
{
574
  drizzle_return_t ret;
575
  drizzle_result_st* result= new drizzle_result_st;
576
  if (drizzle_query_str(&connection, result, str_query.c_str(), &ret) == NULL ||
577
      ret != DRIZZLE_RETURN_OK)
578
  {
579
    if (ret == DRIZZLE_RETURN_ERROR_CODE)
580
    {
581
      std::cerr << _("Error executing query: ") <<
1751.4.23 by Andrew Hutchings
Fix various bugs
582
        drizzle_result_error(result) << std::endl;
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
583
      drizzle_result_free(result);
584
    }
585
    else
586
    {
587
      std::cerr << _("Error executing query: ") <<
1751.4.23 by Andrew Hutchings
Fix various bugs
588
        drizzle_con_error(&connection) << std::endl;
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
589
    }
590
    return NULL;
591
  }
592
593
  if (drizzle_result_buffer(result) != DRIZZLE_RETURN_OK)
594
  {
595
    std::cerr << _("Could not buffer result: ") <<
1751.4.23 by Andrew Hutchings
Fix various bugs
596
        drizzle_con_error(&connection) << std::endl;
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
597
    return NULL;
598
  }
599
  return result;
600
}
601
602
void DrizzleDumpConnection::freeResult(drizzle_result_st* result)
603
{
604
  drizzle_result_free(result);
605
  delete result;
606
}
607
608
bool DrizzleDumpConnection::queryNoResult(std::string &str_query)
609
{
610
  drizzle_return_t ret;
611
  drizzle_result_st result;
612
613
  if (drizzle_query_str(&connection, &result, str_query.c_str(), &ret) == NULL ||
614
      ret != DRIZZLE_RETURN_OK)
615
  {
616
    if (ret == DRIZZLE_RETURN_ERROR_CODE)
617
    {
618
      std::cerr << _("Error executing query: ") <<
1751.4.23 by Andrew Hutchings
Fix various bugs
619
        drizzle_result_error(&result) << std::endl;
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
620
      drizzle_result_free(&result);
621
    }
622
    else
623
    {
624
      std::cerr << _("Error executing query: ") <<
1751.4.23 by Andrew Hutchings
Fix various bugs
625
        drizzle_con_error(&connection) << std::endl;
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
626
    }
627
    return false;
628
  }
629
630
  drizzle_result_free(&result);
631
  return true;
632
}
633
634
bool DrizzleDumpConnection::setDB(std::string databaseName)
635
{
636
  drizzle_return_t ret;
637
  drizzle_result_st result;
638
  if (drizzle_select_db(&connection, &result, databaseName.c_str(), &ret) == 
639
    NULL || ret != DRIZZLE_RETURN_OK)
640
  {
1751.4.25 by Andrew Hutchings
Fix error handling
641
    std::cerr << _("Error: Could not set db '") << databaseName << "'" << std::endl;
642
    if (ret == DRIZZLE_RETURN_ERROR_CODE)
643
      drizzle_result_free(&result);
1751.4.20 by Andrew Hutchings
Add database connection class and the start of a database output ostream
644
    return false;
645
  }
646
  drizzle_result_free(&result);
647
  return true;
648
}
649
1799.7.2 by Andrew Hutchings
Clean up some drizzledump options
650
void DrizzleDumpConnection::errorHandler(drizzle_result_st *res,
651
  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
652
{
1802.6.1 by Andrew Hutchings
Add better error handling and exception handling for database connect
653
  if (res == NULL)
654
  {
655
    std::cerr << _("Got error: ") << drizzle_con_error(&connection) << " "
656
      << when << std::endl;
657
  }
658
  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
659
  {
660
    std::cerr << _("Got error: ") << drizzle_result_error(res)
661
      << " (" << drizzle_result_error_code(res) << ") " << when << std::endl;
662
    drizzle_result_free(res);
663
  }
664
  else
665
  {
666
    std::cerr << _("Got error: ") << ret << " " << when << std::endl;
667
  }
668
669
  return;
670
}
671
672
DrizzleDumpConnection::~DrizzleDumpConnection()
673
{
1751.4.23 by Andrew Hutchings
Fix various bugs
674
  if (verbose)
675
    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
676
  drizzle_con_free(&connection);
677
  drizzle_free(&drizzle);
678
}