1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2010 Andrew Hutchings
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.
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.
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
20
#include "drizzledump_data.h"
21
#include "client_priv.h"
22
#include <drizzled/gettext.h>
25
#include <boost/regex.hpp>
26
#include <boost/unordered_set.hpp>
28
#define EX_DRIZZLEERR 2
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;
38
extern bool opt_databases;
39
extern bool opt_alldbs;
40
extern uint32_t show_progress_size;
41
extern bool opt_ignore;
43
extern boost::unordered_set<std::string> ignore_table;
44
extern void maybe_exit(int error);
52
extern int opt_destination;
54
/* returns true on keep, false on ignore */
55
bool DrizzleDumpDatabase::ignoreTable(std::string tableName)
57
std::string dbTable(databaseName);
59
dbTable.append(tableName);
61
boost::unordered_set<std::string>::iterator iter= ignore_table.find(dbTable);
62
return (iter == ignore_table.end());
65
void DrizzleDumpDatabase::cleanTableName(std::string &tableName)
67
std::string replace("``");
68
std::string find("`");
70
for (;(j = tableName.find(find, j)) != std::string::npos;)
72
tableName.replace(j, find.length(), replace);
78
std::ostream& operator <<(std::ostream &os, const DrizzleDumpIndex &obj)
82
os << " PRIMARY KEY ";
84
else if (obj.isUnique)
86
os << " UNIQUE KEY `" << obj.indexName << "` ";
90
os << " KEY `" << obj.indexName << "` ";
95
std::vector<std::string>::iterator i;
96
std::vector<std::string> fields = obj.columns;
97
for (i= fields.begin(); i != fields.end(); ++i)
99
if (i != fields.begin())
101
std::string field= *i;
102
os << "`" << field << "`";
110
std::ostream& operator <<(std::ostream &os, const DrizzleDumpField &obj)
112
os << " `" << obj.fieldName << "` ";
114
if (((obj.type.compare("VARCHAR") == 0) or
115
(obj.type.compare("VARBINARY") == 0)) and
118
os << "(" << obj.length << ")";
120
else if (((obj.type.compare("DECIMAL") == 0) or
121
(obj.type.compare("DOUBLE") == 0)) and
122
((obj.decimalPrecision + obj.decimalScale) > 0))
124
os << "(" << obj.decimalPrecision << "," << obj.decimalScale << ")";
126
else if (obj.type.compare("ENUM") == 0)
128
os << "(" << obj.enumValues << ")";
136
if ((not obj.collation.empty()) and (obj.collation.compare("binary") != 0))
138
os << " COLLATE " << obj.collation;
141
if (obj.isAutoIncrement)
142
os << " AUTO_INCREMENT";
144
if (not obj.defaultValue.empty())
146
if (obj.defaultValue.compare("CURRENT_TIMESTAMP") != 0)
147
os << " DEFAULT '" << obj.defaultValue << "'";
149
os << " DEFAULT CURRENT_TIMESTAMP";
151
else if ((obj.defaultIsNull))
153
os << " DEFAULT NULL";
159
std::ostream& operator <<(std::ostream &os, const DrizzleDumpDatabase &obj)
161
if ((opt_destination == DESTINATION_DB) or opt_databases or opt_alldbs)
165
std::cerr << "--" << std::endl
166
<< "-- Current Database: `" << obj.databaseName << "`" << std::endl
167
<< "--" << std::endl << std::endl;
170
/* Love that this variable is the opposite of its name */
171
if (not opt_create_db)
173
os << "CREATE DATABASE IF NOT EXISTS `" << obj.databaseName << "`";
174
if (not obj.collate.empty())
175
os << " COLLATE = " << obj.collate;
177
os << ";" << std::endl << std::endl;
180
os << "USE `" << obj.databaseName << "`;" << std::endl << std::endl;
183
std::vector<DrizzleDumpTable*>::iterator i;
184
std::vector<DrizzleDumpTable*> output_tables = obj.tables;
185
for (i= output_tables.begin(); i != output_tables.end(); ++i)
187
DrizzleDumpTable *table= *i;
188
if (not opt_no_create_info)
192
obj.dcon->setDB(obj.databaseName);
193
DrizzleDumpData *data= table->getData();
196
std::cerr << "Error: Could not get data for table " << table->displayName << std::endl;
197
maybe_exit(EX_DRIZZLEERR);
208
std::ostream& operator <<(std::ostream &os, const DrizzleDumpData &obj)
210
bool new_insert= true;
217
std::cerr << _("-- Retrieving data for ") << obj.table->displayName << "..." << std::endl;
219
if (drizzle_result_row_count(obj.result) < 1)
223
std::cerr << "--" << std::endl
224
<< "-- No data to dump for table `" << obj.table->displayName << "`"
225
<< std::endl << "--" << std::endl << std::endl;
231
std::cerr << "--" << std::endl
232
<< "-- Dumping data for table `" << obj.table->displayName << "`"
233
<< std::endl << "--" << std::endl << std::endl;
235
if (opt_disable_keys)
236
os << "ALTER TABLE `" << obj.table->displayName << "` DISABLE KEYS;" << std::endl;
238
std::streampos out_position= os.tellp();
240
while((row= drizzle_row_next(obj.result)))
243
if ((rownr % show_progress_size) == 0)
245
std::cerr << "-- %" << rownr << _(" rows dumped for table ") << obj.table->displayName << std::endl;
248
size_t* row_sizes= drizzle_row_field_sizes(obj.result);
254
os << ");" << std::endl;
261
if (opt_replace_into)
269
os << "INTO `" << obj.table->displayName << "` VALUES (";
273
for (uint32_t i= 0; i < drizzle_result_column_count(obj.result); i++)
279
/* time/date conversion for MySQL connections */
280
else if (obj.table->fields[i]->convertDateTime)
282
os << obj.checkDateTime(os, row[i], i);
286
if (obj.table->fields[i]->type.compare("INT") != 0)
288
/* Hex blob processing or escape text */
289
if (((obj.table->fields[i]->type.compare("BLOB") == 0) or
290
(obj.table->fields[i]->type.compare("VARBINARY") == 0)))
291
os << obj.convertHex((unsigned char*)row[i], row_sizes[i]);
293
os << "'" << obj.escape(row[i], row_sizes[i]) << "'";
298
if (i != obj.table->fields.size() - 1)
301
/* Break insert up if it is too long */
302
if (extended_insert and
303
((os.tellp() - out_position) >= DRIZZLE_MAX_LINE_LENGTH))
305
os << ");" << std::endl;
307
out_position= os.tellp();
310
os << ");" << std::endl;
312
if (opt_disable_keys)
313
os << "ALTER TABLE `" << obj.table->tableName << "` ENABLE KEYS;" << std::endl;
320
std::string DrizzleDumpData::convertHex(const unsigned char* from, size_t from_size) const
322
std::ostringstream output;
325
while (from_size > 0)
327
/* Would be nice if std::hex liked uint8_t, ah well */
328
output << std::uppercase << std::hex << std::setw(2) << std::setfill('0') << (unsigned short)(*from);
336
/* Ripped out of libdrizzle, hopefully a little safer */
337
std::string DrizzleDumpData::escape(const char* from, size_t from_size) const
341
while (from_size > 0)
354
output.push_back('\\');
359
output.push_back(*from);
367
std::ostream& operator <<(std::ostream &os, const DrizzleDumpTable &obj)
371
std::cerr << "--" << std::endl
372
<< "-- Table structure for table `" << obj.displayName << "`" << std::endl
373
<< "--" << std::endl << std::endl;
377
os << "DROP TABLE IF EXISTS `" << obj.displayName << "`;" << std::endl;
379
os << "CREATE TABLE `" << obj.displayName << "` (" << std::endl;
380
std::vector<DrizzleDumpField*>::iterator i;
381
std::vector<DrizzleDumpField*> output_fields = obj.fields;
382
for (i= output_fields.begin(); i != output_fields.end(); ++i)
384
if (i != output_fields.begin())
385
os << "," << std::endl;
386
DrizzleDumpField *field= *i;
390
std::vector<DrizzleDumpIndex*>::iterator j;
391
std::vector<DrizzleDumpIndex*> output_indexes = obj.indexes;
392
for (j= output_indexes.begin(); j != output_indexes.end(); ++j)
394
os << "," << std::endl;;
395
DrizzleDumpIndex *index= *j;
399
os << ") ENGINE=" << obj.engineName << " ";
400
if ((obj.dcon->getServerType() == DrizzleDumpConnection::SERVER_MYSQL_FOUND)
401
and (obj.autoIncrement > 0))
403
os << "AUTO_INCREMENT=" << obj.autoIncrement << " ";
406
os << "COLLATE = " << obj.collate << ";" << std::endl << std::endl;
411
DrizzleDumpConnection::DrizzleDumpConnection(std::string &host, uint16_t port,
412
std::string &username, std::string &password, bool drizzle_protocol) :
414
drizzleProtocol(drizzle_protocol)
416
drizzle_return_t ret;
421
std::string protocol= (drizzle_protocol) ? "Drizzle" : "MySQL";
424
std::cerr << _("-- Connecting to ") << host << _(" using protocol ")
425
<< protocol << "..." << std::endl;
427
drizzle_create(&drizzle);
428
drizzle_con_create(&drizzle, &connection);
429
drizzle_con_set_tcp(&connection, (char *)host.c_str(), port);
430
drizzle_con_set_auth(&connection, (char *)username.c_str(),
431
(char *)password.c_str());
432
drizzle_con_add_options(&connection,
433
drizzle_protocol ? DRIZZLE_CON_EXPERIMENTAL : DRIZZLE_CON_MYSQL);
434
ret= drizzle_con_connect(&connection);
435
if (ret != DRIZZLE_RETURN_OK)
437
errorHandler(NULL, ret, "when trying to connect");
441
boost::match_flag_type flags = boost::match_default;
443
boost::regex mysql_regex("(5\\.[0-9]+\\.[0-9]+)");
444
boost::regex drizzle_regex("(20[0-9]{2}\\.(0[1-9]|1[012])\\.[0-9]+)");
446
std::string version(getServerVersion());
448
if (regex_search(version, mysql_regex, flags))
449
serverType= SERVER_MYSQL_FOUND;
450
else if (regex_search(version, drizzle_regex, flags))
451
serverType= SERVER_DRIZZLE_FOUND;
453
serverType= SERVER_UNKNOWN_FOUND;
456
drizzle_result_st* DrizzleDumpConnection::query(std::string &str_query)
458
drizzle_return_t ret;
459
drizzle_result_st* result= new drizzle_result_st;
460
if (drizzle_query_str(&connection, result, str_query.c_str(), &ret) == NULL ||
461
ret != DRIZZLE_RETURN_OK)
463
if (ret == DRIZZLE_RETURN_ERROR_CODE)
465
std::cerr << _("Error executing query: ") <<
466
drizzle_result_error(result) << std::endl;
467
drizzle_result_free(result);
471
std::cerr << _("Error executing query: ") <<
472
drizzle_con_error(&connection) << std::endl;
477
if (drizzle_result_buffer(result) != DRIZZLE_RETURN_OK)
479
std::cerr << _("Could not buffer result: ") <<
480
drizzle_con_error(&connection) << std::endl;
486
void DrizzleDumpConnection::freeResult(drizzle_result_st* result)
488
drizzle_result_free(result);
492
bool DrizzleDumpConnection::queryNoResult(std::string &str_query)
494
drizzle_return_t ret;
495
drizzle_result_st result;
497
if (drizzle_query_str(&connection, &result, str_query.c_str(), &ret) == NULL ||
498
ret != DRIZZLE_RETURN_OK)
500
if (ret == DRIZZLE_RETURN_ERROR_CODE)
502
std::cerr << _("Error executing query: ") <<
503
drizzle_result_error(&result) << std::endl;
504
drizzle_result_free(&result);
508
std::cerr << _("Error executing query: ") <<
509
drizzle_con_error(&connection) << std::endl;
514
drizzle_result_free(&result);
518
bool DrizzleDumpConnection::setDB(std::string databaseName)
520
drizzle_return_t ret;
521
drizzle_result_st result;
522
if (drizzle_select_db(&connection, &result, databaseName.c_str(), &ret) ==
523
NULL || ret != DRIZZLE_RETURN_OK)
525
std::cerr << _("Error: Could not set db '") << databaseName << "'" << std::endl;
526
if (ret == DRIZZLE_RETURN_ERROR_CODE)
527
drizzle_result_free(&result);
530
drizzle_result_free(&result);
534
void DrizzleDumpConnection::errorHandler(drizzle_result_st *res, drizzle_return_t ret,
537
if (ret == DRIZZLE_RETURN_ERROR_CODE)
539
std::cerr << _("Got error: ") << drizzle_result_error(res)
540
<< " (" << drizzle_result_error_code(res) << ") " << when << std::endl;
541
drizzle_result_free(res);
545
std::cerr << _("Got error: ") << ret << " " << when << std::endl;
551
DrizzleDumpConnection::~DrizzleDumpConnection()
554
std::cerr << _("-- Disconnecting from ") << hostName << "..." << std::endl;
555
drizzle_con_free(&connection);
556
drizzle_free(&drizzle);