Drizzled Public API Documentation

drizzledump.cc

00001 /* Copyright 2000-2008 MySQL AB, 2008, 2009 Sun Microsystems, Inc.
00002  * Copyright (C) 2010 Vijay Samuel
00003  * Copyright (C) 2010 Andrew Hutchings
00004 
00005   This program is free software; you can redistribute it and/or modify
00006   it under the terms of the GNU General Public License as published by
00007   the Free Software Foundation; version 2 of the License.
00008 
00009   This program is distributed in the hope that it will be useful,
00010   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012   GNU General Public License for more details.
00013 
00014   You should have received a copy of the GNU General Public License
00015   along with this program; if not, write to the Free Software
00016   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
00017 
00018 /* drizzledump.cc  - Dump a tables contents and format to an ASCII file
00019 
00020  * Derived from mysqldump, which originally came from:
00021  **
00022  ** The author's original notes follow :-
00023  **
00024  ** AUTHOR: Igor Romanenko (igor@frog.kiev.ua)
00025  ** DATE:   December 3, 1994
00026  ** WARRANTY: None, expressed, impressed, implied
00027  **          or other
00028  ** STATUS: Public domain
00029 
00030  * and more work by Monty, Jani & Sinisa
00031  * and all the MySQL developers over the years.
00032 */
00033 
00034 #include "client_priv.h"
00035 #include <string>
00036 #include <iostream>
00037 #include <stdarg.h>
00038 #include <boost/unordered_set.hpp>
00039 #include <algorithm>
00040 #include <fstream>
00041 #include <drizzled/gettext.h>
00042 #include <drizzled/configmake.h>
00043 #include <drizzled/error.h>
00044 #include <boost/program_options.hpp>
00045 #include <boost/regex.hpp>
00046 #include <boost/date_time/posix_time/posix_time.hpp>
00047 #include "drizzledump_data.h"
00048 #include "drizzledump_mysql.h"
00049 #include "drizzledump_drizzle.h"
00050 
00051 using namespace std;
00052 using namespace drizzled;
00053 namespace po= boost::program_options;
00054 
00055 /* Exit codes */
00056 
00057 #define EX_USAGE 1
00058 #define EX_DRIZZLEERR 2
00059 #define EX_EOF 5 /* ferror for output file was got */
00060 
00061 bool  verbose= false;
00062 static bool use_drizzle_protocol= false;
00063 bool ignore_errors= false;
00064 static bool flush_logs= false;
00065 static bool create_options= true; 
00066 static bool opt_quoted= false;
00067 bool opt_databases= false; 
00068 bool opt_alldbs= false; 
00069 static bool opt_lock_all_tables= false;
00070 static bool opt_dump_date= true;
00071 bool opt_autocommit= false; 
00072 static bool opt_single_transaction= false; 
00073 static bool opt_comments;
00074 static bool opt_compact;
00075 bool opt_ignore= false;
00076 bool opt_drop_database;
00077 bool opt_no_create_info;
00078 bool opt_no_data= false;
00079 bool opt_create_db= false;
00080 bool opt_disable_keys= true;
00081 bool extended_insert= true;
00082 bool opt_replace_into= false;
00083 bool opt_drop= true; 
00084 bool opt_data_is_mangled= false;
00085 uint32_t show_progress_size= 0;
00086 static string insert_pat;
00087 static uint32_t opt_drizzle_port= 0;
00088 static int first_error= 0;
00089 static string extended_row;
00090 FILE *md_result_file= 0;
00091 FILE *stderror_file= 0;
00092 std::vector<DrizzleDumpDatabase*> database_store;
00093 DrizzleDumpConnection* db_connection;
00094 DrizzleDumpConnection* destination_connection;
00095 
00096 enum destinations {
00097   DESTINATION_DB,
00098   DESTINATION_FILES,
00099   DESTINATION_STDOUT
00100 };
00101 
00102 int opt_destination= DESTINATION_STDOUT;
00103 std::string opt_destination_host;
00104 uint16_t opt_destination_port;
00105 std::string opt_destination_user;
00106 std::string opt_destination_password;
00107 std::string opt_destination_database;
00108 
00109 const string progname= "drizzledump";
00110 
00111 string password,
00112   enclosed,
00113   escaped,
00114   current_host,
00115   path,
00116   current_user,
00117   opt_password,
00118   opt_protocol,
00119   where;
00120 
00121 boost::unordered_set<string> ignore_table;
00122 
00123 void maybe_exit(int error);
00124 static void die(int error, const char* reason, ...);
00125 static void write_header(char *db_name);
00126 static int dump_selected_tables(const string &db, const vector<string> &table_names);
00127 static int dump_databases(const vector<string> &db_names);
00128 static int dump_all_databases(void);
00129 int get_server_type();
00130 void dump_all_tables(void);
00131 void generate_dump(void);
00132 void generate_dump_db(void);
00133 
00134 void dump_all_tables(void)
00135 {
00136   std::vector<DrizzleDumpDatabase*>::iterator i;
00137   for (i= database_store.begin(); i != database_store.end(); ++i)
00138   {
00139     if ((not (*i)->populateTables()) && (not ignore_errors))
00140       maybe_exit(EX_DRIZZLEERR);
00141   }
00142 }
00143 
00144 void generate_dump(void)
00145 {
00146   std::vector<DrizzleDumpDatabase*>::iterator i;
00147 
00148   if (path.empty())
00149   {
00150     cout << endl << "SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;"
00151       << endl << "SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;" << endl;
00152   }
00153 
00154   if (opt_autocommit)
00155     cout << "SET AUTOCOMMIT=0;" << endl;
00156 
00157   for (i= database_store.begin(); i != database_store.end(); ++i)
00158   {
00159     DrizzleDumpDatabase *database= *i;
00160     cout << *database;
00161   }
00162 
00163   if (path.empty())
00164   {
00165     cout << "SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;"
00166       << endl << "SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;" << endl;
00167   }
00168 }
00169 
00170 void generate_dump_db(void)
00171 {
00172   std::vector<DrizzleDumpDatabase*>::iterator i;
00173   DrizzleStringBuf sbuf(1024);
00174   try
00175   {
00176     destination_connection= new DrizzleDumpConnection(opt_destination_host,
00177       opt_destination_port, opt_destination_user, opt_destination_password,
00178       false);
00179   }
00180   catch (std::exception&)
00181   {
00182     cerr << "Could not connect to destination database server" << endl;
00183     maybe_exit(EX_DRIZZLEERR);
00184   }
00185   sbuf.setConnection(destination_connection);
00186   std::ostream sout(&sbuf);
00187   sout.exceptions(ios_base::badbit);
00188 
00189   if (path.empty())
00190   {
00191     sout << "SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;" << endl;
00192     sout << "SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;" << endl;
00193   }
00194 
00195   if (opt_autocommit)
00196     cout << "SET AUTOCOMMIT=0;" << endl;
00197 
00198   for (i= database_store.begin(); i != database_store.end(); ++i)
00199   {
00200     try
00201     {
00202       DrizzleDumpDatabase *database= *i;
00203       sout << *database;
00204     }
00205     catch (std::exception&)
00206     {
00207       std::cout << _("Error inserting into destination database") << std::endl;
00208       if (not ignore_errors)
00209         maybe_exit(EX_DRIZZLEERR);
00210     }
00211   }
00212 
00213   if (path.empty())
00214   {
00215     sout << "SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;" << endl;
00216     sout << "SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;" << endl;
00217   }
00218 }
00219 
00220 /*
00221   exit with message if ferror(file)
00222 
00223   SYNOPSIS
00224   check_io()
00225   file        - checked file
00226 */
00227 
00228 static void check_io(FILE *file)
00229 {
00230   if (ferror(file))
00231     die(EX_EOF, _("Got errno %d on write"), errno);
00232 }
00233 
00234 static void write_header(char *db_name)
00235 {
00236   if ((not opt_compact) and (opt_comments))
00237   {
00238     cout << "-- drizzledump " << VERSION << " libdrizzle "
00239       << drizzle_version() << ", for " << HOST_VENDOR << "-" << HOST_OS
00240       << " (" << HOST_CPU << ")" << endl << "--" << endl;
00241     cout << "-- Host: " << current_host << "    Database: " << db_name << endl;
00242     cout << "-- ------------------------------------------------------" << endl;
00243     cout << "-- Server version\t" << db_connection->getServerVersion();
00244     if (db_connection->getServerType() == ServerDetect::SERVER_MYSQL_FOUND)
00245       cout << " (MySQL server)";
00246     else if (db_connection->getServerType() == ServerDetect::SERVER_DRIZZLE_FOUND)
00247       cout << " (Drizzle server)";
00248     cout << endl << endl;
00249   }
00250 
00251 } /* write_header */
00252 
00253 
00254 static void write_footer(FILE *sql_file)
00255 {
00256   if (! opt_compact)
00257   {
00258     if (opt_comments)
00259     {
00260       if (opt_dump_date)
00261       {
00262         boost::posix_time::ptime time(boost::posix_time::second_clock::local_time());
00263         fprintf(sql_file, "-- Dump completed on %s\n",
00264           boost::posix_time::to_simple_string(time).c_str());
00265       }
00266       else
00267         fprintf(sql_file, "-- Dump completed\n");
00268     }
00269     check_io(sql_file);
00270   }
00271 } /* write_footer */
00272 
00273 static int get_options(void)
00274 {
00275   if (opt_single_transaction && opt_lock_all_tables)
00276   {
00277     fprintf(stderr, _("%s: You can't use --single-transaction and "
00278                       "--lock-all-tables at the same time.\n"), progname.c_str());
00279     return(EX_USAGE);
00280   }
00281   if ((opt_databases || opt_alldbs) && ! path.empty())
00282   {
00283     fprintf(stderr,
00284             _("%s: --databases or --all-databases can't be used with --tab.\n"),
00285             progname.c_str());
00286     return(EX_USAGE);
00287   }
00288 
00289   if (tty_password)
00290     opt_password=client_get_tty_password(NULL);
00291   return(0);
00292 } /* get_options */
00293 
00294 
00295 /*
00296   Prints out an error message and kills the process.
00297 
00298   SYNOPSIS
00299   die()
00300   error_num   - process return value
00301   fmt_reason  - a format string for use by vsnprintf.
00302   ...         - variable arguments for above fmt_reason string
00303 
00304   DESCRIPTION
00305   This call prints out the formatted error message to stderr and then
00306   terminates the process.
00307 */
00308 static void die(int error_num, const char* fmt_reason, ...)
00309 {
00310   char buffer[1000];
00311   va_list args;
00312   va_start(args,fmt_reason);
00313   vsnprintf(buffer, sizeof(buffer), fmt_reason, args);
00314   va_end(args);
00315 
00316   fprintf(stderr, "%s: %s\n", progname.c_str(), buffer);
00317   fflush(stderr);
00318 
00319   ignore_errors= 0; /* force the exit */
00320   maybe_exit(error_num);
00321 }
00322 
00323 static void free_resources(void)
00324 {
00325   if (md_result_file && md_result_file != stdout)
00326     fclose(md_result_file);
00327   opt_password.erase();
00328 }
00329 
00330 
00331 void maybe_exit(int error)
00332 {
00333   if (!first_error)
00334     first_error= error;
00335   if (ignore_errors)
00336     return;
00337   delete db_connection;
00338   delete destination_connection;
00339   free_resources();
00340   exit(error);
00341 }
00342 
00343 static int dump_all_databases()
00344 {
00345   drizzle_row_t row;
00346   drizzle_result_st *tableres;
00347   int result=0;
00348   std::string query;
00349   DrizzleDumpDatabase *database;
00350 
00351   if (verbose)
00352     std::cerr << _("-- Retrieving database structures...") << std::endl;
00353 
00354   /* Blocking the MySQL privilege tables too because we can't import them due to bug#646187 */
00355   if (db_connection->getServerType() == ServerDetect::SERVER_MYSQL_FOUND)
00356     query= "SELECT SCHEMA_NAME, DEFAULT_COLLATION_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME NOT IN ('information_schema', 'performance_schema', 'mysql')";
00357   else
00358     query= "SELECT SCHEMA_NAME, DEFAULT_COLLATION_NAME FROM DATA_DICTIONARY.SCHEMAS WHERE SCHEMA_NAME NOT IN ('information_schema','data_dictionary')";
00359 
00360   tableres= db_connection->query(query);
00361   while ((row= drizzle_row_next(tableres)))
00362   {
00363     std::string database_name(row[0]);
00364     if (db_connection->getServerType() == ServerDetect::SERVER_MYSQL_FOUND)
00365       database= new DrizzleDumpDatabaseMySQL(database_name, db_connection);
00366     else
00367       database= new DrizzleDumpDatabaseDrizzle(database_name, db_connection);
00368 
00369     database->setCollate(row[1]);
00370     database_store.push_back(database);
00371   }
00372   db_connection->freeResult(tableres);
00373   return result;
00374 }
00375 /* dump_all_databases */
00376 
00377 
00378 static int dump_databases(const vector<string> &db_names)
00379 {
00380   int result=0;
00381   string temp;
00382   DrizzleDumpDatabase *database;
00383 
00384   for (vector<string>::const_iterator it= db_names.begin(); it != db_names.end(); ++it)
00385   {
00386     temp= *it;
00387     if (db_connection->getServerType() == ServerDetect::SERVER_MYSQL_FOUND)
00388       database= new DrizzleDumpDatabaseMySQL(temp, db_connection);
00389     else
00390       database= new DrizzleDumpDatabaseDrizzle(temp, db_connection);
00391     database_store.push_back(database);
00392   }
00393   return(result);
00394 } /* dump_databases */
00395 
00396 static int dump_selected_tables(const string &db, const vector<string> &table_names)
00397 {
00398   DrizzleDumpDatabase *database;
00399 
00400   if (db_connection->getServerType() == ServerDetect::SERVER_MYSQL_FOUND)
00401     database= new DrizzleDumpDatabaseMySQL(db, db_connection);
00402   else
00403     database= new DrizzleDumpDatabaseDrizzle(db, db_connection);
00404 
00405   if (not database->populateTables(table_names))
00406   {
00407     delete database;
00408     if (not ignore_errors)
00409       maybe_exit(EX_DRIZZLEERR);
00410   }
00411 
00412   database_store.push_back(database); 
00413 
00414   return 0;
00415 } /* dump_selected_tables */
00416 
00417 static int do_flush_tables_read_lock()
00418 {
00419   /*
00420     We do first a FLUSH TABLES. If a long update is running, the FLUSH TABLES
00421     will wait but will not stall the whole mysqld, and when the long update is
00422     done the FLUSH TABLES WITH READ LOCK will start and succeed quickly. So,
00423     FLUSH TABLES is to lower the probability of a stage where both drizzled
00424     and most client connections are stalled. Of course, if a second long
00425     update starts between the two FLUSHes, we have that bad stall.
00426   */
00427 
00428    db_connection->queryNoResult("FLUSH TABLES");
00429    db_connection->queryNoResult("FLUSH TABLES WITH READ LOCK");
00430 
00431   return 0;
00432 }
00433 
00434 static int start_transaction()
00435 {
00436   db_connection->queryNoResult("SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ");
00437   db_connection->queryNoResult("START TRANSACTION WITH CONSISTENT SNAPSHOT");
00438 
00439   if (db_connection->getServerType() == ServerDetect::SERVER_DRIZZLE_FOUND)
00440   {
00441     drizzle_result_st *result;
00442     drizzle_row_t row;
00443     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)");
00444     result= db_connection->query(query);
00445     if ((row= drizzle_row_next(result)))
00446     {
00447       cout << "-- SYS_REPLICATION_LOG: COMMIT_ID = " << row[0] << ", ID = " << row[1] << endl << endl;
00448     }
00449     db_connection->freeResult(result);
00450   }
00451 
00452   return 0;
00453 }
00454 
00455 int main(int argc, char **argv)
00456 {
00457 try
00458 {
00459   int exit_code;
00460 
00461 #if defined(ENABLE_NLS)
00462 # if defined(HAVE_LOCALE_H)
00463   setlocale(LC_ALL, "");
00464 # endif
00465   bindtextdomain("drizzle7", LOCALEDIR);
00466   textdomain("drizzle7");
00467 #endif
00468 
00469   po::options_description commandline_options(_("Options used only in command line"));
00470   commandline_options.add_options()
00471   ("all-databases,A", po::value<bool>(&opt_alldbs)->default_value(false)->zero_tokens(),
00472   _("Dump all the databases. This will be same as --databases with all databases selected."))
00473   ("flush-logs,F", po::value<bool>(&flush_logs)->default_value(false)->zero_tokens(),
00474   _("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"))
00475   ("force,f", po::value<bool>(&ignore_errors)->default_value(false)->zero_tokens(),
00476   _("Continue even if we get an sql-error."))
00477   ("help,?", _("Display this help message and exit."))
00478   ("lock-all-tables,x", po::value<bool>(&opt_lock_all_tables)->default_value(false)->zero_tokens(),
00479   _("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."))
00480   ("single-transaction", po::value<bool>(&opt_single_transaction)->default_value(false)->zero_tokens(),
00481   _("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."))
00482   ("skip-opt", 
00483   _("Disable --opt. Disables --add-drop-table, --add-locks, --create-options, ---extended-insert and --disable-keys."))    
00484   ("tables", _("Overrides option --databases (-B)."))
00485   ("show-progress-size", po::value<uint32_t>(&show_progress_size)->default_value(10000),
00486   _("Number of rows before each output progress report (requires --verbose)."))
00487   ("verbose,v", po::value<bool>(&verbose)->default_value(false)->zero_tokens(),
00488   _("Print info about the various stages."))
00489   ("version,V", _("Output version information and exit."))
00490   ("skip-comments", _("Turn off Comments"))
00491   ("skip-create", _("Turn off create-options"))
00492   ("skip-extended-insert", _("Turn off extended-insert"))
00493   ("skip-dump-date", _( "Turn off dump date at the end of the output"))
00494   ("no-defaults", _("Do not read from the configuration files"))
00495   ;
00496 
00497   po::options_description dump_options(_("Options specific to the drizzle client"));
00498   dump_options.add_options()
00499   ("add-drop-database", po::value<bool>(&opt_drop_database)->default_value(false)->zero_tokens(),
00500   _("Add a 'DROP DATABASE' before each create."))
00501   ("skip-drop-table", _("Do not add a 'drop table' before each create."))
00502   ("compact", po::value<bool>(&opt_compact)->default_value(false)->zero_tokens(),
00503   _("Give less verbose output (useful for debugging). Disables structure comments and header/footer constructs.  Enables options --skip-add-drop-table --no-set-names --skip-disable-keys"))
00504   ("databases,B", po::value<bool>(&opt_databases)->default_value(false)->zero_tokens(),
00505   _("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."))
00506   ("skip-disable-keys,K",
00507   _("'ALTER TABLE tb_name DISABLE KEYS;' and 'ALTER TABLE tb_name ENABLE KEYS;' will not be put in the output."))
00508   ("ignore-table", po::value<string>(),
00509   _("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"))
00510   ("insert-ignore", po::value<bool>(&opt_ignore)->default_value(false)->zero_tokens(),
00511   _("Insert rows with INSERT IGNORE."))
00512   ("no-autocommit", po::value<bool>(&opt_autocommit)->default_value(false)->zero_tokens(),
00513   _("Wrap a table's data in START TRANSACTION/COMMIT statements."))
00514   ("no-create-db,n", po::value<bool>(&opt_create_db)->default_value(false)->zero_tokens(),
00515   _("'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."))
00516   ("no-data,d", po::value<bool>(&opt_no_data)->default_value(false)->zero_tokens(),
00517   _("No row information."))
00518   ("replace", po::value<bool>(&opt_replace_into)->default_value(false)->zero_tokens(),
00519   _("Use REPLACE INTO instead of INSERT INTO."))
00520   ("destination-type", po::value<string>()->default_value("stdout"),
00521   _("Where to send output to (stdout|database"))
00522   ("destination-host", po::value<string>(&opt_destination_host)->default_value("localhost"),
00523   _("Hostname for destination db server (requires --destination-type=database)"))
00524   ("destination-port", po::value<uint16_t>(&opt_destination_port)->default_value(4427),
00525   _("Port number for destination db server (requires --destination-type=database)"))
00526   ("destination-user", po::value<string>(&opt_destination_user),
00527   _("User name for destination db server (resquires --destination-type=database)"))
00528   ("destination-password", po::value<string>(&opt_destination_password),
00529   _("Password for destination db server (requires --destination-type=database)"))
00530   ("destination-database", po::value<string>(&opt_destination_database),
00531   _("The database in the destination db server (requires --destination-type=database, not for use with --all-databases)"))
00532   ("my-data-is-mangled", po::value<bool>(&opt_data_is_mangled)->default_value(false)->zero_tokens(),
00533   _("Do not make a UTF8 connection to MySQL, use if you have UTF8 data in a non-UTF8 table"))
00534   ;
00535 
00536   const char* unix_user= getlogin();
00537 
00538   po::options_description client_options(_("Options specific to the client"));
00539   client_options.add_options()
00540   ("host,h", po::value<string>(&current_host)->default_value("localhost"),
00541   _("Connect to host."))
00542   ("password,P", po::value<string>(&password)->default_value(PASSWORD_SENTINEL),
00543   _("Password to use when connecting to server. If password is not given it's solicited on the tty."))
00544   ("port,p", po::value<uint32_t>(&opt_drizzle_port)->default_value(0),
00545   _("Port number to use for connection."))
00546   ("user,u", po::value<string>(&current_user)->default_value((unix_user ? unix_user : "")),
00547   _("User for login if not current user."))
00548   ("protocol",po::value<string>(&opt_protocol)->default_value("mysql"),
00549   _("The protocol of connection (mysql or drizzle)."))
00550   ;
00551 
00552   po::options_description hidden_options(_("Hidden Options"));
00553   hidden_options.add_options()
00554   ("database-used", po::value<vector<string> >(), _("Used to select the database"))
00555   ("Table-used", po::value<vector<string> >(), _("Used to select the tables"))
00556   ;
00557 
00558   po::options_description all_options(_("Allowed Options + Hidden Options"));
00559   all_options.add(commandline_options).add(dump_options).add(client_options).add(hidden_options);
00560 
00561   po::options_description long_options(_("Allowed Options"));
00562   long_options.add(commandline_options).add(dump_options).add(client_options);
00563 
00564   std::string system_config_dir_dump(SYSCONFDIR); 
00565   system_config_dir_dump.append("/drizzle/drizzledump.cnf");
00566 
00567   std::string system_config_dir_client(SYSCONFDIR); 
00568   system_config_dir_client.append("/drizzle/client.cnf");
00569 
00570   std::string user_config_dir((getenv("XDG_CONFIG_HOME")? getenv("XDG_CONFIG_HOME"):"~/.config"));
00571 
00572   if (user_config_dir.compare(0, 2, "~/") == 0)
00573   {
00574     char *homedir;
00575     homedir= getenv("HOME");
00576     if (homedir != NULL)
00577       user_config_dir.replace(0, 1, homedir);
00578   }
00579 
00580   po::positional_options_description p;
00581   p.add("database-used", 1);
00582   p.add("Table-used",-1);
00583 
00584   md_result_file= stdout;
00585 
00586   po::variables_map vm;
00587 
00588   // Disable allow_guessing
00589   int style = po::command_line_style::default_style & ~po::command_line_style::allow_guessing;
00590 
00591   po::store(po::command_line_parser(argc, argv).style(style).
00592             options(all_options).positional(p).
00593             extra_parser(parse_password_arg).run(), vm);
00594 
00595   if (! vm.count("no-defaults"))
00596   {
00597     std::string user_config_dir_dump(user_config_dir);
00598     user_config_dir_dump.append("/drizzle/drizzledump.cnf"); 
00599 
00600     std::string user_config_dir_client(user_config_dir);
00601     user_config_dir_client.append("/drizzle/client.cnf");
00602 
00603     ifstream user_dump_ifs(user_config_dir_dump.c_str());
00604     po::store(parse_config_file(user_dump_ifs, dump_options), vm);
00605 
00606     ifstream user_client_ifs(user_config_dir_client.c_str());
00607     po::store(parse_config_file(user_client_ifs, client_options), vm);
00608 
00609     ifstream system_dump_ifs(system_config_dir_dump.c_str());
00610     po::store(parse_config_file(system_dump_ifs, dump_options), vm);
00611 
00612     ifstream system_client_ifs(system_config_dir_client.c_str());
00613     po::store(parse_config_file(system_client_ifs, client_options), vm);
00614   }
00615 
00616   po::notify(vm);  
00617   
00618   if ((not vm.count("database-used") && not vm.count("Table-used") 
00619     && not opt_alldbs && path.empty())
00620     || (vm.count("help")) || vm.count("version"))
00621   {
00622     printf(_("Drizzledump %s build %s, for %s-%s (%s)\n"),
00623       drizzle_version(), VERSION, HOST_VENDOR, HOST_OS, HOST_CPU);
00624     if (vm.count("version"))
00625       exit(0);
00626     puts("");
00627     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"));
00628     puts(_("Dumps definitions and data from a Drizzle database server"));
00629     printf(_("Usage: %s [OPTIONS] database [tables]\n"), progname.c_str());
00630     printf(_("OR     %s [OPTIONS] --databases [OPTIONS] DB1 [DB2 DB3...]\n"),
00631           progname.c_str());
00632     printf(_("OR     %s [OPTIONS] --all-databases [OPTIONS]\n"), progname.c_str());
00633     cout << long_options;
00634     if (vm.count("help"))
00635       exit(0);
00636     else
00637       exit(1);
00638   }
00639 
00640   /* Inverted Booleans */
00641 
00642   opt_drop= (vm.count("skip-drop-table")) ? false : true;
00643   opt_comments= (vm.count("skip-comments")) ? false : true;
00644   extended_insert= (vm.count("skip-extended-insert")) ? false : true;
00645   opt_dump_date= (vm.count("skip-dump-date")) ? false : true;
00646   opt_disable_keys= (vm.count("skip-disable-keys")) ? false : true;
00647   opt_quoted= (vm.count("skip-quote-names")) ? false : true;
00648 
00649   if (vm.count("protocol"))
00650   {
00651     std::transform(opt_protocol.begin(), opt_protocol.end(),
00652       opt_protocol.begin(), ::tolower);
00653 
00654     if (not opt_protocol.compare("mysql"))
00655       use_drizzle_protocol=false;
00656     else if (not opt_protocol.compare("drizzle"))
00657       use_drizzle_protocol=true;
00658     else
00659     {
00660       cout << _("Error: Unknown protocol") << " '" << opt_protocol << "'" << endl;
00661       exit(-1);
00662     }
00663   }
00664 
00665   if (vm.count("port"))
00666   {
00667     /* If the port number is > 65535 it is not a valid port
00668      *        This also helps with potential data loss casting unsigned long to a
00669      *               uint32_t. 
00670      */
00671     if (opt_drizzle_port > 65535)
00672     {
00673       fprintf(stderr, _("Value supplied for port is not valid.\n"));
00674       exit(-1);
00675     }
00676   }
00677 
00678   if(vm.count("password"))
00679   {
00680     if (!opt_password.empty())
00681       opt_password.erase();
00682     if (password == PASSWORD_SENTINEL)
00683     {
00684       opt_password= "";
00685     }
00686     else
00687     {
00688       opt_password= password;
00689       tty_password= false;
00690     }
00691   }
00692   else
00693   {
00694       tty_password= true;
00695   }
00696 
00697   if (! path.empty())
00698   { 
00699     opt_disable_keys= 0;
00700   }
00701 
00702   if (vm.count("skip-opt"))
00703   {
00704     extended_insert= opt_drop= create_options= 0;
00705     opt_disable_keys= 0;
00706   }
00707 
00708   if (opt_compact)
00709   { 
00710     opt_comments= opt_drop= opt_disable_keys= 0;
00711   }
00712 
00713   if (vm.count("opt"))
00714   {
00715     extended_insert= opt_drop= create_options= 1;
00716     opt_disable_keys= 1;
00717   }
00718 
00719   if (vm.count("tables"))
00720   { 
00721     opt_databases= false;
00722   }
00723 
00724   if (vm.count("ignore-table"))
00725   {
00726     if (!strchr(vm["ignore-table"].as<string>().c_str(), '.'))
00727     {
00728       fprintf(stderr, _("Illegal use of option --ignore-table=<database>.<table>\n"));
00729       exit(EXIT_ARGUMENT_INVALID);
00730     }
00731     string tmpptr(vm["ignore-table"].as<string>());
00732     ignore_table.insert(tmpptr); 
00733   }
00734 
00735   if (vm.count("skip-create"))
00736   {
00737     opt_create_db= opt_no_create_info= create_options= false;
00738   }
00739  
00740   exit_code= get_options();
00741   if (exit_code)
00742   {
00743     free_resources();
00744     exit(exit_code);
00745   }
00746   try
00747   {
00748     db_connection = new DrizzleDumpConnection(current_host, opt_drizzle_port,
00749       current_user, opt_password, use_drizzle_protocol);
00750   }
00751   catch (std::exception&)
00752   {
00753     maybe_exit(EX_DRIZZLEERR);
00754   }
00755 
00756   if ((db_connection->getServerType() == ServerDetect::SERVER_MYSQL_FOUND) and (not opt_data_is_mangled))
00757     db_connection->queryNoResult("SET NAMES 'utf8'");
00758 
00759   if (vm.count("destination-type"))
00760   {
00761     string tmp_destination(vm["destination-type"].as<string>());
00762     if (tmp_destination.compare("database") == 0)
00763       opt_destination= DESTINATION_DB;
00764     else if (tmp_destination.compare("stdout") == 0)
00765       opt_destination= DESTINATION_STDOUT;
00766     else
00767       exit(EXIT_ARGUMENT_INVALID);
00768   }
00769 
00770 
00771   if (path.empty() && vm.count("database-used"))
00772   {
00773     string database_used= *vm["database-used"].as< vector<string> >().begin();
00774     write_header((char *)database_used.c_str());
00775   }
00776 
00777   if ((opt_lock_all_tables) && do_flush_tables_read_lock())
00778     goto err;
00779   if (opt_single_transaction && start_transaction())
00780     goto err;
00781   if (opt_lock_all_tables)
00782     db_connection->queryNoResult("FLUSH LOGS");
00783 
00784   if (opt_alldbs)
00785   {
00786     dump_all_databases();
00787     dump_all_tables();
00788   }
00789   if (vm.count("database-used") && vm.count("Table-used") && ! opt_databases)
00790   {
00791     string database_used= *vm["database-used"].as< vector<string> >().begin();
00792     /* Only one database and selected table(s) */
00793     dump_selected_tables(database_used, vm["Table-used"].as< vector<string> >());
00794   }
00795 
00796   if (vm.count("Table-used") and opt_databases)
00797   {
00798     vector<string> database_used= vm["database-used"].as< vector<string> >();
00799     vector<string> table_used= vm["Table-used"].as< vector<string> >();
00800 
00801     for (vector<string>::iterator it= table_used.begin();
00802        it != table_used.end();
00803        ++it)
00804     {
00805       database_used.insert(database_used.end(), *it);
00806     }
00807 
00808     dump_databases(database_used);
00809     dump_all_tables();
00810   }
00811 
00812   if (vm.count("database-used") && ! vm.count("Table-used"))
00813   {
00814     dump_databases(vm["database-used"].as< vector<string> >());
00815     dump_all_tables();
00816   }
00817 
00818   if (opt_destination == DESTINATION_STDOUT)
00819     generate_dump();
00820   else
00821     generate_dump_db();
00822 
00823   /* ensure dumped data flushed */
00824   if (md_result_file && fflush(md_result_file))
00825   {
00826     if (!first_error)
00827       first_error= EX_DRIZZLEERR;
00828     goto err;
00829   }
00830 
00831   /*
00832     No reason to explicitely COMMIT the transaction, neither to explicitely
00833     UNLOCK TABLES: these will be automatically be done by the server when we
00834     disconnect now. Saves some code here, some network trips, adds nothing to
00835     server.
00836   */
00837 err:
00838   delete db_connection;
00839   delete destination_connection;
00840   if (path.empty())
00841     write_footer(md_result_file);
00842   free_resources();
00843 
00844   if (stderror_file)
00845     fclose(stderror_file);
00846 }
00847 
00848   catch(exception &err)
00849   {
00850     cerr << err.what() << endl;
00851   }
00852   
00853   return(first_error);
00854 } /* main */