Commit 20530c30 authored by monty@hundin.mysql.fi's avatar monty@hundin.mysql.fi

merge

parents b9d3a552 40fcae6d
......@@ -42,3 +42,4 @@ bell@sanja.is.com.ua
kaj@work.mysql.com
mwagner@cash.mwagner.org
tom@basil-firewall.home.com
jani@rhols221.adsl.netsonic.fi
......@@ -48290,13 +48290,13 @@ Fixed bug in multi table delete.
Fixed bug in @code{SELECT CONCAT(argument-list) ... GROUP BY 1}.
@item
@code{SELECT .. INSERT} did a full rollback in case of an error. Fixed
so that we only rollback the last statement.
so that we only roll back the last statement.
@item
Fixed bug with empty expression for boolean fulltext search.
@item
Fixed core dump bug in updating fulltext key from/to @code{NULL}.
@item
ODBC compatibility: Added @code{BIT_LENGTH()}
ODBC compatibility: Added @code{BIT_LENGTH()}.
@item
Fixed core dump bug in @code{GROUP BY BINARY column}.
@item
......@@ -48315,7 +48315,7 @@ For more information, read @ref{Cast Functions}.
@code{CREATE ... SELECT} on @code{DATE} and @code{TIME} functions now
create columns of the expected type.
@item
Changed order of how keys are created in tables.
Changed order in which keys are created in tables.
@item
Added a new columns @code{Null} and @code{Index_type} to @code{SHOW INDEX}.
@end itemize
......@@ -48330,17 +48330,17 @@ Fixed bug when @code{HANDLER} was used with some unsupported table type.
@code{mysqldump} now puts @code{ALTER TABLE table_name DISABLE KEYS} and
@code{ALTER TABLE table_name DISABLE KEYS} in the sql dump.
@item
Added @code{mysql_fix_extensions} script
Added @code{mysql_fix_extensions} script.
@item
Fixed stack overrun problem @code{LOAD DATA FROM MASTER} on OSF1.
@item
Fixed shutdown problem on HPUX.
Fixed shutdown problem on HP-UX.
@item
Added functions @code{des_encrypt()} and @code{des_decrypt()}.
@item
Added statement @code{FLUSH DES_KEY_FILE}.
@item
Added mysqld option @code{--des-key-file}.
Added @code{mysqld} option @code{--des-key-file}.
@item
@code{HEX(string)} now returns the characters in string converted to
hexadecimal.
......@@ -48352,7 +48352,7 @@ Changed @code{SELECT ... IN SHARE MODE} to
@item
A new query cache to cache results from identical @code{SELECT} queries.
@item
Fixed core dump bug on 64 bit machines when it got a wrong communication
Fixed core dump bug on 64-bit machines when it got an incorrect communication
packet.
@item
@code{MATCH ... AGAINST(... IN BOOLEAN MODE)} can now work
......@@ -48370,7 +48370,7 @@ of @code{FULLTEXT} indexes.
Fixed bug in @code{DELETE ... WHERE ... MATCH ...}.
@item
Added support for @code{MATCH ... AGAINST(... IN BOOLEAN MODE)}.
@strong{Note: you have to rebuild your tables with
@strong{Note: you must rebuild your tables with
@code{ALTER TABLE tablename TYPE=MyISAM} to be
able to use boolean fulltext search}.
@item
......@@ -48391,7 +48391,7 @@ Added boolean fulltext search code. It should be considered early alpha.
Extended @code{MODIFY} and @code{CHANGE} in @code{ALTER TABLE} to accept
the @code{AFTER} keyword.
@item
Index are now used with @code{ORDER BY} on a whole @code{InnoDB} table.
Indexes are now used with @code{ORDER BY} on a whole @code{InnoDB} table.
@end itemize
@node News-4.0.0, , News-4.0.1, News-4.0.x
......@@ -48446,28 +48446,28 @@ Speed up all internal list handling.
@item
Speed up @code{IS NULL}, @code{ISNULL()} and some other internal primitives.
@item
Creating full text indexes are now much faster.
Full text index creation now is much faster.
@item
Tree-like cache to speed up bulk inserts and
@code{myisam_bulk_insert_tree_size} variable.
@item
Searching on packed (@code{CHAR}/@code{VARCHAR}) keys are now much faster.
Searching on packed (@code{CHAR}/@code{VARCHAR}) keys is now much faster.
@item
Optimised queries of type:
@code{SELECT DISTINCT * from table_name ORDER by key_part1 LIMIT #}
@code{SELECT DISTINCT * from table_name ORDER by key_part1 LIMIT #}.
@item
@code{SHOW CREATE TABLE} now shows all table attributes.
@item
@code{ORDER BY ... DESC} can now use keys.
@item
@code{LOAD DATA FROM MASTER} "auto-magically" sets up a slave.
@code{LOAD DATA FROM MASTER} ``auto-magically'' sets up a slave.
@item
Renamed @code{safe_mysqld} to @code{mysqld_safe}.
@item
Added support for symbolic links to @code{MyISAM} tables. Symlink handling is
now enabled by default for Windows.
@item
@code{LOAD DATA FROM MASTER} "auto-magically" sets up a slave.
@code{LOAD DATA FROM MASTER} ``auto-magically'' sets up a slave.
@item
Added @code{SQL_CALC_FOUND_ROWS} and @code{FOUND_ROWS()}. This makes it
possible to know how many rows a query would have returned
......@@ -48486,15 +48486,15 @@ Added @code{ORDER BY} syntax to @code{UPDATE} and @code{DELETE}.
Added @code{ALTER TABLE table_name DISABLE KEYS} and
@code{ALTER TABLE table_name ENABLE KEYS} commands.
@item
Allow one to use @code{IN} instead of @code{FROM} in @code{SHOW} commands.
Allow use of @code{IN} as a synonym for @code{FROM} in @code{SHOW} commands.
@item
Implemented ``repair by sort'' for @code{FULLTEXT} indexes.
@code{REPAIR TABLE}, @code{ALTER TABLE}, and @code{OPTIMIZE TABLE}
for tables with @code{FULLTEXT} indexes are now up to 100 times faster.
@item
Allow ANSI SQL syntax @code{X'hexadecimal-number'}
Allow ANSI SQL syntax @code{X'hexadecimal-number'}.
@item
Cleaned up global lock handling for @code{FLUSH TABLES WITH READ LOCK}
Cleaned up global lock handling for @code{FLUSH TABLES WITH READ LOCK}.
@item
Fixed problem with @code{DATETIME = constant} in @code{WHERE} optimisation.
@item
......@@ -48610,13 +48610,13 @@ Restrict InnoDB keys to 500 bytes.
@item
InnoDB now supports @code{NULL} in keys.
@item
Fixed shutdown problem on HPUX. (Introduced in 3.23.46)
Fixed shutdown problem on HP-UX. (Introduced in 3.23.46)
@item
Fixed core-dump bug in replication when using SELECT RELEASE_LOCK();
Fixed core-dump bug in replication when using @code{SELECT RELEASE_LOCK()}.
@item
Added new command: @code{DO expression,[expression]}
@item
Added @code{slave-skip-errors} option
Added @code{slave-skip-errors} option.
@item
Added statistics variables for all MySQL commands. (@code{SHOW STATUS} is
now much longer).
......@@ -48627,7 +48627,7 @@ Fixed that @code{GROUP BY expr DESC} works.
@item
Fixed bug when using @code{t1 LEFT JOIN t2 ON t2.key=constant}.
@item
@code{mysql_config} now also work with binary (relocated) distributions.
@code{mysql_config} now also works with binary (relocated) distributions.
@end itemize
@node News-3.23.46, News-3.23.45, News-3.23.47, News-3.23.x
......@@ -15,7 +15,8 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* mysqltest test tool
* See man page for more information.
* See the manual for more information
* TODO: document better how mysqltest works
*
* Written by:
* Sasha Pachev <sasha@mysql.com>
......@@ -26,9 +27,6 @@
/**********************************************************************
TODO:
- Print also the queries that returns a result to the log file; This makes
it much easier to find out what's wrong.
- Do comparison line by line, instead of doing a full comparison of
the text file. This will save space as we don't need to keep many
results in memory. It will also make it possible to do simple
......@@ -43,7 +41,7 @@
**********************************************************************/
#define MTEST_VERSION "1.13"
#define MTEST_VERSION "1.14"
#include <my_global.h>
#include <mysql_embed.h>
......@@ -88,6 +86,12 @@
#define CON_RETRY_SLEEP 2
#define MAX_CON_TRIES 5
#ifndef OS2
#define SLAVE_POLL_INTERVAL 300000 /* 0.3 of a sec */
#else
#defile SLAVE_POLL_INTERVAL 0.3
#endif
enum {OPT_MANAGER_USER=256,OPT_MANAGER_HOST,OPT_MANAGER_PASSWD,
OPT_MANAGER_PORT,OPT_MANAGER_WAIT_TIMEOUT};
......@@ -187,6 +191,7 @@ Q_DISABLE_RPL_PARSE, Q_EVAL_RESULT,
Q_ENABLE_QUERY_LOG, Q_DISABLE_QUERY_LOG,
Q_ENABLE_RESULT_LOG, Q_DISABLE_RESULT_LOG,
Q_SERVER_START, Q_SERVER_STOP,Q_REQUIRE_MANAGER,
Q_WAIT_FOR_SLAVE_TO_STOP,
Q_UNKNOWN, /* Unknown command. */
Q_COMMENT, /* Comments, ignored. */
Q_COMMENT_WITH_COMMAND
......@@ -222,7 +227,7 @@ const char *command_names[] = {
"enable_query_log", "disable_query_log",
"enable_result_log", "disable_result_log",
"server_start", "server_stop",
"require_manager",
"require_manager", "wait_for_slave_to_stop",
0
};
......@@ -653,6 +658,45 @@ int open_file(const char* name)
return 0;
}
/* ugly long name, but we are following the convention */
int do_wait_for_slave_to_stop(struct st_query* __attribute__((unused)) q)
{
MYSQL* mysql = &cur_con->mysql;
#ifndef OS2
struct timeval t;
#endif
for (;;)
{
MYSQL_RES* res;
MYSQL_ROW row;
int done;
LINT_INIT(res);
if (mysql_query(mysql,"show status like 'Slave_running'")
|| !(res=mysql_store_result(mysql)))
die("Query failed while probing slave for stop: %s",
mysql_error(mysql));
if (!(row=mysql_fetch_row(res)) || !row[1])
{
mysql_free_result(res);
die("Strange result from query while probing slave for stop");
}
done = !strcmp(row[1],"OFF");
mysql_free_result(res);
if (done)
break;
#ifndef OS2
t.tv_sec=0;
t.tv_usec=SLAVE_POLL_INTERVAL;
select(0,0,0,0,&t); /* sleep */
#else
DosSleep(OS2_SLAVE_POLL_INTERVAL);
#endif
}
return 0;
}
int do_require_manager(struct st_query* __attribute__((unused)) q)
{
if (!manager)
......@@ -2335,6 +2379,7 @@ int main(int argc, char** argv)
case Q_DISABLE_RESULT_LOG: disable_result_log=1; break;
case Q_SOURCE: do_source(q); break;
case Q_SLEEP: do_sleep(q); break;
case Q_WAIT_FOR_SLAVE_TO_STOP: do_wait_for_slave_to_stop(q); break;
case Q_REQUIRE_MANAGER: do_require_manager(q); break;
#ifndef EMBEDDED_LIBRARY
case Q_SERVER_START: do_server_start(q); break;
......
......@@ -28,7 +28,7 @@ noinst_HEADERS = config-win.h \
my_dir.h mysys_err.h my_base.h \
my_nosys.h my_alarm.h queues.h \
my_tree.h hash.h thr_alarm.h thr_lock.h \
getopt.h t_ctype.h violite.h md5.h \
getopt.h my_getopt.h t_ctype.h violite.h md5.h \
mysql_version.h.in
# mysql_version.h are generated
......
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
struct my_optarg
{
char *arg; /* option argument */
int pos; /* next element in ARGV */
int verbose; /* 0 = inhibit warnings of unrecognized options */
int unrecognized; /* position of the unrecognized option */
};
enum get_opt_var_type { GET_NO_ARG, GET_INT, GET_LL, GET_STR };
enum get_opt_arg_type { NO_ARG, OPT_ARG, REQUIRED_ARG };
struct my_option
{
const char *name; /* Name of the option */
const char *comment; /* option comment, for autom. --help */
char *value; /* The variable value */
const char **str_values; /* Pointer to possible values */
enum get_opt_var_type var_type;
enum get_opt_arg_type arg_type;
int id; /* unique id or short option */
long long def_value; /* Default value */
long long min_value; /* Min allowed value */
long long max_value; /* Max allowed value */
long long sub_size; /* Subtract this from given value */
long block_size; /* Value should be a mult. of this */
int app_type; /* To be used by an application */
my_bool changeable_var; /* If true, the option is a variable */
};
......@@ -643,7 +643,10 @@ extern int _my_b_write(IO_CACHE *info,const byte *Buffer,uint Count);
extern int my_b_append(IO_CACHE *info,const byte *Buffer,uint Count);
extern int my_block_write(IO_CACHE *info, const byte *Buffer,
uint Count, my_off_t pos);
extern int flush_io_cache(IO_CACHE *info);
extern int _flush_io_cache(IO_CACHE *info, int need_append_buffer_lock);
#define flush_io_cache(info) _flush_io_cache((info),1)
extern int end_io_cache(IO_CACHE *info);
extern uint my_b_fill(IO_CACHE *info);
extern void my_b_seek(IO_CACHE *info,my_off_t pos);
......
This diff is collapsed.
......@@ -33,7 +33,6 @@ master-bin.003
insert into t2 values(1234);
set insert_id=1234;
insert into t2 values(NULL);
slave stop;
set sql_slave_skip_counter=1;
slave start;
purge master logs to 'master-bin.003';
......@@ -66,7 +65,7 @@ slave stop;
slave start;
show slave status;
Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos
127.0.0.1 root MASTER_PORT 60 master-bin.006 445 mysql-relay-bin.004 1312 master-bin.006 Yes Yes 0 0 445
127.0.0.1 root MASTER_PORT 60 master-bin.006 445 mysql-relay-bin.004 1376 master-bin.006 Yes Yes 0 0 445
lock tables t3 read;
select count(*) from t3 where n >= 4;
count(*)
......
......@@ -51,9 +51,7 @@ insert into t2 values(NULL);
connection slave;
sync_with_master;
#the slave may have already stopped, so we ignore the error
--error 0,1199
!slave stop;
wait_for_slave_to_stop;
#restart slave skipping one event
set sql_slave_skip_counter=1;
......
......@@ -44,7 +44,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c\
my_delete.c my_rename.c my_redel.c my_tempnam.c \
my_chsize.c my_lread.c my_lwrite.c my_clock.c \
my_quick.c my_lockmem.c my_static.c \
getopt.c getopt1.c getvar.c my_mkdir.c \
getopt.c getopt1.c my_getopt.c getvar.c my_mkdir.c \
default.c my_compress.c checksum.c raid.cc my_net.c \
my_vsnprintf.c charset.c my_bitmap.c my_bit.c md5.c
EXTRA_DIST = thr_alarm.c thr_lock.c my_pthread.c my_thr_init.c \
......
......@@ -19,7 +19,7 @@
#include "mysys_priv.h"
#include <m_string.h>
#include <m_ctype.h>
#include <my_getopt.h>
/* set all changeable variables */
void set_all_changeable_vars(CHANGEABLE_VAR *vars)
......@@ -109,3 +109,78 @@ my_bool set_changeable_var(my_string str,CHANGEABLE_VAR *vars)
}
DBUG_RETURN(1);
}
my_bool my_set_changeable_var(my_string str, const struct my_option *vars)
{
char endchar;
my_string end;
DBUG_ENTER("my_set_changeable_var");
DBUG_PRINT("enter",("%s",str));
if (str)
{
if (!(end=strchr(str,'=')))
fprintf(stderr,"Can't find '=' in expression '%s' to option -O\n",str);
else
{
uint length,found_count=0;
const struct my_option *var, *found;
my_string var_end;
const char *name;
longlong num;
/* Skip end space from variable */
for (var_end=end ; end > str && isspace(var_end[-1]) ; var_end--) ;
length=(uint) (var_end-str);
/* Skip start space from argument */
for (end++ ; isspace(*end) ; end++) ;
for (var= vars, found= 0; (name= var->name); var++)
{
if (var->changeable_var)
{
if (!my_casecmp(name, str, length))
{
found= var; found_count++;
if (!name[length])
{
found_count=1;
break;
}
}
}
}
if (found_count == 0)
{
fprintf(stderr,"No variable match for: -O '%s'\n",str);
DBUG_RETURN(1);
}
if (found_count > 1)
{
fprintf(stderr,"Variable prefix '%*s' is not unique\n",length,str);
DBUG_RETURN(1);
}
num=strtoll(end, (char **)NULL, 10); endchar=strend(end)[-1];
if (endchar == 'k' || endchar == 'K')
num*=1024;
else if (endchar == 'm' || endchar == 'M')
num*=1024L*1024L;
else if (endchar == 'g' || endchar == 'G')
num*=1024L*1024L*1024L;
else if (!isdigit(endchar))
{
fprintf(stderr,"Unknown prefix used for variable value '%s'\n",str);
DBUG_RETURN(1);
}
if (num < (longlong) found->min_value)
num=(longlong) found->min_value;
else if (num > 0 && (ulonglong) num > (ulonglong) (ulong) found->max_value)
num=(longlong) (ulong) found->max_value;
num=((num- (longlong) found->sub_size) / (ulonglong) found->block_size);
/* (*found->varptr)= (long) (num*(ulonglong) found->block_size);*/
DBUG_RETURN(0);
}
}
DBUG_RETURN(1);
}
......@@ -808,13 +808,19 @@ int my_b_append(register IO_CACHE *info, const byte *Buffer, uint Count)
Buffer+=rest_length;
Count-=rest_length;
info->write_pos+=rest_length;
if (flush_io_cache(info))
if (_flush_io_cache(info,0))
{
unlock_append_buffer(info);
return 1;
}
if (Count >= IO_SIZE)
{ /* Fill first intern buffer */
length=Count & (uint) ~(IO_SIZE-1);
if (my_write(info->file,Buffer,(uint) length,info->myflags | MY_NABP))
{
unlock_append_buffer(info);
return info->error= -1;
}
Count-=length;
Buffer+=length;
}
......@@ -883,14 +889,16 @@ int my_block_write(register IO_CACHE *info, const byte *Buffer, uint Count,
/* Flush write cache */
int flush_io_cache(IO_CACHE *info)
int _flush_io_cache(IO_CACHE *info, int need_append_buffer_lock)
{
uint length;
my_bool append_cache;
my_off_t pos_in_file;
DBUG_ENTER("flush_io_cache");
append_cache = (info->type == SEQ_READ_APPEND);
if (!(append_cache = (info->type == SEQ_READ_APPEND)))
need_append_buffer_lock=0;
if (info->type == WRITE_CACHE || append_cache)
{
if (info->file == -1)
......@@ -898,6 +906,8 @@ int flush_io_cache(IO_CACHE *info)
if (real_open_cached_file(info))
DBUG_RETURN((info->error= -1));
}
if (need_append_buffer_lock)
lock_append_buffer(info);
if ((length=(uint) (info->write_pos - info->write_buffer)))
{
pos_in_file=info->pos_in_file;
......@@ -909,6 +919,8 @@ int flush_io_cache(IO_CACHE *info)
if (my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0)) ==
MY_FILEPOS_ERROR)
{
if (need_append_buffer_lock)
unlock_append_buffer(info);
DBUG_RETURN((info->error= -1));
}
if (!append_cache)
......@@ -932,6 +944,8 @@ int flush_io_cache(IO_CACHE *info)
info->end_of_file+=(info->write_pos-info->append_read_pos);
info->append_read_pos=info->write_pos=info->write_buffer;
if (need_append_buffer_lock)
unlock_append_buffer(info);
DBUG_RETURN(info->error);
}
}
......@@ -942,6 +956,8 @@ int flush_io_cache(IO_CACHE *info)
info->inited=0;
}
#endif
if (need_append_buffer_lock)
unlock_append_buffer(info);
DBUG_RETURN(0);
}
......
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <my_config.h>
#include <my_global.h>
#include <m_string.h>
#include <stdlib.h>
#include <my_getopt.h>
#include <assert.h>
static int sortopt (int *argc, char ***argv);
static int findopt (char *optpat, uint length,
const struct my_option **opt_res,
char **ffname);
#define DISABLE_OPTION_COUNT 2
static char *special_opt_prefix[] = {"skip", "disable", "enable", 0};
/* function: handle_options
Sort options; put options first, until special end of options (--), or
until end of argv. Parse options; check that the given option matches with
one of the options in struct 'my_option', return error in case of ambiguous
or unknown option. Check that option was given an argument if it requires
one. Call function 'get_one_option()' once for each option.
*/
extern int handle_options (int *argc, char ***argv,
const struct my_option *longopts,
my_bool (*get_one_option)(int,
const struct my_option *,
char *))
{
uint opt_found, argvpos = 0, length, spec_len, i;
my_bool end_of_options = 0, must_be_var = 0;
char *progname = *(*argv), **pos, *optend, *prev_found;
const struct my_option *optp;
(*argc)--;
(*argv)++;
for (pos = *argv; *pos; pos++)
{
char *cur_arg= *pos;
if (*cur_arg == '-' && *(cur_arg + 1) && !end_of_options) // must be opt.
{
char *argument = 0;
must_be_var= 0;
// check for long option, or --set-variable (-O)
if (*(cur_arg + 1) == '-' || *(cur_arg + 1) == 'O')
{
if (*(cur_arg + 1) == 'O' || !strncmp(cur_arg, "--set-variable", 14))
{
must_be_var= 1;
if (*(cur_arg + 1) == 'O')
{
cur_arg+= 2;
if (!(*cur_arg))
{
// the argument must be in next argv
if (!(*(pos + 1)))
{
fprintf(stderr, "%s: Option '-O' requires an argument\n",
progname);
return 4;
}
pos++;
cur_arg= *pos;
(*argc)--;
}
}
else // Option argument begins with string '--set-variable'
{
cur_arg+= 14;
if (*cur_arg == '=')
{
cur_arg++;
if (!(*cur_arg))
{
fprintf(stderr,
"%s: Option '--set-variable' requires an argument\n",
progname);
return 4;
}
}
else if (*cur_arg) // garbage, or another option. break out
{
cur_arg-= 14;
must_be_var= 0;
}
else
{
// the argument must be in next argv
if (!(*(pos + 1)))
{
fprintf(stderr,
"%s: Option '--set-variable' requires an argument\n",
progname);
return 4;
}
pos++;
cur_arg= *pos;
(*argc)--;
}
}
}
else if (!must_be_var)
{
if (!*(cur_arg + 2)) // '--' means end of options, look no further
{
end_of_options = 1;
(*argc)--;
continue;
}
cur_arg+= 2; // skip the double dash
}
for (optend = cur_arg; *optend && *optend != '='; optend++) ;
length = optend - cur_arg;
/*
Find first the right option. Return error in case of an ambiguous,
or unknown option
*/
optp = longopts;
if (!(opt_found = findopt(cur_arg, length, &optp, &prev_found)))
{
/*
Didn't find any matching option. Let's see if someone called
option with a special option prefix
*/
if (*optend != '=' && !must_be_var)
{
for (i = 0; special_opt_prefix[i]; i++)
{
spec_len = strlen(special_opt_prefix[i]);
if (!strncmp(special_opt_prefix[i], cur_arg, spec_len) &&
cur_arg[spec_len] == '-')
{
// We were called with a special prefix, we can reuse opt_found
cur_arg += (spec_len + 1);
if ((opt_found = findopt(cur_arg, length - (spec_len + 1),
&optp, &prev_found)))
{
if (opt_found > 1)
{
fprintf(stderr,
"%s: ambiguous option '--%s-%s' (--%s-%s)\n",
progname, special_opt_prefix[i], cur_arg,
special_opt_prefix[i], prev_found);
return 2;
}
if (i < DISABLE_OPTION_COUNT)
optend= "=0";
else // enable
optend= "=1";
break; // note break from the inner loop, main loop continues
}
}
}
}
if (!opt_found)
{
if (must_be_var)
{
fprintf(stderr,
"%s: unknown variable '%s'\n", progname, cur_arg);
return 7;
}
else
{
fprintf(stderr,
"%s: unknown option '--%s'\n", progname, cur_arg);
return 1;
}
}
}
if (opt_found > 1)
{
if (must_be_var)
{
fprintf(stderr, "%s: variable prefix '%s' is not unique\n",
progname, cur_arg);
return 6;
}
else
{
fprintf(stderr, "%s: ambiguous option '--%s' (%s, %s)\n",
progname, cur_arg, prev_found, optp->name);
return 2;
}
}
if (must_be_var && !optp->changeable_var)
{
fprintf(stderr, "%s: the argument to -O must be a variable\n",
progname);
return 8;
}
if (optp->arg_type == NO_ARG && *optend == '=')
{
fprintf(stderr, "%s: option '--%s' cannot take an argument\n",
progname, optp->name);
return 3;
}
else if (optp->arg_type == REQUIRED_ARG && !*optend)
{
/* Check if there are more arguments after this one */
if (!(*(pos + 1)))
{
fprintf(stderr, "%s: option '--%s' requires an argument\n",
progname, optp->name);
return 4;
}
pos++;
argument = *pos;
(*argc)--;
}
else if (*optend == '=')
argument = *(optend + 1) ? optend + 1 : "";
}
else // must be short option
{
my_bool skip;
for (skip = 0, optend = (cur_arg + 1); *optend && !skip; optend++)
{
for (optp = longopts; optp->id ; optp++)
{
if (optp->id == (int) (uchar) *optend)
{
/* Option recognized. Find next what to do with it */
if (optp->arg_type == REQUIRED_ARG || optp->arg_type == OPT_ARG)
{
if (*(optend + 1))
{
argument = (optend + 1);
/*
The rest of the option is option argument
This is in effect a jump out of this loop
*/
skip = 1;
}
else if (optp->arg_type == REQUIRED_ARG)
{
/* Check if there are more arguments after this one */
if (!(*(pos + 1)))
{
fprintf(stderr, "%s: option '-%c' requires an argument\n",
progname, optp->id);
return 4;
}
pos++;
argument = *pos;
(*argc)--;
}
}
else if (*(optend + 1)) // we are hitting many options in 1 argv
get_one_option(optp->id, optp, 0);
break;
}
}
}
}
get_one_option(optp->id, optp, argument);
(*argc)--; // option handled (short or long), decrease argument count
}
else // non-option found
(*argv)[argvpos++] = cur_arg;
}
return 0;
}
/* function: findopt
Arguments: opt_pattern, length of opt_pattern, opt_struct, first found
name (ffname)
Go through all options in the my_option struct. Return number
of options found that match the pattern and in the argument
list the option found, if any. In case of ambiguous option, store
the name in ffname argument
*/
static int findopt (char *optpat, uint length,
const struct my_option **opt_res,
char **ffname)
{
int count;
struct my_option *opt= (struct my_option *) *opt_res;
for (count = 0; opt->id; opt++)
{
if (!strncmp(opt->name, optpat, length)) // match found
{
(*opt_res) = opt;
if (!count)
*ffname = (char *) opt->name; // we only need to know one prev
if (length == strlen(opt->name)) // exact match
return 1;
count++;
}
}
return count;
}
......@@ -703,12 +703,37 @@ void MYSQL_LOG::new_file(bool inside_mutex)
}
}
bool MYSQL_LOG::append(Log_event* ev)
{
bool error = 0;
pthread_mutex_lock(&LOCK_log);
DBUG_ASSERT(log_file.type == SEQ_READ_APPEND);
// Log_event::write() is smart enough to use my_b_write() or
// my_b_append() depending on the kind of cache we have
if (ev->write(&log_file))
{
error=1;
goto err;
}
if ((uint)my_b_append_tell(&log_file) > max_binlog_size)
{
new_file(1);
}
signal_update();
err:
pthread_mutex_unlock(&LOCK_log);
return error;
}
bool MYSQL_LOG::appendv(const char* buf, uint len,...)
{
bool error = 0;
va_list(args);
va_start(args,len);
DBUG_ASSERT(log_file.type == SEQ_READ_APPEND);
pthread_mutex_lock(&LOCK_log);
do
{
......
......@@ -26,6 +26,18 @@
#include <assert.h>
inline int my_b_safe_write(IO_CACHE* file, const char* buf,
int len)
{
// Sasha: We are not writing this with the ? operator to avoid hitting
// a possible compiler bug. At least gcc 2.95 cannot deal with
// several layers of ternary operators that evaluated comma(,) operator
// expressions inside - I do have a test case if somebody wants it
if (file->type == SEQ_READ_APPEND)
return my_b_append(file,buf,len);
return my_b_write(file,buf,len);
}
#ifdef MYSQL_CLIENT
static void pretty_print_str(FILE* file, char* str, int len)
{
......@@ -403,7 +415,7 @@ int Log_event::write_header(IO_CACHE* file)
pos += 4;
int2store(pos, flags);
pos += 2;
return (my_b_write(file, (byte*) buf, (uint) (pos - buf)));
return (my_b_safe_write(file, (byte*) buf, (uint) (pos - buf)));
}
#ifndef MYSQL_CLIENT
......@@ -677,7 +689,7 @@ int Start_log_event::write_data(IO_CACHE* file)
int2store(buff + ST_BINLOG_VER_OFFSET,binlog_version);
memcpy(buff + ST_SERVER_VER_OFFSET,server_version,ST_SERVER_VER_LEN);
int4store(buff + ST_CREATED_OFFSET,created);
return (my_b_write(file, (byte*) buff, sizeof(buff)) ? -1 : 0);
return (my_b_safe_write(file, (byte*) buff, sizeof(buff)) ? -1 : 0);
}
Rotate_log_event::Rotate_log_event(const char* buf, int event_len,
......@@ -714,8 +726,8 @@ int Rotate_log_event::write_data(IO_CACHE* file)
{
char buf[ROTATE_HEADER_LEN];
int8store(buf, pos + R_POS_OFFSET);
return my_b_write(file, (byte*)buf, ROTATE_HEADER_LEN) ||
my_b_write(file, (byte*)new_log_ident, (uint) ident_len);
return my_b_safe_write(file, (byte*)buf, ROTATE_HEADER_LEN) ||
my_b_safe_write(file, (byte*)new_log_ident, (uint) ident_len);
}
#ifndef MYSQL_CLIENT
......@@ -812,9 +824,9 @@ int Query_log_event::write_data(IO_CACHE* file)
buf[Q_DB_LEN_OFFSET] = (char)db_len;
int2store(buf + Q_ERR_CODE_OFFSET, error_code);
return (my_b_write(file, (byte*) buf, QUERY_HEADER_LEN) ||
my_b_write(file, (db) ? (byte*) db : (byte*)"", db_len + 1) ||
my_b_write(file, (byte*) query, q_len)) ? -1 : 0;
return (my_b_safe_write(file, (byte*) buf, QUERY_HEADER_LEN) ||
my_b_safe_write(file, (db) ? (byte*) db : (byte*)"", db_len + 1) ||
my_b_safe_write(file, (byte*) query, q_len)) ? -1 : 0;
}
Intvar_log_event::Intvar_log_event(const char* buf, bool old_format):
......@@ -840,7 +852,7 @@ int Intvar_log_event::write_data(IO_CACHE* file)
char buf[9];
buf[I_TYPE_OFFSET] = type;
int8store(buf + I_VAL_OFFSET, val);
return my_b_write(file, (byte*) buf, sizeof(buf));
return my_b_safe_write(file, (byte*) buf, sizeof(buf));
}
#ifdef MYSQL_CLIENT
......@@ -878,7 +890,7 @@ int Load_log_event::write_data_header(IO_CACHE* file)
buf[L_TBL_LEN_OFFSET] = (char)table_name_len;
buf[L_DB_LEN_OFFSET] = (char)db_len;
int4store(buf + L_NUM_FIELDS_OFFSET, num_fields);
return my_b_write(file, (byte*)buf, LOAD_HEADER_LEN);
return my_b_safe_write(file, (byte*)buf, LOAD_HEADER_LEN);
}
int Load_log_event::write_data_body(IO_CACHE* file)
......@@ -886,20 +898,20 @@ int Load_log_event::write_data_body(IO_CACHE* file)
if (sql_ex.write_data(file)) return 1;
if (num_fields && fields && field_lens)
{
if (my_b_write(file, (byte*)field_lens, num_fields) ||
my_b_write(file, (byte*)fields, field_block_len))
if (my_b_safe_write(file, (byte*)field_lens, num_fields) ||
my_b_safe_write(file, (byte*)fields, field_block_len))
return 1;
}
return (my_b_write(file, (byte*)table_name, table_name_len + 1) ||
my_b_write(file, (byte*)db, db_len + 1) ||
my_b_write(file, (byte*)fname, fname_len));
return (my_b_safe_write(file, (byte*)table_name, table_name_len + 1) ||
my_b_safe_write(file, (byte*)db, db_len + 1) ||
my_b_safe_write(file, (byte*)fname, fname_len));
}
static bool write_str(IO_CACHE *file, char *str, byte length)
{
return (my_b_write(file, &length, 1) ||
my_b_write(file, (byte*) str, (int) length));
return (my_b_safe_write(file, &length, 1) ||
my_b_safe_write(file, (byte*) str, (int) length));
}
int sql_ex_info::write_data(IO_CACHE* file)
......@@ -911,7 +923,7 @@ int sql_ex_info::write_data(IO_CACHE* file)
write_str(file, line_term, line_term_len) ||
write_str(file, line_start, line_start_len) ||
write_str(file, escaped, escaped_len) ||
my_b_write(file,(byte*) &opt_flags,1));
my_b_safe_write(file,(byte*) &opt_flags,1));
}
else
{
......@@ -923,7 +935,7 @@ int sql_ex_info::write_data(IO_CACHE* file)
old_ex.escaped= *escaped;
old_ex.opt_flags= opt_flags;
old_ex.empty_flags=empty_flags;
return my_b_write(file, (byte*) &old_ex, sizeof(old_ex));
return my_b_safe_write(file, (byte*) &old_ex, sizeof(old_ex));
}
}
......@@ -1280,7 +1292,7 @@ int Slave_log_event::write_data(IO_CACHE* file)
int8store(mem_pool + SL_MASTER_POS_OFFSET, master_pos);
int2store(mem_pool + SL_MASTER_PORT_OFFSET, master_port);
// log and host are already there
return my_b_write(file, (byte*)mem_pool, get_data_size());
return my_b_safe_write(file, (byte*)mem_pool, get_data_size());
}
void Slave_log_event::init_from_mem_pool(int data_size)
......@@ -1330,8 +1342,8 @@ int Create_file_log_event::write_data_body(IO_CACHE* file)
int res;
if ((res = Load_log_event::write_data_body(file)) || fake_base)
return res;
return (my_b_write(file, (byte*) "", 1) ||
my_b_write(file, (byte*) block, block_len));
return (my_b_safe_write(file, (byte*) "", 1) ||
my_b_safe_write(file, (byte*) block, block_len));
}
int Create_file_log_event::write_data_header(IO_CACHE* file)
......@@ -1341,7 +1353,7 @@ int Create_file_log_event::write_data_header(IO_CACHE* file)
return res;
byte buf[CREATE_FILE_HEADER_LEN];
int4store(buf + CF_FILE_ID_OFFSET, file_id);
return my_b_write(file, buf, CREATE_FILE_HEADER_LEN);
return my_b_safe_write(file, buf, CREATE_FILE_HEADER_LEN);
}
int Create_file_log_event::write_base(IO_CACHE* file)
......@@ -1423,8 +1435,8 @@ int Append_block_log_event::write_data(IO_CACHE* file)
{
byte buf[APPEND_BLOCK_HEADER_LEN];
int4store(buf + AB_FILE_ID_OFFSET, file_id);
return (my_b_write(file, buf, APPEND_BLOCK_HEADER_LEN) ||
my_b_write(file, (byte*) block, block_len));
return (my_b_safe_write(file, buf, APPEND_BLOCK_HEADER_LEN) ||
my_b_safe_write(file, (byte*) block, block_len));
}
#ifdef MYSQL_CLIENT
......@@ -1473,7 +1485,7 @@ int Delete_file_log_event::write_data(IO_CACHE* file)
{
byte buf[DELETE_FILE_HEADER_LEN];
int4store(buf + DF_FILE_ID_OFFSET, file_id);
return my_b_write(file, buf, DELETE_FILE_HEADER_LEN);
return my_b_safe_write(file, buf, DELETE_FILE_HEADER_LEN);
}
#ifdef MYSQL_CLIENT
......@@ -1520,7 +1532,7 @@ int Execute_load_log_event::write_data(IO_CACHE* file)
{
byte buf[EXEC_LOAD_HEADER_LEN];
int4store(buf + EL_FILE_ID_OFFSET, file_id);
return my_b_write(file, buf, EXEC_LOAD_HEADER_LEN);
return my_b_safe_write(file, buf, EXEC_LOAD_HEADER_LEN);
}
#ifdef MYSQL_CLIENT
......
......@@ -54,6 +54,9 @@ static int stuck_count = 0;
typedef enum { SLAVE_THD_IO, SLAVE_THD_SQL} SLAVE_THD_TYPE;
void skip_load_data_infile(NET* net);
static int process_io_rotate(MASTER_INFO* mi, Rotate_log_event* rev);
static int queue_old_event(MASTER_INFO* mi, const char* buf,
uint event_len);
static inline bool slave_killed(THD* thd,MASTER_INFO* mi);
static inline bool slave_killed(THD* thd,RELAY_LOG_INFO* rli);
static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type);
......@@ -1918,34 +1921,86 @@ the slave SQL thread with \"mysqladmin start-slave\". We stopped at log \
DBUG_RETURN(0); // Can't return anything here
}
static int process_io_rotate(MASTER_INFO* mi, Rotate_log_event* rev)
{
if (!rev->is_valid())
return 1;
DBUG_ASSERT(rev->ident_len<sizeof(mi->master_log_name));
memcpy(mi->master_log_name,rev->new_log_ident,
rev->ident_len);
mi->master_log_name[rev->ident_len] = 0;
mi->master_log_pos = rev->pos;
#ifndef DBUG_OFF
/* if we do not do this, we will be getting the first
rotate event forever, so
we need to not disconnect after one
*/
if (disconnect_slave_event_count)
events_till_disconnect++;
#endif
return 0;
}
static int queue_old_event(MASTER_INFO* mi, const char* buf,
uint event_len)
{
const char* errmsg = 0;
bool inc_pos = 1;
Log_event* ev = Log_event::read_log_event(buf,event_len, &errmsg,
1/*old format*/);
if (!ev)
{
sql_print_error("Read invalid event from master: '%s',\
master could be corrupt but a more likely cause of this is a bug",
errmsg);
return 1;
}
ev->log_pos = mi->master_log_pos;
switch (ev->get_type_code())
{
case ROTATE_EVENT:
if (process_io_rotate(mi,(Rotate_log_event*)ev))
{
delete ev;
return 1;
}
inc_pos = 0;
break;
case LOAD_EVENT:
// TODO: actually process it
mi->master_log_pos += event_len;
return 0;
break;
default:
break;
}
if (mi->rli.relay_log.append(ev))
{
delete ev;
return 1;
}
delete ev;
if (inc_pos)
mi->master_log_pos += event_len;
return 0;
}
int queue_event(MASTER_INFO* mi,const char* buf,uint event_len)
{
int error;
bool inc_pos = 1;
if (mi->old_format)
return 1; // TODO: deal with old format
return queue_old_event(mi,buf,event_len);
// TODO: figure out if other events in addition to Rotate
// require special processing
switch (buf[EVENT_TYPE_OFFSET])
{
case ROTATE_EVENT:
{
Rotate_log_event rev(buf,event_len,0);
if (!rev.is_valid())
if (process_io_rotate(mi,&rev))
return 1;
DBUG_ASSERT(rev.ident_len<sizeof(mi->master_log_name));
memcpy(mi->master_log_name,rev.new_log_ident,
rev.ident_len);
mi->master_log_name[rev.ident_len] = 0;
mi->master_log_pos = rev.pos;
inc_pos = 0;
#ifndef DBUG_OFF
/* if we do not do this, we will be getting the first
rotate event forever, so
we need to not disconnect after one
*/
if (disconnect_slave_event_count)
events_till_disconnect++;
#endif
inc_pos=0;
break;
}
default:
......
......@@ -108,6 +108,7 @@ public:
//v stands for vector
//invoked as appendv(buf1,len1,buf2,len2,...,bufn,lenn,0)
bool appendv(const char* buf,uint len,...);
bool append(Log_event* ev);
int generate_new_name(char *new_name,const char *old_name);
void make_log_name(char* buf, const char* log_ident);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment