summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormonty@mashka.mysql.fi <>2003-01-09 22:43:23 +0200
committermonty@mashka.mysql.fi <>2003-01-09 22:43:23 +0200
commitc9dc5a206bd162b10a3a1a2bebc054cf3c5a6ed0 (patch)
tree5ffbc6660efade54ba4bc490d83c1538515feb3e
parentaf76ac08fd64f57bb1939db1cc6b39b18eae969f (diff)
parentbf683af4cea9a9efc3e524d5aabde4886e93540f (diff)
downloadmariadb-git-c9dc5a206bd162b10a3a1a2bebc054cf3c5a6ed0.tar.gz
Merge work:/home/bk/mysql-4.1 into mashka.mysql.fi:/home/my/mysql-4.1
-rwxr-xr-xBuild-tools/Do-compile27
-rw-r--r--Docs/internals.texi73
-rw-r--r--client/mysqladmin.c62
-rw-r--r--client/mysqltest.c8
-rw-r--r--extra/Makefile.am2
-rw-r--r--extra/mysql_waitpid.c86
-rw-r--r--include/my_base.h1
-rw-r--r--myisam/ft_nlq_search.c1
-rw-r--r--myisam/mi_check.c3
-rw-r--r--myisam/mi_extra.c5
-rw-r--r--myisam/mi_open.c14
-rw-r--r--myisam/mi_search.c8
-rw-r--r--myisam/myisamdef.h4
-rw-r--r--mysql-test/mysql-test-run.sh33
-rw-r--r--mysql-test/r/myisam.result50
-rw-r--r--mysql-test/t/myisam.test27
-rw-r--r--mysys/my_handler.c87
-rw-r--r--sql-bench/bench-init.pl.sh5
-rw-r--r--sql-bench/crash-me.sh126
-rw-r--r--sql-bench/test-alter-table.sh43
-rw-r--r--sql-bench/test-insert.sh7
-rw-r--r--sql/lex.h1
-rw-r--r--sql/log_event.cc65
-rw-r--r--sql/log_event.h5
-rw-r--r--sql/mysql_priv.h5
-rw-r--r--sql/mysqld.cc43
-rw-r--r--sql/opt_range.cc4
-rw-r--r--sql/protocol.cc5
-rw-r--r--sql/slave.cc8
-rw-r--r--sql/sql_base.cc6
-rw-r--r--sql/sql_lex.cc8
-rw-r--r--sql/sql_lex.h7
-rw-r--r--sql/sql_parse.cc33
-rw-r--r--sql/sql_select.cc3
-rw-r--r--sql/sql_show.cc2
-rw-r--r--sql/sql_yacc.yy65
-rw-r--r--sql/table.h2
37 files changed, 707 insertions, 227 deletions
diff --git a/Build-tools/Do-compile b/Build-tools/Do-compile
index 4351a4f69f4..8695c72b913 100755
--- a/Build-tools/Do-compile
+++ b/Build-tools/Do-compile
@@ -135,6 +135,7 @@ $ENV{'MYSQL_UNIX_PORT'}=$mysql_unix_port="$opt_tmp/mysql$opt_suffix.build";
$ENV{"PERL5LIB"}="$pwd/$host/perl5:$pwd/$host/perl5/site_perl";
$slave_port=$mysql_tcp_port+16;
$manager_port=$mysql_tcp_port+1;
+$mysqladmin_args="--no-defaults -u root --connect_timeout=5 --shutdown_timeout=20";
if ($opt_stage == 0)
{
@@ -154,13 +155,18 @@ log_timestamp();
if (-x "$host/bin/mysqladmin")
{
- log_system("$host/bin/mysqladmin --no-defaults -u root -S $mysql_unix_port -s shutdown");
- log_system("$host/bin/mysqladmin --no-defaults -u root -P $mysql_tcp_port -h $host -s shutdown");
- log_system("$host/bin/mysqladmin --no-defaults -u root -P $slave_port -h $host -s shutdown");
- log_system("$host/bin/mysqladmin --no-defaults -u root -P 9306 -h $host -s shutdown");
- log_system("$host/bin/mysqladmin --no-defaults -u root -P 9307 -h $host -s shutdown");
+ log_system("$host/bin/mysqladmin $mysqladmin_args -S $mysql_unix_port -s shutdown");
+ log_system("$host/bin/mysqladmin $mysqladmin_args -P $mysql_tcp_port -h $host -s shutdown");
+ log_system("$host/bin/mysqladmin $mysqladmin_args -P $slave_port -h $host -s shutdown");
+ log_system("$host/bin/mysqladmin $mysqladmin_args -P 9306 -h $host -s shutdown");
+ log_system("$host/bin/mysqladmin $mysqladmin_args -P 9307 -h $host -s shutdown");
}
kill_all("mysqlmanager");
+#
+# Kill all old processes that are in the build directories
+# This is to find any old mysqld servers left from previous builds
+kill_all("$pwd/host/mysql");
+kill_all("$pwd/host/test");
if ($opt_stage == 0)
{
@@ -308,8 +314,9 @@ if ($opt_stage <= 4 && !$opt_no_test)
$tar_file =~ /(mysql[^\/]*)\.tar/;
$ver=$1;
$test_dir="$pwd/$host/test/$ver";
-$ENV{"LD_LIBRARY_PATH"}= "$test_dir/lib:" . $ENV{"LD_LIBRARY_PATH"};
-
+$ENV{"LD_LIBRARY_PATH"}= ("$test_dir/lib" .
+ (defined($ENV{"LD_LIBRARY_PATH"}) ?
+ ":" . $ENV{"LD_LIBRARY_PATH"} : ""));
#
# Run the test suite
#
@@ -328,7 +335,7 @@ if (!$opt_no_test && !$opt_no_benchmark)
{
my $extra;
safe_cd($test_dir);
- log_system("./bin/mysqladmin --no-defaults -u root -S $mysql_unix_port -s shutdown") || info("There was no mysqld running\n");
+ log_system("./bin/mysqladmin $mysqladmin_args -S $mysql_unix_port -s shutdown") || info("There was no mysqld running\n");
sleep(2);
log_system("rm -f ./data/mysql/*");
check_system("scripts/mysql_install_db --no-defaults --skip-locking","https://order");
@@ -418,7 +425,7 @@ if ($opt_stage <= 9 && !$opt_no_test && !$opt_no_benchmark)
rm_all($bench_tmpdir);
rm_all("$opt_tmp") if ($new_opt_tmp);
-log_system("$pwd/$host/bin/mysqladmin --no-defaults -S $mysql_unix_port -u root shutdown");
+log_system("$pwd/$host/bin/mysqladmin $mysqladmin_args -S $mysql_unix_port -u root shutdown");
print LOG "ok\n";
close LOG;
print "$host: ok\n";
@@ -429,7 +436,7 @@ exit 0;
sub usage
{
print <<EOF;
-$0 version 1.4
+$0 version 1.5
$0 takes the following options:
diff --git a/Docs/internals.texi b/Docs/internals.texi
index 6719bd4a6fa..a94158f84f8 100644
--- a/Docs/internals.texi
+++ b/Docs/internals.texi
@@ -96,13 +96,84 @@ cached for each user/database combination.
Many use of @code{GROUP BY} or @code{DISTINCT} caches all found rows in
a @code{HEAP} table. (This is a very quick in-memory table with hash index.)
-@item Join Row Cache
+@item Join buffer Cache
For every full join in a @code{SELECT} statement (a full join here means
there were no keys that one could use to find the next table in a list),
the found rows are cached in a join cache. One @code{SELECT} query can
use many join caches in the worst case.
@end table
+@node join_buffer_size, flush tables, caching, Top
+@subchapter How MySQL uses the join_buffer cache
+
+Basic information about @code{join_buffer_size}:
+
+@itemize @bullet
+@item
+It's only used in the case when join type is of type @code{ALL} or
+@code{index}; In other words: no possible keys can be used.
+@item
+A join buffer is never allocated for the first not-const table,
+even it it would be of type @code{ALL}/@code{index}.
+@item
+The buffer is allocated when we need to do a each full join between two
+tables and freed after the query is done.
+@item
+Accepted row combinations of tables before the @code{ALL}/@code{index}
+able is stored in the cache and is used to compare against each read
+row in the @code{ALL} table.
+@item
+We only store the used fields in the join_buffer cache, not the
+whole rows.
+@end itemize
+
+Assume you have the following join:
+
+@example
+Table name Type
+t1 range
+t2 ref
+t3 @code{ALL}
+@end example
+
+The join is then done as follows:
+
+@example
+- While rows in t1 matching range
+ - Read through all rows in t2 according to reference key
+ - Store used fields form t1,t2 in cache
+ - If cache is full
+ - Read through all rows in t3
+ - Compare t3 row against all t1,t2 combination in cache
+ - If rows satisfying join condition, send it to client
+ - Empty cache
+
+- Read through all rows in t3
+ - Compare t3 row against all stored t1,t2 combinations in cache
+ - If rows satisfying join condition, send it to client
+@end example
+
+The above means that table t3 is scanned
+
+@example
+(size-of-stored-row(t1,t2) * accepted-row-cominations(t1,t2))/
+join_buffer_size+1
+@end example
+times.
+
+Some conclusions:
+
+@itemize @bullet
+@item
+The larger the join_buff_size, the fewer scans of t3.
+If @code{join_buff_size} is already large enough to hold all previous row
+combinations then there is no speed to gain by making it bigger.
+@item
+If there is several tables of @code{ALL}/@code{index} then the we
+allocate one @code{join_buffer_size buffer} for each of them and use the
+same algorithm described above to handle it. (In other words, we store
+the same row combination several times into different buffers)
+@end itemize
@node flush tables, filesort, caching, Top
@chapter How MySQL Handles @code{FLUSH TABLES}
diff --git a/client/mysqladmin.c b/client/mysqladmin.c
index 2c8314d83ca..2fc77552d5f 100644
--- a/client/mysqladmin.c
+++ b/client/mysqladmin.c
@@ -25,7 +25,7 @@
#include <sys/stat.h>
#include <mysql.h>
-#define ADMIN_VERSION "8.38"
+#define ADMIN_VERSION "8.39"
#define MAX_MYSQL_VAR 128
#define SHUTDOWN_DEF_TIMEOUT 3600 /* Wait for shutdown */
#define MAX_TRUNC_LENGTH 3
@@ -76,8 +76,8 @@ static void print_relative_header();
static void print_relative_line();
static void truncate_names();
static my_bool get_pidfile(MYSQL *mysql, char *pidfile);
-static void wait_pidfile(char *pidfile, time_t last_modified,
- struct stat *pidfile_status);
+static my_bool wait_pidfile(char *pidfile, time_t last_modified,
+ struct stat *pidfile_status);
static void store_values(MYSQL_RES *result);
/*
@@ -513,7 +513,8 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
printf("Shutdown signal sent to server; Waiting for pid file to disappear\n");
/* Wait until pid file is gone */
- wait_pidfile(pidfile, last_modified, &pidfile_status);
+ if (wait_pidfile(pidfile, last_modified, &pidfile_status))
+ return -1;
}
break;
}
@@ -1150,34 +1151,51 @@ static my_bool get_pidfile(MYSQL *mysql, char *pidfile)
return 1; /* Error */
}
+/*
+ Return 1 if pid file didn't disappear or change
+*/
-static void wait_pidfile(char *pidfile, time_t last_modified,
- struct stat *pidfile_status)
+static my_bool wait_pidfile(char *pidfile, time_t last_modified,
+ struct stat *pidfile_status)
{
char buff[FN_REFLEN];
- int fd = -1;
- uint count=0;
+ int error= 1;
+ uint count= 0;
+ DBUG_ENTER("wait_pidfile");
system_filename(buff, pidfile);
- while (count++ <= opt_shutdown_timeout && !interrupted &&
- (!last_modified || (last_modified == pidfile_status->st_mtime)) &&
- (fd= my_open(buff, O_RDONLY, MYF(0))) >= 0)
+ do
{
- if (!my_close(fd,MYF(0)))
- fd= -1;
+ int fd;
+ if ((fd= my_open(buff, O_RDONLY, MYF(0))) < 0)
+ {
+ error= 0;
+ break;
+ }
+ (void) my_close(fd,MYF(0));
+ if (last_modified && !stat(pidfile, pidfile_status))
+ {
+ if (last_modified != pidfile_status->st_mtime)
+ {
+ /* File changed; Let's assume that mysqld did restart */
+ if (opt_verbose)
+ printf("pid file '%s' changed while waiting for it to disappear!\nmysqld did probably restart\n",
+ buff);
+ error= 0;
+ break;
+ }
+ }
+ if (count++ == opt_shutdown_timeout)
+ break;
sleep(1);
- if (last_modified && stat(pidfile, pidfile_status))
- last_modified= 0;
- }
- if (opt_verbose && last_modified &&
- last_modified != pidfile_status->st_mtime)
- printf("Warning; pid file '%s' changed while waiting for it to disappear!\n",
- buff);
- if (fd >= 0)
+ } while (!interrupted);
+
+ if (error)
{
- my_close(fd,MYF(0));
+ DBUG_PRINT("warning",("Pid file didn't disappear"));
fprintf(stderr,
"Warning; Aborted waiting on pid file: '%s' after %d seconds\n",
buff, count-1);
}
+ DBUG_RETURN(error);
}
diff --git a/client/mysqltest.c b/client/mysqltest.c
index ed95efc282e..f3037fcc173 100644
--- a/client/mysqltest.c
+++ b/client/mysqltest.c
@@ -42,7 +42,7 @@
**********************************************************************/
-#define MTEST_VERSION "1.25"
+#define MTEST_VERSION "1.26"
#include <my_global.h>
#include <mysql_embed.h>
@@ -1809,10 +1809,8 @@ int read_query(struct st_query** q_ptr)
static struct my_option my_long_options[] =
{
-#ifndef DBUG_OFF
{"debug", '#', "Output debug log. Often this is 'd:t:o,filename'",
0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
-#endif
{"database", 'D', "Database to use.", (gptr*) &db, (gptr*) &db, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"basedir", 'b', "Basedir for tests", (gptr*) &opt_basedir,
@@ -1905,7 +1903,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
{
switch(optid) {
case '#':
+#ifndef DBUG_OFF
DBUG_PUSH(argument ? argument : "d:t:S:i:O,/tmp/mysqltest.trace");
+#endif
break;
case 'r':
record = 1;
@@ -1983,7 +1983,7 @@ int parse_args(int argc, char **argv)
default_argv= argv;
if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
- exit(ho_error);
+ exit(1);
if (argc > 1)
{
diff --git a/extra/Makefile.am b/extra/Makefile.am
index 6895d7a09f8..8107beb2657 100644
--- a/extra/Makefile.am
+++ b/extra/Makefile.am
@@ -18,7 +18,7 @@ INCLUDES = @MT_INCLUDES@ -I$(top_srcdir)/include
LDADD = @CLIENT_EXTRA_LDFLAGS@ ../mysys/libmysys.a \
../dbug/libdbug.a ../strings/libmystrings.a
bin_PROGRAMS = replace comp_err perror resolveip my_print_defaults \
- resolve_stack_dump mysql_install
+ resolve_stack_dump mysql_install mysql_waitpid
# Don't update the files from bitkeeper
%::SCCS/s.%
diff --git a/extra/mysql_waitpid.c b/extra/mysql_waitpid.c
new file mode 100644
index 00000000000..14d3f893c60
--- /dev/null
+++ b/extra/mysql_waitpid.c
@@ -0,0 +1,86 @@
+#include <sys/types.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <my_global.h>
+#include <my_getopt.h>
+
+static const char *VER= "1.1";
+static char *progname;
+static my_bool verbose;
+
+void usage(void);
+
+static struct my_option my_long_options[] =
+{
+ {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
+ 0, 0, 0, 0, 0},
+ {"help", 'I', "Synonym for -?.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
+ 0, 0, 0, 0, 0},
+ {"verbose", 'v',
+ "Be more verbose. Give a warning, if kill can't handle signal 0.",
+ (gptr*) &verbose, (gptr*) &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"version", 'V', "Print version information and exit.", 0, 0, 0,
+ GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
+};
+
+static my_bool
+get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
+ char *argument __attribute__((unused)))
+{
+ switch(optid) {
+ case 'V':
+ printf("%s version %s by Jani Tolonen\n", progname, VER);
+ exit(-1);
+ case 'I':
+ case '?':
+ usage();
+ }
+ return 0;
+}
+
+
+int main(int argc, char *argv[])
+{
+ int pid= 0, t= 0, sig= 0;
+
+ progname= argv[0];
+
+ if (handle_options(&argc, &argv, my_long_options, get_one_option))
+ exit(-1);
+ if (!argv[0] || !argv[1] || (pid= atoi(argv[0])) <= 0 ||
+ (t= atoi(argv[1])) <= 0)
+ usage();
+ for (; t > 0; t--)
+ {
+ if (kill((pid_t) pid, sig))
+ {
+ if (errno == EINVAL)
+ {
+ if (verbose)
+ printf("WARNING: kill couldn't handle signal 0, using signal 1.\n");
+ sig= 1;
+ t++;
+ continue;
+ }
+ return 0;
+ }
+ sleep(1);
+ }
+ return 1;
+}
+
+void usage(void)
+{
+ printf("%s version %s by Jani Tolonen\n\n", progname, VER);
+ printf("usage: %s [options] #pid #time\n\n", progname);
+ printf("Description: Waits for a program, which program id is #pid, to\n");
+ printf("terminate within #time seconds. If the program terminates within\n");
+ printf("this time, or if the #pid no longer exists, value 0 is returned.\n");
+ printf("Otherwise 1 is returned. Both #pid and #time must be positive\n");
+ printf("integer arguments.\n\n");
+ printf("Options:\n");
+ my_print_help(my_long_options);
+ exit(-1);
+}
diff --git a/include/my_base.h b/include/my_base.h
index 6efac979a4e..b16a545b937 100644
--- a/include/my_base.h
+++ b/include/my_base.h
@@ -264,6 +264,7 @@ enum ha_base_keytype {
#define MBR_EQUAL 8192
#define MBR_DATA 16384
#define SEARCH_NULL_ARE_EQUAL 32768 /* NULL in keys are equal */
+#define SEARCH_NULL_ARE_NOT_EQUAL 65536 /* NULL in keys are not equal */
/* bits in opt_flag */
#define QUICK_USED 1
diff --git a/myisam/ft_nlq_search.c b/myisam/ft_nlq_search.c
index f9c276de32f..858a8dcbe06 100644
--- a/myisam/ft_nlq_search.c
+++ b/myisam/ft_nlq_search.c
@@ -97,6 +97,7 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio)
r=_mi_search(aio->info, aio->keyinfo, aio->keybuff, keylen,
SEARCH_FIND | SEARCH_PREFIX, aio->key_root);
+ aio->info->update|= HA_STATE_AKTIV; /* for _mi_test_if_changed() */
while (!r)
{
diff --git a/myisam/mi_check.c b/myisam/mi_check.c
index 1ca342f3998..28c28e628ea 100644
--- a/myisam/mi_check.c
+++ b/myisam/mi_check.c
@@ -601,7 +601,8 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
if (*keys != 1L) /* not first_key */
{
uint diff;
- ha_key_cmp(keyinfo->seg,info->lastkey,key,USE_WHOLE_KEY,SEARCH_FIND,
+ ha_key_cmp(keyinfo->seg,info->lastkey,key,USE_WHOLE_KEY,
+ SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL,
&diff);
param->unique_count[diff-1]++;
}
diff --git a/myisam/mi_extra.c b/myisam/mi_extra.c
index 8429b22dad4..75057dd4e6a 100644
--- a/myisam/mi_extra.c
+++ b/myisam/mi_extra.c
@@ -55,12 +55,17 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg)
/*
Free buffers and reset the following flags:
EXTRA_CACHE, EXTRA_WRITE_CACHE, EXTRA_KEYREAD, EXTRA_QUICK
+
+ If the row buffer cache is large (for dynamic tables), reduce it
+ to save memory.
*/
if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
{
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
error=end_io_cache(&info->rec_cache);
}
+ if (share->base.blobs)
+ mi_alloc_rec_buff(info, -1, &info->rec_buff);
#if defined(HAVE_MMAP) && defined(HAVE_MADVICE)
if (info->opt_flag & MEMMAP_USED)
madvise(share->file_map,share->state.state.data_file_length,MADV_RANDOM);
diff --git a/myisam/mi_open.c b/myisam/mi_open.c
index 8f0da612c3a..ef1906e0c00 100644
--- a/myisam/mi_open.c
+++ b/myisam/mi_open.c
@@ -573,28 +573,36 @@ err:
DBUG_RETURN (NULL);
} /* mi_open */
+
byte *mi_alloc_rec_buff(MI_INFO *info, ulong length, byte **buf)
{
uint extra;
+ uint32 old_length;
+ LINT_INIT(old_length);
- if (! *buf || length > mi_get_rec_buff_len(info, *buf))
+ if (! *buf || length > (old_length=mi_get_rec_buff_len(info, *buf)))
{
byte *newptr = *buf;
/* to simplify initial init of info->rec_buf in mi_open and mi_extra */
if (length == (ulong) -1)
+ {
length= max(info->s->base.pack_reclength+info->s->base.pack_bits,
info->s->base.max_key_length);
+ /* Avoid unnecessary realloc */
+ if (newptr && length == old_length)
+ return newptr;
+ }
extra= ((info->s->options & HA_OPTION_PACK_RECORD) ?
ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
MI_REC_BUFF_OFFSET : 0);
if (extra && newptr)
- newptr-=MI_REC_BUFF_OFFSET;
+ newptr-= MI_REC_BUFF_OFFSET;
if (!(newptr=(byte*) my_realloc((gptr)newptr, length+extra+8,
MYF(MY_ALLOW_ZERO_PTR))))
return newptr;
- *((uint *)newptr)=length;
+ *((uint32 *) newptr)= (uint32) length;
*buf= newptr+(extra ? MI_REC_BUFF_OFFSET : 0);
}
return *buf;
diff --git a/myisam/mi_search.c b/myisam/mi_search.c
index 8aeccbbf559..04803d7a901 100644
--- a/myisam/mi_search.c
+++ b/myisam/mi_search.c
@@ -260,9 +260,11 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
uchar *key, uint key_len, uint nextflag, uchar **ret_pos,
uchar *buff, my_bool *last_key)
{
- /* my_flag is raw comparison result to be changed according to
- SEARCH_NO_FIND,SEARCH_LAST and HA_REVERSE_SORT flags.
- flag is the value returned by ha_key_cmp and as treated as final */
+ /*
+ my_flag is raw comparison result to be changed according to
+ SEARCH_NO_FIND,SEARCH_LAST and HA_REVERSE_SORT flags.
+ flag is the value returned by ha_key_cmp and as treated as final
+ */
int flag=0, my_flag=-1;
uint nod_flag, length, len, matched, cmplen, kseg_len;
uint prefix_len,suffix_len;
diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h
index e5cac1f090e..005c36271bf 100644
--- a/myisam/myisamdef.h
+++ b/myisam/myisamdef.h
@@ -385,7 +385,7 @@ typedef struct st_mi_sort_param
#define MI_DYN_ALIGN_SIZE 4 /* Align blocks on this */
#define MI_MAX_DYN_HEADER_BYTE 13 /* max header byte for dynamic rows */
#define MI_MAX_BLOCK_LENGTH ((((ulong) 1 << 24)-1) & (~ (ulong) (MI_DYN_ALIGN_SIZE-1)))
-#define MI_REC_BUFF_OFFSET ALIGN_SIZE(MI_DYN_DELETE_BLOCK_HEADER+sizeof(uint))
+#define MI_REC_BUFF_OFFSET ALIGN_SIZE(MI_DYN_DELETE_BLOCK_HEADER+sizeof(uint32))
#define MEMMAP_EXTRA_MARGIN 7 /* Write this as a suffix for file */
@@ -554,7 +554,7 @@ extern byte *mi_alloc_rec_buff(MI_INFO *,ulong, byte**);
((((info)->s->options & HA_OPTION_PACK_RECORD) && (buf)) ? \
(buf) - MI_REC_BUFF_OFFSET : (buf))
#define mi_get_rec_buff_len(info,buf) \
- (*((uint *)(mi_get_rec_buff_ptr(info,buf))))
+ (*((uint32 *)(mi_get_rec_buff_ptr(info,buf))))
extern ulong _mi_rec_unpack(MI_INFO *info,byte *to,byte *from,
ulong reclength);
diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh
index 34f3d365d7d..edd573f50a3 100644
--- a/mysql-test/mysql-test-run.sh
+++ b/mysql-test/mysql-test-run.sh
@@ -88,6 +88,7 @@ sleep_until_file_created ()
wait_for_pid()
{
pid=$1
+ #$WAIT_PID pid $SLEEP_TIME_FOR_DELETE
}
# No paths below as we can't be sure where the program is!
@@ -347,9 +348,9 @@ while test $# -gt 0; do
;;
--debug)
EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT \
- --debug=d:t:i:O,$MYSQL_TEST_DIR/var/log/master.trace"
+ --debug=d:t:i:A,$MYSQL_TEST_DIR/var/log/master.trace"
EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT \
- --debug=d:t:i:O,$MYSQL_TEST_DIR/var/log/slave.trace"
+ --debug=d:t:i:A,$MYSQL_TEST_DIR/var/log/slave.trace"
EXTRA_MYSQL_TEST_OPT="$EXTRA_MYSQL_TEST_OPT --debug"
;;
--fast)
@@ -423,6 +424,7 @@ if [ x$SOURCE_DIST = x1 ] ; then
fi
MYSQLADMIN="$BASEDIR/client/mysqladmin"
+ WAIT_PID="$BASEDIR/extra/mysql_waitpid"
MYSQL_MANAGER_CLIENT="$BASEDIR/client/mysqlmanagerc"
MYSQL_MANAGER="$BASEDIR/tools/mysqlmanager"
MYSQL_MANAGER_PWGEN="$BASEDIR/client/mysqlmanager-pwgen"
@@ -439,6 +441,7 @@ else
fi
MYSQL_TEST="$BASEDIR/bin/mysqltest"
MYSQLADMIN="$BASEDIR/bin/mysqladmin"
+ WAIT_PID="$BASEDIR/bin/mysql_waitpid"
MYSQL_MANAGER="$BASEDIR/bin/mysqlmanager"
MYSQL_MANAGER_CLIENT="$BASEDIR/bin/mysqlmanagerc"
MYSQL_MANAGER_PWGEN="$BASEDIR/bin/mysqlmanager-pwgen"
@@ -753,9 +756,9 @@ manager_term()
{
pid=$1
ident=$2
- shift
if [ $USE_MANAGER = 0 ] ; then
- $MYSQLADMIN --no-defaults -uroot --socket=$MYSQL_TMP_DIR/$ident.sock --connect_timeout=5 --shutdown_timeout=20 shutdown >> $MYSQL_MANAGER_LOG 2>&1
+ # Shutdown time must be high as slave may be in reconnect
+ $MYSQLADMIN --no-defaults -uroot --socket=$MYSQL_TMP_DIR/$ident.sock --connect_timeout=5 --shutdown_timeout=70 shutdown >> $MYSQL_MANAGER_LOG 2>&1
res=$?
# Some systems require an extra connect
$MYSQLADMIN --no-defaults -uroot --socket=$MYSQL_TMP_DIR/$ident.sock --connect_timeout=1 ping >> $MYSQL_MANAGER_LOG 2>&1
@@ -875,8 +878,8 @@ start_slave()
[ x$SKIP_SLAVE = x1 ] && return
eval "this_slave_running=\$SLAVE$1_RUNNING"
[ x$this_slave_running = 1 ] && return
- #when testing fail-safe replication, we will have more than one slave
- #in this case, we start secondary slaves with an argument
+ # When testing fail-safe replication, we will have more than one slave
+ # in this case, we start secondary slaves with an argument
slave_ident="slave$1"
if [ -n "$1" ] ;
then
@@ -984,9 +987,12 @@ EOF
mysql_start ()
{
- $ECHO "Starting MySQL daemon"
- start_master
- start_slave
+# We should not start the deamon here as we don't know the argumens
+# for the test. Better to let the test start the deamon
+
+# $ECHO "Starting MySQL daemon"
+# start_master
+# start_slave
cd $MYSQL_TEST_DIR
return 1
}
@@ -1087,8 +1093,6 @@ run_testcase ()
slave_init_script=$TESTDIR/$tname-slave.sh
slave_master_info_file=$TESTDIR/$tname-slave-master-info.opt
echo $tname > $CURRENT_TEST
- echo "CURRENT_TEST: $tname" >> $SLAVE_MYERR
- echo "CURRENT_TEST: $tname" >> $MASTER_MYERR
SKIP_SLAVE=`$EXPR \( $tname : rpl \) = 0`
if [ $USE_MANAGER = 1 ] ; then
many_slaves=`$EXPR \( $tname : rpl_failsafe \) != 0`
@@ -1125,13 +1129,17 @@ run_testcase ()
then
EXTRA_MASTER_OPT=`$CAT $master_opt_file | $SED -e "s;\\$MYSQL_TEST_DIR;$MYSQL_TEST_DIR;"`
stop_master
+ echo "CURRENT_TEST: $tname" >> $MASTER_MYERR
start_master
else
if [ ! -z "$EXTRA_MASTER_OPT" ] || [ x$MASTER_RUNNING != x1 ] ;
then
EXTRA_MASTER_OPT=""
stop_master
+ echo "CURRENT_TEST: $tname" >> $MASTER_MYERR
start_master
+ else
+ echo "CURRENT_TEST: $tname" >> $MASTER_MYERR
fi
fi
@@ -1161,7 +1169,10 @@ run_testcase ()
if [ x$do_slave_restart = x1 ] ; then
stop_slave
+ echo "CURRENT_TEST: $tname" >> $SLAVE_MYERR
start_slave
+ else
+ echo "CURRENT_TEST: $tname" >> $SLAVE_MYERR
fi
if [ x$many_slaves = x1 ]; then
start_slave 1
diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result
index f06194bb412..23610be36c4 100644
--- a/mysql-test/r/myisam.result
+++ b/mysql-test/r/myisam.result
@@ -1,4 +1,4 @@
-drop table if exists t1;
+drop table if exists t1,t2;
CREATE TABLE t1 (
STRING_DATA char(255) default NULL,
KEY string_data (STRING_DATA)
@@ -316,3 +316,51 @@ CREATE TABLE t1 (a varchar(255), b varchar(255), c varchar(255));
ALTER TABLE t1 ADD INDEX t1 (a, b, c);
Specified key was too long. Max key length is 500
DROP TABLE t1;
+CREATE TABLE t1 (a int not null, b int, c int, key(b), key(c), key(a,b), key(c,a));
+INSERT into t1 values (0, null, 0), (0, null, 1), (0, null, 2), (0, null,3), (1,1,4);
+create table t2 (a int not null, b int, c int, key(b), key(c), key(a));
+INSERT into t2 values (1,1,1), (2,2,2);
+optimize table t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+show index from t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t1 1 b 1 b A 5 NULL NULL YES BTREE
+t1 1 c 1 c A 5 NULL NULL YES BTREE
+t1 1 a 1 a A 1 NULL NULL BTREE
+t1 1 a 2 b A 5 NULL NULL YES BTREE
+t1 1 c_2 1 c A 5 NULL NULL YES BTREE
+t1 1 c_2 2 a A 5 NULL NULL BTREE
+explain select * from t1,t2 where t1.a=t2.a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL a NULL NULL NULL 5
+1 SIMPLE t2 ALL a NULL NULL NULL 2 Using where
+explain select * from t1,t2 force index(a) where t1.a=t2.a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL a NULL NULL NULL 2
+1 SIMPLE t1 ALL a NULL NULL NULL 5 Using where
+explain select * from t1 force index(a),t2 force index(a) where t1.a=t2.a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL a NULL NULL NULL 2
+1 SIMPLE t1 ref a a 4 t2.a 3
+explain select * from t1,t2 where t1.b=t2.b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL b NULL NULL NULL 2
+1 SIMPLE t1 ref b b 5 t2.b 1 Using where
+explain select * from t1,t2 force index(c) where t1.a=t2.a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL a NULL NULL NULL 5
+1 SIMPLE t2 ALL NULL NULL NULL NULL 2 Using where
+explain select * from t1 where a=0 or a=2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL a NULL NULL NULL 5 Using where
+explain select * from t1 force index (a) where a=0 or a=2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 4 NULL 4 Using where
+explain select * from t1 where c=1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref c,c_2 c 5 const 1 Using where
+explain select * from t1 use index() where c=1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where
+drop table t1,t2;
diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test
index 780a060e204..ed08b1cbacb 100644
--- a/mysql-test/t/myisam.test
+++ b/mysql-test/t/myisam.test
@@ -2,10 +2,15 @@
# Test bugs in the MyISAM code
#
+# Initialise
--disable_warnings
-drop table if exists t1;
+drop table if exists t1,t2;
--enable_warnings
+#
+# Test problem with CHECK TABLE;
+#
+
CREATE TABLE t1 (
STRING_DATA char(255) default NULL,
KEY string_data (STRING_DATA)
@@ -327,3 +332,23 @@ CREATE TABLE t1 (a varchar(255), b varchar(255), c varchar(255));
ALTER TABLE t1 ADD INDEX t1 (a, b, c);
DROP TABLE t1;
+#
+# Test of cardinality of keys with NULL
+#
+
+CREATE TABLE t1 (a int not null, b int, c int, key(b), key(c), key(a,b), key(c,a));
+INSERT into t1 values (0, null, 0), (0, null, 1), (0, null, 2), (0, null,3), (1,1,4);
+create table t2 (a int not null, b int, c int, key(b), key(c), key(a));
+INSERT into t2 values (1,1,1), (2,2,2);
+optimize table t1;
+show index from t1;
+explain select * from t1,t2 where t1.a=t2.a;
+explain select * from t1,t2 force index(a) where t1.a=t2.a;
+explain select * from t1 force index(a),t2 force index(a) where t1.a=t2.a;
+explain select * from t1,t2 where t1.b=t2.b;
+explain select * from t1,t2 force index(c) where t1.a=t2.a;
+explain select * from t1 where a=0 or a=2;
+explain select * from t1 force index (a) where a=0 or a=2;
+explain select * from t1 where c=1;
+explain select * from t1 use index() where c=1;
+drop table t1,t2;
diff --git a/mysys/my_handler.c b/mysys/my_handler.c
index 2d51ab13f69..2fd7f1fcdee 100644
--- a/mysys/my_handler.c
+++ b/mysys/my_handler.c
@@ -40,15 +40,33 @@ static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length,
return (int) (a_length-b_length);
}
-#define FCMP(A,B) ((int) (A) - (int) (B))
/*
Compare two keys
- Returns <0, 0, >0 acording to which is bigger
- Key_length specifies length of key to use. Number-keys can't be splited
- If flag <> SEARCH_FIND compare also position
+
+ SYNOPSIS
+ ha_key_cmp()
+ keyseg Key segments of key to compare
+ a First key to compare, in format from _mi_pack_key()
+ This is normally key specified by user
+ b Second key to compare. This is always from a row
+ key_length Length of key to compare. This can be shorter than
+ a to just compare sub keys
+ next_flag How keys should be compared
+ If bit SEARCH_FIND is not set the keys includes the row
+ position and this should also be compared
+
+ NOTES
+ Number-keys can't be splited
+
+ RETURN VALUES
+ <0 If a < b
+ 0 If a == b
+ >0 If a > b
*/
+#define FCMP(A,B) ((int) (A) - (int) (B))
+
int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
register uchar *b, uint key_length, uint nextflag,
uint *diff_pos)
@@ -59,9 +77,10 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
uint32 u_1,u_2;
float f_1,f_2;
double d_1,d_2;
+ uint next_key_length;
*diff_pos=0;
- for ( ; (int) key_length >0 ; keyseg++)
+ for ( ; (int) key_length >0 ; key_length=next_key_length, keyseg++)
{
uchar *end;
uint piks=! (keyseg->flag & HA_NO_SORT);
@@ -81,10 +100,21 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
{
if (nextflag == (SEARCH_FIND | SEARCH_UPDATE))
nextflag=SEARCH_SAME; /* Allow duplicate keys */
+ else if (nextflag & SEARCH_NULL_ARE_NOT_EQUAL)
+ {
+ /*
+ This is only used from mi_check() to calculate cardinality.
+ It can't be used when searching for a key as this would cause
+ compare of (a,b) and (b,a) to return the same value.
+ */
+ return -1;
+ }
+ next_key_length=key_length;
continue; /* To next key part */
}
}
end= a+ min(keyseg->length,key_length);
+ next_key_length=key_length-keyseg->length;
switch ((enum ha_base_keytype) keyseg->type) {
case HA_KEYTYPE_TEXT: /* Ascii; Key is converted */
@@ -93,12 +123,12 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
int a_length,b_length,pack_length;
get_key_length(a_length,a);
get_key_pack_length(b_length,pack_length,b);
- key_length-= b_length + pack_length;
+ next_key_length=key_length-b_length-pack_length;
if (piks &&
- (flag= mi_compare_text(keyseg->charset,a,a_length,b,b_length,
- (my_bool) ((nextflag & SEARCH_PREFIX) &&
- key_length <= 0))))
+ (flag=mi_compare_text(keyseg->charset,a,a_length,b,b_length,
+ (my_bool) ((nextflag & SEARCH_PREFIX) &&
+ next_key_length <= 0))))
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a+=a_length;
b+=b_length;
@@ -107,7 +137,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
else
{
uint length=(uint) (end-a), a_length=length, b_length=length;
- key_length-= keyseg->length;
if (!(nextflag & SEARCH_PREFIX))
{
while (a_length && a[a_length-1] == ' ')
@@ -116,9 +145,9 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
b_length--;
}
if (piks &&
- (flag= mi_compare_text(keyseg->charset,a,a_length,b,b_length,
- (my_bool) ((nextflag & SEARCH_PREFIX) &&
- key_length <= 0))))
+ (flag= mi_compare_text(keyseg->charset, a, a_length, b, b_length,
+ (my_bool) ((nextflag & SEARCH_PREFIX) &&
+ next_key_length <= 0))))
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a=end;
b+=length;
@@ -130,12 +159,12 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
int a_length,b_length,pack_length;
get_key_length(a_length,a);
get_key_pack_length(b_length,pack_length,b);
- key_length-= b_length + pack_length;
+ next_key_length=key_length-b_length-pack_length;
if (piks &&
(flag=compare_bin(a,a_length,b,b_length,
(my_bool) ((nextflag & SEARCH_PREFIX) &&
- key_length <= 0))))
+ next_key_length <= 0))))
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a+=a_length;
b+=b_length;
@@ -144,11 +173,10 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
else
{
uint length=keyseg->length;
- key_length-= keyseg->length;
if (piks &&
(flag=compare_bin(a,length,b,length,
(my_bool) ((nextflag & SEARCH_PREFIX) &&
- key_length <= 0))))
+ next_key_length <= 0))))
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a+=length;
b+=length;
@@ -159,12 +187,12 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
int a_length,b_length,pack_length;
get_key_length(a_length,a);
get_key_pack_length(b_length,pack_length,b);
- key_length-= b_length + pack_length;
+ next_key_length=key_length-b_length-pack_length;
if (piks &&
(flag= mi_compare_text(keyseg->charset,a,a_length,b,b_length,
(my_bool) ((nextflag & SEARCH_PREFIX) &&
- key_length <= 0))))
+ next_key_length <= 0))))
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a+=a_length;
b+=b_length;
@@ -176,12 +204,12 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
int a_length,b_length,pack_length;
get_key_length(a_length,a);
get_key_pack_length(b_length,pack_length,b);
- key_length-= b_length + pack_length;
+ next_key_length=key_length-b_length-pack_length;
if (piks &&
(flag=compare_bin(a,a_length,b,b_length,
(my_bool) ((nextflag & SEARCH_PREFIX) &&
- key_length <= 0))))
+ next_key_length <= 0))))
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a+=a_length;
b+=b_length;
@@ -196,7 +224,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b++;
- key_length-= keyseg->length;
break;
}
case HA_KEYTYPE_SHORT_INT:
@@ -206,7 +233,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b+= 2; /* sizeof(short int); */
- key_length-= keyseg->length;
break;
case HA_KEYTYPE_USHORT_INT:
{
@@ -217,7 +243,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b+=2; /* sizeof(short int); */
- key_length-= keyseg->length;
break;
}
case HA_KEYTYPE_LONG_INT:
@@ -227,7 +252,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b+= 4; /* sizeof(long int); */
- key_length-= keyseg->length;
break;
case HA_KEYTYPE_ULONG_INT:
u_1= mi_sint4korr(a);
@@ -236,7 +260,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b+= 4; /* sizeof(long int); */
- key_length-= keyseg->length;
break;
case HA_KEYTYPE_INT24:
l_1=mi_sint3korr(a);
@@ -245,7 +268,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b+= 3;
- key_length-= keyseg->length;
break;
case HA_KEYTYPE_UINT24:
l_1=mi_uint3korr(a);
@@ -254,7 +276,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b+= 3;
- key_length-= keyseg->length;
break;
case HA_KEYTYPE_FLOAT:
mi_float4get(f_1,a);
@@ -263,7 +284,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b+= 4; /* sizeof(float); */
- key_length-= keyseg->length;
break;
case HA_KEYTYPE_DOUBLE:
mi_float8get(d_1,a);
@@ -272,13 +292,12 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b+= 8; /* sizeof(double); */
- key_length-= keyseg->length;
break;
case HA_KEYTYPE_NUM: /* Numeric key */
{
int swap_flag= 0;
int alength,blength;
-
+
if (keyseg->flag & HA_REVERSE_SORT)
{
swap(uchar*,a,b);
@@ -289,7 +308,7 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
{
alength= *a++; blength= *b++;
end=a+alength;
- key_length-= blength + 1;
+ next_key_length=key_length-blength-1;
}
else
{
@@ -298,9 +317,7 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
/* remove pre space from keys */
for ( ; alength && *a == ' ' ; a++, alength--) ;
for ( ; blength && *b == ' ' ; b++, blength--) ;
- key_length-= keyseg->length;
}
-
if (piks)
{
if (*a == '-')
@@ -350,7 +367,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b+= 8;
- key_length-= keyseg->length;
break;
}
case HA_KEYTYPE_ULONGLONG:
@@ -362,7 +378,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
a= end;
b+= 8;
- key_length-= keyseg->length;
break;
}
#endif
diff --git a/sql-bench/bench-init.pl.sh b/sql-bench/bench-init.pl.sh
index 9b999ee7f95..b7d2b962e13 100644
--- a/sql-bench/bench-init.pl.sh
+++ b/sql-bench/bench-init.pl.sh
@@ -48,7 +48,10 @@ $opt_optimization="None";
$opt_hw="";
$opt_threads=5;
-$opt_time_limit=10*60; # Don't wait more than 10 min for some tests
+if (!defined($opt_time_limit))
+{
+ $opt_time_limit=10*60; # Don't wait more than 10 min for some tests
+}
$log_prog_args=join(" ", skip_arguments(\@ARGV,"comments","cmp","server",
"user", "host", "database", "password",
diff --git a/sql-bench/crash-me.sh b/sql-bench/crash-me.sh
index ea18431f8da..130816de0be 100644
--- a/sql-bench/crash-me.sh
+++ b/sql-bench/crash-me.sh
@@ -39,7 +39,7 @@
# as such, and clarify ones such as "mediumint" with comments such as
# "3-byte int" or "same as xxx".
-$version="1.59";
+$version="1.60";
use DBI;
use Getopt::Long;
@@ -50,7 +50,7 @@ $opt_server="mysql"; $opt_host="localhost"; $opt_database="test";
$opt_dir="limits";
$opt_user=$opt_password="";$opt_verbose="";
$opt_debug=$opt_help=$opt_Information=$opt_restart=$opt_force=$opt_quick=0;
-$opt_log_all_queries=$opt_fix_limit_file=$opt_batch_mode=0;
+$opt_log_all_queries=$opt_fix_limit_file=$opt_batch_mode=$opt_version=0;
$opt_db_start_cmd=""; # the db server start command
$opt_check_server=0; # Check if server is alive before each query
$opt_sleep=10; # time to sleep while starting the db server
@@ -68,8 +68,10 @@ GetOptions("Information","help","server=s","debug","user=s","password=s",
"database=s","restart","force","quick","log-all-queries","comment=s",
"host=s","fix-limit-file","dir=s","db-start-cmd=s","sleep=s","suffix=s",
"batch-mode","config-file=s","log-queries-to-file=s","check-server",
+"version",
"verbose!" => \$opt_verbose) || usage();
usage() if ($opt_help || $opt_Information);
+version() && exit(0) if ($opt_version);
$opt_suffix = '-'.$opt_suffix if (length($opt_suffix) != 0);
$opt_config_file = "$pwd/$opt_dir/$opt_server$opt_suffix.cfg"
@@ -1190,7 +1192,7 @@ else
# Test: NOROUND
{
- my $resultat = 'undefined';
+ my $result = 'undefined';
my $error;
print "NOROUND: ";
save_incomplete('func_extra_noround','Function NOROUND');
@@ -1199,21 +1201,25 @@ else
$error = safe_query_l('func_extra_noround',"select noround(22.6) $end_query");
if ($error ne 1) # syntax error -- noround is not supported
{
- $resultat = 'no'
- } else # Ok, now check if it really works
- {
+ $result = 'no'
+ }
+ else # Ok, now check if it really works
+ {
$error=safe_query_l('func_extra_noround',
["create table crash_me_nr (a int)",
"insert into crash_me_nr values(noround(10.2))",
"drop table crash_me_nr $drop_attr"]);
- if ($error eq 1) {
- $resultat = "syntax only";
- } else {
- $resultat = 'yes';
- }
- }
- print "$resultat\n";
- save_config_data('func_extra_noround',$resultat,"Function NOROUND");
+ if ($error == 1)
+ {
+ $result= "syntax only";
+ }
+ else
+ {
+ $result= 'yes';
+ }
+ }
+ print "$result\n";
+ save_config_data('func_extra_noround',$result,"Function NOROUND");
}
check_parenthesis("func_sql_","CURRENT_USER");
@@ -1377,7 +1383,7 @@ if ($limits{'type_sql_date'} eq 'yes')
# Test: WEEK()
{
- my $resultat="no";
+ my $result="no";
my $error;
print "WEEK:";
save_incomplete('func_odbc_week','WEEK');
@@ -1388,17 +1394,17 @@ if ($limits{'type_sql_date'} eq 'yes')
# and 0 - EURO weeks
if ($error == -1) {
if ($last_result == 4) {
- $resultat = 'USA';
+ $result = 'USA';
} else {
- $resultat='error';
+ $result='error';
add_log('func_odbc_week',
" must return 4 or 5, but $last_result");
}
} elsif ($error == 0) {
- $resultat = 'EURO';
+ $result = 'EURO';
}
- print " $resultat\n";
- save_config_data('func_odbc_week',$resultat,"WEEK");
+ print " $result\n";
+ save_config_data('func_odbc_week',$result,"WEEK");
}
my $insert_query ='insert into crash_me_d values('.
@@ -1498,7 +1504,7 @@ if ($limits{'type_sql_date'} eq 'yes')
# NOT id BETWEEN a and b
if ($limits{'func_where_not_between'} eq 'yes')
{
- my $resultat = 'error';
+ my $result = 'error';
my $err;
my $key='not_id_between';
my $prompt='NOT ID BETWEEN interprets as ID NOT BETWEEN';
@@ -1512,15 +1518,15 @@ if ($limits{'func_where_not_between'} eq 'yes')
5,0);
if ($err eq 1) {
if (not defined($last_result)) {
- $resultat='no';
+ $result='no';
};
};
if ( $err eq 0) {
- $resultat = 'yes';
+ $result = 'yes';
};
safe_query_l($key,["drop table crash_me_b"]);
- save_config_data($key,$resultat,$prompt);
- print "$resultat\n";
+ save_config_data($key,$result,$prompt);
+ print "$result\n";
};
@@ -2018,37 +2024,44 @@ report("views","views",
# Test: foreign key
{
- my $resultat = 'undefined';
+ my $result = 'undefined';
my $error;
print "foreign keys: ";
save_incomplete('foreign_key','foreign keys');
# 1) check if foreign keys are supported
- safe_query_l('foreign_key',create_table("crash_me_qf",["a integer not null"],
- ["primary key (a)"]));
- $error = safe_query_l('foreign_key',
- create_table("crash_me_qf2",["a integer not null",
- "foreign key (a) references crash_me_qf (a)"], []));
-
- if ($error eq 1) # OK -- syntax is supported
+ safe_query_l('foreign_key',
+ create_table("crash_me_qf",
+ ["a integer not null"],
+ ["primary key (a)"]));
+ $error= safe_query_l('foreign_key',
+ create_table("crash_me_qf2",
+ ["a integer not null",
+ "foreign key (a) references crash_me_qf (a)"],
+ []));
+
+ if ($error == 1) # OK -- syntax is supported
{
- $resultat = 'error';
+ $result = 'error';
# now check if foreign key really works
safe_query_l('foreign_key', "insert into crash_me_qf values (1)");
- if (safe_query_l('foreign_key', "insert into crash_me_qf2 values (2)") eq 1)
+ if (safe_query_l('foreign_key', "insert into crash_me_qf2 values (2)") eq 1)
{
- $resultat = 'syntax only';
- } else {
- $resultat = 'yes';
- }
-
- } else {
- $resultat = "no";
- }
- safe_query_l('foreign_key',
- "drop table crash_me_qf2 $drop_attr","drop table crash_me_qf $drop_attr");
- print "$resultat\n";
- save_config_data('foreign_key',$resultat,"foreign keys");
+ $result = 'syntax only';
+ }
+ else
+ {
+ $result = 'yes';
+ }
+ }
+ else
+ {
+ $result = "no";
+ }
+ safe_query_l('foreign_key', "drop table crash_me_qf2 $drop_attr");
+ safe_query_l('foreign_key', "drop table crash_me_qf $drop_attr");
+ print "$result\n";
+ save_config_data('foreign_key',$result,"foreign keys");
}
report("Create SCHEMA","create_schema",
@@ -2607,7 +2620,7 @@ sub detect_null_position
sub check_parenthesis {
my $prefix=shift;
my $fn=shift;
- my $resultat='no';
+ my $result='no';
my $param_name=$prefix.lc($fn);
my $r;
@@ -2616,18 +2629,18 @@ sub check_parenthesis {
add_log($param_name,$safe_query_log);
if ($r == 1)
{
- $resultat="yes";
+ $result="yes";
}
else{
$r = safe_query("select $fn() $end_query");
add_log($param_name,$safe_query_log);
if ( $r == 1)
{
- $resultat="with_parenthesis";
+ $result="with_parenthesis";
}
}
- save_config_data($param_name,$resultat,$fn);
+ save_config_data($param_name,$result,$fn);
}
sub check_constraint {
@@ -2699,10 +2712,16 @@ sub make_date {
}
+sub version
+{
+ print "$0 Ver $version\n";
+}
+
+
sub usage
{
+ version();
print <<EOF;
-$0 Ver $version
This program tries to find all limits and capabilities for a SQL
server. As it will use the server in some 'unexpected' ways, one
@@ -3048,7 +3067,7 @@ sub safe_query_l {
my $r = safe_query($q);
add_log($key,$safe_query_log);
return $r;
-}
+}
sub safe_query
{
@@ -3110,7 +3129,6 @@ sub safe_query
$retry = $retry_limit;
$retry_ok = 1;
$safe_query_log .= "> OK\n";
-
}
$sth->finish;
}
diff --git a/sql-bench/test-alter-table.sh b/sql-bench/test-alter-table.sh
index cc6453188de..f338792e9ef 100644
--- a/sql-bench/test-alter-table.sh
+++ b/sql-bench/test-alter-table.sh
@@ -27,6 +27,7 @@ $opt_start_field_count=8; # start with this many fields
$opt_loop_count=20; # How many tests to do
$opt_row_count=1000; # Rows in the table
$opt_field_count=1000; # Add until this many fields.
+$opt_time_limit=10*60; # Don't wait more than 10 min for some tests
chomp($pwd = `pwd`); $pwd = "." if ($pwd eq '');
require "$pwd/bench-init.pl" || die "Can't read Configuration file: $!\n";
@@ -113,10 +114,9 @@ if ($opt_fast)
}
else
{
- $add=1 if (!$limits{'alter_add_multi_col'});
+ $add=1 if (!$limits->{'alter_add_multi_col'});
}
-
$count=0;
while ($field_count < $opt_field_count)
{
@@ -131,19 +131,43 @@ while ($field_count < $opt_field_count)
$tmp="" if (!$multi_add); # Adabas
}
do_query($dbh,"ALTER TABLE bench " . substr($fields,1));
+ $end_time=new Benchmark;
+ last if ($estimated=predict_query_time($loop_time,$end_time,\$count,$count,
+ $opt_field_count/$add+1));
}
$end_time=new Benchmark;
-print "Time for alter_table_add ($count): " .
+if ($estimated)
+{ print "Estimated time"; }
+else
+{ print "Time"; }
+print " for alter_table_add ($count): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+#
+# If estimated, fix table to have known number of fields
+#
+if ($estimated && $field_count < $opt_field_count)
+{
+ $fields="";
+ $tmp="ADD ";
+ while ($field_count < $opt_field_count)
+ {
+ $field_count++;
+ $fields.=",$tmp i${field_count} integer";
+ $tmp="" if (!$multi_add); # Adabas
+ }
+ do_query($dbh,"ALTER TABLE bench " . substr($fields,1));
+}
+
####
#### Test adding and deleting index on the first $opt_start_fields
####
$loop_time=new Benchmark;
-for ($i=1; $i < $opt_start_field_count ; $i++)
+$count= 0;
+for ($i=1; $i <= $opt_start_field_count ; $i++)
{
$dbh->do("CREATE INDEX bench_ind$i ON bench (i${i})") || die $DBI::errstr;
}
@@ -153,7 +177,7 @@ print "Time for create_index ($opt_start_field_count): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
$loop_time=new Benchmark;
-for ($i=1; $i < $opt_start_field_count ; $i++)
+for ($i=1; $i <= $opt_start_field_count ; $i++)
{
$dbh->do($server->drop_index("bench","bench_ind$i")) || die $DBI::errstr;
}
@@ -182,10 +206,17 @@ while ($field_count > $opt_start_field_count)
}
$dbh->do("ALTER TABLE bench " . substr($fields,1) . $server->{'drop_attr'})
|| die $DBI::errstr;
+ $end_time=new Benchmark;
+ last if ($estimated=predict_query_time($loop_time,$end_time,\$count,$count,
+ $opt_field_count/$add+1));
}
$end_time=new Benchmark;
-print "Time for alter_table_drop ($count): " .
+if ($estimated)
+{ print "Estimated time"; }
+else
+{ print "Time"; }
+print " for alter_table_drop ($count): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
skip_dropcol:
diff --git a/sql-bench/test-insert.sh b/sql-bench/test-insert.sh
index 93bc2840b3b..c26ed42f7ed 100644
--- a/sql-bench/test-insert.sh
+++ b/sql-bench/test-insert.sh
@@ -21,10 +21,11 @@
# $opt_loop_count rows in random order
#
# changes made for Oracle compatibility
-# - $limits{'func_odbc_mod'} is OK from crash-me, but it fails here so set we
+# - $limits->{'func_odbc_mod'} is OK from crash-me, but it fails here so set we
# set it to 0 in server-cfg
-# - the default server config runs out of rollback segments, so I added a couple
-# of disconnect/connects to reset
+# - the default server config runs out of rollback segments, so we added a
+# couple of disconnect/connects to reset
+#
##################### Standard benchmark inits ##############################
use DBI;
diff --git a/sql/lex.h b/sql/lex.h
index 2ddc540991b..a505911ccf6 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -161,6 +161,7 @@ static SYMBOL symbols[] = {
{ "FLUSH", SYM(FLUSH_SYM),0,0},
{ "FALSE", SYM(FALSE_SYM),0,0},
{ "FOREIGN", SYM(FOREIGN),0,0},
+ { "FORCE", SYM(FORCE_SYM),0,0},
{ "RAID_TYPE", SYM(RAID_TYPE),0,0},
{ "RAID_CHUNKS", SYM(RAID_CHUNKS),0,0},
{ "RAID_CHUNKSIZE", SYM(RAID_CHUNKSIZE),0,0},
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 8f98fa511a0..d025f8a57a7 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -294,7 +294,19 @@ Log_event::Log_event(const char* buf, bool old_format)
****************************************************************************/
int Log_event::exec_event(struct st_relay_log_info* rli)
{
- if (rli) // QQ When is this not true ?
+ /*
+ rli is null when (as far as I (Guilhem) know)
+ the caller is
+ Load_log_event::exec_event *and* that one is called from
+ Execute_load_log_event::exec_event.
+ In this case, we don't do anything here ;
+ Execute_load_log_event::exec_event will call Log_event::exec_event
+ again later with the proper rli.
+ Strictly speaking, if we were sure that rli is null
+ only in the case discussed above, 'if (rli)' is useless here.
+ But as we are not 100% sure, keep it for now.
+ */
+ if (rli)
{
if (rli->inside_transaction)
rli->inc_pending(get_event_len());
@@ -1435,13 +1447,36 @@ void Load_log_event::set_fields(List<Item> &field_list)
}
#endif // !MYSQL_CLIENT
-/*****************************************************************************
-
- Load_log_event::exec_event()
-
- ****************************************************************************/
#ifndef MYSQL_CLIENT
-int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli)
+
+/*
+ Does the data loading job when executing a LOAD DATA on the slave
+
+ SYNOPSIS
+ Load_log_event::exec_event
+ net
+ rli
+ use_rli_only_for_errors - if set to 1, rli is provided to
+ Load_log_event::exec_event only for this
+ function to have RPL_LOG_NAME and
+ rli->last_slave_error, both being used by
+ error reports. rli's position advancing
+ is skipped (done by the caller which is
+ Execute_load_log_event::exec_event).
+ - if set to 0, rli is provided for full use,
+ i.e. for error reports and position
+ advancing.
+
+ DESCRIPTION
+ Does the data loading job when executing a LOAD DATA on the slave
+
+ RETURN VALUE
+ 0 Success
+ 1 Failure
+*/
+
+int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
+ bool use_rli_only_for_errors)
{
init_sql_alloc(&thd->mem_root, 8192,0);
thd->db = rewrite_db((char*)db);
@@ -1503,9 +1538,15 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli)
TL_WRITE))
thd->query_error = 1;
if (thd->cuted_fields)
+ {
+ /*
+ log_pos is the position of the LOAD
+ event in the master log
+ */
sql_print_error("Slave: load data infile at position %s in log \
-'%s' produced %d warning(s)", llstr(rli->master_log_pos,llbuff), RPL_LOG_NAME,
+'%s' produced %d warning(s)", llstr(log_pos,llbuff), RPL_LOG_NAME,
thd->cuted_fields );
+ }
if (net)
net->pkt_nr= thd->net.pkt_nr;
}
@@ -1544,7 +1585,7 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli)
return 1;
}
- return Log_event::exec_event(rli);
+ return ( use_rli_only_for_errors ? 0 : Log_event::exec_event(rli) );
}
#endif // !MYSQL_CLIENT
@@ -2680,7 +2721,11 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli)
save_options = thd->options;
thd->options &= ~ (ulong) (OPTION_BIN_LOG);
lev->thd = thd;
- if (lev->exec_event(0,0))
+ /*
+ lev->exec_event should use rli only for errors
+ i.e. should not advance rli's position
+ */
+ if (lev->exec_event(0,rli,1))
{
slave_print_error(rli,my_errno, "Failed executing load from '%s'", fname);
thd->options = save_options;
diff --git a/sql/log_event.h b/sql/log_event.h
index ec3b4819e74..80c448e1550 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -460,9 +460,10 @@ public:
const char* get_db() { return db; }
int exec_event(struct st_relay_log_info* rli)
{
- return exec_event(thd->slave_net,rli);
+ return exec_event(thd->slave_net,rli,0);
}
- int exec_event(NET* net, struct st_relay_log_info* rli);
+ int exec_event(NET* net, struct st_relay_log_info* rli,
+ bool use_rli_only_for_errors);
#else
void print(FILE* file, bool short_form = 0, char* last_db = 0);
#endif
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 655e4d7b972..cdc668d9b28 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -235,6 +235,10 @@ void debug_sync_point(const char* lock_name, uint lock_timeout);
#define SHOW_LOG_STATUS_FREE "FREE"
#define SHOW_LOG_STATUS_INUSE "IN USE"
+/* Options to add_table_to_list() */
+#define TL_OPTION_UPDATING 1
+#define TL_OPTION_FORCE_INDEX 2
+
/* Some portable defines */
#define portable_sizeof_char_ptr 8
@@ -820,7 +824,6 @@ uint calc_week(TIME *ltime, bool with_year, bool sunday_first_day_of_week,
void find_date(char *pos,uint *vek,uint flag);
TYPELIB *convert_strings_to_array_type(my_string *typelibs, my_string *end);
TYPELIB *typelib(List<String> &strings);
-void clean_up(bool print_message=1);
ulong get_form_pos(File file, uchar *head, TYPELIB *save_names);
ulong make_new_entry(File file,uchar *fileinfo,TYPELIB *formnames,
const char *newname);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index d6a5c0b8412..f66122e72a6 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -491,6 +491,7 @@ extern "C" pthread_handler_decl(handle_slave,arg);
static uint set_maximum_open_files(uint max_file_limit);
#endif
static ulong find_bit_type(const char *x, TYPELIB *bit_lib);
+static void clean_up(bool print_message);
/****************************************************************************
** Code to end mysqld
@@ -763,13 +764,13 @@ void kill_mysql(void)
#if defined(OS2)
extern "C" void kill_server(int sig_ptr)
-#define RETURN_FROM_KILL_SERVER return
+#define RETURN_FROM_KILL_SERVER DBUG_RETURN
#elif !defined(__WIN__)
static void *kill_server(void *sig_ptr)
-#define RETURN_FROM_KILL_SERVER return 0
+#define RETURN_FROM_KILL_SERVER DBUG_RETURN(0)
#else
static void __cdecl kill_server(int sig_ptr)
-#define RETURN_FROM_KILL_SERVER return
+#define RETURN_FROM_KILL_SERVER DBUG_RETURN
#endif
{
int sig=(int) (long) sig_ptr; // This is passed a int
@@ -848,7 +849,7 @@ extern "C" sig_handler print_signal_warning(int sig)
void unireg_end(void)
{
- clean_up();
+ clean_up(1);
my_thread_end();
#ifdef SIGNALS_DONT_BREAK_READ
exit(0);
@@ -863,7 +864,7 @@ extern "C" void unireg_abort(int exit_code)
DBUG_ENTER("unireg_abort");
if (exit_code)
sql_print_error("Aborting\n");
- clean_up(); /* purecov: inspected */
+ clean_up(1); /* purecov: inspected */
DBUG_PRINT("quit",("done with cleanup in unireg_abort"));
my_thread_end();
exit(exit_code); /* purecov: inspected */
@@ -908,12 +909,12 @@ void clean_up(bool print_message)
regex_end();
#endif
+ if (print_message && errmesg)
+ sql_print_error(ER(ER_SHUTDOWN_COMPLETE),my_progname);
#if !defined(__WIN__) && !defined(EMBEDDED_LIBRARY)
if (!opt_bootstrap)
(void) my_delete(pidfile_name,MYF(0)); // This may not always exist
#endif
- if (print_message && errmesg)
- sql_print_error(ER(ER_SHUTDOWN_COMPLETE),my_progname);
x_free((gptr) my_errmsg[ERRMAPP]); /* Free messages */
DBUG_PRINT("quit", ("Error messages freed"));
/* Tell main we are ready */
@@ -923,6 +924,10 @@ void clean_up(bool print_message)
/* do the broadcast inside the lock to ensure that my_end() is not called */
(void) pthread_cond_broadcast(&COND_thread_count);
(void) pthread_mutex_unlock(&LOCK_thread_count);
+ /*
+ The following lines may never be executed as the main thread may have
+ killed us
+ */
DBUG_PRINT("quit", ("done with cleanup"));
} /* clean_up */
@@ -1502,7 +1507,7 @@ static void init_signals(void)
/* Change limits so that we will get a core file */
struct rlimit rl;
rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
- if (setrlimit(RLIMIT_CORE, &rl))
+ if (setrlimit(RLIMIT_CORE, &rl) && global_system_variables.log_warnings)
sql_print_error("Warning: setrlimit could not change the size of core files to 'infinity'; We may not be able to generate a core file on signals");
}
#endif
@@ -1571,8 +1576,11 @@ extern "C" void *signal_hand(void *arg __attribute__((unused)))
my_thread_init(); // Init new thread
DBUG_ENTER("signal_hand");
SIGNAL_THD;
- /* Setup alarm handler */
- init_thr_alarm(max_connections+max_insert_delayed_threads);
+ /*
+ Setup alarm handler
+ The two extra handlers are for slave threads
+ */
+ init_thr_alarm(max_connections+max_insert_delayed_threads+2);
#if SIGINT != THR_KILL_SIGNAL
(void) sigemptyset(&set); // Setup up SIGINT for debug
(void) sigaddset(&set,SIGINT); // For debugging
@@ -1660,12 +1668,15 @@ extern "C" void *signal_hand(void *arg __attribute__((unused)))
}
break;
case SIGHUP:
- reload_acl_and_cache((THD*) 0,
- (REFRESH_LOG | REFRESH_TABLES | REFRESH_FAST |
- REFRESH_STATUS | REFRESH_GRANT | REFRESH_THREADS |
- REFRESH_HOSTS),
- (TABLE_LIST*) 0); // Flush logs
- mysql_print_status((THD*) 0); // Send debug some info
+ if (!abort_loop)
+ {
+ reload_acl_and_cache((THD*) 0,
+ (REFRESH_LOG | REFRESH_TABLES | REFRESH_FAST |
+ REFRESH_STATUS | REFRESH_GRANT |
+ REFRESH_THREADS | REFRESH_HOSTS),
+ (TABLE_LIST*) 0); // Flush logs
+ mysql_print_status((THD*) 0); // Send debug some info
+ }
break;
#ifdef USE_ONE_SIGNAL_HAND
case THR_SERVER_ALARM:
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 887ce6c561a..0adde4d39e0 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -603,12 +603,14 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
records++; /* purecov: inspected */
scan_time=(double) records / TIME_FOR_COMPARE+1;
read_time=(double) head->file->scan_time()+ scan_time + 1.0;
+ if (head->force_index)
+ scan_time= read_time= DBL_MAX;
if (limit < records)
read_time=(double) records+scan_time+1; // Force to use index
else if (read_time <= 2.0 && !force_quick_range)
DBUG_RETURN(0); /* No need for quick select */
- DBUG_PRINT("info",("Time to scan table: %ld",(long) read_time));
+ DBUG_PRINT("info",("Time to scan table: %g", read_time));
keys_to_use&=head->keys_in_use_for_query;
if (keys_to_use)
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 15f4ca9ad94..48ef9ecb71e 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -171,7 +171,10 @@ net_printf(THD *thd, uint errcode, ...)
{
if (thd->bootstrap)
{
- /* In bootstrap it's ok to print on stderr */
+ /*
+ In bootstrap it's ok to print on stderr
+ This may also happen when we get an error from a slave thread
+ */
fprintf(stderr,"ERROR: %d %s\n",errcode,text_pos);
thd->fatal_error=1;
}
diff --git a/sql/slave.cc b/sql/slave.cc
index 342a35b8821..271fe8bc2d6 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -413,6 +413,7 @@ int terminate_slave_threads(MASTER_INFO* mi,int thread_mask,bool skip_lock)
}
if ((thread_mask & (SLAVE_IO|SLAVE_FORCE_ALL)) && mi->slave_running)
{
+ DBUG_PRINT("info",("Terminating IO thread"));
mi->abort_slave=1;
if ((error=terminate_slave_thread(mi->io_thd,io_lock,
io_cond_lock,
@@ -423,6 +424,7 @@ int terminate_slave_threads(MASTER_INFO* mi,int thread_mask,bool skip_lock)
}
if ((thread_mask & (SLAVE_SQL|SLAVE_FORCE_ALL)) && mi->rli.slave_running)
{
+ DBUG_PRINT("info",("Terminating SQL thread"));
DBUG_ASSERT(mi->rli.sql_thd != 0) ;
mi->rli.abort_slave=1;
if ((error=terminate_slave_thread(mi->rli.sql_thd,sql_lock,
@@ -2572,12 +2574,6 @@ static int process_io_rotate(MASTER_INFO *mi, Rotate_log_event *rev)
memcpy(mi->master_log_name, rev->new_log_ident, rev->ident_len+1);
mi->master_log_pos= rev->pos;
-
- pthread_mutex_lock(&mi->rli.data_lock);
- memcpy(mi->rli.master_log_name, rev->new_log_ident, rev->ident_len+1);
- mi->rli.master_log_pos= rev->pos;
- pthread_mutex_unlock(&mi->rli.data_lock);
-
DBUG_PRINT("info", ("master_log_pos: '%s' %d",
mi->master_log_name, (ulong) mi->master_log_pos));
#ifndef DBUG_OFF
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index b5178076258..a384e723e32 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -747,7 +747,7 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list)
table->tablenr=thd->current_tablenr++;
table->used_fields=0;
table->const_table=0;
- table->outer_join=table->null_row=table->maybe_null=0;
+ table->outer_join= table->null_row= table->maybe_null= table->force_index= 0;
table->status=STATUS_NO_RECORD;
table->keys_in_use_for_query= table->keys_in_use;
table->used_keys= table->keys_for_keyread;
@@ -906,7 +906,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
table->tablenr=thd->current_tablenr++;
table->used_fields=0;
table->const_table=0;
- table->outer_join=table->null_row=table->maybe_null=0;
+ table->outer_join= table->null_row= table->maybe_null= table->force_index= 0;
table->status=STATUS_NO_RECORD;
table->keys_in_use_for_query= table->keys_in_use;
table->used_keys= table->keys_for_keyread;
@@ -977,6 +977,7 @@ bool reopen_table(TABLE *table,bool locked)
tmp.status= table->status;
tmp.keys_in_use_for_query= tmp.keys_in_use;
tmp.used_keys= tmp.keys_for_keyread;
+ tmp.force_index= tmp.force_index;
/* Get state */
tmp.key_length= table->key_length;
@@ -1969,6 +1970,7 @@ bool setup_tables(TABLE_LIST *tables)
table->maybe_null=test(table->outer_join=table_list->outer_join);
table->tablenr=tablenr;
table->map= (table_map) 1 << tablenr;
+ table->force_index= table_list->force_index;
if (table_list->use_index)
{
key_map map= get_key_map_from_key_list(table,
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index c7c7a97cdc2..dda3d4e822e 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1171,13 +1171,14 @@ List<String>* st_select_lex_node::get_use_index() { return 0; }
List<String>* st_select_lex_node::get_ignore_index() { return 0; }
TABLE_LIST *st_select_lex_node::add_table_to_list(THD *thd, Table_ident *table,
LEX_STRING *alias,
- bool updating,
+ ulong table_join_options,
thr_lock_type flags,
List<String> *use_index,
List<String> *ignore_index)
{
return 0;
}
+ulong st_select_lex_node::get_table_join_options() { return 0; }
/*
This is used for UNION & subselect to create a new table list of all used
@@ -1334,6 +1335,11 @@ List<String>* st_select_lex::get_ignore_index()
return ignore_index_ptr;
}
+ulong st_select_lex::get_table_join_options()
+{
+ return table_join_options;
+}
+
/*
There are st_select_lex::add_table_to_list &
st_select_lex::set_lock_for_tables in sql_parse.cc
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 9b8f4a47515..4b6ac927f07 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -243,9 +243,10 @@ public:
virtual List<Item>* get_item_list();
virtual List<String>* get_use_index();
virtual List<String>* get_ignore_index();
+ virtual ulong get_table_join_options();
virtual TABLE_LIST *add_table_to_list(THD *thd, Table_ident *table,
LEX_STRING *alias,
- bool updating,
+ ulong table_options,
thr_lock_type flags= TL_UNLOCK,
List<String> *use_index= 0,
List<String> *ignore_index= 0);
@@ -336,6 +337,7 @@ public:
List<Item_func_match> ftfunc_list_alloc;
JOIN *join; /* after JOIN::prepare it is pointer to corresponding JOIN */
const char *type; /* type of select for EXPLAIN */
+ ulong table_join_options;
uint in_sum_expr;
uint select_number; /* number of select (used for EXPLAIN) */
bool braces; /* SELECT ... UNION (SELECT ... ) <- this braces */
@@ -373,9 +375,10 @@ public:
List<Item>* get_item_list();
List<String>* get_use_index();
List<String>* get_ignore_index();
+ ulong get_table_join_options();
TABLE_LIST* add_table_to_list(THD *thd, Table_ident *table,
LEX_STRING *alias,
- bool updating,
+ ulong table_options,
thr_lock_type flags= TL_UNLOCK,
List<String> *use_index= 0,
List<String> *ignore_index= 0);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index f6e21e421d9..81fb5a6d12c 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -518,7 +518,8 @@ check_connections(THD *thd)
vio_in_addr(net->vio,&thd->remote.sin_addr);
thd->host=ip_to_hostname(&thd->remote.sin_addr,&connect_errors);
/* Cut very long hostnames to avoid possible overflows */
- thd->host[min(strlen(thd->host), HOSTNAME_LENGTH)]= 0;
+ if (thd->host)
+ thd->host[min(strlen(thd->host), HOSTNAME_LENGTH)]= 0;
if (connect_errors > max_connect_errors)
return(ER_HOST_IS_BLOCKED);
}
@@ -3597,11 +3598,30 @@ bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc)
}
+/*
+ Add a table to list of used tables
+
+ SYNOPSIS
+ add_table_to_list()
+ table Table to add
+ alias alias for table (or null if no alias)
+ table_options A set of the following bits:
+ TL_OPTION_UPDATING Table will be updated
+ TL_OPTION_FORCE_INDEX Force usage of index
+ lock_type How table should be locked
+ use_index List of indexed used in USE INDEX
+ ignore_index List of indexed used in IGNORE INDEX
+
+ RETURN
+ 0 Error
+ # Pointer to TABLE_LIST element added to the total table list
+*/
+
TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
Table_ident *table,
LEX_STRING *alias,
- bool updating,
- thr_lock_type flags,
+ ulong table_options,
+ thr_lock_type lock_type,
List<String> *use_index,
List<String> *ignore_index)
{
@@ -3658,8 +3678,9 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
}
ptr->real_name=table->table.str;
ptr->real_name_length=table->table.length;
- ptr->lock_type=flags;
- ptr->updating=updating;
+ ptr->lock_type= lock_type;
+ ptr->updating= test(table_options & TL_OPTION_UPDATING);
+ ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
ptr->derived= (SELECT_LEX_UNIT *) table->sel;
if (use_index)
ptr->use_index=(List<String> *) thd->memdup((gptr) use_index,
@@ -3669,7 +3690,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
sizeof(*ignore_index));
/* check that used name is unique */
- if (flags != TL_IGNORE)
+ if (lock_type != TL_IGNORE)
{
for (TABLE_LIST *tables=(TABLE_LIST*) table_list.first ;
tables ;
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index e7784cad04d..aab8d883204 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -2305,7 +2305,8 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
!(s->quick && best_key && s->quick->index == best_key->key &&
best_max_key_part >= s->table->quick_key_parts[best_key->key]) &&
!((s->table->file->table_flags() & HA_TABLE_SCAN_ON_INDEX) &&
- s->table->used_keys && best_key))
+ s->table->used_keys && best_key) &&
+ !(s->table->force_index && best_key))
{ // Check full join
if (s->on_expr)
{
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index b01555effa8..281fa92de6a 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1497,6 +1497,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
case SHOW_RPL_STATUS:
end= strmov(buff, rpl_status_type[(int)rpl_status]);
break;
+#ifndef EMBEDDED_LIBRARY
case SHOW_SLAVE_RUNNING:
{
LOCK_ACTIVE_MI;
@@ -1505,6 +1506,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
UNLOCK_ACTIVE_MI;
break;
}
+#endif
case SHOW_OPENTABLES:
end= int10_to_str((long) cached_tables(), buff, 10);
break;
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index e83b4da728f..8fa17f0d5ed 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2001 MySQL AB
+/* Copyright (C) 2000-2003 MySQL 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
@@ -222,6 +222,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token FIRST_SYM
%token FIXED_SYM
%token FLOAT_NUM
+%token FORCE_SYM
%token FOREIGN
%token FROM
%token FULL
@@ -823,7 +824,8 @@ create:
($2 &
HA_LEX_CREATE_TMP_TABLE ?
&tmp_table_alias :
- (LEX_STRING*) 0),1,
+ (LEX_STRING*) 0),
+ TL_OPTION_UPDATING,
((using_update_log)?
TL_READ_NO_INSERT:
TL_READ)))
@@ -844,7 +846,8 @@ create:
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_CREATE_INDEX;
- if (!lex->current_select->add_table_to_list(lex->thd, $7,NULL,1))
+ if (!lex->current_select->add_table_to_list(lex->thd, $7, NULL,
+ TL_OPTION_UPDATING))
YYABORT;
lex->create_list.empty();
lex->key_list.empty();
@@ -1380,6 +1383,7 @@ opt_unique_or_fulltext:
key_alg:
/* empty */ { $$= HA_KEY_ALG_UNDEF; }
| USING opt_btree_or_rtree { $$= $2; };
+ | TYPE_SYM opt_btree_or_rtree { $$= $2; };
opt_btree_or_rtree:
BTREE_SYM { $$= HA_KEY_ALG_BTREE; }
@@ -1413,7 +1417,8 @@ alter:
LEX *lex=&thd->lex;
lex->sql_command = SQLCOM_ALTER_TABLE;
lex->name=0;
- if (!lex->select_lex.add_table_to_list(thd, $4, NULL,1))
+ if (!lex->select_lex.add_table_to_list(thd, $4, NULL,
+ TL_OPTION_UPDATING))
YYABORT;
lex->drop_primary=0;
lex->create_list.empty();
@@ -1679,8 +1684,10 @@ table_to_table:
{
LEX *lex=Lex;
SELECT_LEX_NODE *sl= lex->current_select;
- if (!sl->add_table_to_list(lex->thd, $1,NULL,1,TL_IGNORE) ||
- !sl->add_table_to_list(lex->thd, $3,NULL,1,TL_IGNORE))
+ if (!sl->add_table_to_list(lex->thd, $1,NULL,TL_OPTION_UPDATING,
+ TL_IGNORE) ||
+ !sl->add_table_to_list(lex->thd, $3,NULL,TL_OPTION_UPDATING,
+ TL_IGNORE))
YYABORT;
};
@@ -2532,12 +2539,14 @@ join_table:
{
SELECT_LEX *sel= Select->select_lex();
sel->use_index_ptr=sel->ignore_index_ptr=0;
+ sel->table_join_options= 0;
}
table_ident opt_table_alias opt_key_definition
{
LEX *lex= Lex;
SELECT_LEX_NODE *sel= lex->current_select;
- if (!($$= sel->add_table_to_list(lex->thd, $2, $3, 0,
+ if (!($$= sel->add_table_to_list(lex->thd, $2, $3,
+ sel->get_table_join_options(),
lex->lock_option,
sel->get_use_index(),
sel->get_ignore_index())))
@@ -2583,6 +2592,13 @@ opt_key_definition:
sel->use_index= *$2;
sel->use_index_ptr= &sel->use_index;
}
+ | FORCE_SYM key_usage_list
+ {
+ SELECT_LEX *sel= Select->select_lex();
+ sel->use_index= *$2;
+ sel->use_index_ptr= &sel->use_index;
+ sel->table_join_options|= TL_OPTION_FORCE_INDEX;
+ }
| IGNORE_SYM key_usage_list
{
SELECT_LEX *sel= Select->select_lex();
@@ -2592,8 +2608,14 @@ opt_key_definition:
key_usage_list:
key_or_index { Select->select_lex()->interval_list.empty(); }
- '(' key_usage_list2 ')'
- { $$= &Select->select_lex()->interval_list; };
+ '(' key_list_or_empty ')'
+ { $$= &Select->select_lex()->interval_list; }
+ ;
+
+key_list_or_empty:
+ /* empty */ {}
+ | key_usage_list2 {}
+ ;
key_usage_list2:
key_usage_list2 ',' ident
@@ -2954,7 +2976,8 @@ drop:
lex->drop_list.empty();
lex->drop_list.push_back(new Alter_drop(Alter_drop::KEY,
$3.str));
- if (!lex->current_select->add_table_to_list(lex->thd, $5,NULL, 1))
+ if (!lex->current_select->add_table_to_list(lex->thd, $5, NULL,
+ TL_OPTION_UPDATING))
YYABORT;
}
| DROP DATABASE if_exists ident
@@ -2978,7 +3001,11 @@ table_list:
table_name:
table_ident
- { if (!Select->add_table_to_list(YYTHD, $1, NULL, 1)) YYABORT; };
+ {
+ if (!Select->add_table_to_list(YYTHD, $1, NULL, TL_OPTION_UPDATING))
+ YYABORT;
+ }
+ ;
if_exists:
/* empty */ { $$= 0; }
@@ -3213,7 +3240,8 @@ delete:
single_multi:
FROM table_ident
{
- if (!Select->add_table_to_list(YYTHD, $2, NULL, 1, Lex->lock_option))
+ if (!Select->add_table_to_list(YYTHD, $2, NULL, TL_OPTION_UPDATING,
+ Lex->lock_option))
YYABORT;
}
where_clause opt_order_clause
@@ -3234,14 +3262,15 @@ table_wild_list:
table_wild_one:
ident opt_wild opt_table_alias
{
- if (!Select->add_table_to_list(YYTHD, new Table_ident($1), $3, 1,
- Lex->lock_option))
+ if (!Select->add_table_to_list(YYTHD, new Table_ident($1), $3,
+ TL_OPTION_UPDATING, Lex->lock_option))
YYABORT;
}
| ident '.' ident opt_wild opt_table_alias
{
if (!Select->add_table_to_list(YYTHD, new Table_ident($1, $3, 0),
- $5, 1, Lex->lock_option))
+ $5, TL_OPTION_UPDATING,
+ Lex->lock_option))
YYABORT;
}
;
@@ -3405,7 +3434,7 @@ show_param:
| CREATE TABLE_SYM table_ident
{
Lex->sql_command = SQLCOM_SHOW_CREATE;
- if(!Select->add_table_to_list(YYTHD, $3, NULL,0))
+ if (!Select->add_table_to_list(YYTHD, $3, NULL,0))
YYABORT;
}
| MASTER_SYM STATUS_SYM
@@ -3574,14 +3603,14 @@ load: LOAD DATA_SYM load_data_lock opt_local INFILE TEXT_STRING
opt_duplicate INTO TABLE_SYM table_ident opt_field_term opt_line_term
opt_ignore_lines opt_field_spec
{
- if (!Select->add_table_to_list(YYTHD, $11, NULL, 1))
+ if (!Select->add_table_to_list(YYTHD, $11, NULL, TL_OPTION_UPDATING))
YYABORT;
}
|
LOAD TABLE_SYM table_ident FROM MASTER_SYM
{
Lex->sql_command = SQLCOM_LOAD_MASTER_TABLE;
- if (!Select->add_table_to_list(YYTHD, $3, NULL, 1))
+ if (!Select->add_table_to_list(YYTHD, $3, NULL, TL_OPTION_UPDATING))
YYABORT;
}
diff --git a/sql/table.h b/sql/table.h
index d24e4e1e422..6291b250787 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -91,6 +91,7 @@ struct st_table {
my_bool copy_blobs; /* copy_blobs when storing */
my_bool null_row; /* All columns are null */
my_bool maybe_null,outer_join; /* Used with OUTER JOIN */
+ my_bool force_index;
my_bool distinct,const_table,no_rows;
my_bool key_read, bulk_insert;
my_bool crypted;
@@ -168,6 +169,7 @@ typedef struct st_table_list
bool straight; /* optimize with prev table */
bool updating; /* for replicate-do/ignore table */
bool do_redirect; /* To get the struct in UNION's */
+ bool force_index; /* Prefer index over table scan */
} TABLE_LIST;
typedef struct st_changed_table_list