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