diff options
author | unknown <monty@mashka.mysql.fi> | 2003-01-09 03:55:26 +0200 |
---|---|---|
committer | unknown <monty@mashka.mysql.fi> | 2003-01-09 03:55:26 +0200 |
commit | 0396f97e6e009c76f646ca55586eb4abb002cbbe (patch) | |
tree | af09adc5a3ec6814545553d72fda1d33e443d162 | |
parent | 997418c5e3e72f818d66b453bbd3f5a6699639b8 (diff) | |
parent | f5310091748db98072769e7f36ced7fafcc35a11 (diff) | |
download | mariadb-git-0396f97e6e009c76f646ca55586eb4abb002cbbe.tar.gz |
merge with 4.0.9
To get bug fixes for TCP/IP connections, FORCE INDEX and OPTIMIZE TABLE with NULL keys
client/mysqladmin.c:
Auto merged
client/mysqltest.c:
Auto merged
extra/Makefile.am:
Auto merged
include/my_base.h:
Auto merged
innobase/log/log0log.c:
Auto merged
myisam/ft_nlq_search.c:
Auto merged
myisam/mi_open.c:
Auto merged
myisam/myisamdef.h:
Auto merged
mysql-test/mysql-test-run.sh:
Auto merged
mysql-test/r/myisam.result:
Auto merged
sql/lex.h:
Auto merged
sql/log_event.h:
Auto merged
sql/mysqld.cc:
Auto merged
sql/opt_range.cc:
Auto merged
sql/protocol.cc:
Auto merged
sql/slave.cc:
Auto merged
sql/sql_base.cc:
Auto merged
sql/sql_select.cc:
Auto merged
sql-bench/crash-me.sh:
Auto merged
sql-bench/test-insert.sh:
Auto merged
sql/sql_show.cc:
Auto merged
sql/table.h:
Auto merged
configure.in:
merge with 4.0.9
innobase/btr/btr0pcur.c:
merge with 4.0.9
myisam/mi_check.c:
merge with 4.0.9
myisam/mi_search.c:
merge with 4.0.9
mysql-test/t/myisam.test:
merge with 4.0.9
sql/log_event.cc:
merge with 4.0.9
sql/mysql_priv.h:
merge with 4.0.9
sql/sql_lex.h:
merge with 4.0.9
sql/sql_parse.cc:
merge with 4.0.9
sql/sql_yacc.yy:
merge with 4.0.9
36 files changed, 601 insertions, 197 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/innobase/mem/mem0pool.c b/innobase/mem/mem0pool.c index 1c32a4d02a6..382e505b63f 100644 --- a/innobase/mem/mem0pool.c +++ b/innobase/mem/mem0pool.c @@ -259,19 +259,6 @@ mem_pool_fill_free_list( /* We come here when we have run out of space in the memory pool: */ - if (mem_out_of_mem_err_msg_count % 1000000000 == 0) { - /* We do not print the message every time: */ - - ut_print_timestamp(stderr); - - fprintf(stderr, - " InnoDB: Out of memory in additional memory pool.\n" - "InnoDB: InnoDB will start allocating memory from the OS.\n" - "InnoDB: You may get better performance if you configure a bigger\n" - "InnoDB: value in the MySQL my.cnf file for\n" - "InnoDB: innodb_additional_mem_pool_size.\n"); - } - mem_out_of_mem_err_msg_count++; return(FALSE); 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..3d4b1dbd46d 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,45 @@ 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; +table type possible_keys key key_len ref rows Extra +t1 ALL a NULL NULL NULL 5 +t2 ALL a NULL NULL NULL 2 Using where +explain select * from t1,t2 force index(a) where t1.a=t2.a; +table type possible_keys key key_len ref rows Extra +t2 ALL a NULL NULL NULL 2 +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; +table type possible_keys key key_len ref rows Extra +t2 ALL a NULL NULL NULL 2 +t1 ref a a 4 t2.a 3 +explain select * from t1,t2 where t1.b=t2.b; +table type possible_keys key key_len ref rows Extra +t2 ALL b NULL NULL NULL 2 +t1 ref b b 5 t2.b 1 Using where +explain select * from t1,t2 force index(c) where t1.a=t2.a; +table type possible_keys key key_len ref rows Extra +t1 ALL a NULL NULL NULL 5 +t2 ALL NULL NULL NULL NULL 2 Using where +explain select * from t1 where a=0 or a=2; +table type possible_keys key key_len ref rows Extra +t1 ALL a NULL NULL NULL 5 Using where +explain select * from t1 force index (a) where a=0 or a=2; +table type possible_keys key key_len ref rows Extra +t1 range a a 4 NULL 4 Using where +drop table t1,t2; diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index 780a060e204..7b541d98cef 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,21 @@ 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; +drop table t1,t2; 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.h b/sql/sql_lex.h index 9b8f4a47515..b32e4489b01 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 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 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..ce8bd41d3a6 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); } @@ -3669,7 +3670,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 c5a4362c71e..8b1886fd438 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 c66764d673f..53e18f918f6 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1480,6 +1480,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; @@ -1488,6 +1489,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 77325bad3a0..106fa61e535 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 @@ -822,7 +823,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))) @@ -843,7 +845,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(); @@ -1390,7 +1393,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(); @@ -1657,8 +1661,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; }; @@ -2510,12 +2516,14 @@ join_table: { SELECT_LEX *sel= Select->select_lex(); sel->use_index_ptr=sel->ignore_index_ptr=0; + sel->table_join_ptions= 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, + lex->table_join_options(), lex->lock_option, sel->get_use_index(), sel->get_ignore_index()))) @@ -2932,7 +2940,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 @@ -2956,7 +2965,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; } @@ -3191,7 +3204,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 @@ -3212,14 +3226,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; } ; @@ -3383,7 +3398,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 @@ -3552,14 +3567,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 |