diff --git a/BitKeeper/triggers/post-commit b/BitKeeper/triggers/post-commit index d19c724268c..fe263b79325 100755 --- a/BitKeeper/triggers/post-commit +++ b/BitKeeper/triggers/post-commit @@ -27,6 +27,7 @@ then fi CHANGESET=`bk -R prs -r+ -h -d':P:::I:' ChangeSet` +CSETKEY=`bk -R prs -r+ -h -d':KEY:' ChangeSet` BUG=`bk -R prs -r+ -h -d':C:' ChangeSet | sed -ne 's/^.*[Bb][Uu][Gg] *# *\([0-9][0-9]*\).*$/\1/p'` WL=`bk -R prs -r+ -h -d':C:' ChangeSet | sed -ne 's/^.*[Ww][Ll] *# *\([0-9][0-9]*\).*$/ WL#\1/p'` @@ -52,6 +53,7 @@ List-ID: From: $FROM To: $TO Subject: bk commit - $VERSION tree ($CHANGESET)${BS}${WL} +X-CSetKey: <$CSETKEY> $BH EOF bk changes -v -r+ @@ -68,6 +70,7 @@ List-ID: From: $FROM To: $INTERNALS Subject: bk commit into $VERSION tree ($CHANGESET)$BS +X-CSetKey: <$CSETKEY> $BH Below is the list of changes that have just been committed into a local $VERSION repository of $USER. When $USER does a push these changes will diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index 15be51853cd..c767f1c89b7 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -566,6 +566,7 @@ static void print_result() my_bool found_error=0; res = mysql_use_result(sock); + prev[0] = '\0'; for (i = 0; (row = mysql_fetch_row(res)); i++) { @@ -595,7 +596,7 @@ static void print_result() putchar('\n'); } if (found_error && opt_auto_repair && what_to_do != DO_REPAIR && - (!opt_fast || strcmp(row[3],"OK"))) + !opt_fast) insert_dynamic(&tables4repair, prev); mysql_free_result(res); } diff --git a/configure.in b/configure.in index c7e93c9676a..01f669a0d1b 100644 --- a/configure.in +++ b/configure.in @@ -351,6 +351,15 @@ then if echo $CXX | grep gcc > /dev/null 2>&1 then GCC_VERSION=`gcc -v 2>&1 | grep version | sed -e 's/[[^0-9. ]]//g; s/^ *//g; s/ .*//g'` + case $SYSTEM_TYPE in + *freebsd*) + # The libsupc++ library on freebsd with gcc 3.4.2 is dependent on + # libstdc++, disable it since other solution works fine + GCC_VERSION="NOSUPCPP_$GCC_VERSION" + ;; + *) + ;; + esac echo "Using gcc version '$GCC_VERSION'" case "$GCC_VERSION" in 3.4.*|3.5.*) diff --git a/include/m_ctype.h b/include/m_ctype.h index f5a1503234c..61524dc4ddd 100644 --- a/include/m_ctype.h +++ b/include/m_ctype.h @@ -149,7 +149,8 @@ typedef struct my_charset_handler_st uint (*numchars)(struct charset_info_st *, const char *b, const char *e); uint (*charpos)(struct charset_info_st *, const char *b, const char *e, uint pos); uint (*well_formed_len)(struct charset_info_st *, - const char *b,const char *e, uint nchars); + const char *b,const char *e, + uint nchars, int *error); uint (*lengthsp)(struct charset_info_st *, const char *ptr, uint length); uint (*numcells)(struct charset_info_st *, const char *b, const char *e); @@ -349,7 +350,8 @@ int my_wildcmp_8bit(CHARSET_INFO *, uint my_numchars_8bit(CHARSET_INFO *, const char *b, const char *e); uint my_numcells_8bit(CHARSET_INFO *, const char *b, const char *e); uint my_charpos_8bit(CHARSET_INFO *, const char *b, const char *e, uint pos); -uint my_well_formed_len_8bit(CHARSET_INFO *, const char *b, const char *e, uint pos); +uint my_well_formed_len_8bit(CHARSET_INFO *, const char *b, const char *e, + uint pos, int *error); int my_mbcharlen_8bit(CHARSET_INFO *, uint c); @@ -367,7 +369,8 @@ int my_wildcmp_mb(CHARSET_INFO *, uint my_numchars_mb(CHARSET_INFO *, const char *b, const char *e); uint my_numcells_mb(CHARSET_INFO *, const char *b, const char *e); uint my_charpos_mb(CHARSET_INFO *, const char *b, const char *e, uint pos); -uint my_well_formed_len_mb(CHARSET_INFO *, const char *b, const char *e, uint pos); +uint my_well_formed_len_mb(CHARSET_INFO *, const char *b, const char *e, + uint pos, int *error); uint my_instr_mb(struct charset_info_st *, const char *b, uint b_length, const char *s, uint s_length, diff --git a/innobase/btr/btr0pcur.c b/innobase/btr/btr0pcur.c index ceaa4f41a18..74feff8653c 100644 --- a/innobase/btr/btr0pcur.c +++ b/innobase/btr/btr0pcur.c @@ -14,6 +14,7 @@ Created 2/23/1996 Heikki Tuuri #include "ut0byte.h" #include "rem0cmp.h" +#include "trx0trx.h" /****************************************************************** Allocates memory for a persistent cursor object and initializes the cursor. */ @@ -206,7 +207,14 @@ btr_pcur_restore_position( ut_a(cursor->pos_state == BTR_PCUR_WAS_POSITIONED || cursor->pos_state == BTR_PCUR_IS_POSITIONED); - ut_a(cursor->old_stored == BTR_PCUR_OLD_STORED); + if (cursor->old_stored != BTR_PCUR_OLD_STORED) { + ut_print_buf(stderr, (const byte*)cursor, sizeof(btr_pcur_t)); + if (cursor->trx_if_known) { + trx_print(stderr, cursor->trx_if_known); + } + + ut_a(0); + } if (cursor->rel_pos == BTR_PCUR_AFTER_LAST_IN_TREE || cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE) { diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c index 02f46ea7b18..f973b994055 100644 --- a/innobase/dict/dict0dict.c +++ b/innobase/dict/dict0dict.c @@ -3333,6 +3333,9 @@ try_find_index: "Cannot find an index in the referenced table where the\n" "referenced columns appear as the first columns, or column types\n" "in the table and the referenced table do not match for constraint.\n" +"Note that the internal storage type of ENUM and SET changed in\n" +"tables created with >= InnoDB-4.1.12, and such columns in old tables\n" +"cannot be referenced by such columns in new tables.\n" "See http://dev.mysql.com/doc/mysql/en/InnoDB_foreign_key_constraints.html\n" "for correct foreign key definition.\n", start_of_latest_foreign); diff --git a/innobase/include/btr0pcur.h b/innobase/include/btr0pcur.h index 6384222be51..eb3822aab7a 100644 --- a/innobase/include/btr0pcur.h +++ b/innobase/include/btr0pcur.h @@ -478,6 +478,10 @@ struct btr_pcur_struct{ BTR_PCUR_WAS_POSITIONED, BTR_PCUR_NOT_POSITIONED */ ulint search_mode; /* PAGE_CUR_G, ... */ + trx_t* trx_if_known; /* the transaction, if we know it; + otherwise this field is not defined; + can ONLY BE USED in error prints in + fatal assertion failures! */ /*-----------------------------*/ /* NOTE that the following fields may possess dynamically allocated memory which should be freed if not needed anymore! */ diff --git a/innobase/include/btr0pcur.ic b/innobase/include/btr0pcur.ic index b553a569bda..9a7d7867025 100644 --- a/innobase/include/btr0pcur.ic +++ b/innobase/include/btr0pcur.ic @@ -493,6 +493,8 @@ btr_pcur_open( btr_cur_search_to_nth_level(index, 0, tuple, mode, latch_mode, btr_cursor, 0, mtr); cursor->pos_state = BTR_PCUR_IS_POSITIONED; + + cursor->trx_if_known = NULL; } /****************************************************************** @@ -535,6 +537,8 @@ btr_pcur_open_with_no_init( cursor->pos_state = BTR_PCUR_IS_POSITIONED; cursor->old_stored = BTR_PCUR_OLD_NOT_STORED; + + cursor->trx_if_known = NULL; } /********************************************************************* @@ -568,6 +572,8 @@ btr_pcur_open_at_index_side( pcur->pos_state = BTR_PCUR_IS_POSITIONED; pcur->old_stored = BTR_PCUR_OLD_NOT_STORED; + + pcur->trx_if_known = NULL; } /************************************************************************** @@ -592,6 +598,8 @@ btr_pcur_open_at_rnd_pos( btr_pcur_get_btr_cur(cursor), mtr); cursor->pos_state = BTR_PCUR_IS_POSITIONED; cursor->old_stored = BTR_PCUR_OLD_NOT_STORED; + + cursor->trx_if_known = NULL; } /****************************************************************** @@ -617,4 +625,6 @@ btr_pcur_close( cursor->latch_mode = BTR_NO_LATCHES; cursor->pos_state = BTR_PCUR_NOT_POSITIONED; + + cursor->trx_if_known = NULL; } diff --git a/innobase/include/os0file.h b/innobase/include/os0file.h index 599e78bab48..f55c345537e 100644 --- a/innobase/include/os0file.h +++ b/innobase/include/os0file.h @@ -68,6 +68,8 @@ log. */ #define OS_FILE_OVERWRITE 53 #define OS_FILE_OPEN_RAW 54 #define OS_FILE_CREATE_PATH 55 +#define OS_FILE_OPEN_RETRY 56 /* for os_file_create() on + the first ibdata file */ #define OS_FILE_READ_ONLY 333 #define OS_FILE_READ_WRITE 444 diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index eeba98a8ab2..9df26150160 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -413,8 +413,6 @@ os_file_lock( "InnoDB: using the same InnoDB data or log files.\n"); } - close(fd); - return(-1); } @@ -989,6 +987,7 @@ try_again: } else if (access_type == OS_FILE_READ_WRITE && os_file_lock(file, name)) { *success = FALSE; + close(file); file = -1; #endif } else { @@ -1101,6 +1100,7 @@ os_file_create_simple_no_error_handling( } else if (access_type == OS_FILE_READ_WRITE && os_file_lock(file, name)) { *success = FALSE; + close(file); file = -1; #endif } else { @@ -1152,7 +1152,8 @@ try_again: if (create_mode == OS_FILE_OPEN_RAW) { create_flag = OPEN_EXISTING; share_mode = FILE_SHARE_WRITE; - } else if (create_mode == OS_FILE_OPEN) { + } else if (create_mode == OS_FILE_OPEN + || create_mode == OS_FILE_OPEN_RETRY) { create_flag = OPEN_EXISTING; } else if (create_mode == OS_FILE_CREATE) { create_flag = CREATE_NEW; @@ -1243,7 +1244,8 @@ try_again: try_again: ut_a(name); - if (create_mode == OS_FILE_OPEN || create_mode == OS_FILE_OPEN_RAW) { + if (create_mode == OS_FILE_OPEN || create_mode == OS_FILE_OPEN_RAW + || create_mode == OS_FILE_OPEN_RETRY) { mode_str = "OPEN"; create_flag = O_RDWR; } else if (create_mode == OS_FILE_CREATE) { @@ -1316,6 +1318,23 @@ try_again: } else if (create_mode != OS_FILE_OPEN_RAW && os_file_lock(file, name)) { *success = FALSE; + if (create_mode == OS_FILE_OPEN_RETRY) { + int i; + ut_print_timestamp(stderr); + fputs(" InnoDB: Retrying to lock the first data file\n", + stderr); + for (i = 0; i < 100; i++) { + os_thread_sleep(1000000); + if (!os_file_lock(file, name)) { + *success = TRUE; + return(file); + } + } + ut_print_timestamp(stderr); + fputs(" InnoDB: Unable to open the first data file\n", + stderr); + } + close(file); file = -1; #endif } else { diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index e3f31c116fa..96abbda8e64 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -2644,6 +2644,8 @@ row_sel_get_clust_rec_for_mysql( clust_rec = btr_pcur_get_rec(prebuilt->clust_pcur); + prebuilt->clust_pcur->trx_if_known = trx; + /* Note: only if the search ends up on a non-infimum record is the low_match value the real match to the search tuple */ @@ -3406,6 +3408,8 @@ shortcut_fails_too_big_rec: btr_pcur_open_with_no_init(index, search_tuple, mode, BTR_SEARCH_LEAF, pcur, 0, &mtr); + + pcur->trx_if_known = trx; } else { if (mode == PAGE_CUR_G) { btr_pcur_open_at_index_side(TRUE, index, diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index c65b7d3e141..5bb7cfa7421 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -789,6 +789,11 @@ open_or_create_data_files( files[i] = os_file_create( name, OS_FILE_OPEN_RAW, OS_FILE_NORMAL, OS_DATA_FILE, &ret); + } else if (i == 0) { + files[i] = os_file_create( + name, OS_FILE_OPEN_RETRY, + OS_FILE_NORMAL, + OS_DATA_FILE, &ret); } else { files[i] = os_file_create( name, OS_FILE_OPEN, OS_FILE_NORMAL, diff --git a/mysql-test/Makefile.am b/mysql-test/Makefile.am index 1325b90631f..9963074daf5 100644 --- a/mysql-test/Makefile.am +++ b/mysql-test/Makefile.am @@ -32,21 +32,21 @@ endif benchdir_root= $(prefix) testdir = $(benchdir_root)/mysql-test -EXTRA_SCRIPTS = mysql-test-run.sh install_test_db.sh +EXTRA_SCRIPTS = mysql-test-run.sh mysql-test-run.pl install_test_db.sh valgrind.supp EXTRA_DIST = $(EXTRA_SCRIPTS) test_SCRIPTS = mysql-test-run install_test_db test_DATA = std_data/client-key.pem std_data/client-cert.pem std_data/cacert.pem CLEANFILES = $(test_SCRIPTS) $(test_DATA) -INCLUDES = -I$(srcdir)/../include -I../include -I.. -EXTRA_PROGRAMS = mysql_test_run_new +INCLUDES = -I$(srcdir)/../include -I../include -I.. +EXTRA_PROGRAMS = mysql_test_run_new noinst_HEADERS = my_manage.h mysql_test_run_new_SOURCES= mysql_test_run_new.c my_manage.c my_create_tables.c dist-hook: mkdir -p $(distdir)/t $(distdir)/r $(distdir)/include \ - $(distdir)/std_data + $(distdir)/std_data $(distdir)/lib $(INSTALL_DATA) $(srcdir)/t/*.test $(distdir)/t -$(INSTALL_DATA) $(srcdir)/t/*.disabled $(distdir)/t $(INSTALL_DATA) $(srcdir)/t/*.opt $(srcdir)/t/*.sh $(srcdir)/t/*.slave-mi $(distdir)/t @@ -57,13 +57,16 @@ dist-hook: $(INSTALL_DATA) $(srcdir)/std_data/des_key_file $(distdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/*.pem $(distdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/*.frm $(distdir)/std_data + $(INSTALL_DATA) $(srcdir)/lib/init_db.sql $(distdir)/lib + $(INSTALL_DATA) $(srcdir)/lib/*.pl $(distdir)/lib install-data-local: $(mkinstalldirs) \ $(DESTDIR)$(testdir)/t \ $(DESTDIR)$(testdir)/r \ $(DESTDIR)$(testdir)/include \ - $(DESTDIR)$(testdir)/std_data + $(DESTDIR)$(testdir)/std_data \ + $(DESTDIR)$(testdir)/lib $(INSTALL_DATA) $(srcdir)/README $(DESTDIR)$(testdir) $(INSTALL_DATA) $(srcdir)/t/*.test $(DESTDIR)$(testdir)/t -$(INSTALL_DATA) $(srcdir)/t/*.disabled $(DESTDIR)$(testdir)/t @@ -79,6 +82,8 @@ install-data-local: $(INSTALL_DATA) $(srcdir)/std_data/Moscow_leap $(DESTDIR)$(testdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/*.pem $(DESTDIR)$(testdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/*.frm $(DESTDIR)$(testdir)/std_data + $(INSTALL_DATA) $(srcdir)/lib/init_db.sql $(DESTDIR)$(testdir)/lib + $(INSTALL_DATA) $(srcdir)/lib/*.pl $(DESTDIR)$(testdir)/lib std_data/%.pem: @CP@ $(top_srcdir)/SSL/$(@F) $(srcdir)/std_data diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 90fc97b537b..117095f8add 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -635,7 +635,6 @@ sub command_line_setup () { { mtr_error("Can't use --extern with --embedded-server"); } - $opt_result_ext= ".es"; } # FIXME don't understand what this is diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 64df533fe18..0ad8536f579 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -416,7 +416,7 @@ while test $# -gt 0; do fi # >=2.1.2 requires the --tool option, some versions write to stdout, some to stderr valgrind --help 2>&1 | grep "\-\-tool" > /dev/null && VALGRIND="$VALGRIND --tool=memcheck" - VALGRIND="$VALGRIND --alignment=8 --leak-check=yes --num-callers=16" + VALGRIND="$VALGRIND --alignment=8 --leak-check=yes --num-callers=16 --suppressions=$CWD/valgrind.supp" EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --skip-safemalloc --skip-bdb" EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --skip-safemalloc --skip-bdb" SLEEP_TIME_AFTER_RESTART=10 diff --git a/mysql-test/r/drop.result b/mysql-test/r/drop.result index b91cc89cfea..979e5d48871 100644 --- a/mysql-test/r/drop.result +++ b/mysql-test/r/drop.result @@ -30,13 +30,13 @@ table7, table8, table9, table10, table11, table12, table13, table14, table15, table16, table17, table18, table19, table20, table21, table22, table23, table24, table25, table26, table27, table28; -ERROR 42S02: Unknown table 'table1,table2,table3,table4,table5,table6,table7,table8,table9,table10,table11,table12,table13,table14,table15,table16,table17,table18,table19,table20,table21,table22,table23,table' +ERROR 42S02: Unknown table 'table1,table2,table3,table4,table5,table6,table7,table8,table9,table10,table11,table12,table13,table' drop table table1, table2, table3, table4, table5, table6, table7, table8, table9, table10, table11, table12, table13, table14, table15, table16, table17, table18, table19, table20, table21, table22, table23, table24, table25, table26, table27, table28, table29, table30; -ERROR 42S02: Unknown table 'table1,table2,table3,table4,table5,table6,table7,table8,table9,table10,table11,table12,table13,table14,table15,table16,table17,table18,table19,table20,table21,table22,table23,table' +ERROR 42S02: Unknown table 'table1,table2,table3,table4,table5,table6,table7,table8,table9,table10,table11,table12,table13,table' use test; drop database mysqltest; flush tables with read lock; diff --git a/mysql-test/r/heap.result b/mysql-test/r/heap.result index db20b242962..631bd8c713c 100644 --- a/mysql-test/r/heap.result +++ b/mysql-test/r/heap.result @@ -667,14 +667,7 @@ drop table t1; set storage_engine=MyISAM; create table t1 (a bigint unsigned auto_increment primary key, b int, key (b, a)) engine=heap; -insert t1 (b) values (1); -insert t1 (b) values (1); -insert t1 (b) values (1); -insert t1 (b) values (1); -insert t1 (b) values (1); -insert t1 (b) values (1); -insert t1 (b) values (1); -insert t1 (b) values (1); +insert t1 (b) values (1),(1),(1),(1),(1),(1),(1),(1); select * from t1; a b 1 1 @@ -688,14 +681,7 @@ a b drop table t1; create table t1 (a int not null, b int not null auto_increment, primary key(a, b), key(b)) engine=heap; -insert t1 (a) values (1); -insert t1 (a) values (1); -insert t1 (a) values (1); -insert t1 (a) values (1); -insert t1 (a) values (1); -insert t1 (a) values (1); -insert t1 (a) values (1); -insert t1 (a) values (1); +insert t1 (a) values (1),(1),(1),(1),(1),(1),(1),(1); select * from t1; a b 1 1 @@ -707,3 +693,6 @@ a b 1 7 1 8 drop table t1; +create table t1 (a int not null, b int not null auto_increment, +primary key(a, b)) engine=heap; +ERROR 42000: Incorrect table definition; there can be only one auto column and it must be defined as a key diff --git a/mysql-test/r/kill.result b/mysql-test/r/kill.result index 049281ad5d4..754568093ff 100644 --- a/mysql-test/r/kill.result +++ b/mysql-test/r/kill.result @@ -6,7 +6,7 @@ select ((@id := kill_id) - kill_id) from t1; 0 kill @id; select 1; -ERROR HY000: MySQL server has gone away +Got one of the listed errors select ((@id := kill_id) - kill_id) from t1; ((@id := kill_id) - kill_id) 0 diff --git a/mysql-test/r/rpl_rewrite_db.result b/mysql-test/r/rpl_rewrite_db.result index b22eb98067b..d4a24626cc3 100644 --- a/mysql-test/r/rpl_rewrite_db.result +++ b/mysql-test/r/rpl_rewrite_db.result @@ -89,4 +89,5 @@ a b 2 row 2 3 row 3 0 +drop database rewrite; drop table t1; diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index c979ee34df0..ff7d71b3384 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -503,4 +503,14 @@ ERROR 0A000: LOCK is not allowed in stored procedures create procedure bug6600() unlock table t1| ERROR 0A000: UNLOCK is not allowed in stored procedures +drop procedure if exists bug9566| +create procedure bug9566() +begin +select * from t1; +end| +lock table t1 read| +call bug9566()| +ERROR HY000: Table 'proc' was not locked with LOCK TABLES +unlock tables| +drop procedure bug9566| drop table t1| diff --git a/mysql-test/r/user_var.result b/mysql-test/r/user_var.result index 24470c8f716..68eae111111 100644 --- a/mysql-test/r/user_var.result +++ b/mysql-test/r/user_var.result @@ -179,3 +179,6 @@ set @v1=null, @v2=1, @v3=1.1, @v4=now(); select coercibility(@v1),coercibility(@v2),coercibility(@v3),coercibility(@v4); coercibility(@v1) coercibility(@v2) coercibility(@v3) coercibility(@v4) 2 2 2 2 +set session @honk=99; +set one_shot @honk=99; +ERROR HY000: The 'SET ONE_SHOT' syntax is reserved for purposes internal to the MySQL server diff --git a/mysql-test/t/heap.test b/mysql-test/t/heap.test index b69649585ff..c36474bda30 100644 --- a/mysql-test/t/heap.test +++ b/mysql-test/t/heap.test @@ -413,25 +413,16 @@ eval set storage_engine=$default; create table t1 (a bigint unsigned auto_increment primary key, b int, key (b, a)) engine=heap; -insert t1 (b) values (1); -insert t1 (b) values (1); -insert t1 (b) values (1); -insert t1 (b) values (1); -insert t1 (b) values (1); -insert t1 (b) values (1); -insert t1 (b) values (1); -insert t1 (b) values (1); -select * from t1; +insert t1 (b) values (1),(1),(1),(1),(1),(1),(1),(1); +select * from t1; drop table t1; + create table t1 (a int not null, b int not null auto_increment, primary key(a, b), key(b)) engine=heap; -insert t1 (a) values (1); -insert t1 (a) values (1); -insert t1 (a) values (1); -insert t1 (a) values (1); -insert t1 (a) values (1); -insert t1 (a) values (1); -insert t1 (a) values (1); -insert t1 (a) values (1); -select * from t1; +insert t1 (a) values (1),(1),(1),(1),(1),(1),(1),(1); +select * from t1; drop table t1; + +--error 1075 +create table t1 (a int not null, b int not null auto_increment, + primary key(a, b)) engine=heap; diff --git a/mysql-test/t/kill.test b/mysql-test/t/kill.test index 6744a212828..37e11e14df5 100644 --- a/mysql-test/t/kill.test +++ b/mysql-test/t/kill.test @@ -27,7 +27,7 @@ connection con1; --disable_reconnect # this statement should fail ---error 2006 +--error 2006,2013 select 1; --enable_reconnect # this should work, and we should have a new connection_id() diff --git a/mysql-test/t/rpl_rewrite_db.test b/mysql-test/t/rpl_rewrite_db.test index b6118854037..b77d57294fa 100644 --- a/mysql-test/t/rpl_rewrite_db.test +++ b/mysql-test/t/rpl_rewrite_db.test @@ -73,5 +73,8 @@ connection slave; # The empty line last comes from the end line field in the file select * from rewrite.t1; +drop database rewrite; + connection master; drop table t1; + diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 621700b732a..51776453730 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -696,6 +696,29 @@ create procedure bug6600() create procedure bug6600() unlock table t1| +# +# BUG#9566: explicit LOCK TABLE and store procedures result in illegal state +# +# We should not think that mysql.proc table does not exist if we are unable +# to open it under LOCK TABLE or in prelocked mode. Probably this test +# should be removed when Monty will allow access to mysql.proc without +# locking it. +# +--disable_warnings +drop procedure if exists bug9566| +--enable_warnings +create procedure bug9566() +begin + select * from t1; +end| +lock table t1 read| +# This should fail because we forgot to lock mysql.proc table explicitly +--error 1100 +call bug9566()| +unlock tables| +# This should succeed +drop procedure bug9566| + # # BUG#NNNN: New bug synopsis diff --git a/mysql-test/t/user_var.test b/mysql-test/t/user_var.test index 6ac60783501..ef360f2231d 100644 --- a/mysql-test/t/user_var.test +++ b/mysql-test/t/user_var.test @@ -112,3 +112,10 @@ select FIELD( @var,'1it','Hit') as my_column; select @v, coercibility(@v); set @v1=null, @v2=1, @v3=1.1, @v4=now(); select coercibility(@v1),coercibility(@v2),coercibility(@v3),coercibility(@v4); + +# +# Bug #9286 SESSION/GLOBAL should be disallowed for user variables +# +set session @honk=99; +--error 1382 +set one_shot @honk=99; diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp new file mode 100644 index 00000000000..d8a13ca9dfd --- /dev/null +++ b/mysql-test/valgrind.supp @@ -0,0 +1,94 @@ +# +# Suppress some common (not fatal) errors in system libraries found by valgrind +# + +# +# Pthread doesn't free all thread specific memory before program exists +# +{ + pthread allocate_tls memory loss + Memcheck:Leak + fun:calloc + fun:_dl_allocate_tls + fun:allocate_stack + fun:pthread_create@@GLIBC_2.1 +} + +{ + pthread allocate_dtv memory loss + Memcheck:Leak + fun:calloc + fun:allocate_dtv + fun:_dl_allocate_tls_storage + fun:__GI__dl_allocate_tls + fun:pthread_create +} + +{ + pthread memalign memory loss + Memcheck:Leak + fun:memalign + fun:_dl_allocate_tls_storage + fun:__GI__dl_allocate_tls + fun:pthread_create +} + +{ + pthread errno + Memcheck:Leak + fun:calloc + fun:_dlerror_run + fun:dlsym + fun:__errno_location +} + + +# +# Warnings in libz becasue it works with aligned memory(?) +# + +{ + libz tr_flush_block + Memcheck:Cond + fun:_tr_flush_block + fun:deflate_slow + fun:deflate + fun:do_flush + fun:gzclose +} + +{ + libz tr_flush_block2 + Memcheck:Cond + fun:_tr_flush_block + fun:deflate_slow + fun:deflate + fun:compress2 +} + +{ + libz longest_match + Memcheck:Cond + fun:longest_match + fun:deflate_slow + fun:deflate + fun:do_flush +} + +{ + libz longest_match2 + Memcheck:Cond + fun:longest_match + fun:deflate_slow + fun:deflate + fun:compress2 +} + +{ + libz deflate + Memcheck:Cond + obj:/usr/lib/libz.so.* + obj:/usr/lib/libz.so.* + fun:deflate + fun:compress2 +} diff --git a/mysys/default.c b/mysys/default.c index ddff4e26be5..6352cc18d56 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -477,13 +477,13 @@ static int search_default_file_with_ext(Process_option_func opt_handler, if ((stat_info.st_mode & S_IWOTH) && (stat_info.st_mode & S_IFMT) == S_IFREG) { - fprintf(stderr, "warning: World-writable config file %s is ignored\n", + fprintf(stderr, "Warning: World-writable config file '%s' is ignored\n", name); return 0; } } #endif - if (!(fp= my_fopen(fn_format(name, name, "", "", 4), O_RDONLY, MYF(0)))) + if (!(fp= my_fopen(name, O_RDONLY, MYF(0)))) return 0; /* Ignore wrong files */ while (fgets(buff, sizeof(buff) - 1, fp)) diff --git a/mysys/my_sync.c b/mysys/my_sync.c index bfaf09ce402..c557324b52c 100644 --- a/mysys/my_sync.c +++ b/mysys/my_sync.c @@ -65,7 +65,7 @@ int my_sync(File fd, myf my_flags) int er= errno; if (!(my_errno= er)) my_errno= -1; /* Unknown error */ - if (my_flags & MY_IGNORE_BADFD && + if ((my_flags & MY_IGNORE_BADFD) && (er == EBADF || er == EINVAL || er == EROFS)) res= 0; else if (my_flags & MY_WME) diff --git a/ndb/include/ndbapi/NdbTransaction.hpp b/ndb/include/ndbapi/NdbTransaction.hpp index 50e4e766803..2e102b104d8 100644 --- a/ndb/include/ndbapi/NdbTransaction.hpp +++ b/ndb/include/ndbapi/NdbTransaction.hpp @@ -658,6 +658,7 @@ private: // Release all cursor operations in connection void releaseOps(NdbOperation*); void releaseScanOperations(NdbIndexScanOperation*); + void releaseExecutedScanOperation(NdbIndexScanOperation*); // Set the transaction identity of the transaction void setTransactionId(Uint64 aTransactionId); diff --git a/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp b/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp index c3f85cdebd5..3170d23499a 100644 --- a/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp +++ b/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp @@ -813,6 +813,7 @@ Dbtup::updateFixedSizeTHManyWordNotNULL(Uint32* inBuffer, ndbrequire(i < regTabPtr->noOfCharsets); // not const in MySQL CHARSET_INFO* cs = regTabPtr->charsetArray[i]; + int not_used; const char* ssrc = (const char*)&inBuffer[tInBufIndex + 1]; Uint32 lb, len; if (! NdbSqlUtil::get_var_length(typeId, ssrc, bytes, lb, len)) { @@ -822,7 +823,7 @@ Dbtup::updateFixedSizeTHManyWordNotNULL(Uint32* inBuffer, } // fast fix bug#7340 if (typeId != NDB_TYPE_TEXT && - (*cs->cset->well_formed_len)(cs, ssrc + lb, ssrc + lb + len, ZNIL) != len) { + (*cs->cset->well_formed_len)(cs, ssrc + lb, ssrc + lb + len, ZNIL, ¬_used) != len) { ljam(); terrorCode = ZINVALID_CHAR_FORMAT; return false; diff --git a/ndb/src/ndbapi/NdbTransaction.cpp b/ndb/src/ndbapi/NdbTransaction.cpp index 67581e4a0f8..c2ded3560fc 100644 --- a/ndb/src/ndbapi/NdbTransaction.cpp +++ b/ndb/src/ndbapi/NdbTransaction.cpp @@ -948,6 +948,37 @@ NdbTransaction::releaseScanOperations(NdbIndexScanOperation* cursorOp) } }//NdbTransaction::releaseScanOperations() +/***************************************************************************** +void releaseExecutedScanOperation(); + +Remark: Release scan op when hupp'ed trans closed (save memory) +******************************************************************************/ +void +NdbConnection::releaseExecutedScanOperation(NdbIndexScanOperation* cursorOp) +{ + DBUG_ENTER("NdbConnection::releaseExecutedScanOperation"); + DBUG_PRINT("enter", ("this=0x%x op=0x%x", (UintPtr)this, (UintPtr)cursorOp)) + + // here is one reason to make op lists doubly linked + if (m_firstExecutedScanOp == cursorOp) { + m_firstExecutedScanOp = (NdbIndexScanOperation*)cursorOp->theNext; + cursorOp->release(); + theNdb->releaseScanOperation(cursorOp); + } else if (m_firstExecutedScanOp != NULL) { + NdbIndexScanOperation* tOp = m_firstExecutedScanOp; + while (tOp->theNext != NULL) { + if (tOp->theNext == cursorOp) { + tOp->theNext = cursorOp->theNext; + cursorOp->release(); + theNdb->releaseScanOperation(cursorOp); + break; + } + tOp = (NdbIndexScanOperation*)tOp->theNext; + } + } + DBUG_VOID_RETURN; +}//NdbConnection::releaseExecutedScanOperation() + /***************************************************************************** NdbOperation* getNdbOperation(const char* aTableName); diff --git a/scripts/make_binary_distribution.sh b/scripts/make_binary_distribution.sh index a1c380780b0..b99519b87c9 100644 --- a/scripts/make_binary_distribution.sh +++ b/scripts/make_binary_distribution.sh @@ -208,6 +208,7 @@ rm -f $MYSQL_SHARE/Makefile* $MYSQL_SHARE/*/*.OLD for i in mysql-test/mysql-test-run mysql-test/install_test_db \ mysql-test/mysql-test-run.pl mysql-test/README \ + mysql-test/valgrind.supp \ netware/mysql_test_run.nlm netware/install_test_db.ncf do if [ -f $i ] diff --git a/sql/field.cc b/sql/field.cc index cfda1ab29fc..3afc8a2eb12 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5777,7 +5777,7 @@ void Field_datetime::sql_type(String &res) const int Field_string::store(const char *from,uint length,CHARSET_INFO *cs) { - int error= 0; + int error= 0, well_formed_error; uint32 not_used; char buff[STRING_BUFFER_USUAL_SIZE]; String tmpstr(buff,sizeof(buff), &my_charset_bin); @@ -5802,9 +5802,10 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs) as well as don't copy a malformed data. */ copy_length= field_charset->cset->well_formed_len(field_charset, - from,from+length, - field_length/ - field_charset->mbmaxlen); + from,from+length, + field_length/ + field_charset->mbmaxlen, + &well_formed_error); memcpy(ptr,from,copy_length); if (copy_length < field_length) // Append spaces if shorter field_charset->cset->fill(field_charset,ptr+copy_length, @@ -6152,7 +6153,7 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs) uint32 not_used, copy_length; char buff[STRING_BUFFER_USUAL_SIZE]; String tmpstr(buff,sizeof(buff), &my_charset_bin); - int error_code= 0; + int error_code= 0, well_formed_error; enum MYSQL_ERROR::enum_warning_level level= MYSQL_ERROR::WARN_LEVEL_WARN; /* Convert character set if necessary */ @@ -6172,7 +6173,8 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs) copy_length= field_charset->cset->well_formed_len(field_charset, from,from+length, field_length/ - field_charset->mbmaxlen); + field_charset->mbmaxlen, + &well_formed_error); memcpy(ptr + length_bytes, from, copy_length); if (length_bytes == 1) *ptr= (uchar) copy_length; @@ -6746,7 +6748,7 @@ void Field_blob::put_length(char *pos, uint32 length) int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) { - int error= 0; + int error= 0, well_formed_error; if (!length) { bzero(ptr,Field_blob::pack_length()); @@ -6778,9 +6780,10 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) the 'min()' call below. */ copy_length= field_charset->cset->well_formed_len(field_charset, - from,from + - min(length, copy_length), - copy_length); + from,from + + min(length, copy_length), + copy_length, + &well_formed_error); if (copy_length < length) error= 1; Field_blob::store_length(copy_length); diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index 8000aae180d..33acc9cad0b 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -548,12 +548,12 @@ error: static int parse_url(FEDERATED_SHARE *share, TABLE *table, uint table_create_flag) { + uint error_num= (table_create_flag ? ER_CANT_CREATE_TABLE : + ER_CONNECT_TO_MASTER); DBUG_ENTER("ha_federated::parse_url"); share->port= 0; - uint error_num= (table_create_flag ? ER_CANT_CREATE_TABLE : - ER_CONNECT_TO_MASTER); - + share->socket= 0; share->scheme= my_strdup(table->s->comment, MYF(0)); if ((share->username= strstr(share->scheme, "://"))) diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc index de51fad4365..0d700f6c9a5 100644 --- a/sql/ha_heap.cc +++ b/sql/ha_heap.cc @@ -548,6 +548,7 @@ int ha_heap::create(const char *name, TABLE *table_arg, hp_create_info.auto_increment= (create_info->auto_increment_value ? create_info->auto_increment_value - 1 : 0); hp_create_info.max_table_size=current_thd->variables.max_heap_table_size; + hp_create_info.with_auto_increment= found_real_auto_increment; max_rows = (ha_rows) (hp_create_info.max_table_size / mem_per_row); error= heap_create(fn_format(buff,name,"","",4+2), keys, keydef, share->reclength, diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index a60f8133d47..b22e09725ee 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -5822,6 +5822,7 @@ extern "C" pthread_handler_decl(ndb_util_thread_func, { thd->cleanup(); delete thd; + delete ndb; DBUG_RETURN(NULL); } @@ -5940,6 +5941,7 @@ extern "C" pthread_handler_decl(ndb_util_thread_func, thd->cleanup(); delete thd; + delete ndb; DBUG_PRINT("exit", ("ndb_util_thread")); my_thread_end(); pthread_exit(0); diff --git a/sql/handler.cc b/sql/handler.cc index f20ee0c4d77..dc63b4b038f 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -506,10 +506,16 @@ void ha_close_connection(THD* thd) "beginning of transaction" and "beginning of statement"). Only storage engines registered for the transaction/statement will know when to commit/rollback it. + + NOTE + trans_register_ha is idempotent - storage engine may register many + times per transaction. + */ void trans_register_ha(THD *thd, bool all, handlerton *ht_arg) { THD_TRANS *trans; + handlerton **ht; DBUG_ENTER("trans_register_ha"); DBUG_PRINT("enter",("%s", all ? "all" : "stmt")); @@ -521,15 +527,12 @@ void trans_register_ha(THD *thd, bool all, handlerton *ht_arg) else trans= &thd->transaction.stmt; - handlerton **ht=trans->ht; - while (*ht) - { + for (ht=trans->ht; *ht; ht++) if (*ht == ht_arg) DBUG_VOID_RETURN; /* already registered, return */ - ht++; - } trans->ht[trans->nht++]=ht_arg; + DBUG_ASSERT(*ht == ht_arg); trans->no_2pc|=(ht_arg->prepare==0); if (thd->transaction.xid.is_null()) thd->transaction.xid.set(thd->query_id); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index c213fcbf050..2d8a0eca877 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1510,6 +1510,7 @@ void end_thread(THD *thd, bool put_in_cache) thd=thread_cache.get(); thd->real_id=pthread_self(); (void) thd->store_globals(); + thd->thr_create_time= time(NULL); threads.append(thd); pthread_mutex_unlock(&LOCK_thread_count); DBUG_VOID_RETURN; @@ -5170,7 +5171,7 @@ log and this option does nothing anymore.", (gptr*) &dflt_key_cache_var.param_buff_size, (gptr*) 0, 0, (GET_ULL | GET_ASK_ADDR), - REQUIRED_ARG, KEY_CACHE_SIZE, MALLOC_OVERHEAD, UINT_MAX32, MALLOC_OVERHEAD, + REQUIRED_ARG, KEY_CACHE_SIZE, MALLOC_OVERHEAD, ~(ulong) 0, MALLOC_OVERHEAD, IO_SIZE, 0}, {"key_cache_age_threshold", OPT_KEY_CACHE_AGE_THRESHOLD, "This characterizes the number of hits a hot block has to be untouched until it is considered aged enough to be downgraded to a warm block. This specifies the percentage ratio of that number of hits to the total number of blocks in key cache", diff --git a/sql/records.cc b/sql/records.cc index cfb7cb3d065..b71bcf70865 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -131,7 +131,7 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table, /* Condition pushdown to storage engine */ if (thd->variables.engine_condition_pushdown && select && select->cond && - select->cond->used_tables() & table->map && + (select->cond->used_tables() & table->map) && !table->file->pushed_cond) table->file->cond_push(select->cond); diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 047c30f6cd0..2ef2555753d 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -1214,30 +1214,30 @@ ER_TABLE_EXISTS_ERROR 42S01 swe "Tabellen '%-.64s' finns redan" ukr "ôÁÂÌÉÃÑ '%-.64s' ×ÖÅ ¦ÓÎÕ¤" ER_BAD_TABLE_ERROR 42S02 - cze "Nezn-Bámá tabulka '%-.180s'" - dan "Ukendt tabel '%-.180s'" - nla "Onbekende tabel '%-.180s'" - eng "Unknown table '%-.180s'" - jps "table '%-.180s' ‚Í‚ ‚è‚Ü‚¹‚ñ.", - est "Tundmatu tabel '%-.180s'" - fre "Table '%-.180s' inconnue" - ger "Unbekannte Tabelle '%-.180s'" - greek "Áãíùóôïò ðßíáêáò '%-.180s'" - hun "Ervenytelen tabla: '%-.180s'" - ita "Tabella '%-.180s' sconosciuta" - jpn "table '%-.180s' ¤Ï¤¢¤ê¤Þ¤»¤ó." - kor "Å×À̺í '%-.180s'´Â ¾Ë¼ö ¾øÀ½" - nor "Ukjent tabell '%-.180s'" - norwegian-ny "Ukjent tabell '%-.180s'" - pol "Nieznana tabela '%-.180s'" - por "Tabela '%-.180s' desconhecida" - rum "Tabela '%-.180s' este invalida" - rus "îÅÉÚ×ÅÓÔÎÁÑ ÔÁÂÌÉÃÁ '%-.180s'" - serbian "Nepoznata tabela '%-.180s'" - slo "Neznáma tabuµka '%-.180s'" - spa "Tabla '%-.180s' desconocida" - swe "Okänd tabell '%-.180s'" - ukr "îÅצÄÏÍÁ ÔÁÂÌÉÃÑ '%-.180s'" + cze "Nezn-Bámá tabulka '%-.100s'" + dan "Ukendt tabel '%-.100s'" + nla "Onbekende tabel '%-.100s'" + eng "Unknown table '%-.100s'" + jps "table '%-.100s' ‚Í‚ ‚è‚Ü‚¹‚ñ.", + est "Tundmatu tabel '%-.100s'" + fre "Table '%-.100s' inconnue" + ger "Unbekannte Tabelle '%-.100s'" + greek "Áãíùóôïò ðßíáêáò '%-.100s'" + hun "Ervenytelen tabla: '%-.100s'" + ita "Tabella '%-.100s' sconosciuta" + jpn "table '%-.100s' ¤Ï¤¢¤ê¤Þ¤»¤ó." + kor "Å×À̺í '%-.100s'´Â ¾Ë¼ö ¾øÀ½" + nor "Ukjent tabell '%-.100s'" + norwegian-ny "Ukjent tabell '%-.100s'" + pol "Nieznana tabela '%-.100s'" + por "Tabela '%-.100s' desconhecida" + rum "Tabela '%-.100s' este invalida" + rus "îÅÉÚ×ÅÓÔÎÁÑ ÔÁÂÌÉÃÁ '%-.100s'" + serbian "Nepoznata tabela '%-.100s'" + slo "Neznáma tabuµka '%-.100s'" + spa "Tabla '%-.100s' desconocida" + swe "Okänd tabell '%-.100s'" + ukr "îÅצÄÏÍÁ ÔÁÂÌÉÃÑ '%-.100s'" ER_NON_UNIQ_ERROR 23000 cze "Sloupec '%-.64s' v %s nen-Bí zcela jasný" dan "Felt: '%-.64s' i tabel %s er ikke entydigt" diff --git a/sql/sp.cc b/sql/sp.cc index 23d389cd299..1956f32f2c6 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -70,9 +70,8 @@ db_find_routine_aux(THD *thd, int type, sp_name *name, type, name->m_name.length, name->m_name.str)); /* - Speed up things if mysql.proc doesn't exists - mysql_proc_table_exists is set when on creates a stored procedure - or on flush privileges + Speed up things if mysql.proc doesn't exists. mysql_proc_table_exists + is set when we create or read stored procedure or on flush privileges. */ if (!mysql_proc_table_exists && ltype == TL_READ) DBUG_RETURN(SP_OPEN_TABLE_FAILED); @@ -98,7 +97,13 @@ db_find_routine_aux(THD *thd, int type, sp_name *name, if (! (table= open_ltable(thd, &tables, ltype))) { *tablep= NULL; - mysql_proc_table_exists= 0; + /* + Under explicit LOCK TABLES or in prelocked mode we should not + say that mysql.proc table does not exist if we are unable to + open it since this condition may be transient. + */ + if (!(thd->locked_tables || thd->prelocked_mode)) + mysql_proc_table_exists= 0; DBUG_RETURN(SP_OPEN_TABLE_FAILED); } *opened= TRUE; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index cdda013d23a..c68dc826147 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -343,8 +343,9 @@ void THD::change_user(void) void THD::cleanup(void) { DBUG_ENTER("THD::cleanup"); - /* TODO uncomment the line below when binlog will be able to prepare */ - // if (transaction.xa_state != XA_PREPARED) +#ifdef ENABLE_WHEN_BINLOG_WILL_BE_ABLE_TO_PREPARE + if (transaction.xa_state != XA_PREPARED) +#endif ha_rollback(this); if (locked_tables) { diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 693229c5a24..ac1b1148cf8 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1103,7 +1103,8 @@ pthread_handler_decl(handle_one_connection,arg) thd->proc_info=0; thd->set_time(); thd->init_for_queries(); - while (!net->error && net->vio != 0 && !(thd->killed == THD::KILL_CONNECTION)) + while (!net->error && net->vio != 0 && + !(thd->killed == THD::KILL_CONNECTION)) { net->no_send_error= 0; if (do_command(thd)) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 410b3090b5c..e134e62c049 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -111,6 +111,7 @@ static bool const_expression_in_where(COND *conds,Item *item, Item **comp_item); static bool open_tmp_table(TABLE *table); static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param, ulong options); +static Next_select_func setup_end_select_func(JOIN *join); static int do_select(JOIN *join,List *fields,TABLE *tmp_table, Procedure *proc); static int sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records); @@ -1638,6 +1639,8 @@ JOIN::exec() { thd->proc_info="Sending data"; DBUG_PRINT("info", ("%s", thd->proc_info)); + result->send_fields(*curr_fields_list, + Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF); error= do_select(curr_join, curr_fields_list, NULL, procedure); thd->limit_found_rows= curr_join->send_records; thd->examined_row_count= curr_join->examined_rows; @@ -1776,12 +1779,8 @@ Cursor::open(JOIN *join_arg) thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS; /* Prepare JOIN for reading rows. */ - - Next_select_func end_select= join->sort_and_group || join->procedure && - join->procedure->flags & PROC_GROUP ? - end_send_group : end_send; - - join->join_tab[join->tables-1].next_select= end_select; + join->tmp_table= 0; + join->join_tab[join->tables-1].next_select= setup_end_select_func(join); join->send_records= 0; join->fetch_limit= join->unit->offset_limit_cnt; @@ -1802,6 +1801,11 @@ Cursor::open(JOIN *join_arg) */ DBUG_ASSERT(join_tab->table->null_row == 0); + /* + There is always at least one record in the table, as otherwise we + wouldn't have opened the cursor. Therefore a failure is the only + reason read_first_record can return not 0. + */ DBUG_RETURN(join_tab->read_first_record(join_tab)); } @@ -2231,6 +2235,8 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, if (s->dependent & table->map) s->dependent |= table->reginfo.join_tab->dependent; } + if (s->dependent) + s->table->maybe_null= 1; } /* Catch illegal cross references for outer joins */ for (i= 0, s= stat ; i < table_count ; i++, s++) @@ -2480,6 +2486,11 @@ typedef struct key_field_t { // Used when finding key fields uint level; uint optimize; bool eq_func; + /* + If true, the condition this struct represents will not be satisfied + when val IS NULL. + */ + bool null_rejecting; } KEY_FIELD; /* Values in optimize */ @@ -2496,6 +2507,12 @@ typedef struct key_field_t { // Used when finding key fields that are internally transformed to something like: SELECT * FROM t1 WHERE t1.key=outer_ref_field or t1.key IS NULL + + KEY_FIELD::null_rejecting is processed as follows: + result has null_rejecting=true if it is set for both ORed references. + for example: + (t2.key = t1.field OR t2.key = t1.field) -> null_rejecting=true + (t2.key = t1.field OR t2.key <=> t1.field) -> null_rejecting=false */ static KEY_FIELD * @@ -2529,6 +2546,8 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end, KEY_OPTIMIZE_EXISTS) | ((old->optimize | new_fields->optimize) & KEY_OPTIMIZE_REF_OR_NULL)); + old->null_rejecting= old->null_rejecting && + new_fields->null_rejecting; } } else if (old->eq_func && new_fields->eq_func && @@ -2540,6 +2559,8 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end, KEY_OPTIMIZE_EXISTS) | ((old->optimize | new_fields->optimize) & KEY_OPTIMIZE_REF_OR_NULL)); + old->null_rejecting= old->null_rejecting && + new_fields->null_rejecting; } else if (old->eq_func && new_fields->eq_func && (old->val->is_null() || new_fields->val->is_null())) @@ -2550,6 +2571,8 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end, /* Remember the NOT NULL value */ if (old->val->is_null()) old->val= new_fields->val; + /* The referred expression can be NULL: */ + old->null_rejecting= false; } else { @@ -2605,7 +2628,7 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end, */ static void -add_key_field(KEY_FIELD **key_fields, uint and_level, COND *cond, +add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond, Field *field, bool eq_func, Item **value, uint num_values, table_map usable_tables) { @@ -2707,10 +2730,17 @@ add_key_field(KEY_FIELD **key_fields, uint and_level, COND *cond, (*key_fields)->val= *value; (*key_fields)->level= and_level; (*key_fields)->optimize= exists_optimize; + /* + If the condition has form "tbl.keypart = othertbl.field" and + othertbl.field can be NULL, there will be no matches if othertbl.field + has NULL value. + */ + (*key_fields)->null_rejecting= (cond->functype() == Item_func::EQ_FUNC) && + ((*value)->type() == Item::FIELD_ITEM) && + ((Item_field*)*value)->field->maybe_null(); (*key_fields)++; } - /* Add possible keys to array of possible keys originated from a simple predicate @@ -2735,7 +2765,7 @@ add_key_field(KEY_FIELD **key_fields, uint and_level, COND *cond, static void add_key_equal_fields(KEY_FIELD **key_fields, uint and_level, - COND *cond, Item_field *field_item, + Item_func *cond, Item_field *field_item, bool eq_func, Item **val, uint num_values, table_map usable_tables) { @@ -2763,7 +2793,7 @@ add_key_equal_fields(KEY_FIELD **key_fields, uint and_level, } static void -add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level, +add_key_fields(KEY_FIELD **key_fields,uint *and_level, COND *cond, table_map usable_tables) { if (cond->type() == Item_func::COND_ITEM) @@ -2775,20 +2805,20 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level, { Item *item; while ((item=li++)) - add_key_fields(stat,key_fields,and_level,item,usable_tables); + add_key_fields(key_fields,and_level,item,usable_tables); for (; org_key_fields != *key_fields ; org_key_fields++) org_key_fields->level= *and_level; } else { (*and_level)++; - add_key_fields(stat,key_fields,and_level,li++,usable_tables); + add_key_fields(key_fields,and_level,li++,usable_tables); Item *item; while ((item=li++)) { KEY_FIELD *start_key_fields= *key_fields; (*and_level)++; - add_key_fields(stat,key_fields,and_level,item,usable_tables); + add_key_fields(key_fields,and_level,item,usable_tables); *key_fields=merge_key_fields(org_key_fields,start_key_fields, *key_fields,++(*and_level)); } @@ -2876,7 +2906,7 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level, */ while ((item= it++)) { - add_key_field(key_fields, *and_level, cond, item->field, + add_key_field(key_fields, *and_level, cond_func, item->field, TRUE, &const_item, 1, usable_tables); } } @@ -2896,7 +2926,7 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level, { if (!field->eq(item->field)) { - add_key_field(key_fields, *and_level, cond, field, + add_key_field(key_fields, *and_level, cond_func, field, TRUE, (Item **) &item, 1, usable_tables); } } @@ -2948,6 +2978,7 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field) keyuse.keypart_map= (key_part_map) 1 << part; keyuse.used_tables=key_field->val->used_tables(); keyuse.optimize= key_field->optimize & KEY_OPTIMIZE_REF_OR_NULL; + keyuse.null_rejecting= key_field->null_rejecting; VOID(insert_dynamic(keyuse_array,(gptr) &keyuse)); } } @@ -3041,8 +3072,22 @@ sort_keyuse(KEYUSE *a,KEYUSE *b) /* Update keyuse array with all possible keys we can use to fetch rows - join_tab is a array in tablenr_order - stat is a reference array in 'prefered' order. + + SYNOPSIS + update_ref_and_keys() + thd + keyuse OUT Put here ordered array of KEYUSE structures + join_tab Array in tablenr_order + tables Number of tables in join + cond WHERE condition (note that the function analyzes + join_tab[i]->on_expr too) + normal_tables tables not inner w.r.t some outer join (ones for which + we can make ref access based the WHERE clause) + select_lex current SELECT + + RETURN + 0 - OK + 1 - Out of memory. */ static bool @@ -3067,7 +3112,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, return TRUE; if (cond) { - add_key_fields(join_tab,&end,&and_level,cond,normal_tables); + add_key_fields(&end,&and_level,cond,normal_tables); for (; field != end ; field++) { add_key_part(keyuse,field); @@ -3090,7 +3135,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, */ if (*join_tab[i].on_expr_ref) { - add_key_fields(join_tab,&end,&and_level,*join_tab[i].on_expr_ref, + add_key_fields(&end,&and_level,*join_tab[i].on_expr_ref, join_tab[i].table->map); } else @@ -3101,7 +3146,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, { NESTED_JOIN *nested_join= embedding->nested_join; if (nested_join->join_list.head() == tab) - add_key_fields(join_tab, &end, &and_level, embedding->on_expr, + add_key_fields(&end, &and_level, embedding->on_expr, nested_join->used_tables); } } @@ -4875,6 +4920,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse, } j->ref.key_buff2=j->ref.key_buff+ALIGN_SIZE(length); j->ref.key_err=1; + j->ref.null_rejecting= 0; keyuse=org_keyuse; store_key **ref_key= j->ref.key_copy; @@ -4899,6 +4945,8 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse, uint maybe_null= test(keyinfo->key_part[i].null_bit); j->ref.items[i]=keyuse->val; // Save for cond removal + if (keyuse->null_rejecting) + j->ref.null_rejecting |= 1 << i; keyuse_uses_no_tables= keyuse_uses_no_tables && !keyuse->used_tables; if (!keyuse->used_tables && !(join->select_options & SELECT_DESCRIBE)) @@ -5057,6 +5105,91 @@ make_simple_join(JOIN *join,TABLE *tmp_table) } +inline void add_cond_and_fix(Item **e1, Item *e2) +{ + if (*e1) + { + Item *res; + if ((res= new Item_cond_and(*e1, e2))) + { + *e1= res; + res->quick_fix_field(); + } + } + else + *e1= e2; +} + + +/* + Add to join_tab->select_cond[i] "table.field IS NOT NULL" conditions we've + inferred from ref/eq_ref access performed. + + SYNOPSIS + add_not_null_conds() + join Join to process + + NOTES + This function is a part of "Early NULL-values filtering for ref access" + optimization. + + Example of this optimization: + For query SELECT * FROM t1,t2 WHERE t2.key=t1.field + and plan " any-access(t1), ref(t2.key=t1.field) " + add "t1.field IS NOT NULL" to t1's table condition. + Description of the optimization: + + We look through equalities choosen to perform ref/eq_ref access, + pick equalities that have form "tbl.part_of_key = othertbl.field" + (where othertbl is a non-const table and othertbl.field may be NULL) + and add them to conditions on correspoding tables (othertbl in this + example). + + This optimization doesn't affect the choices that ref, range, or join + optimizer make. This was intentional because this was added after 4.1 + was GA. + + Implementation overview + 1. update_ref_and_keys() accumulates info about null-rejecting + predicates in in KEY_FIELD::null_rejecting + 1.1 add_key_part saves these to KEYUSE. + 2. create_ref_for_key copies them to TABLE_REF. + 3. add_not_null_conds adds "x IS NOT NULL" to join_tab->select_cond of + appropiate JOIN_TAB members. +*/ + +static void add_not_null_conds(JOIN *join) +{ + DBUG_ENTER("add_not_null_conds"); + for (uint i=join->const_tables ; i < join->tables ; i++) + { + JOIN_TAB *tab=join->join_tab+i; + if ((tab->type == JT_REF || tab->type == JT_REF_OR_NULL) && + !tab->table->maybe_null) + { + for (uint keypart= 0; keypart < tab->ref.key_parts; keypart++) + { + if (tab->ref.null_rejecting & (1 << keypart)) + { + Item *item= tab->ref.items[keypart]; + DBUG_ASSERT(item->type() == Item::FIELD_ITEM); + Item_field *not_null_item= (Item_field*)item; + JOIN_TAB *referred_tab= not_null_item->field->table->reginfo.join_tab; + Item_func_isnotnull *notnull; + if (!(notnull= new Item_func_isnotnull(not_null_item))) + DBUG_VOID_RETURN; + + notnull->quick_fix_field(); + DBUG_EXECUTE("where",print_where(notnull, + referred_tab->table->alias);); + add_cond_and_fix(&referred_tab->select_cond, notnull); + } + } + } + } + DBUG_VOID_RETURN; +} + /* Build a predicate guarded by match variables for embedding outer joins @@ -5194,6 +5327,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) DBUG_ENTER("make_join_select"); if (select) { + add_not_null_conds(join); table_map used_tables; if (cond) /* Because of QUICK_GROUP_MIN_MAX_SELECT */ { /* there may be a select without a cond. */ @@ -5327,6 +5461,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) tab->select_cond= sel->cond= NULL; sel->head=tab->table; + DBUG_EXECUTE("where",print_where(tmp,tab->table->alias);); if (tab->quick) { /* Use quick key read if it's a constant and it's not used @@ -8733,36 +8868,24 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, } -/**************************************************************************** - Make a join of all tables and write it on socket or to table - Return: 0 if ok - 1 if error is sent - -1 if error should be sent -****************************************************************************/ +/* + SYNOPSIS + setup_end_select_func() + join join to setup the function for. -static int -do_select(JOIN *join,List *fields,TABLE *table,Procedure *procedure) + DESCRIPTION + Rows produced by a join sweep may end up in a temporary table or be sent + to a client. Setup the function of the nested loop join algorithm which + handles final fully constructed and matched records. + + RETURN + end_select function to use. This function can't fail. +*/ + +static Next_select_func setup_end_select_func(JOIN *join) { - int error= 0; - JOIN_TAB *join_tab; + TABLE *table= join->tmp_table; Next_select_func end_select; - DBUG_ENTER("do_select"); - - join->procedure=procedure; - /* - Tell the client how many fields there are in a row - */ - if (!table) - join->result->send_fields(*fields, - Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF); - else - { - VOID(table->file->extra(HA_EXTRA_WRITE_CACHE)); - empty_record(table); - } - join->tmp_table= table; /* Save for easy recursion */ - join->fields= fields; - /* Set up select_end */ if (table) { @@ -8772,8 +8895,6 @@ do_select(JOIN *join,List *fields,TABLE *table,Procedure *procedure) { DBUG_PRINT("info",("Using end_update")); end_select=end_update; - if (!table->file->inited) - table->file->ha_index_init(0); } else { @@ -8807,7 +8928,38 @@ do_select(JOIN *join,List *fields,TABLE *table,Procedure *procedure) else end_select= end_send; } - join->join_tab[join->tables-1].next_select=end_select; + return end_select; +} + + +/**************************************************************************** + Make a join of all tables and write it on socket or to table + Return: 0 if ok + 1 if error is sent + -1 if error should be sent +****************************************************************************/ + +static int +do_select(JOIN *join,List *fields,TABLE *table,Procedure *procedure) +{ + int error= 0; + JOIN_TAB *join_tab; + DBUG_ENTER("do_select"); + + join->procedure=procedure; + join->tmp_table= table; /* Save for easy recursion */ + join->fields= fields; + + if (table) + { + VOID(table->file->extra(HA_EXTRA_WRITE_CACHE)); + empty_record(table); + if (table->group && join->tmp_table_param.sum_func_count && + table->s->keys && !table->file->inited) + table->file->ha_index_init(0); + } + /* Set up select_end */ + join->join_tab[join->tables-1].next_select= setup_end_select_func(join); join_tab=join->join_tab+join->const_tables; join->send_records=0; @@ -8819,6 +8971,7 @@ do_select(JOIN *join,List *fields,TABLE *table,Procedure *procedure) */ if (!join->conds || join->conds->val_int()) { + Next_select_func end_select= join->join_tab[join->tables-1].next_select; if (!(error=(*end_select)(join,join_tab,0)) || error == -3) error=(*end_select)(join,join_tab,1); } diff --git a/sql/sql_select.h b/sql/sql_select.h index 381ccbba4fd..e9397925b6a 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -31,6 +31,11 @@ typedef struct keyuse_t { uint key, keypart, optimize; key_part_map keypart_map; ha_rows ref_table_rows; + /* + If true, the comparison this value was created from will not be + satisfied if val has NULL 'value'. + */ + bool null_rejecting; } KEYUSE; class store_key; @@ -45,6 +50,11 @@ typedef struct st_table_ref byte *key_buff2; // key_buff+key_length store_key **key_copy; // Item **items; // val()'s for each keypart + /* + (null_rejecting & (1<