=== modified file 'client/client_priv.h' --- client/client_priv.h 2008-01-31 16:46:50 +0000 +++ client/client_priv.h 2009-12-11 08:41:04 +0000 @@ -79,6 +79,6 @@ OPT_MYSQL_REPLACE_INTO, OPT_BASE64_OUTPUT_MODE, OPT_SERVER_ID, OPT_FIX_TABLE_NAMES, OPT_FIX_DB_NAMES, OPT_SSL_VERIFY_SERVER_CERT, OPT_DEBUG_INFO, OPT_DEBUG_CHECK, OPT_COLUMN_TYPES, OPT_ERROR_LOG_FILE, - OPT_WRITE_BINLOG, OPT_DUMP_DATE, + OPT_WRITE_BINLOG, OPT_DUMP_DATE, OPT_BACKUP_BASEDIR, OPT_MAX_CLIENT_OPTION }; === modified file 'client/mysqldump.c' --- client/mysqldump.c 2009-08-28 15:06:59 +0000 +++ client/mysqldump.c 2009-12-14 01:23:33 +0000 @@ -45,6 +45,7 @@ #include #include #include +#include #include "client_priv.h" #include "mysql.h" @@ -60,6 +61,7 @@ #define EX_EOM 4 #define EX_EOF 5 /* ferror for output file was got */ #define EX_ILLEGAL_TABLE 6 +#define EX_FILEOP 7 /* index into 'show fields from table' */ @@ -110,7 +112,8 @@ *where=0, *order_by=0, *opt_compatible_mode_str= 0, *err_ptr= 0, - *log_error_file= NULL; + *log_error_file= NULL, + *opt_backup_basedir= NULL; static char **defaults_argv= 0; static char compatible_mode_normal_str[255]; /* Server supports character_set_results session variable? */ @@ -126,6 +129,7 @@ #include FILE *md_result_file= 0; FILE *stderror_file=0; +static char backup_dir[FN_REFLEN]; #ifdef HAVE_SMEM static char *shared_memory_base_name=0; @@ -175,7 +179,13 @@ TYPELIB compatible_mode_typelib= {array_elements(compatible_mode_names) - 1, "", compatible_mode_names, NULL}; +typedef struct st_db_ent { + char *database; + FILE *sql_file; +} db_entry; + HASH ignore_table; +HASH per_file_databases; static struct my_option my_long_options[] = { @@ -210,6 +220,9 @@ {"autoclose", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif + {"backup-basedir", OPT_BACKUP_BASEDIR, "Create dump files under this directory instead of writing results to stdout. One dump file is created per database. This option must be combined with --[all-]databases option. Cannot be combined with --tab option. Dump files are created under directory /backup-basedir// where num is a sequential number.", + (uchar**) &opt_backup_basedir, (uchar**) &opt_backup_basedir, 0, GET_STR, + REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"character-sets-dir", OPT_CHARSETS_DIR, "Directory where character sets are.", (uchar**) &charsets_dir, (uchar**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -690,6 +703,143 @@ return (uchar*) entry; } +static void free_db_ent(db_entry *entry) +{ + if (entry->sql_file) { + md_result_file= entry->sql_file; + write_footer(entry->sql_file); + my_fclose(entry->sql_file, MYF(0)); + entry->sql_file= NULL; + } + my_free(entry->database, MYF(MY_ALLOW_ZERO_PTR)); + my_free((void*)entry, MYF(0)); +} + + +uchar* get_db_key(const db_entry *entry, size_t *length, + my_bool not_used __attribute__((unused))) +{ + *length= strlen(entry->database); + return (uchar*) entry->database; +} + +int my_mkdir(const char *dir, int Flags, myf MyFlags __attribute__((unused))) +{ + DBUG_ENTER("my_dir"); + DBUG_PRINT("enter",("dir: %s",dir)); + +#if defined(__WIN__) + if (mkdir((char*) dir)) +#else + if (mkdir((char*) dir, Flags & my_umask_dir)) +#endif + { + my_errno=errno; + DBUG_PRINT("error",("error %d when creating direcory %s",my_errno,dir)); + DBUG_RETURN(-1); + } + DBUG_RETURN(0); +} + +static my_bool +create_backup_dir(const char *basedir) +{ + MY_DIR *dirp; + FILEINFO *file; + uint i; + ulong seq, len; + + if (NULL == basedir) { + goto err; /* for safety */ + } + + len= strlen(basedir); + if (len > FN_REFLEN - 8) { + goto err; + } + + if (!(dirp= my_dir(basedir, MYF(MY_WANT_STAT)))) + { + fprintf(stderr, "Specified directory name for --backup-basedir is too long.\n"); + goto err; + } + + for (i=0, seq=0 ; i < (uint) dirp->number_off_files ; i++) + { + ulong current_seq; + file=dirp->dir_entry+i; + if ((file->name[0] == '.' && + ((file->name[1] == '.' && file->name[2] == '\0') || + file->name[1] == '\0'))) + { + continue; /* current and parent directories. */ + } + current_seq= (ulong)atoi(file->name); + seq= (current_seq > seq) ? current_seq : seq; + } + my_dirend(dirp); + seq++; + + convert_dirname(backup_dir,basedir,NullS); + my_snprintf(backup_dir+len, FN_REFLEN - len, "/%06u", seq); + + if (my_mkdir(backup_dir, 0777, MYF(0)) < 0) + { + goto err; + } + + return 0; /* SUCCESS */ + +err: + fprintf(stderr, + "%s: Error occured when creating a directory for --backup-basedir option.\n", my_progname); + return 1; +} + +static FILE* +open_sql_file_for_db(const char* db, int flags) +{ + FILE *res, *tmp; + char filename[FN_REFLEN]; + db_entry *e; + + if((e = (db_entry*)hash_search(&per_file_databases, db, strlen(db)))) { + return e->sql_file; + } + + e= my_malloc(sizeof(db_entry), MYF(0)); + if (NULL == e) { + return NULL; + } + e->database = my_strdup(db, MYF(0)); + + res= my_fopen(fn_format(filename, db, backup_dir, ".sql", 4), + flags, MYF(MY_WME)); + e->sql_file= res; + tmp= md_result_file; + md_result_file= res; + write_header(res, (char*)db); + check_io(res); + md_result_file= tmp; + + if (my_hash_insert(&per_file_databases, (uchar*)e)) + return NULL; + + return res; +} + +static void +select_sql_file_for_db(const char *db) +{ + if (!opt_backup_basedir) { + return; + } + md_result_file= open_sql_file_for_db(db, O_WRONLY | FILE_BINARY); + + if (md_result_file == NULL) { + exit(EX_EOM); + } +} static my_bool get_one_option(int optid, const struct my_option *opt __attribute__((unused)), @@ -853,6 +1003,7 @@ { int ho_error; MYSQL_PARAMETERS *mysql_params= mysql_get_parameters(); + MY_STAT stat_info; opt_max_allowed_packet= *mysql_params->p_max_allowed_packet; opt_net_buffer_length= *mysql_params->p_net_buffer_length; @@ -875,10 +1026,10 @@ my_hash_insert(&ignore_table, (uchar*) my_strdup("mysql.slow_log", MYF(MY_WME)))) return(EX_EOM); - + if ((ho_error= handle_options(argc, argv, my_long_options, get_one_option))) return(ho_error); - + *mysql_params->p_max_allowed_packet= opt_max_allowed_packet; *mysql_params->p_net_buffer_length= opt_net_buffer_length; if (debug_info_flag) @@ -895,7 +1046,27 @@ "%s: You must use option --tab with --fields-...\n", my_progname); return(EX_USAGE); } + + if (opt_backup_basedir) { + if ((!opt_alldbs && !opt_databases) || path) + { + fprintf(stderr, + "%s: --backup-basedir option must be used with --all-databases or --databases, mustn't used with --tab options.\n", my_progname); + return(EX_USAGE); + } + if (!my_stat(opt_backup_basedir, &stat_info, MYF(0))) + { + fprintf(stderr, + "%s: Directory '%s' doesn't exist. --backup-basedir option needs an existing directory as its argument.\n", my_progname, opt_backup_basedir); + return(EX_USAGE); + } + if (hash_init(&per_file_databases, charset_info, 16, 0, 0, + (hash_get_key) get_db_key, + (hash_free_key) free_db_ent, 0)) + return(EX_EOM); + } + /* Ensure consistency of the set of binlog & locking options */ if (opt_delete_master_logs && !opt_master_data) opt_master_data= MYSQL_OPT_MASTER_DATA_COMMENTED_SQL; @@ -1416,11 +1587,13 @@ static void free_resources() { - if (md_result_file && md_result_file != stdout) + if (md_result_file && md_result_file != stdout && !opt_backup_basedir) my_fclose(md_result_file, MYF(0)); my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR)); if (hash_inited(&ignore_table)) hash_free(&ignore_table); + if (hash_inited(&per_file_databases)) + hash_free(&per_file_databases); if (extended_insert) dynstr_free(&extended_row); if (insert_pat_inited) @@ -4005,6 +4178,8 @@ char *afterdot; int using_mysql_db= my_strcasecmp(&my_charset_latin1, database, "mysql"); DBUG_ENTER("dump_all_tables_in_db"); + + select_sql_file_for_db(database); afterdot= strmov(hash_key, database); *afterdot++= '.'; @@ -4106,6 +4281,8 @@ char table_buff[NAME_LEN*2+3]; char hash_key[2*NAME_LEN+2]; /* "db.tablename" */ char *afterdot; + + select_sql_file_for_db(database); afterdot= strmov(hash_key, database); *afterdot++= '.'; @@ -5011,6 +5188,13 @@ free_resources(); exit(exit_code); } + + if (opt_backup_basedir) + { + if (create_backup_dir(opt_backup_basedir)) { + return(EX_FILEOP); + } + } if (log_error_file) { @@ -5026,7 +5210,7 @@ free_resources(); exit(EX_MYSQLERR); } - if (!path) + if (!path && !opt_backup_basedir) write_header(md_result_file, *argv); if ((opt_lock_all_tables || opt_master_data) && @@ -5098,7 +5282,7 @@ */ err: dbDisconnect(current_host); - if (!path) + if (!path && !opt_backup_basedir) write_footer(md_result_file); free_resources();