00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "drizzledump_data.h"
00021 #include "drizzledump_mysql.h"
00022 #include "client_priv.h"
00023 #include <string>
00024 #include <iostream>
00025 #include <boost/regex.hpp>
00026 #include <boost/date_time/posix_time/posix_time.hpp>
00027 #include <drizzled/gettext.h>
00028
00029 extern bool verbose;
00030 extern bool ignore_errors;
00031
00032 bool DrizzleDumpDatabaseMySQL::populateTables()
00033 {
00034 drizzle_result_st *result;
00035 drizzle_row_t row;
00036 std::string query;
00037
00038 if (not dcon->setDB(databaseName))
00039 return false;
00040
00041 if (verbose)
00042 std::cerr << _("-- Retrieving table structures for ") << databaseName << "..." << std::endl;
00043
00044 query="SELECT TABLE_NAME, TABLE_COLLATION, ENGINE, AUTO_INCREMENT, TABLE_COMMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE != 'VIEW' AND TABLE_SCHEMA='";
00045 query.append(databaseName);
00046 query.append("' ORDER BY TABLE_NAME");
00047
00048 result= dcon->query(query);
00049
00050 if (result == NULL)
00051 return false;
00052
00053 while ((row= drizzle_row_next(result)))
00054 {
00055 size_t* row_sizes= drizzle_row_field_sizes(result);
00056 std::string tableName(row[0]);
00057 std::string displayName(tableName);
00058 cleanTableName(displayName);
00059 if (not ignoreTable(displayName))
00060 continue;
00061
00062 DrizzleDumpTableMySQL *table = new DrizzleDumpTableMySQL(tableName, dcon);
00063 table->displayName= displayName;
00064 table->setCollate(row[1]);
00065 table->setEngine(row[2]);
00066 if (row[3])
00067 table->autoIncrement= boost::lexical_cast<uint64_t>(row[3]);
00068 else
00069 table->autoIncrement= 0;
00070
00071 if ((row[4]) and (strstr(row[4], "InnoDB free") == NULL))
00072 table->comment= DrizzleDumpData::escape(row[4], row_sizes[4]);
00073 else
00074 table->comment= "";
00075
00076 table->database= this;
00077 if ((not table->populateFields()) or (not table->populateIndexes()) or
00078 (not table->populateFkeys()))
00079 {
00080 delete table;
00081 if (not ignore_errors)
00082 return false;
00083 else
00084 continue;
00085 }
00086 tables.push_back(table);
00087 }
00088
00089 dcon->freeResult(result);
00090
00091 return true;
00092 }
00093
00094 bool DrizzleDumpDatabaseMySQL::populateTables(const std::vector<std::string> &table_names)
00095 {
00096 drizzle_result_st *result;
00097 drizzle_row_t row;
00098 std::string query;
00099
00100 if (not dcon->setDB(databaseName))
00101 return false;
00102
00103 if (verbose)
00104 std::cerr << _("-- Retrieving table structures for ") << databaseName << "..." << std::endl;
00105 for (std::vector<std::string>::const_iterator it= table_names.begin(); it != table_names.end(); ++it)
00106 {
00107 std::string tableName= *it;
00108 std::string displayName(tableName);
00109 cleanTableName(displayName);
00110 if (not ignoreTable(displayName))
00111 continue;
00112
00113 query="SELECT TABLE_NAME, TABLE_COLLATION, ENGINE, AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='";
00114 query.append(databaseName);
00115 query.append("' AND TABLE_NAME = '");
00116 query.append(tableName);
00117 query.append("'");
00118
00119 result= dcon->query(query);
00120
00121 if (result == NULL)
00122 return false;
00123
00124 if ((row= drizzle_row_next(result)))
00125 {
00126 DrizzleDumpTableMySQL *table = new DrizzleDumpTableMySQL(tableName, dcon);
00127 table->displayName= displayName;
00128 table->setCollate(row[1]);
00129 table->setEngine(row[2]);
00130 if (row[3])
00131 table->autoIncrement= boost::lexical_cast<uint64_t>(row[3]);
00132 else
00133 table->autoIncrement= 0;
00134
00135 table->database= this;
00136 if ((not table->populateFields()) or (not table->populateIndexes()))
00137 {
00138 delete table;
00139 if (not ignore_errors)
00140 return false;
00141 else
00142 continue;
00143 }
00144 tables.push_back(table);
00145 dcon->freeResult(result);
00146 }
00147 else
00148 {
00149 dcon->freeResult(result);
00150 if (not ignore_errors)
00151 return false;
00152 else
00153 continue;
00154 }
00155 }
00156
00157 return true;
00158
00159 }
00160
00161 bool DrizzleDumpTableMySQL::populateFields()
00162 {
00163 drizzle_result_st *result;
00164 drizzle_row_t row;
00165 std::string query;
00166
00167 if (verbose)
00168 std::cerr << _("-- Retrieving fields for ") << tableName << "..." << std::endl;
00169
00170 query="SELECT COLUMN_NAME, COLUMN_TYPE, COLUMN_DEFAULT, IS_NULLABLE, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION, NUMERIC_SCALE, COLLATION_NAME, EXTRA, COLUMN_COMMENT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='";
00171 query.append(database->databaseName);
00172 query.append("' AND TABLE_NAME='");
00173 query.append(tableName);
00174 query.append("' ORDER BY ORDINAL_POSITION");
00175
00176 result= dcon->query(query);
00177
00178 if (result == NULL)
00179 return false;
00180
00181 while ((row= drizzle_row_next(result)))
00182 {
00183 std::string fieldName(row[0]);
00184 DrizzleDumpFieldMySQL *field = new DrizzleDumpFieldMySQL(fieldName, dcon);
00185
00186 field->convertDateTime= false;
00187 field->isNull= (strcmp(row[3], "YES") == 0) ? true : false;
00188
00189 field->setType(row[1], row[8]);
00190 if (field->type.compare("ENUM") == 0)
00191 field->isNull= true;
00192
00193 if ((row[2]) and (field->type.compare("TEXT") != 0))
00194 {
00195 field->defaultValue= row[2];
00196 if (field->convertDateTime)
00197 {
00198 field->dateTimeConvert();
00199 }
00200 }
00201 else
00202 {
00203 field->defaultValue= "";
00204 }
00205
00206 field->isAutoIncrement= (strcmp(row[8], "auto_increment") == 0) ? true : false;
00207 field->defaultIsNull= field->isNull;
00208
00209
00210 if ((strncmp(row[1], "bit", 3) == 0) and (row[5] != NULL))
00211 field->length= ((boost::lexical_cast<uint32_t>(row[5]) - 1) / 8) + 1;
00212 else
00213 field->length= (row[4]) ? boost::lexical_cast<uint32_t>(row[4]) : 0;
00214
00215
00216 if (((field->type.compare("VARBINARY") == 0)
00217 or (field->type.compare("VARCHAR") == 0))
00218 and (field->length == 0))
00219 {
00220 field->length= 1;
00221 }
00222
00223 field->decimalPrecision= (row[5]) ? boost::lexical_cast<uint32_t>(row[5]) : 0;
00224 field->decimalScale= (row[6]) ? boost::lexical_cast<uint32_t>(row[6]) : 0;
00225 field->comment= (row[9]) ? row[9] : "";
00226 fields.push_back(field);
00227 }
00228
00229 dcon->freeResult(result);
00230 return true;
00231 }
00232
00233
00234 void DrizzleDumpFieldMySQL::dateTimeConvert(void)
00235 {
00236 boost::match_flag_type flags = boost::match_default;
00237
00238 if (strcmp(defaultValue.c_str(), "CURRENT_TIMESTAMP") == 0)
00239 return;
00240
00241 if (type.compare("INT") == 0)
00242 {
00243
00244 std::string ts(defaultValue);
00245 boost::posix_time::time_duration td(boost::posix_time::duration_from_string(ts));
00246 defaultValue= boost::lexical_cast<std::string>(td.total_seconds());
00247 return;
00248 }
00249
00250 boost::regex date_regex("(0000|-00)");
00251
00252 if (regex_search(defaultValue, date_regex, flags))
00253 {
00254 defaultIsNull= true;
00255 defaultValue="";
00256 }
00257 }
00258
00259
00260 bool DrizzleDumpTableMySQL::populateIndexes()
00261 {
00262 drizzle_result_st *result;
00263 drizzle_row_t row;
00264 std::string query;
00265 std::string lastKey;
00266 bool firstIndex= true;
00267 DrizzleDumpIndex *index;
00268
00269 if (verbose)
00270 std::cerr << _("-- Retrieving indexes for ") << tableName << "..." << std::endl;
00271
00272 query="SHOW INDEXES FROM ";
00273 query.append(tableName);
00274
00275 result= dcon->query(query);
00276
00277 if (result == NULL)
00278 return false;
00279
00280 while ((row= drizzle_row_next(result)))
00281 {
00282 std::string indexName(row[2]);
00283 if (indexName.compare(lastKey) != 0)
00284 {
00285 if (strcmp(row[10], "FULLTEXT") == 0)
00286 continue;
00287
00288 if (!firstIndex)
00289 indexes.push_back(index);
00290 index = new DrizzleDumpIndexMySQL(indexName, dcon);
00291 index->isPrimary= (strcmp(row[2], "PRIMARY") == 0);
00292 index->isUnique= (strcmp(row[1], "0") == 0);
00293 index->isHash= (strcmp(row[10], "HASH") == 0);
00294 lastKey= row[2];
00295 firstIndex= false;
00296 }
00297 uint32_t length= (row[7]) ? boost::lexical_cast<uint32_t>(row[7]) : 0;
00298 index->columns.push_back(std::make_pair(row[4], length));
00299 }
00300 if (!firstIndex)
00301 indexes.push_back(index);
00302
00303 dcon->freeResult(result);
00304 return true;
00305 }
00306
00307 bool DrizzleDumpTableMySQL::populateFkeys()
00308 {
00309 drizzle_result_st *result;
00310 drizzle_row_t row;
00311 std::string query;
00312 DrizzleDumpForeignKey *fkey;
00313
00314 if (verbose)
00315 std::cerr << _("-- Retrieving foreign keys for ") << tableName << "..." << std::endl;
00316
00317 query= "SHOW CREATE TABLE `";
00318 query.append(database->databaseName);
00319 query.append("`.`");
00320 query.append(tableName);
00321 query.append("`");
00322 result= dcon->query(query);
00323
00324 if (result == NULL)
00325 return false;
00326
00327 if ((row= drizzle_row_next(result)))
00328 {
00329 boost::match_flag_type flags = boost::match_default;
00330 boost::regex constraint_regex("CONSTRAINT `(.*?)` FOREIGN KEY \\((.*?)\\) REFERENCES `(.*?)` \\((.*?)\\)( ON (UPDATE|DELETE) (CASCADE|RESTRICT|SET NULL))?( ON (UPDATE|DELETE) (CASCADE|RESTRICT|SET NULL))?");
00331
00332 boost::match_results<std::string::const_iterator> constraint_results;
00333
00334 std::string search_body(row[1]);
00335 std::string::const_iterator start, end;
00336 start= search_body.begin();
00337 end= search_body.end();
00338 while (regex_search(start, end, constraint_results, constraint_regex, flags))
00339 {
00340 fkey= new DrizzleDumpForeignKey(constraint_results[1], dcon);
00341 fkey->parentColumns= constraint_results[2];
00342 fkey->childTable= constraint_results[3];
00343 fkey->childColumns= constraint_results[4];
00344
00345 if (constraint_results[5].compare("") != 0)
00346 {
00347 if (constraint_results[6].compare("UPDATE") == 0)
00348 fkey->updateRule= constraint_results[7];
00349 else if (constraint_results[6].compare("DELETE") == 0)
00350 fkey->deleteRule= constraint_results[7];
00351 }
00352 if (constraint_results[8].compare("") != 0)
00353 {
00354 if (constraint_results[9].compare("UPDATE") == 0)
00355 fkey->updateRule= constraint_results[10];
00356 else if (constraint_results[9].compare("DELETE") == 0)
00357 fkey->deleteRule= constraint_results[10];
00358 }
00359 fkey->matchOption= "";
00360
00361 fkeys.push_back(fkey);
00362
00363 start= constraint_results[0].second;
00364 flags |= boost::match_prev_avail;
00365 flags |= boost::match_not_bob;
00366 }
00367 }
00368 dcon->freeResult(result);
00369 return true;
00370 }
00371
00372 void DrizzleDumpFieldMySQL::setType(const char* raw_type, const char* raw_collation)
00373 {
00374 std::string old_type(raw_type);
00375 std::string extra;
00376 size_t pos;
00377
00378 if (((pos= old_type.find("(")) != std::string::npos) or
00379 ((pos= old_type.find(" ")) != std::string::npos))
00380 {
00381 extra= old_type.substr(pos);
00382 old_type.erase(pos, std::string::npos);
00383 }
00384
00385 std::transform(old_type.begin(), old_type.end(), old_type.begin(), ::toupper);
00386 if ((old_type.find("CHAR") != std::string::npos) or
00387 (old_type.find("TEXT") != std::string::npos))
00388 setCollate(raw_collation);
00389
00390 if ((old_type.compare("BIGINT") == 0) and
00391 ((extra.find("unsigned") != std::string::npos)))
00392 {
00393 rangeCheck= true;
00394 }
00395
00396 if ((old_type.compare("INT") == 0) and
00397 ((extra.find("unsigned") != std::string::npos)))
00398 {
00399 type= "BIGINT";
00400 return;
00401 }
00402
00403 if ((old_type.compare("TINYINT") == 0) or
00404 (old_type.compare("SMALLINT") == 0) or
00405 (old_type.compare("MEDIUMINT") == 0))
00406 {
00407 type= "INT";
00408 return;
00409 }
00410
00411 if ((old_type.compare("TINYBLOB") == 0) or
00412 (old_type.compare("MEDIUMBLOB") == 0) or
00413 (old_type.compare("LONGBLOB") == 0))
00414 {
00415 type= "BLOB";
00416 return;
00417 }
00418
00419 if ((old_type.compare("TINYTEXT") == 0) or
00420 (old_type.compare("MEDIUMTEXT") == 0) or
00421 (old_type.compare("LONGTEXT") == 0) or
00422 (old_type.compare("SET") == 0))
00423 {
00424 type= "TEXT";
00425 return;
00426 }
00427
00428 if (old_type.compare("CHAR") == 0)
00429 {
00430 type= "VARCHAR";
00431 return;
00432 }
00433
00434 if (old_type.compare("BINARY") == 0)
00435 {
00436 type= "VARBINARY";
00437
00438 return;
00439 }
00440
00441 if (old_type.compare("ENUM") == 0)
00442 {
00443 type= old_type;
00444
00445 enumValues= extra.substr(1, extra.length()-2);
00446 return;
00447 }
00448
00449 if ((old_type.find("TIME") != std::string::npos) or
00450 (old_type.find("DATE") != std::string::npos))
00451 {
00452
00453
00454 convertDateTime= true;
00455 isNull= true;
00456 }
00457
00458 if ((old_type.compare("TIME") == 0) or (old_type.compare("YEAR") == 0))
00459 {
00460 type= "INT";
00461 return;
00462 }
00463
00464 if (old_type.compare("FLOAT") == 0)
00465 {
00466 type= "DOUBLE";
00467 return;
00468 }
00469
00470 if (old_type.compare("BIT") == 0)
00471 {
00472 type= "VARBINARY";
00473 return;
00474 }
00475
00476 type= old_type;
00477 return;
00478 }
00479
00480 void DrizzleDumpTableMySQL::setEngine(const char* newEngine)
00481 {
00482 if ((strcmp(newEngine, "MyISAM") == 0) || (strcmp(newEngine, "MEMORY") == 0))
00483 engineName= "InnoDB";
00484 else
00485 engineName= newEngine;
00486 }
00487
00488 DrizzleDumpData* DrizzleDumpTableMySQL::getData(void)
00489 {
00490 try
00491 {
00492 return new DrizzleDumpDataMySQL(this, dcon);
00493 }
00494 catch(...)
00495 {
00496 return NULL;
00497 }
00498 }
00499
00500 void DrizzleDumpDatabaseMySQL::setCollate(const char* newCollate)
00501 {
00502 if (newCollate)
00503 {
00504 std::string tmpCollate(newCollate);
00505 if (tmpCollate.find("utf8") != std::string::npos)
00506 {
00507 collate= tmpCollate;
00508 return;
00509 }
00510 }
00511 collate= "utf8_general_ci";
00512 }
00513
00514 void DrizzleDumpTableMySQL::setCollate(const char* newCollate)
00515 {
00516 if (newCollate)
00517 {
00518 std::string tmpCollate(newCollate);
00519 if (tmpCollate.find("utf8") != std::string::npos)
00520 {
00521 collate= tmpCollate;
00522 return;
00523 }
00524 }
00525
00526 collate= "utf8_general_ci";
00527 }
00528
00529 void DrizzleDumpFieldMySQL::setCollate(const char* newCollate)
00530 {
00531 if (newCollate)
00532 {
00533 std::string tmpCollate(newCollate);
00534 if (tmpCollate.find("utf8") != std::string::npos)
00535 {
00536 collation= tmpCollate;
00537 return;
00538 }
00539 }
00540 collation= "utf8_general_ci";
00541 }
00542
00543 DrizzleDumpDataMySQL::DrizzleDumpDataMySQL(DrizzleDumpTable *dataTable,
00544 DrizzleDumpConnection *connection)
00545 : DrizzleDumpData(dataTable, connection)
00546 {
00547 std::string query;
00548 query= "SELECT * FROM `";
00549 query.append(table->displayName);
00550 query.append("`");
00551
00552 result= dcon->query(query);
00553 if (result == NULL)
00554 throw std::exception();
00555 }
00556
00557 DrizzleDumpDataMySQL::~DrizzleDumpDataMySQL()
00558 {
00559 drizzle_result_free(result);
00560 delete result;
00561 }
00562
00563 long DrizzleDumpDataMySQL::convertTime(const char* oldTime) const
00564 {
00565 std::string ts(oldTime);
00566 boost::posix_time::time_duration td(boost::posix_time::duration_from_string(ts));
00567 long seconds= td.total_seconds();
00568 return seconds;
00569 }
00570
00571 std::string DrizzleDumpDataMySQL::convertDate(const char* oldDate) const
00572 {
00573 boost::match_flag_type flags = boost::match_default;
00574 std::string output;
00575 boost::regex date_regex("(0000|-00)");
00576
00577 if (not regex_search(oldDate, date_regex, flags))
00578 {
00579 output.push_back('\'');
00580 output.append(oldDate);
00581 output.push_back('\'');
00582 }
00583 else
00584 output= "NULL";
00585
00586 return output;
00587 }
00588
00589 std::string DrizzleDumpDataMySQL::checkDateTime(const char* item, uint32_t field) const
00590 {
00591 std::string ret;
00592
00593 if (table->fields[field]->convertDateTime)
00594 {
00595 if (table->fields[field]->type.compare("INT") == 0)
00596 ret= boost::lexical_cast<std::string>(convertTime(item));
00597 else
00598 ret= convertDate(item);
00599 }
00600 return ret;
00601 }
00602