diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b8c3af6582..8a6260ecc7b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,12 @@ #SET(CMAKE_C_FLAGS_DEBUG "-DSAFEMALLOC -DSAFE_MUTEX") ADD_DEFINITIONS(-DMYSQL_SERVER -D_WIN32 -DWIN32 -D_LIB) -INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include include) +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/zlib + include + handler + ${CMAKE_SOURCE_DIR}/sql + ${CMAKE_SOURCE_DIR}/regex + ${CMAKE_SOURCE_DIR}/extra/yassl/include) ADD_LIBRARY(innobase btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c btr/btr0sea.c buf/buf0buf.c buf/buf0flu.c buf/buf0lru.c buf/buf0rea.c data/data0data.c data/data0type.c @@ -23,6 +28,7 @@ ADD_LIBRARY(innobase btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c btr/btr0sea.c os/os0file.c os/os0proc.c os/os0sync.c os/os0thread.c page/page0cur.c page/page0page.c que/que0que.c + handler/ha_innodb.cc read/read0read.c rem/rem0cmp.c rem/rem0rec.c row/row0ins.c row/row0mysql.c row/row0purge.c row/row0row.c row/row0sel.c row/row0uins.c diff --git a/Makefile.am b/Makefile.am index a68dbbcc2e6..bdab35f1dc0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -34,6 +34,7 @@ noinst_HEADERS = SUBDIRS = os ut btr buf data dict dyn eval fil fsp fut \ ha ibuf lock log mach mem mtr page \ + handler \ pars que read rem row srv sync thr trx usr EXTRA_DIST = include/btr0btr.h include/btr0btr.ic include/btr0cur.h include/btr0cur.ic \ @@ -86,6 +87,7 @@ EXTRA_DIST = include/btr0btr.h include/btr0btr.ic include/btr0cur.h include/btr include/univ.i include/usr0sess.h include/usr0sess.ic include/usr0types.h \ include/ut0byte.h include/ut0byte.ic include/ut0dbg.h include/ut0lst.h \ include/ut0mem.h include/ut0mem.ic include/ut0rnd.h include/ut0rnd.ic \ + handler/ha_innodb.h \ include/ut0sort.h include/ut0ut.h include/ut0ut.ic include/ut0vec.h include/ut0vec.ic include/ha_prototypes.h \ include/ut0list.h include/ut0list.ic \ include/ut0wqueue.h \ @@ -102,6 +104,7 @@ libinnobase_a_LIBADD = usr/libusr.a srv/libsrv.a dict/libdict.a \ page/libpage.a rem/librem.a thr/libthr.a \ sync/libsync.a data/libdata.a mach/libmach.a \ ha/libha.a dyn/libdyn.a mem/libmem.a \ + handler/libhandler.a \ ut/libut.a os/libos.a ut/libut.a libinnobase_a_SOURCES = diff --git a/dict/dict0dict.c b/dict/dict0dict.c index 7743bfb66d5..3f6e8debd18 100644 --- a/dict/dict0dict.c +++ b/dict/dict0dict.c @@ -1726,8 +1726,6 @@ dict_index_copy_types( dict_index_t* index, /* in: index */ ulint n_fields) /* in: number of field types to copy */ { - dtype_t* dfield_type; - dtype_t* type; ulint i; if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) { @@ -1737,10 +1735,17 @@ dict_index_copy_types( } for (i = 0; i < n_fields; i++) { + dict_field_t* ifield; + dtype_t* dfield_type; + dtype_t* type; + + ifield = dict_index_get_nth_field(index, i); dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i)); - type = dict_col_get_type(dict_field_get_col - (dict_index_get_nth_field(index, i))); + type = dict_col_get_type(dict_field_get_col(ifield)); *dfield_type = *type; + if (UNIV_UNLIKELY(ifield->prefix_len)) { + dfield_type->len = ifield->prefix_len; + } } } diff --git a/handler/Makefile.am b/handler/Makefile.am new file mode 100644 index 00000000000..78f9fdc9887 --- /dev/null +++ b/handler/Makefile.am @@ -0,0 +1,26 @@ +# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +# & Innobase Oy +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +include ../include/Makefile.i + +DEFS = -DMYSQL_SERVER @DEFS@ + +noinst_LIBRARIES = libhandler.a + +libhandler_a_SOURCES = ha_innodb.cc + +EXTRA_PROGRAMS = diff --git a/handler/ha_innodb.cc b/handler/ha_innodb.cc index 0513445b9a8..8d13d26bc1f 100644 --- a/handler/ha_innodb.cc +++ b/handler/ha_innodb.cc @@ -31,8 +31,7 @@ have disables the InnoDB inlining in this file. */ #pragma implementation // gcc: Class implementation #endif -#include "mysql_priv.h" -#include "slave.h" +#include #include #include @@ -1601,21 +1600,6 @@ innobase_init(void) pthread_cond_init(&commit_cond, NULL); innodb_inited= 1; - /* If this is a replication slave and we needed to do a crash recovery, - set the master binlog position to what InnoDB internally knew about - how far we got transactions durable inside InnoDB. There is a - problem here: if the user used also MyISAM tables, InnoDB might not - know the right position for them. - - THIS DOES NOT WORK CURRENTLY because replication seems to initialize - glob_mi also after innobase_init. */ - -/* if (trx_sys_mysql_master_log_pos != -1) { - ut_memcpy(glob_mi.log_file_name, trx_sys_mysql_master_log_name, - 1 + ut_strlen(trx_sys_mysql_master_log_name)); - glob_mi.pos = trx_sys_mysql_master_log_pos; - } -*/ DBUG_RETURN(FALSE); error: have_innodb= SHOW_OPTION_DISABLED; // If we couldn't use handler @@ -1690,19 +1674,6 @@ innobase_commit_low( return; } -#ifdef HAVE_REPLICATION - THD *thd=current_thd; - - if (thd && thd->slave_thread) { - /* Update the replication position info inside InnoDB */ - - trx->mysql_master_log_file_name - = active_mi->rli.group_master_log_name; - trx->mysql_master_log_pos = ((ib_longlong) - active_mi->rli.future_group_master_log_pos); - } -#endif /* HAVE_REPLICATION */ - trx_commit_for_mysql(trx); } @@ -2914,7 +2885,6 @@ ha_innobase::store_key_val_for_row( CHARSET_INFO* cs; ulint key_len; - ulint len; ulint true_len; int error=0; ulint blob_len; diff --git a/ibuf/ibuf0ibuf.c b/ibuf/ibuf0ibuf.c index a26f8f15299..73719ef807f 100644 --- a/ibuf/ibuf0ibuf.c +++ b/ibuf/ibuf0ibuf.c @@ -1411,8 +1411,8 @@ ibuf_entry_build( index tree; NOTE that the original entry must be kept because we copy pointers to its fields */ + dict_index_t* index, /* in: non-clustered index */ dtuple_t* entry, /* in: entry for a non-clustered index */ - ibool comp, /* in: flag: TRUE=compact record format */ ulint space, /* in: space id */ ulint page_no,/* in: index page number where entry should be inserted */ @@ -1476,13 +1476,12 @@ ibuf_entry_build( dfield_set_data(field, buf, 4); - ut_ad(comp == 0 || comp == 1); /* Store the type info in buf2, and add the fields from entry to tuple */ buf2 = mem_heap_alloc(heap, n_fields * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE - + comp); - if (comp) { + + dict_table_is_comp(index->table)); + if (dict_table_is_comp(index->table)) { *buf2++ = 0; /* write the compact format indicator */ } for (i = 0; i < n_fields; i++) { @@ -1495,20 +1494,21 @@ ibuf_entry_build( dtype_new_store_for_order_and_null_size (buf2 + i * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE, - dfield_get_type(entry_field)); + dfield_get_type(entry_field), + dict_index_get_nth_field(index, i)->prefix_len); } /* Store the type info in buf2 to field 3 of tuple */ field = dtuple_get_nth_field(tuple, 3); - if (comp) { + if (dict_table_is_comp(index->table)) { buf2--; } dfield_set_data(field, buf2, n_fields * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE - + comp); + + dict_table_is_comp(index->table)); /* Set all the types in the new tuple binary */ dtuple_set_types_binary(tuple, n_fields + 4); @@ -2658,8 +2658,7 @@ ibuf_insert_low( the first fields and the type information for other fields, and which will be inserted to the insert buffer. */ - ibuf_entry = ibuf_entry_build(entry, dict_table_is_comp(index->table), - space, page_no, heap); + ibuf_entry = ibuf_entry_build(index, entry, space, page_no, heap); /* Open a cursor to the insert buffer tree to calculate if we can add the new entry to it without exceeding the free space limit for the diff --git a/include/data0type.h b/include/data0type.h index 7a9456637d6..07e241775f2 100644 --- a/include/data0type.h +++ b/include/data0type.h @@ -376,7 +376,9 @@ dtype_new_store_for_order_and_null_size( byte* buf, /* in: buffer for DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE bytes where we store the info */ - dtype_t* type); /* in: type struct */ + dtype_t* type, /* in: type struct */ + ulint prefix_len);/* in: prefix length to + replace type->len, or 0 */ /************************************************************************** Reads to a type the stored information which determines its alphabetical ordering and the storage size of an SQL NULL value. This is the 4.1.x storage diff --git a/include/data0type.ic b/include/data0type.ic index d2027592c09..6daf88e7fab 100644 --- a/include/data0type.ic +++ b/include/data0type.ic @@ -244,11 +244,14 @@ dtype_new_store_for_order_and_null_size( byte* buf, /* in: buffer for DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE bytes where we store the info */ - dtype_t* type) /* in: type struct */ + dtype_t* type, /* in: type struct */ + ulint prefix_len)/* in: prefix length to + replace type->len, or 0 */ { #if 6 != DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE #error "6 != DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE" #endif + ulint len; buf[0] = (byte)(type->mtype & 0xFFUL); @@ -263,7 +266,9 @@ dtype_new_store_for_order_and_null_size( buf[1] = (byte)(type->prtype & 0xFFUL); - mach_write_to_2(buf + 2, type->len & 0xFFFFUL); + len = prefix_len ? prefix_len : type->len; + + mach_write_to_2(buf + 2, len & 0xFFFFUL); ut_ad(dtype_get_charset_coll(type->prtype) < 256); mach_write_to_2(buf + 4, dtype_get_charset_coll(type->prtype)); diff --git a/mysql-test/innodb_mysql.result b/mysql-test/innodb_mysql.result index 9f177e99a17..a5b263b759d 100644 --- a/mysql-test/innodb_mysql.result +++ b/mysql-test/innodb_mysql.result @@ -89,6 +89,27 @@ b a 3 3 3 3 DROP TABLE t1, t2, t3; +CREATE TABLE `t1` (`id1` INT) ; +INSERT INTO `t1` (`id1`) VALUES (1),(5),(2); +CREATE TABLE `t2` ( +`id1` INT, +`id2` INT NOT NULL, +`id3` INT, +`id4` INT NOT NULL, +UNIQUE (`id2`,`id4`), +KEY (`id1`) +) ENGINE=InnoDB; +INSERT INTO `t2`(`id1`,`id2`,`id3`,`id4`) VALUES +(1,1,1,0), +(1,1,2,1), +(5,1,2,2), +(6,1,2,3), +(1,2,2,2), +(1,2,1,1); +SELECT `id1` FROM `t1` WHERE `id1` NOT IN (SELECT `id1` FROM `t2` WHERE `id2` = 1 AND `id3` = 2); +id1 +2 +DROP TABLE t1, t2; create table t1m (a int) engine=myisam; create table t1i (a int) engine=innodb; create table t2m (a int) engine=myisam; @@ -303,6 +324,25 @@ explain select distinct f1, f2 from t1; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range NULL PRIMARY 5 NULL 3 Using index for group-by; Using temporary drop table t1; +CREATE TABLE t1 (id int(11) NOT NULL PRIMARY KEY, name varchar(20), +INDEX (name)) ENGINE=InnoDB; +CREATE TABLE t2 (id int(11) NOT NULL PRIMARY KEY, fkey int(11), +FOREIGN KEY (fkey) REFERENCES t2(id)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1,'A1'),(2,'A2'),(3,'B'); +INSERT INTO t2 VALUES (1,1),(2,2),(3,2),(4,3),(5,3); +EXPLAIN +SELECT COUNT(*) FROM t2 LEFT JOIN t1 ON t2.fkey = t1.id +WHERE t1.name LIKE 'A%'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index PRIMARY,name name 23 NULL 3 Using where; Using index +1 SIMPLE t2 ref fkey fkey 5 test.t1.id 1 Using where; Using index +EXPLAIN +SELECT COUNT(*) FROM t2 LEFT JOIN t1 ON t2.fkey = t1.id +WHERE t1.name LIKE 'A%' OR FALSE; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index NULL fkey 5 NULL 5 Using index +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.fkey 1 Using where +DROP TABLE t1,t2; set storage_engine=innodb; CREATE TABLE t1 (a int, b int); insert into t1 values (1,1),(1,2); @@ -367,3 +407,49 @@ Warnings: Warning 1071 Specified key was too long; max key length is 765 bytes insert into t1 values('aaa'); drop table t1; +CREATE TABLE `t2` ( +`k` int(11) NOT NULL auto_increment, +`a` int(11) default NULL, +`c` int(11) default NULL, +PRIMARY KEY (`k`), +UNIQUE KEY `idx_1` (`a`) +) ENGINE=InnoDB; +insert into t2 ( a ) values ( 6 ) on duplicate key update c = +ifnull( c, +0 ) + 1; +insert into t2 ( a ) values ( 7 ) on duplicate key update c = +ifnull( c, +0 ) + 1; +select last_insert_id(); +last_insert_id() +2 +select * from t2; +k a c +1 6 NULL +2 7 NULL +insert into t2 ( a ) values ( 6 ) on duplicate key update c = +ifnull( c, +0 ) + 1; +select last_insert_id(); +last_insert_id() +1 +select * from t2; +k a c +1 6 1 +2 7 NULL +insert ignore into t2 values (null,6,1),(10,8,1); +select last_insert_id(); +last_insert_id() +1 +insert ignore into t2 values (null,6,1),(null,8,1),(null,15,1),(null,20,1); +select last_insert_id(); +last_insert_id() +11 +select * from t2; +k a c +1 6 1 +2 7 NULL +10 8 1 +11 15 1 +12 20 1 +drop table t2; diff --git a/mysql-test/innodb_mysql.test b/mysql-test/innodb_mysql.test index 2be53b58a39..d61509317ca 100644 --- a/mysql-test/innodb_mysql.test +++ b/mysql-test/innodb_mysql.test @@ -98,6 +98,33 @@ SELECT STRAIGHT_JOIN SQL_NO_CACHE t1.b, t1.a FROM t1, t3, t2 WHERE t3.a = t2.a AND t2.b = t1.a AND t3.b = 1 AND t3.c IN (1, 2) ORDER BY t1.b LIMIT 5; DROP TABLE t1, t2, t3; + + +# BUG#21077 (The testcase is not deterministic so correct execution doesn't +# prove anything) For proof one should track if sequence of ha_innodb::* func +# calls is correct. +CREATE TABLE `t1` (`id1` INT) ; +INSERT INTO `t1` (`id1`) VALUES (1),(5),(2); + +CREATE TABLE `t2` ( + `id1` INT, + `id2` INT NOT NULL, + `id3` INT, + `id4` INT NOT NULL, + UNIQUE (`id2`,`id4`), + KEY (`id1`) +) ENGINE=InnoDB; + +INSERT INTO `t2`(`id1`,`id2`,`id3`,`id4`) VALUES +(1,1,1,0), +(1,1,2,1), +(5,1,2,2), +(6,1,2,3), +(1,2,2,2), +(1,2,1,1); + +SELECT `id1` FROM `t1` WHERE `id1` NOT IN (SELECT `id1` FROM `t2` WHERE `id2` = 1 AND `id3` = 2); +DROP TABLE t1, t2; # # Bug #12882 min/max inconsistent on empty table # @@ -263,6 +290,26 @@ explain select distinct f1 a, f1 b from t1; explain select distinct f1, f2 from t1; drop table t1; +# +# Test for bug #17164: ORed FALSE blocked conversion of outer join into join +# + +CREATE TABLE t1 (id int(11) NOT NULL PRIMARY KEY, name varchar(20), + INDEX (name)) ENGINE=InnoDB; +CREATE TABLE t2 (id int(11) NOT NULL PRIMARY KEY, fkey int(11), + FOREIGN KEY (fkey) REFERENCES t2(id)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1,'A1'),(2,'A2'),(3,'B'); +INSERT INTO t2 VALUES (1,1),(2,2),(3,2),(4,3),(5,3); + +EXPLAIN +SELECT COUNT(*) FROM t2 LEFT JOIN t1 ON t2.fkey = t1.id + WHERE t1.name LIKE 'A%'; + +EXPLAIN +SELECT COUNT(*) FROM t2 LEFT JOIN t1 ON t2.fkey = t1.id + WHERE t1.name LIKE 'A%' OR FALSE; + +DROP TABLE t1,t2; # # Test of behaviour with CREATE ... SELECT @@ -320,3 +367,40 @@ create table t1(f1 varchar(800) binary not null, key(f1)) engine = innodb character set utf8 collate utf8_general_ci; insert into t1 values('aaa'); drop table t1; + +# Fix for BUG#19243 "wrong LAST_INSERT_ID() after ON DUPLICATE KEY +# UPDATE": now LAST_INSERT_ID() will return the id of the updated +# row. +CREATE TABLE `t2` ( + `k` int(11) NOT NULL auto_increment, + `a` int(11) default NULL, + `c` int(11) default NULL, + PRIMARY KEY (`k`), + UNIQUE KEY `idx_1` (`a`) +) ENGINE=InnoDB; + insert into t2 ( a ) values ( 6 ) on duplicate key update c = +ifnull( c, +0 ) + 1; +insert into t2 ( a ) values ( 7 ) on duplicate key update c = +ifnull( c, +0 ) + 1; +select last_insert_id(); +select * from t2; +insert into t2 ( a ) values ( 6 ) on duplicate key update c = +ifnull( c, +0 ) + 1; +select last_insert_id(); +select * from t2; + +# Test of LAST_INSERT_ID() when autogenerated will fail: +# last_insert_id() should not change +insert ignore into t2 values (null,6,1),(10,8,1); +select last_insert_id(); +# First and second autogenerated will fail, last_insert_id() should +# point to third +insert ignore into t2 values (null,6,1),(null,8,1),(null,15,1),(null,20,1); +select last_insert_id(); +select * from t2; + +drop table t2; + diff --git a/plug.in b/plug.in index fc1d758fd87..028937882b2 100644 --- a/plug.in +++ b/plug.in @@ -65,6 +65,7 @@ MYSQL_PLUGIN_ACTIONS(innobase, [ storage/innobase/sync/Makefile storage/innobase/thr/Makefile storage/innobase/trx/Makefile + storage/innobase/handler/Makefile storage/innobase/usr/Makefile) ]) diff --git a/row/row0row.c b/row/row0row.c index b92b757c6e4..69d1392e670 100644 --- a/row/row0row.c +++ b/row/row0row.c @@ -103,17 +103,22 @@ row_build_index_entry( dfield_copy(dfield, dfield2); /* If a column prefix index, take only the prefix */ - if (ind_field->prefix_len > 0 - && dfield_get_len(dfield2) != UNIV_SQL_NULL) { + if (ind_field->prefix_len) { + if (dfield_get_len(dfield2) != UNIV_SQL_NULL) { - cur_type = dict_col_get_type - (dict_field_get_col(ind_field)); + cur_type = dict_col_get_type + (dict_field_get_col(ind_field)); - storage_len = dtype_get_at_most_n_mbchars - (cur_type, ind_field->prefix_len, - dfield_get_len(dfield2), dfield2->data); + storage_len = dtype_get_at_most_n_mbchars + (cur_type, + ind_field->prefix_len, + dfield_get_len(dfield2), + dfield2->data); - dfield_set_len(dfield, storage_len); + dfield_set_len(dfield, storage_len); + } + + dfield_get_type(dfield)->len = ind_field->prefix_len; } } diff --git a/setup.sh b/setup.sh index 57ab3c68c90..bc5b13beee6 100755 --- a/setup.sh +++ b/setup.sh @@ -19,7 +19,6 @@ ln -sf ../innodb/compile-innodb{,-debug} ../BUILD for dir in */ do case "$dir" in - handler/) ;; mysql-test/) ;; *.svn*) ;; *to-mysql*) ;; @@ -40,11 +39,7 @@ do ln -s ../../innodb/"$file" . done -cd .. -ln -sf ../innodb/handler/ha_innodb.h ../sql/ -ln -sf ../innodb/handler/ha_innodb.cc ../sql/ - -cd ../mysql-test/t +cd ../../mysql-test/t ln -sf ../../innodb/mysql-test/*.test ../../innodb/mysql-test/*.opt ./ ln -sf ../../innodb/mysql-test/*.result ../r/ ln -sf ../../innodb/mysql-test/*.inc ../include/