diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index 7957579ec8f..4986ccbba58 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -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 diff --git a/Docs/manual.texi b/Docs/manual.texi index 09aa557258e..6ac76194e5d 100644 --- a/Docs/manual.texi +++ b/Docs/manual.texi @@ -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 diff --git a/client/mysqltest.c b/client/mysqltest.c index 762589b0374..510fe6a3f4c 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -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 @@ -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 #include @@ -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; diff --git a/include/Makefile.am b/include/Makefile.am index 54451e9d4f6..b943e8d76e6 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -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 diff --git a/include/my_getopt.h b/include/my_getopt.h new file mode 100644 index 00000000000..3132d6a1672 --- /dev/null +++ b/include/my_getopt.h @@ -0,0 +1,46 @@ +/* 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 */ +}; + diff --git a/include/my_sys.h b/include/my_sys.h index f899e4f9324..1d7c0b7ddb1 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -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); diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c index 1ed23ffe4f6..eedbb6af940 100644 --- a/myisam/myisamchk.c +++ b/myisam/myisamchk.c @@ -20,7 +20,7 @@ #include #include -#include +#include #include #ifdef HAVE_SYS_VADVICE_H #include @@ -169,58 +169,75 @@ static CHANGEABLE_VAR changeable_vars[] = { enum options { OPT_CHARSETS_DIR=256, OPT_SET_CHARSET,OPT_START_CHECK_POS, - OPT_CORRECT_CHECKSUM + OPT_CORRECT_CHECKSUM, OPT_KEY_BUFFER_SIZE, OPT_MYISAM_BLOCK_SIZE, + OPT_READ_BUFFER_SIZE, OPT_WRITE_BUFFER_SIZE, OPT_SORT_BUFFER_SIZE, + OPT_SORT_KEY_BLOCKS, OPT_DECODE_BITS, OPT_FT_MIN_WORD_LEN, + OPT_FT_MAX_WORD_LEN, OPT_FT_MAX_WORD_LEN_FOR_SORT }; - -static struct option long_options[] = +static struct my_option my_long_options[] = { - {"analyze", no_argument, 0, 'a'}, - {"block-search", required_argument,0, 'b'}, - {"backup", no_argument, 0, 'B'}, - {"character-sets-dir",required_argument,0, OPT_CHARSETS_DIR}, - {"check", no_argument, 0, 'c'}, - {"check-only-changed",no_argument, 0, 'C'}, - {"correct-checksum", no_argument, 0, OPT_CORRECT_CHECKSUM}, + {"analyze", "", 0, 0, GET_NO_ARG, NO_ARG, 'a', 0, 0, 0, 0, 0, 0, 0}, + {"block-search", "", 0, 0, GET_LL, REQUIRED_ARG, 'b', 0, 0, 0, 0, 0, 0, 0}, + {"backup", "", 0, 0, GET_NO_ARG, NO_ARG, 'B', 0, 0, 0, 0, 0, 0, 0}, + {"character-sets-dir", "", 0, 0, GET_STR, REQUIRED_ARG, OPT_CHARSETS_DIR, 0, 0, 0, 0, 0, 0, 0}, + + {"check", "", 0, 0, GET_NO_ARG, NO_ARG, 'c', 0, 0, 0, 0, 0, 0, 0}, + {"check-only-changed", "", 0, 0, GET_NO_ARG, NO_ARG, 'C', 0, 0, 0, 0, 0, 0, 0}, + + {"correct-checksum", "", 0, 0, GET_NO_ARG, NO_ARG, OPT_CORRECT_CHECKSUM, 0, 0, 0, 0, 0, 0, 0}, #ifndef DBUG_OFF - {"debug", optional_argument, 0, '#'}, + {"debug", "", 0, 0, GET_STR, OPT_ARG, '#', 0, 0, 0, 0, 0, 0, 0}, #endif - {"description", no_argument, 0, 'd'}, - {"data-file-length", required_argument, 0, 'D'}, - {"extend-check", no_argument, 0, 'e'}, - {"fast", no_argument, 0, 'F'}, - {"force", no_argument, 0, 'f'}, - {"help", no_argument, 0, '?'}, - {"information", no_argument, 0, 'i'}, - {"keys-used", required_argument, 0, 'k'}, - {"medium-check", no_argument, 0, 'm'}, - {"quick", no_argument, 0, 'q'}, - {"read-only", no_argument, 0, 'T'}, - {"recover", no_argument, 0, 'r'}, - {"safe-recover", no_argument, 0, 'o'}, - {"start-check-pos", required_argument, 0, OPT_START_CHECK_POS}, - {"set-auto-increment",optional_argument, 0, 'A'}, - {"set-character-set",required_argument,0,OPT_SET_CHARSET}, - {"set-variable", required_argument, 0, 'O'}, - {"silent", no_argument, 0, 's'}, - {"sort-index", no_argument, 0, 'S'}, - {"sort-records", required_argument, 0, 'R'}, - {"sort-recover", no_argument, 0, 'n'}, - {"tmpdir", required_argument, 0, 't'}, - {"update-state", no_argument, 0, 'U'}, - {"unpack", no_argument, 0, 'u'}, - {"verbose", no_argument, 0, 'v'}, - {"version", no_argument, 0, 'V'}, - {"wait", no_argument, 0, 'w'}, - {0, 0, 0, 0} + {"description", "", 0, 0, GET_NO_ARG, NO_ARG, 'd', 0, 0, 0, 0, 0, 0, 0}, + {"data-file-length", "", 0, 0, GET_LL, REQUIRED_ARG, 'D', 0, 0, 0, 0, 0, 0, 0}, + {"extend-check", "", 0, 0, GET_NO_ARG, NO_ARG, 'e', 0, 0, 0, 0, 0, 0, 0}, + {"fast", "", 0, 0, GET_NO_ARG, NO_ARG, 'F', 0, 0, 0, 0, 0, 0, 0}, + {"force", "", 0, 0, GET_NO_ARG, NO_ARG, 'f', 0, 0, 0, 0, 0, 0, 0}, + {"help", "", 0, 0, GET_NO_ARG, NO_ARG, '?', 0, 0, 0, 0, 0, 0, 0}, + {"information", "", 0, 0, GET_NO_ARG, NO_ARG, 'i', 0, 0, 0, 0, 0, 0, 0}, + {"keys-used", "", 0, 0, GET_LL, REQUIRED_ARG, 'k', 0, 0, 0, 0, 0, 0, 0}, + {"medium-check", "", 0, 0, GET_NO_ARG, NO_ARG, 'm', 0, 0, 0, 0, 0, 0, 0}, + {"quick", "", 0, 0, GET_NO_ARG, NO_ARG, 'q', 0, 0, 0, 0, 0, 0, 0}, + {"read-only", "", 0, 0, GET_NO_ARG, NO_ARG, 'T', 0, 0, 0, 0, 0, 0, 0}, + {"recover", "", 0, 0, GET_NO_ARG, NO_ARG, 'r', 0, 0, 0, 0, 0, 0, 0}, + {"safe-recover", "", 0, 0, GET_NO_ARG, NO_ARG, 'o', 0, 0, 0, 0, 0, 0, 0}, + {"start-check-pos", "", 0, 0, GET_LL, REQUIRED_ARG, OPT_START_CHECK_POS, 0, 0, 0, 0, 0, 0, 0}, + {"set-auto-increment", "", 0, 0, GET_LL, OPT_ARG, 'A', 0, 0, 0, 0, 0, 0, 0}, + {"set-character-set", "", 0, 0, GET_STR, REQUIRED_ARG, OPT_SET_CHARSET, 0, 0, 0, 0, 0, 0, 0}, + {"set-variable", "", 0, 0, GET_STR, REQUIRED_ARG, 'O', 0, 0, 0, 0, 0, 0, 0}, + {"silent", "", 0, 0, GET_NO_ARG, NO_ARG, 's', 0, 0, 0, 0, 0, 0, 0}, + {"sort-index", "", 0, 0, GET_NO_ARG, NO_ARG, 'S', 0, 0, 0, 0, 0, 0, 0}, + {"sort-records", "", 0, 0, GET_INT, REQUIRED_ARG, 'R', 0, 0, 0, 0, 0, 0, 0}, + {"sort-recover", "", 0, 0, GET_NO_ARG, NO_ARG, 'n', 0, 0, 0, 0, 0, 0, 0}, + {"tmpdir", "", 0, 0, GET_STR, REQUIRED_ARG, 't', 0, 0, 0, 0, 0, 0, 0}, + {"update-state", "", 0, 0, GET_NO_ARG, NO_ARG, 'U', 0, 0, 0, 0, 0, 0, 0}, + {"unpack", "", 0, 0, GET_NO_ARG, NO_ARG, 'u', 0, 0, 0, 0, 0, 0, 0}, + {"verbose", "", 0, 0, GET_NO_ARG, NO_ARG, 'v', 0, 0, 0, 0, 0, 0, 0}, + {"version", "", 0, 0, GET_NO_ARG, NO_ARG, 'V', 0, 0, 0, 0, 0, 0, 0}, + {"wait", "", 0, 0, GET_NO_ARG, NO_ARG, 'w', 0, 0, 0, 0, 0, 0, 0}, + /* variables begin here */ + { "key_buffer_size", "", 0, 0, GET_LL, REQUIRED_ARG, OPT_KEY_BUFFER_SIZE, 0, 0, 0, 0, 0, 0, 1}, + { "myisam_block_size", "", 0, 0, GET_LL, REQUIRED_ARG, OPT_MYISAM_BLOCK_SIZE, 0, 0, 0, 0, 0, 0, 1}, + { "read_buffer_size", "", 0, 0, GET_LL, REQUIRED_ARG, OPT_READ_BUFFER_SIZE, 0, 0, 0, 0, 0, 0, 1}, + { "write_buffer_size", "", 0, 0, GET_LL, REQUIRED_ARG, OPT_WRITE_BUFFER_SIZE, 0, 0, 0, 0, 0, 0, 1}, + { "sort_buffer_size", "", 0, 0, GET_LL, REQUIRED_ARG, OPT_SORT_BUFFER_SIZE, 0, 0, 0, 0, 0, 0, 1}, + { "sort_key_blocks", "", 0, 0, GET_LL, REQUIRED_ARG, OPT_SORT_KEY_BLOCKS, 0, 0, 0, 0, 0, 0, 1}, + { "decode_bits", "", 0, 0, GET_LL, REQUIRED_ARG, OPT_DECODE_BITS, 0, 0, 0, 0, 0, 0, 1}, + { "ft_min_word_len", "", 0, 0, GET_LL, REQUIRED_ARG, OPT_FT_MIN_WORD_LEN, 0, 0, 0, 0, 0, 0, 1}, + { "ft_max_word_len", "", 0, 0, GET_LL, REQUIRED_ARG, OPT_FT_MAX_WORD_LEN, 0, 0, 0, 0, 0, 0, 1}, + { "ft_max_word_len_for_sort", "", 0, 0, GET_LL, REQUIRED_ARG, OPT_FT_MAX_WORD_LEN_FOR_SORT, 0, 0, 0, 0, 0, 0, 1}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; + static void print_version(void) { - printf("%s Ver 2.0 for %s at %s\n",my_progname,SYSTEM_TYPE, + printf("%s Ver 2.1 for %s at %s\n", my_progname, SYSTEM_TYPE, MACHINE_TYPE); } + static void usage(void) { uint i; @@ -315,163 +332,182 @@ static void usage(void) /* Read options */ +static my_bool get_one_option(int optid, const struct my_option *opt, + char *argument) +{ + uint old_testflag; + char buff[255], *end; + + switch(optid) { + case 'a': + check_param.testflag|= T_STATISTICS; + break; + case 'A': + if (argument) + check_param.auto_increment_value=strtoull(argument, NULL, 0); + else + check_param.auto_increment_value=0; /* Set to max used value */ + check_param.testflag|= T_AUTO_INC; + break; + case 'b': + check_param.search_after_block=strtoul(argument, NULL, 10); + break; + case 'B': + check_param.testflag|= T_BACKUP_DATA; + break; + case 'c': + check_param.testflag|= T_CHECK; + break; + case 'C': + check_param.testflag|= T_CHECK | T_CHECK_ONLY_CHANGED; + break; + case 'D': + check_param.max_data_file_length=strtoll(argument, NULL, 10); + break; + case 's': /* silent */ + if (check_param.testflag & T_SILENT) + check_param.testflag|=T_VERY_SILENT; + check_param.testflag|= T_SILENT; + check_param.testflag&= ~T_WRITE_LOOP; + break; + case 'w': + check_param.testflag|= T_WAIT_FOREVER; + break; + case 'd': /* description if isam-file */ + check_param.testflag|= T_DESCRIPT; + break; + case 'e': /* extend check */ + check_param.testflag|= T_EXTEND; + break; + case 'i': + check_param.testflag|= T_INFO; + break; + case 'f': + check_param.tmpfile_createflag= O_RDWR | O_TRUNC; + check_param.testflag|= T_FORCE_CREATE | T_UPDATE_STATE; + break; + case 'F': + check_param.testflag|=T_FAST; + break; + case 'k': + check_param.keys_in_use= (ulonglong) strtoll(argument, NULL, 10); + break; + case 'm': + check_param.testflag|= T_MEDIUM; /* Medium check */ + break; + case 'r': /* Repair table */ + check_param.testflag= (check_param.testflag & ~T_REP) | T_REP_BY_SORT; + break; + case 'o': + check_param.testflag= (check_param.testflag & ~T_REP_BY_SORT) | T_REP; + check_param.force_sort=0; + my_disable_async_io=1; /* More safety */ + break; + case 'n': + check_param.testflag= (check_param.testflag & ~T_REP) | T_REP_BY_SORT; + check_param.force_sort=1; + break; + case 'q': + check_param.opt_rep_quick++; + break; + case 'u': + check_param.testflag|= T_UNPACK | T_REP_BY_SORT; + break; + case 'v': /* Verbose */ + check_param.testflag|= T_VERBOSE; + check_param.verbose++; + break; + case 'O': + /* this is a temporary fix for variables to work until my_getopt */ + /* can my_set_changeable_vars */ + case OPT_KEY_BUFFER_SIZE: + case OPT_MYISAM_BLOCK_SIZE: + case OPT_READ_BUFFER_SIZE: + case OPT_WRITE_BUFFER_SIZE: + case OPT_SORT_BUFFER_SIZE: + case OPT_SORT_KEY_BLOCKS: + case OPT_DECODE_BITS: + case OPT_FT_MIN_WORD_LEN: + case OPT_FT_MAX_WORD_LEN: + case OPT_FT_MAX_WORD_LEN_FOR_SORT: + end= buff; + end= strmov(strmov(strmov(end, opt->name), "="), argument); + if (set_changeable_var(buff, changeable_vars)) + { + usage(); + exit(1); + } + break; + case 'R': /* Sort records */ + old_testflag=check_param.testflag; + check_param.testflag|= T_SORT_RECORDS; + check_param.opt_sort_key=(uint) atoi(argument) - 1; + if (check_param.opt_sort_key >= MI_MAX_KEY) + { + fprintf(stderr, + "The value of the sort key is bigger than max key: %d.\n", + MI_MAX_KEY); + exit(1); + } + break; + case 'S': /* Sort index */ + old_testflag=check_param.testflag; + check_param.testflag|= T_SORT_INDEX; + break; + case 't': + check_param.tmpdir=argument; + break; + case 'T': + check_param.testflag|= T_READONLY; + break; + case 'U': + check_param.testflag|= T_UPDATE_STATE; + break; + case '#': + DBUG_PUSH(argument ? argument : "d:t:o,/tmp/myisamchk.trace"); + break; + case 'V': + print_version(); + exit(0); + case OPT_CORRECT_CHECKSUM: + check_param.testflag|=T_CALC_CHECKSUM; + break; + case OPT_CHARSETS_DIR: + charsets_dir= argument; + break; + case OPT_SET_CHARSET: + set_charset_name= argument; + break; +#ifdef DEBUG /* Only useful if debugging */ + case OPT_START_CHECK_POS: + check_param.start_check_pos=strtoull(argument, NULL, 0); + break; +#endif + case '?': + usage(); + exit(0); + } +} + + static void get_options(register int *argc,register char ***argv) { int c,option_index=0; - uint old_testflag; load_defaults("my",load_default_groups,argc,argv); default_argv= *argv; set_all_changeable_vars(changeable_vars); if (isatty(fileno(stdout))) check_param.testflag|=T_WRITE_LOOP; - while ((c=getopt_long(*argc,*argv, - "aBcCdeifF?lqrmnosSTuUvVw#:b:D:k:O:R:A::t:", - long_options, &option_index)) != EOF) - { - switch(c) { - case 'a': - check_param.testflag|= T_STATISTICS; - break; - case 'A': - if (optarg) - check_param.auto_increment_value=strtoull(optarg,NULL,0); - else - check_param.auto_increment_value=0; /* Set to max used value */ - check_param.testflag|= T_AUTO_INC; - break; - case 'b': - check_param.search_after_block=strtoul(optarg,NULL,10); - break; - case 'B': - check_param.testflag|= T_BACKUP_DATA; - break; - case 'c': - check_param.testflag|= T_CHECK; - break; - case 'C': - check_param.testflag|= T_CHECK | T_CHECK_ONLY_CHANGED; - break; - case 'D': - check_param.max_data_file_length=strtoll(optarg,NULL,10); - break; - case 's': /* silent */ - if (check_param.testflag & T_SILENT) - check_param.testflag|=T_VERY_SILENT; - check_param.testflag|= T_SILENT; - check_param.testflag&= ~T_WRITE_LOOP; - break; - case 'w': - check_param.testflag|= T_WAIT_FOREVER; - break; - case 'd': /* description if isam-file */ - check_param.testflag|= T_DESCRIPT; - break; - case 'e': /* extend check */ - check_param.testflag|= T_EXTEND; - break; - case 'i': - check_param.testflag|= T_INFO; - break; - case 'f': - check_param.tmpfile_createflag= O_RDWR | O_TRUNC; - check_param.testflag|= T_FORCE_CREATE | T_UPDATE_STATE; - break; - case 'F': - check_param.testflag|=T_FAST; - break; - case 'k': - check_param.keys_in_use= (ulonglong) strtoll(optarg,NULL,10); - break; - case 'm': - check_param.testflag|= T_MEDIUM; /* Medium check */ - break; - case 'r': /* Repair table */ - check_param.testflag= (check_param.testflag & ~T_REP) | T_REP_BY_SORT; - break; - case 'o': - check_param.testflag= (check_param.testflag & ~T_REP_BY_SORT) | T_REP; - check_param.force_sort=0; - my_disable_async_io=1; /* More safety */ - break; - case 'n': - check_param.testflag= (check_param.testflag & ~T_REP) | T_REP_BY_SORT; - check_param.force_sort=1; - break; - case 'q': - check_param.opt_rep_quick++; - break; - case 'u': - check_param.testflag|= T_UNPACK | T_REP_BY_SORT; - break; - case 'v': /* Verbose */ - check_param.testflag|= T_VERBOSE; - check_param.verbose++; - break; - case 'O': - if (set_changeable_var(optarg, changeable_vars)) - { - usage(); - exit(1); - } - break; - case 'R': /* Sort records */ - old_testflag=check_param.testflag; - check_param.testflag|= T_SORT_RECORDS; - check_param.opt_sort_key=(uint) atoi(optarg)-1; - if (check_param.opt_sort_key >= MI_MAX_KEY) - { - fprintf(stderr, - "The value of the sort key is bigger than max key: %d.\n", - MI_MAX_KEY); - exit(1); - } - break; - case 'S': /* Sort index */ - old_testflag=check_param.testflag; - check_param.testflag|= T_SORT_INDEX; - break; - case 't': - check_param.tmpdir=optarg; - break; - case 'T': - check_param.testflag|= T_READONLY; - break; - case 'U': - check_param.testflag|= T_UPDATE_STATE; - break; - case '#': - DBUG_PUSH(optarg ? optarg : "d:t:o,/tmp/myisamchk.trace"); - break; - case 'V': - print_version(); - exit(0); - case OPT_CORRECT_CHECKSUM: - check_param.testflag|=T_CALC_CHECKSUM; - break; - case OPT_CHARSETS_DIR: - charsets_dir = optarg; - break; - case OPT_SET_CHARSET: - set_charset_name=optarg; - break; -#ifdef DEBUG /* Only useful if debugging */ - case OPT_START_CHECK_POS: - check_param.start_check_pos=strtoull(optarg,NULL,0); - break; -#endif - case '?': - usage(); - exit(0); - } - } + + if (handle_options(argc, argv, my_long_options, get_one_option)) + exit(1); + /* If using repair, then update checksum if one uses --update-state */ if ((check_param.testflag & T_UPDATE_STATE) && (check_param.testflag & (T_REP | T_REP_BY_SORT))) check_param.testflag|= T_CALC_CHECKSUM; - (*argc)-=optind; - (*argv)+=optind; if (*argc == 0) { usage(); diff --git a/mysql-test/r/rpl000016.result b/mysql-test/r/rpl000016.result index dae60021157..aab3635ea52 100644 --- a/mysql-test/r/rpl000016.result +++ b/mysql-test/r/rpl000016.result @@ -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(*) diff --git a/mysql-test/t/rpl000016.test b/mysql-test/t/rpl000016.test index 4e094650b2a..7559b2d3515 100644 --- a/mysql-test/t/rpl000016.test +++ b/mysql-test/t/rpl000016.test @@ -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; diff --git a/mysys/Makefile.am b/mysys/Makefile.am index 97f065bc7e2..287dc357b3d 100644 --- a/mysys/Makefile.am +++ b/mysys/Makefile.am @@ -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 \ diff --git a/mysys/getvar.c b/mysys/getvar.c index 49b321f592e..1a2adc10e62 100644 --- a/mysys/getvar.c +++ b/mysys/getvar.c @@ -19,7 +19,7 @@ #include "mysys_priv.h" #include #include - +#include /* 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); +} diff --git a/mysys/mf_iocache.c b/mysys/mf_iocache.c index 6b0d83212c4..34de5dfd7f3 100644 --- a/mysys/mf_iocache.c +++ b/mysys/mf_iocache.c @@ -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); } diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c new file mode 100644 index 00000000000..afe3da214bf --- /dev/null +++ b/mysys/my_getopt.c @@ -0,0 +1,313 @@ +/* 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 +#include +#include +#include +#include +#include + +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; +} diff --git a/sql/log.cc b/sql/log.cc index ec7396bda3c..d3ad4564a73 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -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 { diff --git a/sql/log_event.cc b/sql/log_event.cc index e10352e6c48..4d6d5341312 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -26,6 +26,18 @@ #include +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 diff --git a/sql/slave.cc b/sql/slave.cc index 3d38a7e6f4b..97efbf6036c 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -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,26 +1921,15 @@ the slave SQL thread with \"mysqladmin start-slave\". We stopped at log \ DBUG_RETURN(0); // Can't return anything here } -int queue_event(MASTER_INFO* mi,const char* buf,uint event_len) +static int process_io_rotate(MASTER_INFO* mi, Rotate_log_event* rev) { - int error; - bool inc_pos = 1; - if (mi->old_format) - return 1; // TODO: deal with old format - - switch (buf[EVENT_TYPE_OFFSET]) - { - case ROTATE_EVENT: - { - Rotate_log_event rev(buf,event_len,0); - if (!rev.is_valid()) - return 1; - DBUG_ASSERT(rev.ident_lenmaster_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; + if (!rev->is_valid()) + return 1; + DBUG_ASSERT(rev->ident_lenmaster_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 @@ -1945,7 +1937,70 @@ int queue_event(MASTER_INFO* mi,const char* buf,uint event_len) */ if (disconnect_slave_event_count) events_till_disconnect++; -#endif +#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 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 (process_io_rotate(mi,&rev)) + return 1; + inc_pos=0; break; } default: diff --git a/sql/sql_class.h b/sql/sql_class.h index a34975bc77e..1d8fa1554d3 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -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);