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 "drizzledump_mysql.h"
22
#include "client_priv.h"
25
#include <boost/regex.hpp>
26
#include <boost/date_time/posix_time/posix_time.hpp>
27
#include <drizzled/gettext.h>
30
extern bool ignore_errors;
32
bool DrizzleDumpDatabaseMySQL::populateTables()
34
drizzle_result_st *result;
38
if (not dcon->setDB(databaseName))
42
std::cerr << _("-- Retrieving table structures for ") << databaseName << "..." << std::endl;
44
query="SELECT TABLE_NAME, TABLE_COLLATION, ENGINE, AUTO_INCREMENT, TABLE_COMMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE != 'VIEW' AND TABLE_SCHEMA='";
45
query.append(databaseName);
46
query.append("' ORDER BY TABLE_NAME");
48
result= dcon->query(query);
53
while ((row= drizzle_row_next(result)))
55
size_t* row_sizes= drizzle_row_field_sizes(result);
56
std::string tableName(row[0]);
57
std::string displayName(tableName);
58
cleanTableName(displayName);
59
if (not ignoreTable(displayName))
62
DrizzleDumpTableMySQL *table = new DrizzleDumpTableMySQL(tableName, dcon);
63
table->displayName= displayName;
64
table->setCollate(row[1]);
65
table->setEngine(row[2]);
67
table->autoIncrement= boost::lexical_cast<uint64_t>(row[3]);
69
table->autoIncrement= 0;
71
if ((row[4]) and (strstr(row[4], "InnoDB free") == NULL))
72
table->comment= DrizzleDumpData::escape(row[4], row_sizes[4]);
76
table->database= this;
77
if ((not table->populateFields()) or (not table->populateIndexes()) or
78
(not table->populateFkeys()))
81
if (not ignore_errors)
86
tables.push_back(table);
89
dcon->freeResult(result);
94
bool DrizzleDumpDatabaseMySQL::populateTables(const std::vector<std::string> &table_names)
96
drizzle_result_st *result;
100
if (not dcon->setDB(databaseName))
104
std::cerr << _("-- Retrieving table structures for ") << databaseName << "..." << std::endl;
105
for (std::vector<std::string>::const_iterator it= table_names.begin(); it != table_names.end(); ++it)
107
std::string tableName= *it;
108
std::string displayName(tableName);
109
cleanTableName(displayName);
110
if (not ignoreTable(displayName))
113
query="SELECT TABLE_NAME, TABLE_COLLATION, ENGINE, AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='";
114
query.append(databaseName);
115
query.append("' AND TABLE_NAME = '");
116
query.append(tableName);
119
result= dcon->query(query);
124
if ((row= drizzle_row_next(result)))
126
DrizzleDumpTableMySQL *table = new DrizzleDumpTableMySQL(tableName, dcon);
127
table->displayName= displayName;
128
table->setCollate(row[1]);
129
table->setEngine(row[2]);
131
table->autoIncrement= boost::lexical_cast<uint64_t>(row[3]);
133
table->autoIncrement= 0;
135
table->database= this;
136
if ((not table->populateFields()) or (not table->populateIndexes()))
139
if (not ignore_errors)
144
tables.push_back(table);
145
dcon->freeResult(result);
149
dcon->freeResult(result);
150
if (not ignore_errors)
161
bool DrizzleDumpTableMySQL::populateFields()
163
drizzle_result_st *result;
168
std::cerr << _("-- Retrieving fields for ") << tableName << "..." << std::endl;
170
query="SELECT COLUMN_NAME, COLUMN_TYPE, COLUMN_DEFAULT, IS_NULLABLE, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION, NUMERIC_SCALE, COLLATION_NAME, EXTRA FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='";
171
query.append(database->databaseName);
172
query.append("' AND TABLE_NAME='");
173
query.append(tableName);
174
query.append("' ORDER BY ORDINAL_POSITION");
176
result= dcon->query(query);
181
while ((row= drizzle_row_next(result)))
183
std::string fieldName(row[0]);
184
DrizzleDumpFieldMySQL *field = new DrizzleDumpFieldMySQL(fieldName, dcon);
185
/* Stop valgrind warning */
186
field->convertDateTime= false;
187
field->isNull= (strcmp(row[3], "YES") == 0) ? true : false;
188
/* Also sets collation */
189
field->setType(row[1], row[8]);
190
if (field->type.compare("ENUM") == 0)
195
field->defaultValue= row[2];
196
if (field->convertDateTime)
198
field->dateTimeConvert();
202
field->defaultValue= "";
204
field->isAutoIncrement= (strcmp(row[8], "auto_increment") == 0) ? true : false;
205
field->defaultIsNull= field->isNull;
206
field->length= (row[4]) ? boost::lexical_cast<uint32_t>(row[4]) : 0;
207
if ((row[5] != NULL) and (row[6] != NULL))
209
field->decimalPrecision= boost::lexical_cast<uint32_t>(row[5]);
210
field->decimalScale= boost::lexical_cast<uint32_t>(row[6]);
214
field->decimalPrecision= 0;
215
field->decimalScale= 0;
218
fields.push_back(field);
221
dcon->freeResult(result);
226
void DrizzleDumpFieldMySQL::dateTimeConvert(void)
228
boost::match_flag_type flags = boost::match_default;
230
if (strcmp(defaultValue.c_str(), "CURRENT_TIMESTAMP") == 0)
233
if (type.compare("INT") == 0)
235
/* We were a TIME, now we are an INT */
236
std::string ts(defaultValue);
237
boost::posix_time::time_duration td(boost::posix_time::duration_from_string(ts));
238
defaultValue= boost::lexical_cast<std::string>(td.total_seconds());
242
boost::regex date_regex("(0000|-00)");
244
if (regex_search(defaultValue, date_regex, flags))
252
bool DrizzleDumpTableMySQL::populateIndexes()
254
drizzle_result_st *result;
258
bool firstIndex= true;
259
DrizzleDumpIndex *index;
262
std::cerr << _("-- Retrieving indexes for ") << tableName << "..." << std::endl;
264
query="SHOW INDEXES FROM ";
265
query.append(tableName);
267
result= dcon->query(query);
272
while ((row= drizzle_row_next(result)))
274
std::string indexName(row[2]);
275
if (indexName.compare(lastKey) != 0)
277
if (strcmp(row[10], "FULLTEXT") == 0)
281
indexes.push_back(index);
282
index = new DrizzleDumpIndexMySQL(indexName, dcon);
283
index->isPrimary= (strcmp(row[2], "PRIMARY") == 0);
284
index->isUnique= (strcmp(row[1], "0") == 0);
285
index->isHash= (strcmp(row[10], "HASH") == 0);
286
index->length= (row[7]) ? boost::lexical_cast<uint32_t>(row[7]) : 0;
290
index->columns.push_back(row[4]);
293
indexes.push_back(index);
295
dcon->freeResult(result);
299
bool DrizzleDumpTableMySQL::populateFkeys()
301
drizzle_result_st *result;
304
DrizzleDumpForeignKey *fkey;
307
std::cerr << _("-- Retrieving foreign keys for ") << tableName << "..." << std::endl;
309
query= "SHOW TABLES FROM INFORMATION_SCHEMA LIKE 'REFERENTIAL_CONSTRAINTS'";
311
result= dcon->query(query);
316
uint64_t search_count = drizzle_result_row_count(result);
318
dcon->freeResult(result);
320
/* MySQL 5.0 will be 0 and MySQL 5.1 will be 1 */
321
if (search_count > 0)
323
query= "select rc.constraint_name, rc.referenced_table_name, group_concat(distinct concat('`',kc.column_name,'`')), rc.update_rule, rc.delete_rule, rc.match_option, group_concat(distinct concat('`',kt.column_name,'`')) from information_schema.referential_constraints rc join information_schema.key_column_usage kt on (rc.constraint_schema = kt.constraint_schema and rc.constraint_name = kt.constraint_name) join information_schema.key_column_usage kc on (rc.constraint_schema = kc.constraint_schema and rc.referenced_table_name = kc.table_name and rc.unique_constraint_name = kc.constraint_name) where rc.constraint_schema='";
324
query.append(database->databaseName);
325
query.append("' and rc.table_name='");
326
query.append(tableName);
327
query.append("' group by rc.constraint_name");
329
result= dcon->query(query);
334
while ((row= drizzle_row_next(result)))
336
fkey= new DrizzleDumpForeignKey(row[0], dcon);
337
fkey->parentColumns= row[6];
338
fkey->childTable= row[1];
339
fkey->childColumns= row[2];
340
fkey->updateRule= (strcmp(row[3], "RESTRICT") != 0) ? row[3] : "";
341
fkey->deleteRule= (strcmp(row[4], "RESTRICT") != 0) ? row[4] : "";
342
fkey->matchOption= (strcmp(row[5], "NONE") != 0) ? row[5] : "";
344
fkeys.push_back(fkey);
349
query= "SHOW CREATE TABLE `";
350
query.append(database->databaseName);
352
query.append(tableName);
354
result= dcon->query(query);
359
if ((row= drizzle_row_next(result)))
361
boost::match_flag_type flags = boost::match_default;
362
boost::regex constraint_regex("CONSTRAINT `(.*)` FOREIGN KEY \\((.*)\\) REFERENCES `(.*)` \\((.*)\\)( ON (UPDATE|DELETE) (CASCADE|RESTRICT|SET NULL))?( ON (UPDATE|DELETE) (CASCADE|RESTRICT|SET NULL))?");
364
boost::match_results<std::string::const_iterator> constraint_results;
366
std::string search_body(row[1]);
367
std::string::const_iterator start, end;
368
start= search_body.begin();
369
end= search_body.end();
370
while (regex_search(start, end, constraint_results, constraint_regex, flags))
372
fkey= new DrizzleDumpForeignKey(constraint_results[1], dcon);
373
fkey->parentColumns= constraint_results[2];
374
fkey->childTable= constraint_results[3];
375
fkey->childColumns= constraint_results[4];
377
if (constraint_results[5].compare("") != 0)
379
if (constraint_results[6].compare("UPDATE") == 0)
380
fkey->updateRule= constraint_results[7];
381
else if (constraint_results[6].compare("DELETE") == 0)
382
fkey->deleteRule= constraint_results[7];
384
if (constraint_results[8].compare("") != 0)
386
if (constraint_results[9].compare("UPDATE") == 0)
387
fkey->updateRule= constraint_results[10];
388
else if (constraint_results[9].compare("DELETE") == 0)
389
fkey->deleteRule= constraint_results[10];
391
fkey->matchOption= "";
393
fkeys.push_back(fkey);
395
start= constraint_results[0].second;
396
flags |= boost::match_prev_avail;
397
flags |= boost::match_not_bob;
401
dcon->freeResult(result);
405
void DrizzleDumpFieldMySQL::setType(const char* raw_type, const char* raw_collation)
407
std::string old_type(raw_type);
411
if ((pos= old_type.find("(")) != std::string::npos)
413
extra= old_type.substr(pos);
414
old_type.erase(pos, std::string::npos);
417
std::transform(old_type.begin(), old_type.end(), old_type.begin(), ::toupper);
418
if ((old_type.find("CHAR") != std::string::npos) or
419
(old_type.find("TEXT") != std::string::npos))
420
setCollate(raw_collation);
422
if ((old_type.compare("INT") == 0) and
423
((extra.find("unsigned") != std::string::npos)))
429
if ((old_type.compare("TINYINT") == 0) or
430
(old_type.compare("SMALLINT") == 0) or
431
(old_type.compare("MEDIUMINT") == 0))
437
if ((old_type.compare("TINYBLOB") == 0) or
438
(old_type.compare("MEDIUMBLOB") == 0) or
439
(old_type.compare("LONGBLOB") == 0))
445
if ((old_type.compare("TINYTEXT") == 0) or
446
(old_type.compare("MEDIUMTEXT") == 0) or
447
(old_type.compare("LONGTEXT") == 0) or
448
(old_type.compare("SET") == 0))
454
if (old_type.compare("CHAR") == 0)
460
if (old_type.compare("BINARY") == 0)
466
if (old_type.compare("ENUM") == 0)
469
/* Strip out the braces, we add them again during output */
470
enumValues= extra.substr(1, extra.length()-2);
474
if ((old_type.find("TIME") != std::string::npos) or
475
(old_type.find("DATE") != std::string::npos))
477
/* Intended to catch TIME/DATE/TIMESTAMP/DATETIME
478
We may have a default TIME/DATE which needs converting */
479
convertDateTime= true;
483
if ((old_type.compare("TIME") == 0) or (old_type.compare("YEAR") == 0))
489
if (old_type.compare("FLOAT") == 0)
499
void DrizzleDumpTableMySQL::setEngine(const char* newEngine)
501
if (strcmp(newEngine, "MyISAM") == 0)
502
engineName= "InnoDB";
504
engineName= newEngine;
507
DrizzleDumpData* DrizzleDumpTableMySQL::getData(void)
511
return new DrizzleDumpDataMySQL(this, dcon);
519
void DrizzleDumpDatabaseMySQL::setCollate(const char* newCollate)
523
std::string tmpCollate(newCollate);
524
if (tmpCollate.find("utf8") != std::string::npos)
530
collate= "utf8_general_ci";
533
void DrizzleDumpTableMySQL::setCollate(const char* newCollate)
537
std::string tmpCollate(newCollate);
538
if (tmpCollate.find("utf8") != std::string::npos)
545
collate= "utf8_general_ci";
548
void DrizzleDumpFieldMySQL::setCollate(const char* newCollate)
552
std::string tmpCollate(newCollate);
553
if (tmpCollate.find("utf8") != std::string::npos)
555
collation= tmpCollate;
559
collation= "utf8_general_ci";
562
DrizzleDumpDataMySQL::DrizzleDumpDataMySQL(DrizzleDumpTable *dataTable,
563
DrizzleDumpConnection *connection)
564
: DrizzleDumpData(dataTable, connection)
567
query= "SELECT * FROM `";
568
query.append(table->displayName);
571
result= dcon->query(query);
576
DrizzleDumpDataMySQL::~DrizzleDumpDataMySQL()
578
drizzle_result_free(result);
582
long DrizzleDumpDataMySQL::convertTime(const char* oldTime) const
584
std::string ts(oldTime);
585
boost::posix_time::time_duration td(boost::posix_time::duration_from_string(ts));
586
long seconds= td.total_seconds();
590
std::string DrizzleDumpDataMySQL::convertDate(const char* oldDate) const
592
boost::match_flag_type flags = boost::match_default;
594
boost::regex date_regex("(0000|-00)");
596
if (not regex_search(oldDate, date_regex, flags))
598
output.push_back('\'');
599
output.append(oldDate);
600
output.push_back('\'');
608
std::string DrizzleDumpDataMySQL::checkDateTime(const char* item, uint32_t field) const
612
if (table->fields[field]->convertDateTime)
614
if (table->fields[field]->type.compare("INT") == 0)
615
ret= boost::lexical_cast<std::string>(convertTime(item));
617
ret= convertDate(item);