00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <config.h>
00021
00022 #include "client/drizzledump_data.h"
00023 #include "client/client_priv.h"
00024 #include <drizzled/definitions.h>
00025 #include <drizzled/gettext.h>
00026 #include <string>
00027 #include <iostream>
00028 #include <boost/unordered_set.hpp>
00029 #include <boost/lexical_cast.hpp>
00030
00031 #define EX_DRIZZLEERR 2
00032
00033 extern bool opt_no_create_info;
00034 extern bool opt_no_data;
00035 extern bool opt_create_db;
00036 extern bool opt_disable_keys;
00037 extern bool extended_insert;
00038 extern bool opt_replace_into;
00039 extern bool opt_drop;
00040 extern bool verbose;
00041 extern bool opt_databases;
00042 extern bool opt_alldbs;
00043 extern uint32_t show_progress_size;
00044 extern bool opt_ignore;
00045 extern bool opt_compress;
00046 extern bool opt_drop_database;
00047 extern bool opt_autocommit;
00048 extern bool ignore_errors;
00049 extern std::string opt_destination_database;
00050
00051 extern boost::unordered_set<std::string> ignore_table;
00052 extern void maybe_exit(int error);
00053
00054 enum destinations {
00055 DESTINATION_DB,
00056 DESTINATION_FILES,
00057 DESTINATION_STDOUT
00058 };
00059
00060 extern int opt_destination;
00061
00062
00063 bool DrizzleDumpDatabase::ignoreTable(std::string tableName)
00064 {
00065 return ignore_table.find(databaseName + "." + tableName) == ignore_table.end();
00066 }
00067
00068 void DrizzleDumpDatabase::cleanTableName(std::string &tableName)
00069 {
00070 std::string replace("``");
00071 std::string find("`");
00072 size_t j = 0;
00073 for (;(j = tableName.find(find, j)) != std::string::npos;)
00074 {
00075 tableName.replace(j, find.length(), replace);
00076 j+= replace.length();
00077 }
00078
00079 }
00080
00081 std::ostream& operator <<(std::ostream &os, const DrizzleDumpForeignKey &obj)
00082 {
00083 os << " CONSTRAINT `" << obj.constraintName << "` FOREIGN KEY ("
00084 << obj.parentColumns << ") REFERENCES `" << obj.childTable << "` ("
00085 << obj.childColumns << ")";
00086
00087 if (not obj.deleteRule.empty())
00088 os << " ON DELETE " << obj.deleteRule;
00089
00090 if (not obj.updateRule.empty())
00091 os << " ON UPDATE " << obj.updateRule;
00092
00093 return os;
00094 }
00095
00096 std::ostream& operator <<(std::ostream &os, const DrizzleDumpIndex &obj)
00097 {
00098 if (obj.isPrimary)
00099 {
00100 os << " PRIMARY KEY ";
00101 }
00102 else if (obj.isUnique)
00103 {
00104 os << " UNIQUE KEY `" << obj.indexName << "` ";
00105 }
00106 else
00107 {
00108 os << " KEY `" << obj.indexName << "` ";
00109 }
00110
00111 os << "(";
00112
00113 std::vector<DrizzleDumpIndex::columnData>::iterator i;
00114 std::vector<DrizzleDumpIndex::columnData> fields = obj.columns;
00115 for (i= fields.begin(); i != fields.end(); ++i)
00116 {
00117 if (i != fields.begin())
00118 os << ",";
00119 os << "`" << (*i).first << "`";
00120 if ((*i).second > 0)
00121 os << "(" << (*i).second << ")";
00122 }
00123
00124 os << ")";
00125
00126 return os;
00127 }
00128
00129 std::ostream& operator <<(std::ostream &os, const DrizzleDumpField &obj)
00130 {
00131 os << " `" << obj.fieldName << "` ";
00132 os << obj.type;
00133 if (((obj.type.compare("VARCHAR") == 0) or
00134 (obj.type.compare("VARBINARY") == 0)) and
00135 (obj.length > 0))
00136 {
00137 os << "(" << obj.length << ")";
00138 }
00139 else if (((obj.type.compare("DECIMAL") == 0) or
00140 (obj.type.compare("DOUBLE") == 0)) and
00141 ((obj.decimalPrecision + obj.decimalScale) > 0))
00142 {
00143 os << "(" << obj.decimalPrecision << "," << obj.decimalScale << ")";
00144 }
00145 else if (obj.type.compare("ENUM") == 0)
00146 {
00147 os << "(" << obj.enumValues << ")";
00148 }
00149
00150 if (not obj.isNull)
00151 {
00152 os << " NOT NULL";
00153 }
00154
00155 if ((not obj.collation.empty()) and (obj.collation.compare("binary") != 0))
00156 {
00157 os << " COLLATE " << obj.collation;
00158 }
00159
00160 if (obj.isAutoIncrement)
00161 os << " AUTO_INCREMENT";
00162
00163 if (not obj.defaultValue.empty())
00164 {
00165 if (obj.defaultValue.compare("CURRENT_TIMESTAMP") != 0)
00166 {
00167 if (obj.defaultValue.compare(0, 2, "b'") == 0)
00168 {
00169 os << " DEFAULT " << obj.defaultValue;
00170 }
00171 else
00172 {
00173 os << " DEFAULT '" << obj.defaultValue << "'";
00174 }
00175 }
00176 else
00177 {
00178 os << " DEFAULT CURRENT_TIMESTAMP";
00179 }
00180 }
00181 else if ((obj.defaultIsNull))
00182 {
00183 os << " DEFAULT NULL";
00184 }
00185
00186 if (not obj.comment.empty())
00187 {
00188 os << " COMMENT '" << DrizzleDumpData::escape(obj.comment.c_str(), obj.comment.length()) << "'";
00189 }
00190
00191 return os;
00192 }
00193
00194 std::ostream& operator <<(std::ostream &os, const DrizzleDumpDatabase &obj)
00195 {
00196 if ((opt_destination == DESTINATION_DB) or opt_databases or opt_alldbs)
00197 {
00198 if (verbose)
00199 {
00200 std::cerr << "--" << std::endl
00201 << "-- Current Database: `" << obj.databaseName << "`" << std::endl
00202 << "--" << std::endl << std::endl;
00203 }
00204
00205
00206 if (not opt_create_db)
00207 {
00208 if (opt_drop_database)
00209 {
00210 os << "DROP DATABASE IF EXISTS `"
00211 << ((opt_destination_database.empty()) ? obj.databaseName
00212 : opt_destination_database) << "`" << std::endl;
00213 }
00214
00215 os << "CREATE DATABASE IF NOT EXISTS `"
00216 << ((opt_destination_database.empty()) ? obj.databaseName
00217 : opt_destination_database) << "`";
00218 if (not obj.collate.empty())
00219 os << " COLLATE = " << obj.collate;
00220
00221 os << ";" << std::endl << std::endl;
00222 }
00223 os << "USE `" << ((opt_destination_database.empty()) ? obj.databaseName
00224 : opt_destination_database) << "`;" << std::endl << std::endl;
00225 }
00226
00227 std::vector<DrizzleDumpTable*>::iterator i;
00228 std::vector<DrizzleDumpTable*> output_tables = obj.tables;
00229 for (i= output_tables.begin(); i != output_tables.end(); ++i)
00230 {
00231 DrizzleDumpTable *table= *i;
00232 if (not opt_no_create_info)
00233 os << *table;
00234 if (not opt_no_data)
00235 {
00236 obj.dcon->setDB(obj.databaseName);
00237 DrizzleDumpData *data= table->getData();
00238 if (data == NULL)
00239 {
00240 std::cerr << "Error: Could not get data for table " << table->displayName << std::endl;
00241 if (not ignore_errors)
00242 maybe_exit(EX_DRIZZLEERR);
00243 else
00244 continue;
00245 }
00246 os << *data;
00247 delete data;
00248 }
00249 }
00250
00251 return os;
00252 }
00253
00254
00255 std::ostream& operator <<(std::ostream &os, const DrizzleDumpData &obj)
00256 {
00257 bool new_insert= true;
00258 bool first= true;
00259 uint64_t rownr= 0;
00260 size_t byte_counter= 0;
00261
00262 drizzle_row_t row;
00263
00264 if (verbose)
00265 std::cerr << _("-- Retrieving data for ") << obj.table->displayName << "..." << std::endl;
00266
00267 if (drizzle_result_row_count(obj.result) < 1)
00268 {
00269 if (verbose)
00270 {
00271 std::cerr << "--" << std::endl
00272 << "-- No data to dump for table `" << obj.table->displayName << "`"
00273 << std::endl << "--" << std::endl << std::endl;
00274 }
00275 return os;
00276 }
00277 else if (verbose)
00278 {
00279 std::cerr << "--" << std::endl
00280 << "-- Dumping data for table `" << obj.table->displayName << "`"
00281 << std::endl << "--" << std::endl << std::endl;
00282 }
00283 if (opt_disable_keys)
00284 os << "ALTER TABLE `" << obj.table->displayName << "` DISABLE KEYS;" << std::endl;
00285
00286
00287 if (opt_autocommit)
00288 os << "START TRANSACTION;" << std::endl;
00289
00290 while((row= drizzle_row_next(obj.result)))
00291 {
00292 rownr++;
00293 if (verbose and (rownr % show_progress_size) == 0)
00294 {
00295 std::cerr << "-- " << rownr << _(" rows dumped for table ") << obj.table->displayName << std::endl;
00296 }
00297
00298 size_t* row_sizes= drizzle_row_field_sizes(obj.result);
00299 for (uint32_t i= 0; i < drizzle_result_column_count(obj.result); i++)
00300 byte_counter+= row_sizes[i];
00301
00302 if (not first and not new_insert)
00303 {
00304 if (extended_insert)
00305 os << "),(";
00306 else
00307 os << ");" << std::endl;
00308 byte_counter+= 3;
00309 }
00310 else
00311 first= false;
00312
00313 if (new_insert)
00314 {
00315 if (opt_replace_into)
00316 os << "REPLACE ";
00317 else
00318 {
00319 os << "INSERT ";
00320 if (opt_ignore)
00321 os << "IGNORE ";
00322 }
00323 os << "INTO `" << obj.table->displayName << "` VALUES (";
00324 byte_counter+= 28 + obj.table->displayName.length();
00325 if (extended_insert)
00326 new_insert= false;
00327 }
00328 for (uint32_t i= 0; i < drizzle_result_column_count(obj.result); i++)
00329 {
00330 if (not row[i])
00331 {
00332 os << "NULL";
00333 if (i != obj.table->fields.size() - 1)
00334 os << ",";
00335 continue;
00336 }
00337
00338 if ((obj.table->fields[i]->rangeCheck) and
00339 (obj.table->fields[i]->type.compare("BIGINT") == 0) and
00340 (boost::lexical_cast<uint64_t>(row[i]) > INT64_MAX))
00341 {
00342 std::cerr << "Error: Data for column " << obj.table->fields[i]->fieldName << " is greater than max BIGINT, cannot migrate automatically" << std::endl;
00343 if (not ignore_errors)
00344 maybe_exit(EX_DRIZZLEERR);
00345 else
00346 continue;
00347 }
00348
00349
00350 else if (obj.table->fields[i]->convertDateTime)
00351 {
00352 os << obj.checkDateTime(row[i], i);
00353 }
00354 else
00355 {
00356 if ((obj.table->fields[i]->type.compare("INT") != 0) and
00357 (obj.table->fields[i]->type.compare("BIGINT") != 0))
00358 {
00359
00360 if (((obj.table->fields[i]->type.compare("BLOB") == 0) or
00361 (obj.table->fields[i]->type.compare("VARBINARY") == 0)))
00362 {
00363 os << obj.convertHex((unsigned char*)row[i], row_sizes[i]);
00364 byte_counter+= row_sizes[i];
00365 }
00366 else if ((obj.table->fields[i]->type.compare("ENUM") == 0) and
00367 (strcmp(row[i], "") == 0))
00368 {
00369 os << "NULL";
00370 }
00371 else if (obj.table->fields[i]->type.compare("BOOLEAN") == 0)
00372 {
00373 if (strncmp(row[i], "1", 1) == 0)
00374 os << "TRUE";
00375 else
00376 os << "FALSE";
00377 }
00378 else
00379 os << "'" << DrizzleDumpData::escape(row[i], row_sizes[i]) << "'";
00380 byte_counter+= 3;
00381 }
00382 else
00383 os << row[i];
00384 }
00385 if (i != obj.table->fields.size() - 1)
00386 os << ",";
00387 }
00388
00389 if ((extended_insert and
00390 (byte_counter >= DRIZZLE_MAX_LINE_LENGTH)) or (not extended_insert))
00391 {
00392 os << ");" << std::endl;
00393 new_insert= true;
00394 byte_counter= 0;
00395 }
00396 }
00397 if (not new_insert)
00398 os << ");" << std::endl;
00399
00400 if (opt_autocommit)
00401 os << "COMMIT;" << std::endl;
00402
00403 if (opt_disable_keys)
00404 os << "ALTER TABLE `" << obj.table->tableName << "` ENABLE KEYS;" << std::endl;
00405
00406 os << std::endl;
00407
00408 return os;
00409 }
00410
00411 std::string DrizzleDumpData::convertHex(const unsigned char* from, size_t from_size) const
00412 {
00413 std::ostringstream output;
00414 if (from_size > 0)
00415 output << "0x";
00416 else
00417 output << "''";
00418
00419 while (from_size > 0)
00420 {
00421
00422 output << std::uppercase << std::hex << std::setw(2) << std::setfill('0') << (unsigned short)(*from);
00423 (void) *from++;
00424 from_size--;
00425 }
00426
00427 return output.str();
00428 }
00429
00430
00431 std::string DrizzleDumpData::escape(const char* from, size_t from_size)
00432 {
00433 std::string output;
00434
00435 while (from_size > 0)
00436 {
00437 if (!(*from & 0x80))
00438 {
00439 switch (*from)
00440 {
00441 case 0:
00442 output.append("\\0");
00443 break;
00444 case '\n':
00445 output.append("\\n");
00446 break;
00447 case '\r':
00448 output.append("\\r");
00449 break;
00450 case '\\':
00451 output.append("\\\\");
00452 break;
00453 case '\'':
00454 output.append("\\'");
00455 break;
00456 case '"':
00457 output.append("\\\"");
00458 break;
00459 case '\032':
00460 output.append("\\Z");
00461 break;
00462 default:
00463 output.push_back(*from);
00464 break;
00465 }
00466 }
00467 else
00468 output.push_back(*from);
00469 (void) *from++;
00470 from_size--;
00471 }
00472
00473 return output;
00474 }
00475
00476 std::ostream& operator <<(std::ostream &os, const DrizzleDumpTable &obj)
00477 {
00478 if (verbose)
00479 {
00480 std::cerr << "--" << std::endl
00481 << "-- Table structure for table `" << obj.displayName << "`" << std::endl
00482 << "--" << std::endl << std::endl;
00483 }
00484
00485 if (opt_drop)
00486 os << "DROP TABLE IF EXISTS `" << obj.displayName << "`;" << std::endl;
00487
00488 os << "CREATE TABLE `" << obj.displayName << "` (" << std::endl;
00489 std::vector<DrizzleDumpField*>::iterator i;
00490 std::vector<DrizzleDumpField*> output_fields = obj.fields;
00491 for (i= output_fields.begin(); i != output_fields.end(); ++i)
00492 {
00493 if (i != output_fields.begin())
00494 os << "," << std::endl;
00495 DrizzleDumpField *field= *i;
00496 os << *field;
00497 }
00498
00499 std::vector<DrizzleDumpIndex*>::iterator j;
00500 std::vector<DrizzleDumpIndex*> output_indexes = obj.indexes;
00501 for (j= output_indexes.begin(); j != output_indexes.end(); ++j)
00502 {
00503 os << "," << std::endl;
00504 DrizzleDumpIndex *index= *j;
00505 os << *index;
00506 }
00507
00508 std::vector<DrizzleDumpForeignKey*>::iterator k;
00509 std::vector<DrizzleDumpForeignKey*> output_fkeys = obj.fkeys;
00510 for (k= output_fkeys.begin(); k != output_fkeys.end(); ++k)
00511 {
00512 os << "," << std::endl;
00513 DrizzleDumpForeignKey *fkey= *k;
00514 os << *fkey;
00515 }
00516
00517 os << std::endl;
00518 os << ") ENGINE='" << obj.engineName << "' ";
00519 if (obj.autoIncrement > 0)
00520 {
00521 os << "AUTO_INCREMENT=" << obj.autoIncrement << " ";
00522 }
00523
00524 os << "COLLATE='" << obj.collate << "'";
00525
00526 if (not obj.comment.empty())
00527 {
00528 os << " COMMENT='" << obj.comment << "'";
00529 }
00530
00531 if (not obj.replicate)
00532 {
00533 os << " REPLICATE=FALSE";
00534 }
00535
00536 os << ";" << std::endl << std::endl;
00537
00538 return os;
00539 }
00540
00541 DrizzleDumpConnection::DrizzleDumpConnection(std::string &host, uint16_t port,
00542 std::string &username, std::string &password, bool drizzle_protocol) :
00543 hostName(host),
00544 drizzleProtocol(drizzle_protocol)
00545 {
00546 if (host.empty())
00547 {
00548 host= "localhost";
00549 }
00550
00551 std::string protocol= (drizzle_protocol) ? "Drizzle" : "MySQL";
00552 if (verbose)
00553 {
00554 std::cerr << _("-- Connecting to ") << host << _(" using protocol ")
00555 << protocol << "..." << std::endl;
00556 }
00557
00558 drizzle= drizzle_create();
00559
00560 if (drizzle == NULL)
00561 {
00562 std::cerr << "drizzle_create() failed" << std::endl;
00563 }
00564
00565 connection= drizzle_con_create(drizzle);
00566 drizzle_con_set_tcp(connection, (char *)host.c_str(), port);
00567 drizzle_con_set_auth(connection, (char *)username.c_str(), (char *)password.c_str());
00568 drizzle_con_add_options(connection, drizzle_protocol ? DRIZZLE_CON_EXPERIMENTAL : DRIZZLE_CON_MYSQL);
00569
00570 drizzle_return_t ret= drizzle_con_connect(connection);
00571 if (ret != DRIZZLE_RETURN_OK)
00572 {
00573 errorHandler(NULL, ret, "when trying to connect");
00574 throw std::exception();
00575 }
00576
00577 ServerDetect server_detect= ServerDetect(connection);
00578
00579 serverType= server_detect.getServerType();
00580 serverVersion= server_detect.getServerVersion();
00581 }
00582
00583 drizzle_result_st* DrizzleDumpConnection::query(std::string &str_query)
00584 {
00585 drizzle_return_t ret;
00586 drizzle_result_st* result= new drizzle_result_st;
00587 if (drizzle_query_str(connection, result, str_query.c_str(), &ret) == NULL or
00588 ret != DRIZZLE_RETURN_OK)
00589 {
00590 if (ret == DRIZZLE_RETURN_ERROR_CODE)
00591 {
00592 std::cerr << _("Error executing query: ") <<
00593 drizzle_result_error(result) << std::endl;
00594 drizzle_result_free(result);
00595 }
00596 else
00597 {
00598 std::cerr << _("Error executing query: ") << drizzle_con_error(connection) << std::endl;
00599 }
00600 return NULL;
00601 }
00602
00603 if (drizzle_result_buffer(result) != DRIZZLE_RETURN_OK)
00604 {
00605 std::cerr << _("Could not buffer result: ") << drizzle_con_error(connection) << std::endl;
00606 return NULL;
00607 }
00608 return result;
00609 }
00610
00611 void DrizzleDumpConnection::freeResult(drizzle_result_st* result)
00612 {
00613 drizzle_result_free(result);
00614 delete result;
00615 }
00616
00617 bool DrizzleDumpConnection::queryNoResult(std::string &str_query)
00618 {
00619 drizzle_return_t ret;
00620 drizzle_result_st result;
00621
00622 if (drizzle_query_str(connection, &result, str_query.c_str(), &ret) == NULL or
00623 ret != DRIZZLE_RETURN_OK)
00624 {
00625 if (ret == DRIZZLE_RETURN_ERROR_CODE)
00626 {
00627 std::cerr << _("Error executing query: ") <<
00628 drizzle_result_error(&result) << std::endl;
00629 drizzle_result_free(&result);
00630 }
00631 else
00632 {
00633 std::cerr << _("Error executing query: ") << drizzle_con_error(connection) << std::endl;
00634 }
00635 return false;
00636 }
00637
00638 drizzle_result_free(&result);
00639 return true;
00640 }
00641
00642 bool DrizzleDumpConnection::setDB(std::string databaseName)
00643 {
00644 drizzle_return_t ret;
00645 drizzle_result_st result;
00646
00647 if (drizzle_select_db(connection, &result, databaseName.c_str(), &ret) == NULL or
00648 ret != DRIZZLE_RETURN_OK)
00649 {
00650 std::cerr << _("Error: Could not set db '") << databaseName << "'" << std::endl;
00651 if (ret == DRIZZLE_RETURN_ERROR_CODE)
00652 {
00653 drizzle_result_free(&result);
00654 }
00655
00656 return false;
00657 }
00658 drizzle_result_free(&result);
00659
00660 return true;
00661 }
00662
00663 void DrizzleDumpConnection::errorHandler(drizzle_result_st *res,
00664 drizzle_return_t ret, const char *when)
00665 {
00666 if (res == NULL)
00667 {
00668 std::cerr << _("Got error: ") << drizzle_con_error(connection) << " " << when << std::endl;
00669 }
00670 else if (ret == DRIZZLE_RETURN_ERROR_CODE)
00671 {
00672 std::cerr << _("Got error: ") << drizzle_result_error(res)
00673 << " (" << drizzle_result_error_code(res) << ") " << when << std::endl;
00674 drizzle_result_free(res);
00675 }
00676 else
00677 {
00678 std::cerr << _("Got error: ") << ret << " " << when << std::endl;
00679 }
00680
00681 return;
00682 }
00683
00684 DrizzleDumpConnection::~DrizzleDumpConnection()
00685 {
00686 if (verbose)
00687 {
00688 std::cerr << _("-- Disconnecting from ") << hostName << "..." << std::endl;
00689 }
00690
00691 drizzle_con_free(connection);
00692 drizzle_free(drizzle);
00693 }