34 #include "client_priv.h"
38 #include <boost/unordered_set.hpp>
41 #include <drizzled/gettext.h>
42 #include <drizzled/configmake.h>
43 #include <drizzled/error.h>
44 #include <boost/program_options.hpp>
45 #include <boost/regex.hpp>
46 #include <boost/date_time/posix_time/posix_time.hpp>
48 #include "client/drizzledump_data.h"
49 #include "client/drizzledump_mysql.h"
50 #include "client/drizzledump_drizzle.h"
52 #include "user_detect.h"
55 using namespace drizzled;
56 namespace po= boost::program_options;
61 #define EX_DRIZZLEERR 2
65 static bool use_drizzle_protocol=
false;
66 bool ignore_errors=
false;
67 static bool flush_logs=
false;
68 static bool create_options=
true;
69 static bool opt_quoted=
false;
70 bool opt_databases=
false;
71 bool opt_alldbs=
false;
72 static bool opt_lock_all_tables=
false;
73 static bool opt_dump_date=
true;
74 bool opt_autocommit=
false;
75 static bool opt_single_transaction=
false;
76 static bool opt_comments;
77 static bool opt_compact;
78 bool opt_ignore=
false;
79 bool opt_drop_database;
80 bool opt_no_create_info;
81 bool opt_no_data=
false;
82 bool opt_create_db=
false;
83 bool opt_disable_keys=
true;
84 bool extended_insert=
true;
85 bool opt_replace_into=
false;
87 bool opt_data_is_mangled=
false;
88 uint32_t show_progress_size= 0;
89 static string insert_pat;
90 static uint32_t opt_drizzle_port= 0;
91 static int first_error= 0;
92 static string extended_row;
93 FILE *md_result_file= 0;
94 FILE *stderror_file= 0;
95 std::vector<DrizzleDumpDatabase*> database_store;
105 int opt_destination= DESTINATION_STDOUT;
106 std::string opt_destination_host;
107 uint16_t opt_destination_port;
108 std::string opt_destination_user;
109 std::string opt_destination_password;
110 std::string opt_destination_database;
112 const string progname=
"drizzledump";
124 boost::unordered_set<string> ignore_table;
126 void maybe_exit(
int error);
127 static void die(
int error,
const char* reason, ...);
128 static void write_header(
char *db_name);
129 static int dump_selected_tables(
const string &db,
const vector<string> &table_names);
130 static int dump_databases(
const vector<string> &db_names);
131 static int dump_all_databases(
void);
132 int get_server_type();
133 void dump_all_tables(
void);
134 void generate_dump(
void);
135 void generate_dump_db(
void);
137 void dump_all_tables(
void)
139 std::vector<DrizzleDumpDatabase*>::iterator i;
140 for (i= database_store.begin(); i != database_store.end(); ++i)
142 if ((not (*i)->populateTables()) && (not ignore_errors))
143 maybe_exit(EX_DRIZZLEERR);
147 void generate_dump(
void)
149 std::vector<DrizzleDumpDatabase*>::iterator i;
153 cout << endl <<
"SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;"
154 << endl <<
"SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;" << endl;
158 cout <<
"SET AUTOCOMMIT=0;" << endl;
160 for (i= database_store.begin(); i != database_store.end(); ++i)
168 cout <<
"SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;"
169 << endl <<
"SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;" << endl;
173 void generate_dump_db(
void)
175 std::vector<DrizzleDumpDatabase*>::iterator i;
180 opt_destination_port, opt_destination_user, opt_destination_password,
183 catch (std::exception&)
185 cerr <<
"Could not connect to destination database server" << endl;
186 maybe_exit(EX_DRIZZLEERR);
188 sbuf.setConnection(destination_connection);
189 std::ostream sout(&sbuf);
190 sout.exceptions(ios_base::badbit);
194 sout <<
"SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;" << endl;
195 sout <<
"SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;" << endl;
199 cout <<
"SET AUTOCOMMIT=0;" << endl;
201 for (i= database_store.begin(); i != database_store.end(); ++i)
208 catch (std::exception&)
210 std::cout << _(
"Error inserting into destination database") << std::endl;
211 if (not ignore_errors)
212 maybe_exit(EX_DRIZZLEERR);
218 sout <<
"SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;" << endl;
219 sout <<
"SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;" << endl;
231 static void check_io(FILE *file)
234 die(EX_EOF, _(
"Got errno %d on write"), errno);
237 static void write_header(
char *db_name)
239 if ((not opt_compact) and (opt_comments))
241 cout <<
"-- drizzledump " << VERSION <<
" libdrizzle "
242 << drizzle_version() <<
", for " << HOST_VENDOR <<
"-" << HOST_OS
243 <<
" (" << HOST_CPU <<
")" << endl <<
"--" << endl;
244 cout <<
"-- Host: " << current_host <<
" Database: " << db_name << endl;
245 cout <<
"-- ------------------------------------------------------" << endl;
246 cout <<
"-- Server version\t" << db_connection->getServerVersion();
247 if (db_connection->getServerType() == ServerDetect::SERVER_MYSQL_FOUND)
248 cout <<
" (MySQL server)";
249 else if (db_connection->getServerType() == ServerDetect::SERVER_DRIZZLE_FOUND)
250 cout <<
" (Drizzle server)";
251 cout << endl << endl;
257 static void write_footer(FILE *sql_file)
265 boost::posix_time::ptime time(boost::posix_time::second_clock::local_time());
266 fprintf(sql_file,
"-- Dump completed on %s\n",
267 boost::posix_time::to_simple_string(time).c_str());
270 fprintf(sql_file,
"-- Dump completed\n");
276 static int get_options(
void)
278 if (opt_single_transaction && opt_lock_all_tables)
280 fprintf(stderr, _(
"%s: You can't use --single-transaction and "
281 "--lock-all-tables at the same time.\n"), progname.c_str());
284 if ((opt_databases || opt_alldbs) && ! path.empty())
287 _(
"%s: --databases or --all-databases can't be used with --tab.\n"),
293 opt_password=client_get_tty_password(NULL);
311 static void die(
int error_num,
const char* fmt_reason, ...)
315 va_start(args,fmt_reason);
316 vsnprintf(buffer,
sizeof(buffer), fmt_reason, args);
319 fprintf(stderr,
"%s: %s\n", progname.c_str(), buffer);
323 maybe_exit(error_num);
326 static void free_resources(
void)
328 if (md_result_file && md_result_file != stdout)
329 fclose(md_result_file);
330 opt_password.erase();
334 void maybe_exit(
int error)
340 delete db_connection;
341 delete destination_connection;
346 static int dump_all_databases()
349 drizzle_result_st *tableres;
355 std::cerr << _(
"-- Retrieving database structures...") << std::endl;
358 if (db_connection->getServerType() == ServerDetect::SERVER_MYSQL_FOUND)
359 query=
"SELECT SCHEMA_NAME, DEFAULT_COLLATION_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME NOT IN ('information_schema', 'performance_schema', 'mysql')";
361 query=
"SELECT SCHEMA_NAME, DEFAULT_COLLATION_NAME FROM DATA_DICTIONARY.SCHEMAS WHERE SCHEMA_NAME NOT IN ('information_schema','data_dictionary')";
363 tableres= db_connection->query(query);
364 while ((row= drizzle_row_next(tableres)))
366 std::string database_name(row[0]);
367 if (db_connection->getServerType() == ServerDetect::SERVER_MYSQL_FOUND)
372 database->setCollate(row[1]);
373 database_store.push_back(database);
375 db_connection->freeResult(tableres);
381 static int dump_databases(
const vector<string> &db_names)
387 for (vector<string>::const_iterator it= db_names.begin(); it != db_names.end(); ++it)
390 if (db_connection->getServerType() == ServerDetect::SERVER_MYSQL_FOUND)
394 database_store.push_back(database);
399 static int dump_selected_tables(
const string &db,
const vector<string> &table_names)
403 if (db_connection->getServerType() == ServerDetect::SERVER_MYSQL_FOUND)
408 if (not database->populateTables(table_names))
411 if (not ignore_errors)
412 maybe_exit(EX_DRIZZLEERR);
415 database_store.push_back(database);
420 static int do_flush_tables_read_lock()
431 db_connection->queryNoResult(
"FLUSH TABLES");
432 db_connection->queryNoResult(
"FLUSH TABLES WITH READ LOCK");
437 static int start_transaction()
439 db_connection->queryNoResult(
"SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ");
440 db_connection->queryNoResult(
"START TRANSACTION WITH CONSISTENT SNAPSHOT");
442 if (db_connection->getServerType() == ServerDetect::SERVER_DRIZZLE_FOUND)
444 drizzle_result_st *result;
446 std::string query(
"SELECT COMMIT_ID, ID FROM DATA_DICTIONARY.SYS_REPLICATION_LOG WHERE COMMIT_ID=(SELECT MAX(COMMIT_ID) FROM DATA_DICTIONARY.SYS_REPLICATION_LOG)");
447 result= db_connection->query(query);
448 if ((row= drizzle_row_next(result)))
450 cout <<
"-- SYS_REPLICATION_LOG: COMMIT_ID = " << row[0] <<
", ID = " << row[1] << endl << endl;
452 db_connection->freeResult(result);
458 int main(
int argc,
char **argv)
464 #if defined(ENABLE_NLS)
465 # if defined(HAVE_LOCALE_H)
466 setlocale(LC_ALL,
"");
468 bindtextdomain(
"drizzle", LOCALEDIR);
469 textdomain(
"drizzle");
472 po::options_description commandline_options(_(
"Options used only in command line"));
473 commandline_options.add_options()
474 (
"all-databases,A", po::value<bool>(&opt_alldbs)->default_value(
false)->zero_tokens(),
475 _(
"Dump all the databases. This will be same as --databases with all databases selected."))
476 (
"flush-logs,F", po::value<bool>(&flush_logs)->default_value(
false)->zero_tokens(),
477 _(
"Flush logs file in server before starting dump. Note that if you dump many databases at once (using the option --databases= or --all-databases), the logs will be flushed for each database dumped. The exception is when using --lock-all-tables in this case the logs will be flushed only once, corresponding to the moment all tables are locked. So if you want your dump and the log flush to happen at the same exact moment you should use --lock-all-tables or --flush-logs"))
478 (
"force,f", po::value<bool>(&ignore_errors)->default_value(
false)->zero_tokens(),
479 _(
"Continue even if we get an sql-error."))
480 (
"help,?", _(
"Display this help message and exit."))
481 (
"lock-all-tables,x", po::value<bool>(&opt_lock_all_tables)->default_value(
false)->zero_tokens(),
482 _(
"Locks all tables across all databases. This is achieved by taking a global read lock for the duration of the whole dump. Automatically turns --single-transaction off."))
483 (
"single-transaction", po::value<bool>(&opt_single_transaction)->default_value(
false)->zero_tokens(),
484 _(
"Creates a consistent snapshot by dumping all tables in a single transaction. Works ONLY for tables stored in storage engines which support multiversioning (currently only InnoDB does); the dump is NOT guaranteed to be consistent for other storage engines. While a --single-transaction dump is in process, to ensure a valid dump file (correct table contents), no other connection should use the following statements: ALTER TABLE, DROP TABLE, RENAME TABLE, TRUNCATE TABLE, as consistent snapshot is not isolated from them."))
486 _(
"Disable --opt. Disables --add-drop-table, --add-locks, --create-options, ---extended-insert and --disable-keys."))
487 (
"tables", _(
"Overrides option --databases (-B)."))
488 (
"show-progress-size", po::value<uint32_t>(&show_progress_size)->default_value(10000),
489 _(
"Number of rows before each output progress report (requires --verbose)."))
490 (
"verbose,v", po::value<bool>(&verbose)->default_value(
false)->zero_tokens(),
491 _(
"Print info about the various stages."))
492 (
"version,V", _(
"Output version information and exit."))
493 (
"skip-comments", _(
"Turn off Comments"))
494 (
"skip-create", _(
"Turn off create-options"))
495 (
"skip-extended-insert", _(
"Turn off extended-insert"))
496 (
"skip-dump-date", _(
"Turn off dump date at the end of the output"))
497 (
"no-defaults", _(
"Do not read from the configuration files"))
500 po::options_description dump_options(_(
"Options specific to the drizzle client"));
501 dump_options.add_options()
502 (
"add-drop-database", po::value<bool>(&opt_drop_database)->default_value(
false)->zero_tokens(),
503 _(
"Add a 'DROP DATABASE' before each create."))
504 (
"skip-drop-table", _(
"Do not add a 'drop table' before each create."))
505 (
"compact", po::value<bool>(&opt_compact)->default_value(
false)->zero_tokens(),
506 _(
"Give less verbose output (useful for debugging). Disables structure comments and header/footer constructs. Enables option --skip-disable-keys"))
507 (
"databases,B", po::value<bool>(&opt_databases)->default_value(
false)->zero_tokens(),
508 _(
"To dump several databases. Note the difference in usage; In this case no tables are given. All name arguments are regarded as databasenames. 'USE db_name;' will be included in the output."))
509 (
"skip-disable-keys,K",
510 _(
"'ALTER TABLE tb_name DISABLE KEYS;' and 'ALTER TABLE tb_name ENABLE KEYS;' will not be put in the output."))
511 (
"ignore-table", po::value<string>(),
512 _(
"Do not dump the specified table. To specify more than one table to ignore, use the directive multiple times, once for each table. Each table must be specified with both database and table names, e.g. --ignore-table=database.table"))
513 (
"insert-ignore", po::value<bool>(&opt_ignore)->default_value(
false)->zero_tokens(),
514 _(
"Insert rows with INSERT IGNORE."))
515 (
"no-autocommit", po::value<bool>(&opt_autocommit)->default_value(
false)->zero_tokens(),
516 _(
"Wrap a table's data in START TRANSACTION/COMMIT statements."))
517 (
"no-create-db,n", po::value<bool>(&opt_create_db)->default_value(
false)->zero_tokens(),
518 _(
"'CREATE DATABASE IF NOT EXISTS db_name;' will not be put in the output. The above line will be added otherwise, if --databases or --all-databases option was given."))
519 (
"no-data,d", po::value<bool>(&opt_no_data)->default_value(
false)->zero_tokens(),
520 _(
"No row information."))
521 (
"replace", po::value<bool>(&opt_replace_into)->default_value(
false)->zero_tokens(),
522 _(
"Use REPLACE INTO instead of INSERT INTO."))
523 (
"destination-type", po::value<string>()->default_value(
"stdout"),
524 _(
"Where to send output to (stdout|database"))
525 (
"destination-host", po::value<string>(&opt_destination_host)->default_value(
"localhost"),
526 _(
"Hostname for destination db server (requires --destination-type=database)"))
527 (
"destination-port", po::value<uint16_t>(&opt_destination_port)->default_value(4427),
528 _(
"Port number for destination db server (requires --destination-type=database)"))
529 (
"destination-user", po::value<string>(&opt_destination_user),
530 _(
"User name for destination db server (resquires --destination-type=database)"))
531 (
"destination-password", po::value<string>(&opt_destination_password),
532 _(
"Password for destination db server (requires --destination-type=database)"))
533 (
"destination-database", po::value<string>(&opt_destination_database),
534 _(
"The database in the destination db server (requires --destination-type=database, not for use with --all-databases)"))
535 (
"my-data-is-mangled", po::value<bool>(&opt_data_is_mangled)->default_value(
false)->zero_tokens(),
536 _(
"Do not make a UTF8 connection to MySQL, use if you have UTF8 data in a non-UTF8 table"))
539 po::options_description client_options(_(
"Options specific to the client"));
540 client_options.add_options()
541 (
"host,h", po::value<string>(¤t_host)->default_value(
"localhost"),
542 _(
"Connect to host."))
543 (
"password,P", po::value<string>(&password)->default_value(PASSWORD_SENTINEL),
544 _(
"Password to use when connecting to server. If password is not given it's solicited on the tty."))
545 (
"port,p", po::value<uint32_t>(&opt_drizzle_port)->default_value(0),
546 _(
"Port number to use for connection."))
547 (
"user,u", po::value<string>(¤t_user)->default_value(
UserDetect().getUser()),
548 _(
"User for login if not current user."))
549 (
"protocol",po::value<string>(&opt_protocol)->default_value(
"mysql"),
550 _(
"The protocol of connection (mysql or drizzle)."))
553 po::options_description hidden_options(_(
"Hidden Options"));
554 hidden_options.add_options()
555 (
"database-used", po::value<vector<string> >(), _(
"Used to select the database"))
556 (
"Table-used", po::value<vector<string> >(), _(
"Used to select the tables"))
559 po::options_description all_options(_(
"Allowed Options + Hidden Options"));
560 all_options.add(commandline_options).add(dump_options).add(client_options).add(hidden_options);
562 po::options_description long_options(_(
"Allowed Options"));
563 long_options.add(commandline_options).add(dump_options).add(client_options);
565 std::string system_config_dir_dump(SYSCONFDIR);
566 system_config_dir_dump.append(
"/drizzle/drizzledump.cnf");
568 std::string system_config_dir_client(SYSCONFDIR);
569 system_config_dir_client.append(
"/drizzle/client.cnf");
571 std::string user_config_dir((getenv(
"XDG_CONFIG_HOME")? getenv(
"XDG_CONFIG_HOME"):
"~/.config"));
573 if (user_config_dir.compare(0, 2,
"~/") == 0)
576 homedir= getenv(
"HOME");
578 user_config_dir.replace(0, 1, homedir);
581 po::positional_options_description p;
582 p.add(
"database-used", 1);
583 p.add(
"Table-used",-1);
585 md_result_file= stdout;
587 po::variables_map vm;
590 int style = po::command_line_style::default_style & ~po::command_line_style::allow_guessing;
592 po::store(po::command_line_parser(argc, argv).style(style).
593 options(all_options).positional(p).
594 extra_parser(parse_password_arg).run(), vm);
596 if (! vm.count(
"no-defaults"))
598 std::string user_config_dir_dump(user_config_dir);
599 user_config_dir_dump.append(
"/drizzle/drizzledump.cnf");
601 std::string user_config_dir_client(user_config_dir);
602 user_config_dir_client.append(
"/drizzle/client.cnf");
604 ifstream user_dump_ifs(user_config_dir_dump.c_str());
605 po::store(parse_config_file(user_dump_ifs, dump_options), vm);
607 ifstream user_client_ifs(user_config_dir_client.c_str());
608 po::store(parse_config_file(user_client_ifs, client_options), vm);
610 ifstream system_dump_ifs(system_config_dir_dump.c_str());
611 po::store(parse_config_file(system_dump_ifs, dump_options), vm);
613 ifstream system_client_ifs(system_config_dir_client.c_str());
614 po::store(parse_config_file(system_client_ifs, client_options), vm);
619 if ((not vm.count(
"database-used") && not vm.count(
"Table-used")
620 && not opt_alldbs && path.empty())
621 || (vm.count(
"help")) || vm.count(
"version"))
623 printf(_(
"Drizzledump %s build %s, for %s-%s (%s)\n"),
624 drizzle_version(), VERSION, HOST_VENDOR, HOST_OS, HOST_CPU);
625 if (vm.count(
"version"))
628 puts(_(
"This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n"));
629 puts(_(
"Dumps definitions and data from a Drizzle database server"));
630 printf(_(
"Usage: %s [OPTIONS] database [tables]\n"), progname.c_str());
631 printf(_(
"OR %s [OPTIONS] --databases [OPTIONS] DB1 [DB2 DB3...]\n"),
633 printf(_(
"OR %s [OPTIONS] --all-databases [OPTIONS]\n"), progname.c_str());
634 cout << long_options;
635 if (vm.count(
"help"))
643 opt_drop= not vm.count(
"skip-drop-table");
644 opt_comments= not vm.count(
"skip-comments");
645 extended_insert= not vm.count(
"skip-extended-insert");
646 opt_dump_date= not vm.count(
"skip-dump-date");
647 opt_disable_keys= not vm.count(
"skip-disable-keys");
648 opt_quoted= not vm.count(
"skip-quote-names");
650 if (vm.count(
"protocol"))
652 boost::to_lower(opt_protocol);
653 if (not opt_protocol.compare(
"mysql"))
654 use_drizzle_protocol=
false;
655 else if (not opt_protocol.compare(
"drizzle"))
656 use_drizzle_protocol=
true;
659 cout << _(
"Error: Unknown protocol") <<
" '" << opt_protocol <<
"'" << endl;
664 if (vm.count(
"port"))
670 if (opt_drizzle_port > 65535)
672 fprintf(stderr, _(
"Value supplied for port is not valid.\n"));
677 if (vm.count(
"password"))
679 if (!opt_password.empty())
680 opt_password.erase();
681 if (password == PASSWORD_SENTINEL)
687 opt_password= password;
701 if (vm.count(
"skip-opt"))
703 extended_insert= opt_drop= create_options= 0;
709 opt_comments= opt_drop= opt_disable_keys= 0;
714 extended_insert= opt_drop= create_options= 1;
718 if (vm.count(
"tables"))
720 opt_databases=
false;
723 if (vm.count(
"ignore-table"))
725 if (!strchr(vm[
"ignore-table"].as<string>().c_str(),
'.'))
727 fprintf(stderr, _(
"Illegal use of option --ignore-table=<database>.<table>\n"));
728 exit(EXIT_ARGUMENT_INVALID);
730 string tmpptr(vm[
"ignore-table"].as<string>());
731 ignore_table.insert(tmpptr);
734 if (vm.count(
"skip-create"))
736 opt_create_db= opt_no_create_info= create_options=
false;
739 exit_code= get_options();
748 current_user, opt_password, use_drizzle_protocol);
750 catch (std::exception&)
752 maybe_exit(EX_DRIZZLEERR);
755 if ((db_connection->getServerType() == ServerDetect::SERVER_MYSQL_FOUND) and (not opt_data_is_mangled))
756 db_connection->queryNoResult(
"SET NAMES 'utf8'");
758 if (vm.count(
"destination-type"))
760 string tmp_destination(vm[
"destination-type"].as<string>());
761 if (tmp_destination.compare(
"database") == 0)
762 opt_destination= DESTINATION_DB;
763 else if (tmp_destination.compare(
"stdout") == 0)
764 opt_destination= DESTINATION_STDOUT;
766 exit(EXIT_ARGUMENT_INVALID);
770 if (path.empty() && vm.count(
"database-used"))
772 string database_used= *vm[
"database-used"].as< vector<string> >().begin();
773 write_header((
char *)database_used.c_str());
776 if ((opt_lock_all_tables) && do_flush_tables_read_lock())
778 if (opt_single_transaction && start_transaction())
780 if (opt_lock_all_tables)
781 db_connection->queryNoResult(
"FLUSH LOGS");
785 dump_all_databases();
788 if (vm.count(
"database-used") && vm.count(
"Table-used") && not opt_databases)
790 string database_used= *vm[
"database-used"].as< vector<string> >().begin();
792 dump_selected_tables(database_used, vm[
"Table-used"].as< vector<string> >());
795 if (vm.count(
"Table-used") && opt_databases)
797 vector<string> database_used= vm[
"database-used"].as< vector<string> >();
798 vector<string> table_used= vm[
"Table-used"].as< vector<string> >();
800 for (vector<string>::iterator it= table_used.begin();
801 it != table_used.end();
804 database_used.insert(database_used.end(), *it);
807 dump_databases(database_used);
811 if (vm.count(
"database-used") && not vm.count(
"Table-used"))
813 dump_databases(vm[
"database-used"].as< vector<string> >());
817 if (opt_destination == DESTINATION_STDOUT)
823 if (md_result_file && fflush(md_result_file))
826 first_error= EX_DRIZZLEERR;
837 delete db_connection;
838 delete destination_connection;
840 write_footer(md_result_file);
844 fclose(stderror_file);
847 catch(exception &err)
849 cerr << err.what() << endl;