summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BitKeeper/etc/logging_ok1
-rw-r--r--Docs/manual.texi40
-rw-r--r--client/mysqlcheck.c82
-rw-r--r--client/mysqldump.c137
-rw-r--r--client/mysqltest.c1
-rw-r--r--innobase/include/univ.i5
-rw-r--r--innobase/os/os0file.c32
-rw-r--r--innobase/os/os0sync.c1
-rw-r--r--mysql-test/mysql-test-run.sh2
-rw-r--r--mysql-test/r/binlog-backup-restore.result5
-rw-r--r--mysql-test/t/binlog-backup-restore.test18
-rw-r--r--sql/ha_innobase.cc10
-rw-r--r--sql/log.cc48
-rw-r--r--sql/log_event.cc32
-rw-r--r--sql/log_event.h14
-rw-r--r--sql/mysqlbinlog.cc6
-rw-r--r--sql/slave.cc146
-rw-r--r--sql/slave.h15
-rw-r--r--sql/sql_class.h3
-rw-r--r--sql/sql_repl.cc13
-rw-r--r--sql/sql_repl.h3
21 files changed, 458 insertions, 156 deletions
diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok
index 0cf09ad6901..a2d07539822 100644
--- a/BitKeeper/etc/logging_ok
+++ b/BitKeeper/etc/logging_ok
@@ -5,3 +5,4 @@ monty@donna.mysql.fi
monty@work.mysql.com
sasha@mysql.sashanet.com
serg@serg.mysql.com
+paul@central.snake.net
diff --git a/Docs/manual.texi b/Docs/manual.texi
index 1790454e951..f42e6362d5d 100644
--- a/Docs/manual.texi
+++ b/Docs/manual.texi
@@ -29340,6 +29340,9 @@ index operations (querying/dumping/statistics).
@itemize @bullet
@item Make all operations with @code{FULLTEXT} index @strong{faster}.
@item Support for braces @code{()} in boolean full-text search.
+@item Phrase search, proximity operators
+@item Boolean search can work without @code{FULLTEXT} index
+(yes, @strong{very} slow).
@item Support for "always-index words". They could be any strings
the user wants to treat as words, examples are "C++", "AS/400", "TCP/IP", etc.
@item Support for full-text search in @code{MERGE} tables.
@@ -32555,6 +32558,10 @@ used.)
@item -q, --quick
Don't buffer query, dump directly to stdout. Uses @code{mysql_use_result()}
to do this.
+@item -r, --result-file=...
+Direct output to a given file. This option should be used in MSDOS,
+because it prevents new line '\n' from being converted to '\n\r' (new
+line + carriage return).
@item -S /path/to/socket, --socket=/path/to/socket
The socket file to use when connecting to @code{localhost} (which is the
default host).
@@ -42995,6 +43002,8 @@ import-/export-files. (Freeware). By Ansgar Becker.
@item @uref{http://www.mysql.com/Downloads/Win32/W9xstop.zip,Utility from Artronic to stop MySQL on win9x}.
+@item @uref{http://bardo.hyperlink.cz/mysqlmon,a light weight GUI client for Windows}.
+
@item @uref{http://dbtools.vila.bol.com.br/, Dbtools}
A tool to manage @strong{MySQL} databases. Currently only for Windows.
Some features:
@@ -43233,7 +43242,7 @@ An authentication module for the Cyrus IMAP server. By Aaron Newsome.
@appendixsec Converters
@itemize @bullet
-item @uref{http://www.mysql.com/Downloads/Contrib/mssql2mysql.txt, mssql2mysql.txt}
+@item @uref{http://www.mysql.com/Downloads/Contrib/mssql2mysql.txt, mssql2mysql.txt}
Converter from MS-SQL to MySQL. By Michael Kofler.
@uref{http://www.kofler.cc/mysql/mssql2mysql.html, mssql2mysql home page}.
@@ -43938,9 +43947,9 @@ Our TODO section contains what we plan to have in 4.0. @xref{TODO MySQL 4.0}.
@itemize @bullet
@item
-Added @code{SQL_CALC_FOUND_ROWS} and @code{FOUND_ROWS()}. This make it
-possible to know how many rows a query would have returned if one hadn't
-used @code{LIMIT}.
+Added @code{SQL_CALC_FOUND_ROWS} and @code{FOUND_ROWS()}. This makes it
+possible to know how many rows a query would have returned
+without a @code{LIMIT} clause.
@item
Changed output format of @code{SHOW OPEN TABLES}.
@item
@@ -44050,7 +44059,7 @@ together with a group functions and a @code{WHERE} that didn't match any rows.
@item
New program @code{mysqlcheck}.
@item
-Added database name to output for admin commands like @code{CHECK},
+Added database name to output for administrative commands like @code{CHECK},
@code{REPAIR}, @code{OPTIMIZE}.
@item
Lots of portability fixes for InnoDB.
@@ -44061,7 +44070,7 @@ will use index on @code{key_part1} instead of @code{filesort}.
@item
Fixed bug when doing
@code{LOCK TABLE to_table WRITE,...; INSERT INTO to_table... SELECT ...}
-when to_table was empty.
+when @code{to_table} was empty.
@item
Fixed bug with @code{LOCK TABLE} and BDB tables.
@end itemize
@@ -44087,35 +44096,35 @@ Fixed bug when using indexes on @code{CHAR(255) NULL} columns.
Slave thread will now be started even if @code{master-host} is not set, as
long as @code{server-id} is set and valid @code{master.info} is present
@item
-Partial updates ( terminated with kill) are now logged with a special error
+Partial updates (terminated with kill) are now logged with a special error
code to the binary log. Slave will refuse to execute them if the error code
indicates the update was terminated abnormally, and will have to be recovered
with @code{SET SQL_SLAVE_SKIP_COUNTER=1; SLAVE START} after a manual sanity
-check/correction of data integrity
+check/correction of data integrity.
@item
Fixed bug that erroneously logged a drop of internal temporary table
-on thread termination to the binary log - bug affected replication
+on thread termination to the binary log - bug affected replication.
@item
Fixed a bug in @code{REGEXP()} on 64-bit machines.
@item
@code{UPDATE} and @code{DELETE} with @code{WHERE unique_key_part IS NULL}
didn't update/delete all rows.
@item
-Disabled @code{INSERT DELAYED} for tables that supports transactions.
+Disabled @code{INSERT DELAYED} for tables that support transactions.
@item
Fixed bug when using date functions on @code{TEXT}/@code{BLOB} column
with wrong date format.
@item
-UDF's now also works on windows. (Patch by Ralph Mason)
+UDFs now also work on Windows. (Patch by Ralph Mason)
@item
Fixed bug in @code{ALTER TABLE} and @code{LOAD DATA INFILE} that disabled
-key-sorting. These command should now be faster in most cases.
+key-sorting. These commands should now be faster in most cases.
@item
Fixed performance bug where reopened tables (tables that had been
waiting for @code{FLUSH} or @code{REPAIR}) would not use indexes for the
next query.
@item
-Fixed problem with @code{ALTER TABLE} to Innobase tables on Freebsd.
+Fixed problem with @code{ALTER TABLE} to Innobase tables on FreeBSD.
@item
Added @code{mysqld} variables @code{myisam_max_sort_file_size} and
@code{myisam_max_extra_sort_file_size}.
@@ -44134,8 +44143,9 @@ Added @code{--skip-safemalloc} option to @code{mysqld}.
@appendixsubsec Changes in release 3.23.36
@itemize @bullet
@item
-Fixed a bug that allowed you to use database names with @code{.}. This
-fixes a serious security issue when @code{mysqld} is run as root.
+Fixed a bug that allowed you to use database names containing a @samp{.}
+character. This fixes a serious security issue when @code{mysqld} is run
+as root.
@item
Fixed bug when thread creation failed (could happen when doing a LOT
of connections in a short time).
diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c
index f8ad5d813cd..3d4d4597ef5 100644
--- a/client/mysqlcheck.c
+++ b/client/mysqlcheck.c
@@ -16,7 +16,7 @@
/* By Jani Tolonen, 2001-04-20, MySQL Development Team */
-#define CHECK_VERSION "1.00"
+#define CHECK_VERSION "1.01"
#include <global.h>
#include <my_sys.h>
@@ -40,22 +40,24 @@ static MYSQL mysql_connection, *sock = 0;
static my_bool opt_alldbs = 0, opt_check_only_changed = 0, opt_extended = 0,
opt_compress = 0, opt_databases = 0, opt_fast = 0,
opt_medium_check = 0, opt_quick = 0, opt_all_in_1 = 0,
- opt_silent = 0, ignore_errors = 0;
+ opt_silent = 0, opt_auto_repair = 0, ignore_errors = 0;
static uint verbose = 0, opt_mysql_port=0;
static my_string opt_mysql_unix_port = 0;
static char *opt_password = 0, *current_user = 0, *default_charset = 0,
*current_host = 0;
static int first_error = 0;
+DYNAMIC_ARRAY tables4repair;
enum operations {DO_CHECK, DO_REPAIR, DO_ANALYZE, DO_OPTIMIZE};
enum options {OPT_CHARSETS_DIR=256, OPT_COMPRESS, OPT_DEFAULT_CHARSET,
- OPT_TABLES};
+ OPT_TABLES, OPT_AUTO_REPAIR};
static struct option long_options[] =
{
{"all-databases", no_argument, 0, 'A'},
{"all-in-1", no_argument, 0, '1'},
+ {"auto-repair", no_argument, 0, OPT_AUTO_REPAIR},
{"analyze", no_argument, 0, 'a'},
{"character-sets-dir", required_argument, 0, OPT_CHARSETS_DIR},
{"check", no_argument, 0, 'c'},
@@ -122,13 +124,19 @@ static void usage(void)
puts("By Jani Tolonen, 2001-04-20, MySQL Development Team\n");
puts("This software comes with ABSOLUTELY NO WARRANTY. This is free");
puts("software and you are welcome to modify and redistribute it");
- puts("under the GPL license\n");
+ puts("under the GPL license.\n");
puts("This program can be used to CHECK (-c,-m,-C), REPAIR (-r), ANALYZE (-a)");
puts("or OPTIMIZE (-o) tables. Some of the options (like -e or -q) can be");
- puts("used same time. It works on MyISAM and in some cases on BDB tables");
+ puts("used same time. It works on MyISAM and in some cases on BDB tables.");
puts("Please consult the MySQL manual for latest information about the");
- puts("above. The options above are exclusive to each other, which means");
- puts("that the last option will be used, if several was specified.\n");
+ puts("above. The options -c,-r,-a and -o are exclusive to each other, which");
+ puts("means that the last option will be used, if several was specified.\n");
+ puts("The option -c will be used by default, if none was specified. You");
+ puts("can change the default behavior by making a symbolic link, or");
+ puts("copying this file somewhere with another name, the alternatives are:");
+ puts("mysqlrepair: The default option will be -r");
+ puts("mysqlanalyze: The default option will be -a");
+ puts("mysqloptimize: The default option will be -o\n");
printf("Usage: %s [OPTIONS] database [tables]\n", my_progname);
printf("OR %s [OPTIONS] --databases DB1 [DB2 DB3...]\n",
my_progname);
@@ -140,6 +148,9 @@ static void usage(void)
all queries in 1 query separately for each database.\n\
Table names will be in a comma separeted list.\n\
-a, --analyze Analyze given tables.\n\
+ --auto-repair If a checked table is corrupted, automatically fix\n\
+ it. Repairing will be done after all tables have\n\
+ been checked, if corrupted ones were found.\n\
-#, --debug=... Output debug log. Often this is 'd:t:o,filename'\n\
--character-sets-dir=...\n\
Directory where character sets are\n\
@@ -197,12 +208,18 @@ printf("\
print_defaults("my", load_default_groups);
} /* usage */
-
+
static int get_options(int *argc, char ***argv)
{
int c, option_index;
my_bool tty_password = 0;
+ if (*argc == 1)
+ {
+ usage();
+ exit(0);
+ }
+
load_defaults("my", load_default_groups, argc, argv);
while ((c = getopt_long(*argc, *argv, "#::p::h:u:P:S:BaAcCdeFfmqorsvVw:?I1",
long_options, &option_index)) != EOF)
@@ -217,6 +234,9 @@ static int get_options(int *argc, char ***argv)
case 'A':
opt_alldbs = 1;
break;
+ case OPT_AUTO_REPAIR:
+ opt_auto_repair = 1;
+ break;
case OPT_DEFAULT_CHARSET:
default_charset = optarg;
break;
@@ -315,7 +335,20 @@ static int get_options(int *argc, char ***argv)
}
}
if (!what_to_do)
- what_to_do = DO_CHECK;
+ {
+ int pnlen = strlen(my_progname);
+
+ if (pnlen < 6) // name too short
+ what_to_do = DO_CHECK;
+ else if (!strcmp("repair", my_progname + pnlen - 6))
+ what_to_do = DO_REPAIR;
+ else if (!strcmp("analyze", my_progname + pnlen - 7))
+ what_to_do = DO_ANALYZE;
+ else if (!strcmp("optimize", my_progname + pnlen - 8))
+ what_to_do = DO_OPTIMIZE;
+ else
+ what_to_do = DO_CHECK;
+ }
if (default_charset)
{
if (set_default_charset_by_name(default_charset, MYF(MY_WME)))
@@ -517,7 +550,7 @@ static void print_result()
{
MYSQL_RES *res;
MYSQL_ROW row;
- char prev[1024];
+ char prev[NAME_LEN*2+2];
int i;
res = mysql_use_result(sock);
@@ -531,7 +564,11 @@ static void print_result()
if (status && changed)
printf("%-50s %s", row[0], row[3]);
else if (!status && changed)
+ {
printf("%s\n%-9s: %s", row[0], row[2], row[3]);
+ if (what_to_do != DO_REPAIR && opt_auto_repair)
+ insert_dynamic(&tables4repair, row[0]);
+ }
else
printf("%-9s: %s", row[2], row[3]);
strmov(prev, row[0]);
@@ -610,6 +647,13 @@ int main(int argc, char **argv)
if (dbConnect(current_host, current_user, opt_password))
exit(EX_MYSQLERR);
+ if (opt_auto_repair &&
+ init_dynamic_array(&tables4repair, sizeof(char)*(NAME_LEN*2+2),16,64))
+ {
+ first_error = 1;
+ goto end;
+ }
+
if (opt_alldbs)
process_all_databases();
/* Only one database and selected table(s) */
@@ -618,8 +662,24 @@ int main(int argc, char **argv)
/* One or more databases, all tables */
else
process_databases(argv);
+ if (opt_auto_repair)
+ {
+ uint i;
+
+ if (!opt_silent && tables4repair.elements)
+ puts("\nRepairing tables");
+ what_to_do = DO_REPAIR;
+ for (i = 0; i < tables4repair.elements ; i++)
+ {
+ char *name= (char*) dynamic_array_ptr(&tables4repair, i);
+ handle_request_for_tables(name, strlen(name));
+ }
+ }
+ end:
dbDisconnect(current_host);
+ if (opt_auto_repair)
+ delete_dynamic(&tables4repair);
my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR));
my_end(0);
- return(first_error);
+ return(first_error!=0);
} /* main */
diff --git a/client/mysqldump.c b/client/mysqldump.c
index ce6c64aa00e..aa5a29e45e3 100644
--- a/client/mysqldump.c
+++ b/client/mysqldump.c
@@ -37,7 +37,7 @@
** Tõnu Samuel <tonu@please.do.not.remove.this.spam.ee>
**/
-#define DUMP_VERSION "8.13"
+#define DUMP_VERSION "8.14"
#include <global.h>
#include <my_sys.h>
@@ -73,7 +73,8 @@ static my_bool verbose=0,tFlag=0,cFlag=0,dFlag=0,quick=0, extended_insert = 0,
lock_tables=0,ignore_errors=0,flush_logs=0,replace=0,
ignore=0,opt_drop=0,opt_keywords=0,opt_lock=0,opt_compress=0,
opt_delayed=0,create_options=0,opt_quoted=0,opt_databases=0,
- opt_alldbs=0,opt_create_db=0,opt_first_slave=0;
+ opt_alldbs=0,opt_create_db=0,opt_first_slave=0,
+ opt_resultfile=0;
static MYSQL mysql_connection,*sock=0;
static char insert_pat[12 * 1024],*opt_password=0,*current_user=0,
*current_host=0,*path=0,*fields_terminated=0,
@@ -127,6 +128,7 @@ static struct option long_options[] =
{"port", required_argument, 0, 'P'},
{"quick", no_argument, 0, 'q'},
{"quote-names", no_argument, 0, 'Q'},
+ {"result-file", required_argument, 0, 'r'},
{"set-variable", required_argument, 0, 'O'},
{"socket", required_argument, 0, 'S'},
#include "sslopt-longopts.h"
@@ -227,6 +229,10 @@ puts("\
-P, --port=... Port number to use for connection.\n\
-q, --quick Don't buffer query, dump directly to stdout.\n\
-Q, --quote-names Quote table and column names with `\n\
+ -r, --result-file=... Direct output to a given file. This option should be\n\
+ used in MSDOS, because it prevents new line '\\n'\n\
+ from being converted to '\\n\\r' (newline + carriage\n\
+ return).\n\
-S, --socket=... Socket file to use for connection.\n\
--tables Overrides option --databases (-B).\n");
#include "sslopt-usage.h"
@@ -283,10 +289,12 @@ static int get_options(int *argc,char ***argv)
{
int c,option_index;
my_bool tty_password=0;
+ FILE *resultfile;
load_defaults("my",load_default_groups,argc,argv);
set_all_changeable_vars(changeable_vars);
- while ((c=getopt_long(*argc,*argv,"#::p::h:u:O:P:S:T:EBaAcCdefFlnqtvVw:?Ix",
+ while ((c=getopt_long(*argc,*argv,
+ "#::p::h:u:O:P:r:S:T:EBaAcCdefFlnqtvVw:?Ix",
long_options, &option_index)) != EOF)
{
switch(c) {
@@ -346,6 +354,15 @@ static int get_options(int *argc,char ***argv)
case 'P':
opt_mysql_port= (unsigned int) atoi(optarg);
break;
+ case 'r':
+ if (!(resultfile = my_fopen(optarg, O_WRONLY, MYF(MY_WME))))
+ {
+ printf("Couldn't open result-file %s, aborting!\n", optarg);
+ exit(1);
+ }
+ opt_resultfile = 1;
+ stdout = resultfile;
+ break;
case 'S':
opt_mysql_unix_port= optarg;
break;
@@ -625,8 +642,8 @@ static uint getTableStructure(char *table, char* db)
O_WRONLY, MYF(MY_WME));
if (!sql_file) /* If file couldn't be opened */
{
- safe_exit(EX_MYSQLERR);
- DBUG_RETURN(0);
+ safe_exit(EX_MYSQLERR);
+ DBUG_RETURN(0);
}
write_heder(sql_file, db);
}
@@ -734,20 +751,20 @@ static uint getTableStructure(char *table, char* db)
if (!tFlag)
{
if (opt_keywords)
- fprintf(sql_file, " %s.%s %s", table_name,
- quote_name(row[SHOW_FIELDNAME],name_buff), row[SHOW_TYPE]);
+ fprintf(sql_file, " %s.%s %s", table_name,
+ quote_name(row[SHOW_FIELDNAME],name_buff), row[SHOW_TYPE]);
else
- fprintf(sql_file, " %s %s", quote_name(row[SHOW_FIELDNAME],name_buff),
- row[SHOW_TYPE]);
+ fprintf(sql_file, " %s %s", quote_name(row[SHOW_FIELDNAME],
+ name_buff), row[SHOW_TYPE]);
if (row[SHOW_DEFAULT])
{
- fputs(" DEFAULT ", sql_file);
- unescape(sql_file,row[SHOW_DEFAULT],lengths[SHOW_DEFAULT]);
+ fputs(" DEFAULT ", sql_file);
+ unescape(sql_file,row[SHOW_DEFAULT],lengths[SHOW_DEFAULT]);
}
if (!row[SHOW_NULL][0])
- fputs(" NOT NULL", sql_file);
+ fputs(" NOT NULL", sql_file);
if (row[SHOW_EXTRA][0])
- fprintf(sql_file, " %s",row[SHOW_EXTRA]);
+ fprintf(sql_file, " %s",row[SHOW_EXTRA]);
}
}
numFields = (uint) mysql_num_rows(tableRes);
@@ -761,9 +778,9 @@ static uint getTableStructure(char *table, char* db)
if (mysql_query(sock, buff))
{
fprintf(stderr, "%s: Can't get keys for table '%s' (%s)\n",
- my_progname, table, mysql_error(sock));
+ my_progname, table, mysql_error(sock));
if (sql_file != stdout)
- my_fclose(sql_file, MYF(MY_WME));
+ my_fclose(sql_file, MYF(MY_WME));
safe_exit(EX_MYSQLERR);
DBUG_RETURN(0);
}
@@ -776,16 +793,16 @@ static uint getTableStructure(char *table, char* db)
{
if (atoi(row[3]) == 1)
{
- keynr++;
- #ifdef FORCE_PRIMARY_KEY
- if (atoi(row[1]) == 0 && primary_key == INT_MAX)
- primary_key=keynr;
- #endif
- if (!strcmp(row[2],"PRIMARY"))
- {
- primary_key=keynr;
- break;
- }
+ keynr++;
+#ifdef FORCE_PRIMARY_KEY
+ if (atoi(row[1]) == 0 && primary_key == INT_MAX)
+ primary_key=keynr;
+#endif
+ if (!strcmp(row[2],"PRIMARY"))
+ {
+ primary_key=keynr;
+ break;
+ }
}
}
mysql_data_seek(tableRes,0);
@@ -794,21 +811,21 @@ static uint getTableStructure(char *table, char* db)
{
if (atoi(row[3]) == 1)
{
- if (keynr++)
- putc(')', sql_file);
- if (atoi(row[1])) /* Test if duplicate key */
- /* Duplicate allowed */
- fprintf(sql_file, ",\n KEY %s (",quote_name(row[2],name_buff));
- else if (keynr == primary_key)
- fputs(",\n PRIMARY KEY (",sql_file); /* First UNIQUE is primary */
- else
- fprintf(sql_file, ",\n UNIQUE %s (",quote_name(row[2],name_buff));
+ if (keynr++)
+ putc(')', sql_file);
+ if (atoi(row[1])) /* Test if duplicate key */
+ /* Duplicate allowed */
+ fprintf(sql_file, ",\n KEY %s (",quote_name(row[2],name_buff));
+ else if (keynr == primary_key)
+ fputs(",\n PRIMARY KEY (",sql_file); /* First UNIQUE is primary */
+ else
+ fprintf(sql_file, ",\n UNIQUE %s (",quote_name(row[2],name_buff));
}
else
- putc(',', sql_file);
+ putc(',', sql_file);
fputs(quote_name(row[4],name_buff), sql_file);
if (row[7])
- fprintf(sql_file, " (%s)",row[7]); /* Sub key */
+ fprintf(sql_file, " (%s)",row[7]); /* Sub key */
}
if (keynr)
putc(')', sql_file);
@@ -820,28 +837,28 @@ static uint getTableStructure(char *table, char* db)
sprintf(buff,"show table status like '%s'",table);
if (mysql_query(sock, buff))
{
- if (mysql_errno(sock) != ER_PARSE_ERROR)
- { /* If old MySQL version */
- if (verbose)
- fprintf(stderr,
- "# Warning: Couldn't get status information for table '%s' (%s)\n",
- table,mysql_error(sock));
- }
+ if (mysql_errno(sock) != ER_PARSE_ERROR)
+ { /* If old MySQL version */
+ if (verbose)
+ fprintf(stderr,
+ "# Warning: Couldn't get status information for table '%s' (%s)\n",
+ table,mysql_error(sock));
+ }
}
else if (!(tableRes=mysql_store_result(sock)) ||
- !(row=mysql_fetch_row(tableRes)))
+ !(row=mysql_fetch_row(tableRes)))
{
- fprintf(stderr,
- "Error: Couldn't read status information for table '%s' (%s)\n",
- table,mysql_error(sock));
+ fprintf(stderr,
+ "Error: Couldn't read status information for table '%s' (%s)\n",
+ table,mysql_error(sock));
}
else
{
- fputs("/*!",sql_file);
- print_value(sql_file,tableRes,row,"type=","Type",0);
- print_value(sql_file,tableRes,row,"","Create_options",0);
- print_value(sql_file,tableRes,row,"comment=","Comment",1);
- fputs(" */",sql_file);
+ fputs("/*!",sql_file);
+ print_value(sql_file,tableRes,row,"type=","Type",0);
+ print_value(sql_file,tableRes,row,"","Create_options",0);
+ print_value(sql_file,tableRes,row,"comment=","Comment",1);
+ fputs(" */",sql_file);
}
mysql_free_result(tableRes); /* Is always safe to free */
}
@@ -967,7 +984,7 @@ static void dumpTable(uint numFields, char *table)
printf("# WHERE: %s\n",where);
strxmov(strend(query), " WHERE ",where,NullS);
}
- puts("#\n");
+ fputs("#\n\n", stdout);
if (mysql_query(sock, query))
{
@@ -1090,7 +1107,7 @@ static void dumpTable(uint numFields, char *table)
else
{
if (row_break)
- puts(";");
+ fputs(";\n", stdout);
row_break=1; /* This is first row */
fputs(insert_pat,stdout);
fputs(extended_row.str,stdout);
@@ -1098,12 +1115,10 @@ static void dumpTable(uint numFields, char *table)
}
}
else
- {
- puts(");");
- }
+ fputs(");\n", stdout);
}
if (extended_insert && row_break)
- puts(";"); /* If not empty table */
+ fputs(";\n", stdout); /* If not empty table */
fflush(stdout);
if (mysql_errno(sock))
{
@@ -1118,7 +1133,7 @@ static void dumpTable(uint numFields, char *table)
return;
}
if (opt_lock)
- puts("UNLOCK TABLES;");
+ fputs("UNLOCK TABLES;\n", stdout);
mysql_free_result(res);
}
} /* dumpTable */
@@ -1365,7 +1380,9 @@ int main(int argc, char **argv)
}
}
dbDisconnect(current_host);
- puts("");
+ fputs("\n", stdout);
+ if (opt_resultfile)
+ my_fclose(stdout, MYF(0));
my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR));
if (extended_insert)
dynstr_free(&extended_row);
diff --git a/client/mysqltest.c b/client/mysqltest.c
index dd2d6340bf1..5eaefe165d7 100644
--- a/client/mysqltest.c
+++ b/client/mysqltest.c
@@ -1766,6 +1766,7 @@ static void init_var_hash()
die("Variable hash initialization failed");
var_from_env("MASTER_MYPORT", "9306");
var_from_env("SLAVE_MYPORT", "9307");
+ var_from_env("MYSQL_TEST_DIR", "");
}
int main(int argc, char** argv)
diff --git a/innobase/include/univ.i b/innobase/include/univ.i
index 5e74b7eb09b..46ba508f784 100644
--- a/innobase/include/univ.i
+++ b/innobase/include/univ.i
@@ -9,6 +9,7 @@ Created 1/20/1994 Heikki Tuuri
#ifndef univ_i
#define univ_i
+
#if (defined(_WIN32) || defined(_WIN64))
#define __WIN__
#include <windows.h>
@@ -20,6 +21,10 @@ be defined:
#define CRITICAL_SECTION ulint
*/
+#ifdef _NT_
+#define __NT__
+#endif
+
#else
/* The Unix version */
diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c
index 8e9b8482259..804a63507ce 100644
--- a/innobase/os/os0file.c
+++ b/innobase/os/os0file.c
@@ -163,7 +163,6 @@ os_file_handle_error(
os_file_t file, /* in: file pointer */
char* name) /* in: name of a file or NULL */
{
- int input_char;
ulint err;
UT_NOT_USED(file);
@@ -172,32 +171,19 @@ os_file_handle_error(
if (err == OS_FILE_DISK_FULL) {
ask_again:
- printf("\n");
+ fprintf(stderr, "\n");
if (name) {
- printf(
- "Innobase encountered a problem with file %s.\n",
+ fprintf(stderr,
+ "InnoDB: Encountered a problem with file %s.\n",
name);
}
- printf("Disk is full. Try to clean the disk to free space\n");
- printf("before answering the following: How to continue?\n");
- printf("(Y == freed some space: try again)\n");
- printf("(N == crash the database: will restart it)?\n");
-ask_with_no_question:
- input_char = getchar();
-
- if (input_char == (int) 'N') {
- ut_error;
-
- return(FALSE);
- } else if (input_char == (int) 'Y') {
+ fprintf(stderr,
+ "InnoDB: Cannot continue operation.\n"
+ "InnoDB: Disk is full. Try to clean the disk to free space.\n"
+ "InnoDB: Delete possible created file and restart.\n");
- return(TRUE);
- } else if (input_char == (int) '\n') {
+ exit(1);
- goto ask_with_no_question;
- } else {
- goto ask_again;
- }
} else if (err == OS_FILE_AIO_RESOURCES_RESERVED) {
return(TRUE);
@@ -1413,7 +1399,7 @@ try_again:
return(TRUE);
}
- goto error_handling;
+ err = 1; /* Fall through the next if */
}
#endif
if (err == 0) {
diff --git a/innobase/os/os0sync.c b/innobase/os/os0sync.c
index 4c283431575..c5dd603100d 100644
--- a/innobase/os/os0sync.c
+++ b/innobase/os/os0sync.c
@@ -247,6 +247,7 @@ os_event_wait_time(
return(OS_SYNC_TIME_EXCEEDED);
} else {
ut_error;
+ return(1000000); /* dummy value to eliminate compiler warn. */
}
#else
UT_NOT_USED(time);
diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh
index 1281e368015..ece2e42f40b 100644
--- a/mysql-test/mysql-test-run.sh
+++ b/mysql-test/mysql-test-run.sh
@@ -492,7 +492,7 @@ start_slave()
--core \
--tmpdir=$MYSQL_TMP_DIR \
--language=english \
- --skip-innodb \
+ --skip-innodb --skip-slave-start \
$SMALL_SERVER \
$EXTRA_SLAVE_OPT $EXTRA_SLAVE_MYSQLD_OPT"
if [ x$DO_DDD = x1 ]
diff --git a/mysql-test/r/binlog-backup-restore.result b/mysql-test/r/binlog-backup-restore.result
new file mode 100644
index 00000000000..ebfe8217906
--- /dev/null
+++ b/mysql-test/r/binlog-backup-restore.result
@@ -0,0 +1,5 @@
+n
+11
+12
+13
+14
diff --git a/mysql-test/t/binlog-backup-restore.test b/mysql-test/t/binlog-backup-restore.test
new file mode 100644
index 00000000000..546782c5825
--- /dev/null
+++ b/mysql-test/t/binlog-backup-restore.test
@@ -0,0 +1,18 @@
+reset master;
+drop table if exists t1;
+create table t1(n int);
+insert into t1 values (1),(2),(3),(4);
+flush logs;
+update t1 set n = n + 10;
+save_master_pos;
+flush tables with read lock;
+system rm -rf var/tmp/backup;
+system mkdir -p var/tmp/backup;
+system cp var/master-data/master-bin.* var/tmp/backup;
+unlock tables;
+drop table t1;
+eval change master to master_host='$MYSQL_TEST_DIR/var/tmp/backup/master-bin';
+slave start;
+sync_with_master;
+select * from t1;
+
diff --git a/sql/ha_innobase.cc b/sql/ha_innobase.cc
index f263f693103..72857fc953f 100644
--- a/sql/ha_innobase.cc
+++ b/sql/ha_innobase.cc
@@ -1868,7 +1868,7 @@ corresponding row to buf. */
int
ha_innobase::index_first(
/*=====================*/
- /* out: 0, HA_ERR_KEY_NOT_FOUND,
+ /* out: 0, HA_ERR_END_OF_FILE,
or error code */
mysql_byte* buf) /* in/out: buffer for the row */
{
@@ -1879,6 +1879,12 @@ ha_innobase::index_first(
error = index_read(buf, NULL, 0, HA_READ_AFTER_KEY);
+ /* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
+
+ if (error == HA_ERR_KEY_NOT_FOUND) {
+ error = HA_ERR_END_OF_FILE;
+ }
+
DBUG_RETURN(error);
}
@@ -1899,7 +1905,7 @@ ha_innobase::index_last(
error = index_read(buf, NULL, 0, HA_READ_BEFORE_KEY);
- /* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
+ /* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
if (error == HA_ERR_KEY_NOT_FOUND) {
error = HA_ERR_END_OF_FILE;
diff --git a/sql/log.cc b/sql/log.cc
index 4ae9fa79d5b..4cd93261973 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -103,7 +103,7 @@ MYSQL_LOG::~MYSQL_LOG()
void MYSQL_LOG::set_index_file_name(const char* index_file_name)
{
if (index_file_name)
- fn_format(this->index_file_name,index_file_name,mysql_data_home,"-index",
+ fn_format(this->index_file_name,index_file_name,mysql_data_home,".index",
4);
else
this->index_file_name[0] = 0;
@@ -129,6 +129,32 @@ int MYSQL_LOG::generate_new_name(char *new_name, const char *log_name)
return 0;
}
+bool MYSQL_LOG::open_index( int options)
+{
+ return (index_file < 0 &&
+ (index_file = my_open(index_file_name, options | O_BINARY ,
+ MYF(MY_WME))) < 0);
+}
+
+void MYSQL_LOG::init(enum_log_type log_type_arg)
+{
+ log_type = log_type_arg;
+ if (!inited)
+ {
+ inited=1;
+ (void) pthread_mutex_init(&LOCK_log,MY_MUTEX_INIT_SLOW);
+ (void) pthread_mutex_init(&LOCK_index, MY_MUTEX_INIT_SLOW);
+ }
+}
+
+void MYSQL_LOG::close_index()
+{
+ if(index_file >= 0)
+ {
+ my_close(index_file, MYF(0));
+ index_file = -1;
+ }
+}
void MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
const char *new_name)
@@ -137,17 +163,11 @@ void MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
char buff[512];
File file= -1;
bool do_magic;
-
- if (!inited)
- {
- inited=1;
- (void) pthread_mutex_init(&LOCK_log,MY_MUTEX_INIT_SLOW);
- (void) pthread_mutex_init(&LOCK_index, MY_MUTEX_INIT_SLOW);
- if (log_type_arg == LOG_BIN && *fn_ext(log_name))
+
+ if (!inited && log_type_arg == LOG_BIN && *fn_ext(log_name))
no_rotate = 1;
- }
+ init(log_type_arg);
- log_type=log_type_arg;
if (!(name=my_strdup(log_name,MYF(MY_WME))))
goto err;
if (new_name)
@@ -208,10 +228,7 @@ void MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
clean up if failed
*/
if ((do_magic && my_b_write(&log_file, (byte*) BINLOG_MAGIC, 4)) ||
- (index_file < 0 &&
- (index_file = my_open(index_file_name,
- O_APPEND | O_BINARY | O_RDWR | O_CREAT,
- MYF(MY_WME))) < 0))
+ open_index(O_APPEND | O_RDWR | O_CREAT))
goto err;
Start_log_event s;
bool error;
@@ -224,8 +241,7 @@ void MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
pthread_mutex_unlock(&LOCK_index);
if (error)
{
- my_close(index_file,MYF(0));
- index_file= -1;
+ close_index();
goto err;
}
}
diff --git a/sql/log_event.cc b/sql/log_event.cc
index d643952c5b0..5fc5f7f0e62 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -280,7 +280,7 @@ void Log_event::print_timestamp(FILE* file, time_t* ts)
}
-void Start_log_event::print(FILE* file, bool short_form)
+void Start_log_event::print(FILE* file, bool short_form, char* last_db)
{
if (short_form)
return;
@@ -293,7 +293,7 @@ void Start_log_event::print(FILE* file, bool short_form)
fflush(file);
}
-void Stop_log_event::print(FILE* file, bool short_form)
+void Stop_log_event::print(FILE* file, bool short_form, char* last_db)
{
if (short_form)
return;
@@ -303,7 +303,7 @@ void Stop_log_event::print(FILE* file, bool short_form)
fflush(file);
}
-void Rotate_log_event::print(FILE* file, bool short_form)
+void Rotate_log_event::print(FILE* file, bool short_form, char* last_db)
{
if (short_form)
return;
@@ -441,7 +441,7 @@ Query_log_event::Query_log_event(const char* buf, int event_len):
*((char*)query+q_len) = 0;
}
-void Query_log_event::print(FILE* file, bool short_form)
+void Query_log_event::print(FILE* file, bool short_form, char* last_db)
{
char buff[40],*end; // Enough for SET TIMESTAMP
if (!short_form)
@@ -451,7 +451,15 @@ void Query_log_event::print(FILE* file, bool short_form)
(ulong) thread_id, (ulong) exec_time, error_code);
}
- if (db && db[0])
+ bool same_db = 0;
+
+ if(db && last_db)
+ {
+ if(!(same_db = !memcmp(last_db, db, db_len)))
+ memcpy(last_db, db, db_len + 1);
+ }
+
+ if (db && db[0] && !same_db)
fprintf(file, "use %s;\n", db);
end=int10_to_str((long) when, strmov(buff,"SET TIMESTAMP="),10);
*end++=';';
@@ -507,7 +515,7 @@ int Intvar_log_event::write_data(IO_CACHE* file)
return my_b_write(file, (byte*) buf, sizeof(buf));
}
-void Intvar_log_event::print(FILE* file, bool short_form)
+void Intvar_log_event::print(FILE* file, bool short_form, char* last_db)
{
char llbuff[22];
if(!short_form)
@@ -625,7 +633,7 @@ void Load_log_event::copy_log_event(const char *buf, ulong data_len)
}
-void Load_log_event::print(FILE* file, bool short_form)
+void Load_log_event::print(FILE* file, bool short_form, char* last_db)
{
if (!short_form)
{
@@ -634,7 +642,15 @@ void Load_log_event::print(FILE* file, bool short_form)
thread_id, exec_time);
}
- if(db && db[0])
+ bool same_db = 0;
+
+ if(db && last_db)
+ {
+ if(!(same_db = !memcmp(last_db, db, db_len)))
+ memcpy(last_db, db, db_len + 1);
+ }
+
+ if(db && db[0] && !same_db)
fprintf(file, "use %s;\n", db);
fprintf(file, "LOAD DATA INFILE '%s' ", fname);
diff --git a/sql/log_event.h b/sql/log_event.h
index 0f4945bae3c..41f847e8d92 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -100,7 +100,7 @@ public:
virtual ~Log_event() {}
virtual int get_data_size() { return 0;}
- virtual void print(FILE* file, bool short_form = 0) = 0;
+ virtual void print(FILE* file, bool short_form = 0, char* last_db = 0) = 0;
void print_timestamp(FILE* file, time_t *ts = 0);
void print_header(FILE* file);
@@ -169,7 +169,7 @@ public:
;
}
- void print(FILE* file, bool short_form = 0);
+ void print(FILE* file, bool short_form = 0, char* last_db = 0);
};
#define DUMPFILE_FLAG 0x1
@@ -312,7 +312,7 @@ public:
;
}
- void print(FILE* file, bool short_form = 0);
+ void print(FILE* file, bool short_form = 0, char* last_db = 0);
};
extern char server_version[SERVER_VERSION_LENGTH];
@@ -350,7 +350,7 @@ public:
// sizeof(binlog_version) + sizeof(server_version) sizeof(created)
return 2 + sizeof(server_version) + 4;
}
- void print(FILE* file, bool short_form = 0);
+ void print(FILE* file, bool short_form = 0, char* last_db = 0);
};
class Intvar_log_event: public Log_event
@@ -369,7 +369,7 @@ public:
int write_data(IO_CACHE* file);
- void print(FILE* file, bool short_form = 0);
+ void print(FILE* file, bool short_form = 0, char* last_db = 0);
};
class Stop_log_event: public Log_event
@@ -388,7 +388,7 @@ public:
}
~Stop_log_event() {}
Log_event_type get_type_code() { return STOP_EVENT;}
- void print(FILE* file, bool short_form = 0);
+ void print(FILE* file, bool short_form = 0, char* last_db = 0);
};
class Rotate_log_event: public Log_event
@@ -416,7 +416,7 @@ public:
int get_data_size() { return ident_len;}
int write_data(IO_CACHE* file);
- void print(FILE* file, bool short_form = 0);
+ void print(FILE* file, bool short_form = 0, char* last_db = 0);
};
#endif
diff --git a/sql/mysqlbinlog.cc b/sql/mysqlbinlog.cc
index 60989615390..05ff166cd49 100644
--- a/sql/mysqlbinlog.cc
+++ b/sql/mysqlbinlog.cc
@@ -291,6 +291,7 @@ static void dump_remote_table(NET* net, const char* db, const char* table)
static void dump_remote_log_entries(const char* logname)
{
char buf[128];
+ char last_db[FN_REFLEN+1] = "";
uint len;
NET* net = &mysql->net;
if(!position) position = 4; // protect the innocent from spam
@@ -324,7 +325,7 @@ Unfortunately, no sweepstakes today, adjusted position to 4\n");
len - 1);
if(ev)
{
- ev->print(stdout, short_form);
+ ev->print(stdout, short_form, last_db);
if(ev->get_type_code() == LOAD_EVENT)
dump_remote_file(net, ((Load_log_event*)ev)->fname);
delete ev;
@@ -339,6 +340,7 @@ static void dump_local_log_entries(const char* logname)
File fd = -1;
IO_CACHE cache,*file= &cache;
ulonglong rec_count = 0;
+ char last_db[FN_REFLEN+1] = "";
if (logname && logname[0] != '-')
{
@@ -398,7 +400,7 @@ Could not read entry at offset %s : Error in log format or read error",
if (!short_form)
printf("# at %s\n",llstr(old_off,llbuff));
- ev->print(stdout, short_form);
+ ev->print(stdout, short_form, last_db);
}
rec_count++;
delete ev;
diff --git a/sql/slave.cc b/sql/slave.cc
index aded6d558fc..1ca8324e204 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -20,6 +20,7 @@
#include <myisam.h>
#include "mini_client.h"
#include "slave.h"
+#include "sql_repl.h"
#include <thr_alarm.h>
#include <my_dir.h>
@@ -441,6 +442,101 @@ int fetch_nx_table(THD* thd, MASTER_INFO* mi)
return error;
}
+void MASTER_INFO::close_virtual_master()
+{
+ vm_binlog.close_index();
+ end_io_cache(&vm_cache);
+ if(vm_fd >= 0)
+ {
+ my_close(vm_fd, MYF(0));
+ vm_fd = -1;
+ }
+}
+
+int MASTER_INFO::setup_virtual_master()
+{
+ vm_binlog.init(LOG_BIN);
+ vm_binlog.set_index_file_name(host);
+ if(vm_binlog.open_index(O_RDONLY))
+ {
+ sql_print_error("virtual master: could not open index file '%s': \
+ (%d)", host, my_errno);
+ return 1;
+ }
+
+ if(vm_binlog.find_first_log(&vm_linfo,log_file_name))
+ {
+ sql_print_error("virtual master: could not find first log");
+ return 1;
+ }
+
+ if(open_log())
+ return 1;
+
+ return 0;
+}
+
+int MASTER_INFO::open_log()
+{
+ const char* errmsg = "Unknown error";
+ if(vm_fd >= 0)
+ {
+ end_io_cache(&vm_cache);
+ my_close(vm_fd, MYF(0));
+ }
+
+ // if backup-up logs have relative paths, assume they are relative to
+ // the directory that has the log index, not cwd
+ char logname_buf[FN_REFLEN+1], *logname;
+ if(vm_linfo.log_file_name[0] == FN_LIBCHAR)
+ logname = vm_linfo.log_file_name;
+ else
+ {
+ char* end = strnmov(logname_buf, host,
+ sizeof(logname_buf));
+ for(; *end != FN_LIBCHAR; --end); // we will always find it, first
+ // char of host is always FN_LIBCHAR for virtual master
+
+ strncpy(end + 1, vm_linfo.log_file_name,
+ sizeof(logname_buf) - (end - logname_buf));
+ logname = logname_buf;
+ }
+
+ if((vm_fd = open_binlog(&vm_cache, logname, &errmsg)) < 0)
+ {
+ sql_print_error("virtual master: error opening binlog '%s': %s",
+ vm_linfo.log_file_name, errmsg);
+ return 1;
+ }
+
+ strncpy(log_file_name, vm_linfo.log_file_name, sizeof(log_file_name));
+ return 0;
+}
+
+uint MASTER_INFO::read_event()
+{
+ for(;!(vm_ev = Log_event::read_log_event(&vm_cache, 0));)
+ {
+ if(!vm_cache.error) // eof - try next log
+ {
+ switch(vm_binlog.find_next_log(&vm_linfo))
+ {
+ case LOG_INFO_EOF:
+ return 0;
+ case 0:
+ if(open_log())
+ return packet_error;
+ continue;
+ default:
+ sql_print_error("virtual master: could not read next log");
+ return packet_error;
+ }
+ }
+ }
+
+ return vm_ev->get_data_size() + LOG_EVENT_HEADER_LEN;
+}
+
void end_master_info(MASTER_INFO* mi)
{
if(mi->fd >= 0)
@@ -450,6 +546,8 @@ void end_master_info(MASTER_INFO* mi)
mi->fd = -1;
}
mi->inited = 0;
+ if(mi->virtual_master)
+ mi->close_virtual_master();
}
int init_master_info(MASTER_INFO* mi)
@@ -545,6 +643,7 @@ int init_master_info(MASTER_INFO* mi)
}
mi->inited = 1;
+ mi->virtual_master = (mi->host[0] == FN_LIBCHAR);
// now change the cache from READ to WRITE - must do this
// before flush_master_info
reinit_io_cache(&mi->file, WRITE_CACHE, 0L,0,1);
@@ -742,6 +841,9 @@ static int safe_sleep(THD* thd, int sec)
static int request_dump(MYSQL* mysql, MASTER_INFO* mi)
{
+ if(mi->virtual_master)
+ return 0;
+
char buf[FN_REFLEN + 10];
int len;
int binlog_flags = 0; // for now
@@ -795,6 +897,9 @@ command");
static uint read_event(MYSQL* mysql, MASTER_INFO *mi)
{
+ if(mi->virtual_master)
+ return mi->read_event();
+
uint len = packet_error;
// for convinience lets think we start by
// being in the interrupted state :-)
@@ -860,16 +965,18 @@ point. If you are sure that your master is ok, run this query manually on the\
static int exec_event(THD* thd, NET* net, MASTER_INFO* mi, int event_len)
{
- Log_event * ev = Log_event::read_log_event((const char*)net->read_pos + 1,
- event_len);
+ Log_event * ev = (mi->virtual_master) ? mi->vm_ev :
+ Log_event::read_log_event((const char*)net->read_pos + 1,
+ event_len) ;
char llbuff[22];
if (ev)
{
int type_code = ev->get_type_code();
- if (ev->server_id == ::server_id || slave_skip_counter)
+ if ((!mi->virtual_master && ev->server_id == ::server_id)
+ || slave_skip_counter)
{
- if(type_code == LOAD_EVENT)
+ if(type_code == LOAD_EVENT && !mi->virtual_master)
skip_load_data_infile(net);
mi->inc_pos(event_len);
@@ -971,6 +1078,14 @@ static int exec_event(THD* thd, NET* net, MASTER_INFO* mi, int event_len)
case LOAD_EVENT:
{
+ if(mi->virtual_master)
+ {
+ delete ev;
+ sql_print_error("LOAD DATA INFILE does not yet work with virtual \
+master. Perform in manually, then restart slave with SET SQL_SKIP_COUNTER=1;\
+SLAVE START");
+ return 1;
+ }
Load_log_event* lev = (Load_log_event*)ev;
init_sql_alloc(&thd->mem_root, 8192,0);
thd->db = rewrite_db((char*)lev->db);
@@ -993,7 +1108,8 @@ static int exec_event(THD* thd, NET* net, MASTER_INFO* mi, int event_len)
// the table will be opened in mysql_load
if(table_rules_on && !tables_ok(thd, &tables))
{
- skip_load_data_infile(net);
+ if(!mi->virtual_master)
+ skip_load_data_infile(net);
}
else
{
@@ -1057,7 +1173,8 @@ static int exec_event(THD* thd, NET* net, MASTER_INFO* mi, int event_len)
{
// we will just ask the master to send us /dev/null if we do not
// want to load the data :-)
- skip_load_data_infile(net);
+ if(!mi->virtual_master)
+ skip_load_data_infile(net);
}
thd->net.vio = 0;
@@ -1293,9 +1410,21 @@ try again, log '%s' at postion %s", RPL_LOG_NAME,
sql_print_error("Slave thread killed while reading event");
goto err;
}
+
+ if(!event_len && glob_mi.virtual_master)
+ {
+ sql_print_error("Virtual master replication finished");
+ goto err;
+ }
if (event_len == packet_error)
{
+ if(glob_mi.virtual_master)
+ {
+ sql_print_error("Virtual master replication encountered \
+error while reading event, replication terminated");
+ goto err;
+ }
thd->proc_info = "Waiting to reconnect after a failed read";
if(mysql->net.vio)
vio_close(mysql->net.vio);
@@ -1403,6 +1532,8 @@ position %s",
static int safe_connect(THD* thd, MYSQL* mysql, MASTER_INFO* mi)
{
+ if(mi->virtual_master)
+ return mi->setup_virtual_master();
int slave_was_killed;
#ifndef DBUG_OFF
events_till_disconnect = disconnect_slave_event_count;
@@ -1432,6 +1563,9 @@ static int safe_connect(THD* thd, MYSQL* mysql, MASTER_INFO* mi)
static int safe_reconnect(THD* thd, MYSQL* mysql, MASTER_INFO* mi)
{
+ if(mi->virtual_master)
+ return mi->setup_virtual_master();
+
int slave_was_killed;
char llbuff[22];
diff --git a/sql/slave.h b/sql/slave.h
index 311368a4b82..d04c0c13c23 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -16,8 +16,14 @@ typedef struct st_master_info
pthread_mutex_t lock;
pthread_cond_t cond;
bool inited;
+ bool virtual_master; // for replay of binlogs from a directory
+ MYSQL_LOG vm_binlog;
+ LOG_INFO vm_linfo;
+ IO_CACHE vm_cache;
+ int vm_fd;
+ Log_event* vm_ev;
- st_master_info():pending(0),fd(-1),inited(0)
+ st_master_info():pending(0),fd(-1),inited(0),virtual_master(0),vm_fd(-1)
{
host[0] = 0; user[0] = 0; password[0] = 0;
pthread_mutex_init(&lock, MY_MUTEX_INIT_FAST);
@@ -28,6 +34,8 @@ typedef struct st_master_info
{
pthread_mutex_destroy(&lock);
pthread_cond_destroy(&cond);
+ if(virtual_master)
+ close_virtual_master();
}
inline void inc_pending(ulonglong val)
{
@@ -51,6 +59,11 @@ typedef struct st_master_info
}
int wait_for_pos(THD* thd, String* log_name, ulonglong log_pos);
+ int setup_virtual_master();
+ void close_virtual_master();
+ uint read_event();
+ int open_log();
+
} MASTER_INFO;
typedef struct st_table_rule_ent
diff --git a/sql/sql_class.h b/sql/sql_class.h
index cb08b8a9df4..438898ca294 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -71,9 +71,12 @@ public:
~MYSQL_LOG();
pthread_mutex_t* get_log_lock() { return &LOCK_log; }
void set_index_file_name(const char* index_file_name = 0);
+ void init(enum_log_type log_type_arg);
void open(const char *log_name,enum_log_type log_type,
const char *new_name=0);
void new_file(void);
+ bool open_index(int options);
+ void close_index();
bool write(THD *thd, enum enum_server_command command,const char *format,...);
bool write(THD *thd, const char *query, uint query_length,
time_t query_start=0);
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 05e64670df5..ed41bf53692 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -132,7 +132,7 @@ static int send_file(THD *thd)
}
-static File open_log(IO_CACHE *log, const char *log_file_name,
+File open_binlog(IO_CACHE *log, const char *log_file_name,
const char **errmsg)
{
File file;
@@ -294,7 +294,7 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags)
goto err;
}
- if ((file=open_log(&log, log_file_name, &errmsg)) < 0)
+ if ((file=open_binlog(&log, log_file_name, &errmsg)) < 0)
goto err;
if(pos < 4)
@@ -483,7 +483,7 @@ sweepstakes if you report the bug";
// fake Rotate_log event just in case it did not make it to the log
// otherwise the slave make get confused about the offset
- if ((file=open_log(&log, log_file_name, &errmsg)) < 0 ||
+ if ((file=open_binlog(&log, log_file_name, &errmsg)) < 0 ||
fake_rotate_event(net, packet, log_file_name, &errmsg))
goto err;
@@ -694,7 +694,12 @@ int change_master(THD* thd)
glob_mi.pos = lex_mi->pos;
if(lex_mi->host)
- strmake(glob_mi.host, lex_mi->host, sizeof(glob_mi.host));
+ {
+ if(glob_mi.virtual_master)
+ glob_mi.close_virtual_master();
+ strmake(glob_mi.host, lex_mi->host, sizeof(glob_mi.host));
+ glob_mi.virtual_master = (glob_mi.host[0] == FN_LIBCHAR);
+ }
if(lex_mi->user)
strmake(glob_mi.user, lex_mi->user, sizeof(glob_mi.user));
if(lex_mi->password)
diff --git a/sql/sql_repl.h b/sql/sql_repl.h
index f8a67f51aa2..68f2b4ba6c4 100644
--- a/sql/sql_repl.h
+++ b/sql/sql_repl.h
@@ -9,6 +9,9 @@ extern uint32 server_id;
extern bool server_id_supplied;
extern I_List<i_string> binlog_do_db, binlog_ignore_db;
+File open_binlog(IO_CACHE *log, const char *log_file_name,
+ const char **errmsg);
+
int start_slave(THD* thd = 0, bool net_report = 1);
int stop_slave(THD* thd = 0, bool net_report = 1);
int change_master(THD* thd);