diff options
60 files changed, 1528 insertions, 262 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 3935d9aa655..0ab5a56476c 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -217,12 +217,16 @@ ENDIF(WITHOUT_DYNAMIC_PLUGINS) FILE(GLOB STORAGE_SUBDIRS storage/*) FOREACH(SUBDIR ${STORAGE_SUBDIRS}) FILE(RELATIVE_PATH DIRNAME ${PROJECT_SOURCE_DIR}/storage ${SUBDIR}) - STRING(TOUPPER ${DIRNAME} ENGINE) - STRING(TOLOWER ${DIRNAME} ENGINE_LOWER) IF (EXISTS ${SUBDIR}/CMakeLists.txt) # Check MYSQL_STORAGE_ENGINE macro is present FILE(STRINGS ${SUBDIR}/CMakeLists.txt HAVE_STORAGE_ENGINE REGEX MYSQL_STORAGE_ENGINE) IF(HAVE_STORAGE_ENGINE) + # Extract name of engine from HAVE_STORAGE_ENGINE + STRING(REGEX REPLACE ".*MYSQL_STORAGE_ENGINE\\((.*\)\\).*" + "\\1" ENGINE_NAME ${HAVE_STORAGE_ENGINE}) + STRING(TOUPPER ${ENGINE_NAME} ENGINE) + STRING(TOLOWER ${ENGINE_NAME} ENGINE_LOWER) + SET(ENGINE_BUILD_TYPE "DYNAMIC") # Read plug.in to find out if a plugin is mandatory and whether it supports # build as shared library (dynamic). @@ -248,6 +252,7 @@ FOREACH(SUBDIR ${STORAGE_SUBDIRS}) SET (MYSQLD_STATIC_ENGINE_LIBS ${MYSQLD_STATIC_ENGINE_LIBS} ${ENGINE_LOWER}) SET (STORAGE_ENGINE_DEFS "${STORAGE_ENGINE_DEFS} -DWITH_${ENGINE}_STORAGE_ENGINE") SET (WITH_${ENGINE}_STORAGE_ENGINE TRUE) + SET (${ENGINE}_DIR ${DIRNAME}) ENDIF (ENGINE_BUILD_TYPE STREQUAL "STATIC") ENDIF(EXISTS ${SUBDIR}/plug.in) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 04a7e7b0c6f..e37b7d89a93 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -6775,8 +6775,10 @@ void run_query_stmt(MYSQL *mysql, struct st_command *command, MYSQL_STMT *stmt; DYNAMIC_STRING ds_prepare_warnings; DYNAMIC_STRING ds_execute_warnings; + ulonglong affected_rows; DBUG_ENTER("run_query_stmt"); DBUG_PRINT("query", ("'%-.60s'", query)); + LINT_INIT(affected_rows); /* Init a new stmt if it's not already one created for this connection @@ -6911,9 +6913,6 @@ void run_query_stmt(MYSQL *mysql, struct st_command *command, Need to grab affected rows information before getting warnings here */ - ulonglong affected_rows; - LINT_INIT(affected_rows); - if (!disable_info) affected_rows= mysql_affected_rows(mysql); diff --git a/include/my_sys.h b/include/my_sys.h index 166133251bc..b4aac3a17bd 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -720,7 +720,6 @@ extern int wild_compare(const char *str,const char *wildstr, extern WF_PACK *wf_comp(char * str); extern int wf_test(struct wild_file_pack *wf_pack,const char *name); extern void wf_end(struct wild_file_pack *buffer); -extern size_t strip_sp(char * str); extern my_bool array_append_string_unique(const char *str, const char **array, size_t size); extern void get_date(char * to,int timeflag,time_t use_time); diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt index bea6f6c0e1f..db398258b69 100644 --- a/libmysqld/CMakeLists.txt +++ b/libmysqld/CMakeLists.txt @@ -90,10 +90,11 @@ ENDFOREACH(rpath) FOREACH (ENGINE_LIB ${MYSQLD_STATIC_ENGINE_LIBS}) - INCLUDE(${CMAKE_SOURCE_DIR}/storage/${ENGINE_LIB}/CMakeLists.txt) STRING(TOUPPER ${ENGINE_LIB} ENGINE_LIB_UPPER) + SET(ENGINE_DIR ${${ENGINE_LIB_UPPER}_DIR}) + INCLUDE(${CMAKE_SOURCE_DIR}/storage/${ENGINE_DIR}/CMakeLists.txt) FOREACH(rpath ${${ENGINE_LIB_UPPER}_SOURCES}) - SET(LIB_SOURCES ${LIB_SOURCES} ${CMAKE_SOURCE_DIR}/storage/${ENGINE_LIB}/${rpath}) + SET(LIB_SOURCES ${LIB_SOURCES} ${CMAKE_SOURCE_DIR}/storage/${ENGINE_DIR}/${rpath}) ENDFOREACH(rpath) ENDFOREACH(ENGINE_LIB) @@ -155,6 +156,14 @@ ADD_LIBRARY(mysqlserver STATIC ${LIBMYSQLD_SOURCES}) ADD_DEPENDENCIES(mysqlserver GenServerSource GenError) TARGET_LINK_LIBRARIES(mysqlserver) +# Add any additional libraries requested by engine(s) +FOREACH (ENGINE_LIB ${MYSQLD_STATIC_ENGINE_LIBS}) + STRING(TOUPPER ${ENGINE_LIB} ENGINE_LIB_UPPER) + IF(${ENGINE_LIB_UPPER}_LIBS) + TARGET_LINK_LIBRARIES(mysqlserver ${${ENGINE_LIB_UPPER}_LIBS}) + ENDIF(${ENGINE_LIB_UPPER}_LIBS) +ENDFOREACH(ENGINE_LIB) + ADD_LIBRARY(libmysqld SHARED cmake_dummy.c libmysqld.def) ADD_DEPENDENCIES(libmysqld mysqlserver) TARGET_LINK_LIBRARIES(libmysqld mysqlserver wsock32) diff --git a/mysql-test/extra/binlog_tests/binlog.test b/mysql-test/extra/binlog_tests/binlog.test index 5d898d41a54..b819996acb0 100644 --- a/mysql-test/extra/binlog_tests/binlog.test +++ b/mysql-test/extra/binlog_tests/binlog.test @@ -270,3 +270,42 @@ INSERT INTO test.t1 VALUES (1), (2); CREATE TABLE test.t2 SELECT * FROM test.t1; USE test; DROP TABLES t1, t2; + +# +# Bug#46640 +# This test verifies if the server_id stored in the "format +# description BINLOG statement" will override the server_id +# of the server executing the statements. +# + +connect (fresh,localhost,root,,test); +connection fresh; + +RESET MASTER; +CREATE TABLE t1 (a INT PRIMARY KEY); + +# Format description event, with server_id = 10; +BINLOG ' +3u9kSA8KAAAAZgAAAGoAAAABAAQANS4xLjM1LW1hcmlhLWJldGExLWRlYnVnLWxvZwAAAAAAAAAA +AAAAAAAAAAAAAAAAAADe72RIEzgNAAgAEgAEBAQEEgAAUwAEGggAAAAICAgC +'; + +# What server_id is logged for a statement? Should be our own, not the +# one from the format description event. +INSERT INTO t1 VALUES (1); + +# INSERT INTO t1 VALUES (2), with server_id=20. Check that this is logged +# with our own server id, not the 20 from the BINLOG statement. +BINLOG ' +3u9kSBMUAAAAKQAAAJEBAAAAABoAAAAAAAAABHRlc3QAAnQxAAEDAAA= +3u9kSBcUAAAAIgAAALMBAAAQABoAAAAAAAEAAf/+AgAAAA== +'; + +# Show binlog events to check that server ids are correct. +--replace_column 1 # 2 # 5 # +--replace_regex /Server ver: .*, Binlog ver: .*/Server ver: #, Binlog ver: #/ /table_id: [0-9]+/table_id: #/ +SHOW BINLOG EVENTS; + +DROP TABLE t1; +disconnect fresh; + diff --git a/mysql-test/r/ctype_ldml.result b/mysql-test/r/ctype_ldml.result index 711921eb526..fe870f82743 100644 --- a/mysql-test/r/ctype_ldml.result +++ b/mysql-test/r/ctype_ldml.result @@ -321,3 +321,11 @@ Vv Xx YyÝýỲỳỴỵỶỷỸỹ drop table t1; +Bug#46448 trailing spaces are not ignored when user collation maps space != 0x20 +set names latin1; +show collation like 'latin1_test'; +Collation Charset Id Default Compiled Sortlen +latin1_test latin1 99 Yes 1 +select "foo" = "foo " collate latin1_test; +"foo" = "foo " collate latin1_test +1 diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index 3d989ad1730..94147640cde 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -1477,3 +1477,47 @@ COUNT(*) SET SQL_MODE=default; DROP TABLE t1; End of 5.0 tests +# +# BUG#47280 - strange results from count(*) with order by multiple +# columns without where/group +# +# +# Initialize test +# +CREATE TABLE t1 ( +pk INT NOT NULL, +i INT, +PRIMARY KEY (pk) +); +INSERT INTO t1 VALUES (1,11),(2,12),(3,13); +# +# Start test +# All the following queries shall return 1 record +# + +# Masking all correct values {11...13} for column i in this result. +SELECT MAX(pk) as max, i +FROM t1 +ORDER BY max; +max i +3 # + +EXPLAIN +SELECT MAX(pk) as max, i +FROM t1 +ORDER BY max; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using temporary + +# Only 11 is correct for collumn i in this result +SELECT MAX(pk) as max, i +FROM t1 +WHERE pk<2 +ORDER BY max; +max i +1 11 +# +# Cleanup +# +DROP TABLE t1; +End of 5.1 tests diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result index ac9a53ca238..620f5dc19ec 100644 --- a/mysql-test/r/group_min_max.result +++ b/mysql-test/r/group_min_max.result @@ -876,10 +876,10 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range NULL idx_t1_1 163 NULL 17 Using where; Using index for group-by explain select a1,a2,b, max(c) from t1 where (c > 'b1') or (c <= 'g1') group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using where; Using index for group-by +1 SIMPLE t1 range NULL idx_t1_1 163 NULL 17 Using where; Using index for group-by explain select a1,a2,b,min(c),max(c) from t1 where (c > 'b1') or (c <= 'g1') group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using where; Using index for group-by +1 SIMPLE t1 range NULL idx_t1_1 163 NULL 17 Using where; Using index for group-by explain select a1,a2,b,min(c),max(c) from t1 where (c > 'b111') and (c <= 'g112') group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range NULL idx_t1_1 163 NULL 17 Using where; Using index for group-by @@ -924,7 +924,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 range NULL idx_t2_1 163 NULL # Using where; Using index for group-by explain select a1,a2,b, max(c) from t2 where (c > 'b1') or (c <= 'g1') group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 range NULL idx_t2_1 146 NULL # Using where; Using index for group-by +1 SIMPLE t2 range NULL idx_t2_1 163 NULL # Using where; Using index for group-by explain select a1,a2,b,min(c),max(c) from t2 where (c > 'b1') or (c <= 'g1') group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 range NULL idx_t2_1 163 NULL # Using where; Using index for group-by diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index 58e2e451a0d..df97e96c334 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -2271,4 +2271,32 @@ checksum table t3; Table Checksum test.t3 326284887 drop table t1,t2,t3; +CREATE TABLE t1(a INT, b CHAR(10), KEY(a), KEY(b)); +INSERT INTO t1 VALUES(1,'0'),(2,'0'),(3,'0'),(4,'0'),(5,'0'), +(6,'0'),(7,'0'); +INSERT INTO t1 SELECT a+10,b FROM t1; +INSERT INTO t1 SELECT a+20,b FROM t1; +INSERT INTO t1 SELECT a+40,b FROM t1; +INSERT INTO t1 SELECT a+80,b FROM t1; +INSERT INTO t1 SELECT a+160,b FROM t1; +INSERT INTO t1 SELECT a+320,b FROM t1; +INSERT INTO t1 SELECT a+640,b FROM t1; +INSERT INTO t1 SELECT a+1280,b FROM t1; +INSERT INTO t1 SELECT a+2560,b FROM t1; +INSERT INTO t1 SELECT a+5120,b FROM t1; +SET myisam_sort_buffer_size=4; +REPAIR TABLE t1; +Table Op Msg_type Msg_text +test.t1 repair error myisam_sort_buffer_size is too small +test.t1 repair warning Number of rows changed from 0 to 7168 +test.t1 repair status OK +SET myisam_repair_threads=2; +REPAIR TABLE t1; +Table Op Msg_type Msg_text +test.t1 repair error myisam_sort_buffer_size is too small +test.t1 repair warning Number of rows changed from # to 7168 +test.t1 repair status OK +SET myisam_repair_threads=@@global.myisam_repair_threads; +SET myisam_sort_buffer_size=@@global.myisam_sort_buffer_size; +DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index 306fce1f3c2..0c72f816c21 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -1557,3 +1557,34 @@ a 2001 1991 DROP TABLE t1; +# +# Bug #43029: FORCE INDEX FOR ORDER BY is ignored when join buffering +# is used +# +CREATE TABLE t1 (a INT, b INT, KEY (a)); +INSERT INTO t1 VALUES (0, NULL), (1, NULL), (2, NULL), (3, NULL); +INSERT INTO t1 SELECT a+4, b FROM t1; +INSERT INTO t1 SELECT a+8, b FROM t1; +CREATE TABLE t2 (a INT, b INT); +INSERT INTO t2 VALUES (0,NULL), (1,NULL), (2,NULL), (3,NULL), (4,NULL); +INSERT INTO t2 SELECT a+4, b FROM t2; +# shouldn't have "using filesort" +EXPLAIN +SELECT * FROM t1 FORCE INDEX FOR ORDER BY (a), t2 WHERE t1.a < 2 ORDER BY t1.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 2 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 10 +# should have "using filesort" +EXPLAIN +SELECT * FROM t1 USE INDEX FOR ORDER BY (a), t2 WHERE t1.a < 2 ORDER BY t1.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 2 Using where; Using temporary; Using filesort +1 SIMPLE t2 ALL NULL NULL NULL NULL 10 Using join buffer +# should have "using filesort" +EXPLAIN +SELECT * FROM t1 FORCE INDEX FOR JOIN (a), t2 WHERE t1.a < 2 ORDER BY t1.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 2 Using where; Using temporary; Using filesort +1 SIMPLE t2 ALL NULL NULL NULL NULL 10 Using join buffer +DROP TABLE t1, t2; +End of 5.1 tests diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result index 2d54a66fe11..6611d39628f 100644 --- a/mysql-test/r/partition.result +++ b/mysql-test/r/partition.result @@ -50,6 +50,21 @@ t1 CREATE TABLE `t1` ( PARTITION p3 VALUES LESS THAN (733969) ENGINE = MyISAM, PARTITION pmax VALUES LESS THAN MAXVALUE ENGINE = MyISAM) */ DROP TABLE t1; +create table t1 (a int, b int, key(a)) +partition by list (a) +( partition p0 values in (1), +partition p1 values in (2)); +insert into t1 values (1,1),(2,1),(2,2),(2,3); +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A NULL NULL NULL YES BTREE +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A 1 NULL NULL YES BTREE +drop table t1; CREATE TABLE t1 (a INT, FOREIGN KEY (a) REFERENCES t0 (a)) ENGINE=MyISAM PARTITION BY HASH (a); diff --git a/mysql-test/r/partition_open_files_limit.result b/mysql-test/r/partition_open_files_limit.result new file mode 100644 index 00000000000..1441ba4e78e --- /dev/null +++ b/mysql-test/r/partition_open_files_limit.result @@ -0,0 +1,22 @@ +DROP TABLE IF EXISTS `t1`; +# Bug#46922: crash when adding partitions and open_files_limit is reached +CREATE TABLE t1 (a INT PRIMARY KEY) +ENGINE=MyISAM PARTITION BY KEY () PARTITIONS 1; +INSERT INTO t1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11); +# if the bug exists, then crash will happen here +ALTER TABLE t1 ADD PARTITION PARTITIONS 511; +ERROR HY000: Out of resources when opening file '<partition file>' (Errcode: 24) +SELECT * FROM t1; +a +1 +10 +11 +2 +3 +4 +5 +6 +7 +8 +9 +DROP TABLE t1; diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index cc5e8d2be96..c98a7696ea6 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -1219,3 +1219,182 @@ explain select * from t2 where a=1000 and b<11; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ref a a 5 const 502 Using where drop table t1, t2; +CREATE TABLE t1( a INT, b INT, KEY( a, b ) ); +CREATE TABLE t2( a INT, b INT, KEY( a, b ) ); +CREATE TABLE t3( a INT, b INT, KEY( a, b ) ); +INSERT INTO t1( a, b ) +VALUES (0, 1), (1, 2), (1, 4), (2, 3), (5, 0), (9, 7); +INSERT INTO t2( a, b ) +VALUES ( 1, 1), ( 2, 1), ( 3, 1), ( 4, 1), ( 5, 1), +( 6, 1), ( 7, 1), ( 8, 1), ( 9, 1), (10, 1), +(11, 1), (12, 1), (13, 1), (14, 1), (15, 1), +(16, 1), (17, 1), (18, 1), (19, 1), (20, 1); +INSERT INTO t2 SELECT a, 2 FROM t2 WHERE b = 1; +INSERT INTO t2 SELECT a, 3 FROM t2 WHERE b = 1; +INSERT INTO t2 SELECT -1, -1 FROM t2; +INSERT INTO t2 SELECT -1, -1 FROM t2; +INSERT INTO t2 SELECT -1, -1 FROM t2; +INSERT INTO t3 +VALUES (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), +(6, 0), (7, 0), (8, 0), (9, 0), (10, 0); +INSERT INTO t3 SELECT * FROM t3 WHERE a = 10; +INSERT INTO t3 SELECT * FROM t3 WHERE a = 10; +SELECT * FROM t1 WHERE +3 <= a AND a < 5 OR +5 < a AND b = 3 OR +3 <= a; +a b +5 0 +9 7 +EXPLAIN +SELECT * FROM t1 WHERE +3 <= a AND a < 5 OR +5 < a AND b = 3 OR +3 <= a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 3 Using where; Using index +SELECT * FROM t1 WHERE +3 <= a AND a < 5 OR +5 <= a AND b = 3 OR +3 <= a; +a b +5 0 +9 7 +EXPLAIN +SELECT * FROM t1 WHERE +3 <= a AND a < 5 OR +5 <= a AND b = 3 OR +3 <= a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 4 Using where; Using index +SELECT * FROM t1 WHERE +3 <= a AND a <= 5 OR +5 <= a AND b = 3 OR +3 <= a; +a b +5 0 +9 7 +EXPLAIN +SELECT * FROM t1 WHERE +3 <= a AND a <= 5 OR +5 <= a AND b = 3 OR +3 <= a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 3 Using where; Using index +SELECT * FROM t1 WHERE +3 <= a AND a <= 5 OR +3 <= a; +a b +5 0 +9 7 +EXPLAIN +SELECT * FROM t1 WHERE +3 <= a AND a <= 5 OR +3 <= a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 3 Using where; Using index +SELECT * FROM t2 WHERE +5 <= a AND a < 10 AND b = 1 OR +15 <= a AND a < 20 AND b = 3 +OR +1 <= a AND b = 1; +a b +1 1 +2 1 +3 1 +4 1 +5 1 +6 1 +7 1 +8 1 +9 1 +10 1 +11 1 +12 1 +13 1 +14 1 +15 1 +15 3 +16 1 +16 3 +17 1 +17 3 +18 1 +18 3 +19 1 +19 3 +20 1 +EXPLAIN +SELECT * FROM t2 WHERE +5 <= a AND a < 10 AND b = 1 OR +15 <= a AND a < 20 AND b = 3 +OR +1 <= a AND b = 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range a a 10 NULL 50 Using where; Using index +SELECT * FROM t2 WHERE +5 <= a AND a < 10 AND b = 2 OR +15 <= a AND a < 20 AND b = 3 +OR +1 <= a AND b = 1; +a b +1 1 +2 1 +3 1 +4 1 +5 1 +5 2 +6 1 +6 2 +7 1 +7 2 +8 1 +8 2 +9 1 +9 2 +10 1 +11 1 +12 1 +13 1 +14 1 +15 1 +15 3 +16 1 +16 3 +17 1 +17 3 +18 1 +18 3 +19 1 +19 3 +20 1 +EXPLAIN +SELECT * FROM t2 WHERE +5 <= a AND a < 10 AND b = 2 OR +15 <= a AND a < 20 AND b = 3 +OR +1 <= a AND b = 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range a a 10 NULL 50 Using where; Using index +SELECT * FROM t3 WHERE +5 <= a AND a < 10 AND b = 3 OR +a < 5 OR +a < 10; +a b +1 0 +2 0 +3 0 +4 0 +5 0 +6 0 +7 0 +8 0 +9 0 +EXPLAIN +SELECT * FROM t3 WHERE +5 <= a AND a < 10 AND b = 3 OR +a < 5 OR +a < 10; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 range a a 5 NULL 8 Using where; Using index +DROP TABLE t1, t2, t3; diff --git a/mysql-test/r/type_bit.result b/mysql-test/r/type_bit.result index b831771d9c5..51feab0a421 100644 --- a/mysql-test/r/type_bit.result +++ b/mysql-test/r/type_bit.result @@ -749,6 +749,16 @@ bin(a1) 110000111111111 110001011111111 drop table t1bit7, t2bit7; +# +# Bug42803: Field_bit does not have unsigned_flag field, +# can lead to bad memory access +# +CREATE TABLE t1 (a BIT(7), b BIT(9), KEY(a, b)); +INSERT INTO t1 VALUES(0, 0), (5, 3), (5, 6), (6, 4), (7, 0); +EXPLAIN SELECT a+0, b+0 FROM t1 WHERE a > 4 and b < 7 ORDER BY 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 2 NULL 4 Using where; Using index; Using filesort +DROP TABLE t1; End of 5.0 tests create table t1(a bit(7)); insert into t1 values(0x40); diff --git a/mysql-test/std_data/Index.xml b/mysql-test/std_data/Index.xml index 988dddcc68a..3dc647d8195 100644 --- a/mysql-test/std_data/Index.xml +++ b/mysql-test/std_data/Index.xml @@ -68,4 +68,17 @@ </charset> + <charset name="latin1"> + <family>Western</family> + <description>cp1252 West European</description> + <alias>csisolatin1</alias> + <alias>iso-8859-1</alias> + <alias>iso-ir-100</alias> + <alias>iso_8859-1</alias> + <alias>iso_8859-1:1987</alias> + <alias>l1</alias> + <alias>latin1</alias> + <collation name="latin1_test" id="99" order="test"/> + </charset> + </charsets> diff --git a/mysql-test/std_data/latin1.xml b/mysql-test/std_data/latin1.xml new file mode 100644 index 00000000000..458b1c34da1 --- /dev/null +++ b/mysql-test/std_data/latin1.xml @@ -0,0 +1,135 @@ +<?xml version='1.0' encoding="utf-8"?> + +<charsets> + +<copyright> + Copyright (C) 2009 Sun Microsystems, Inc + + 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; version 2 of the License. + + 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 +</copyright> + +<charset name="latin1"> + +<ctype> +<map> + 00 + 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20 + 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 + 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 + 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10 + 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01 + 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10 + 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02 + 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20 + 10 00 10 02 10 10 10 10 10 10 01 10 01 00 01 00 + 00 10 10 10 10 10 10 10 10 10 02 10 02 00 02 01 + 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 + 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 + 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 + 01 01 01 01 01 01 01 10 01 01 01 01 01 01 01 02 + 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 + 02 02 02 02 02 02 02 10 02 02 02 02 02 02 02 02 +</map> +</ctype> + + +<lower> +<map> + 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F + 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F + 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F + 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F + 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F + 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F + 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F + 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F + 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F + 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F + A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF + B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF + E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF + F0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE DF + E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF + F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF +</map> +</lower> + + +<upper> +<map> + 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F + 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F + 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F + 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F + 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F + 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F + 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F + 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F + 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F + 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F + A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF + B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF + C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF + D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF + C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF + D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF +</map> +</upper> + + +<unicode> +<map> + 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F + 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F + 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F + 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F + 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F + 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F + 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F + 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F + 20AC 0081 201A 0192 201E 2026 2020 2021 02C6 2030 0160 2039 0152 008D 017D 008F + 0090 2018 2019 201C 201D 2022 2013 2014 02DC 2122 0161 203A 0153 009D 017E 0178 + 00A0 00A1 00A2 00A3 00A4 00A5 00A6 00A7 00A8 00A9 00AA 00AB 00AC 00AD 00AE 00AF + 00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00B8 00B9 00BA 00BB 00BC 00BD 00BE 00BF + 00C0 00C1 00C2 00C3 00C4 00C5 00C6 00C7 00C8 00C9 00CA 00CB 00CC 00CD 00CE 00CF + 00D0 00D1 00D2 00D3 00D4 00D5 00D6 00D7 00D8 00D9 00DA 00DB 00DC 00DD 00DE 00DF + 00E0 00E1 00E2 00E3 00E4 00E5 00E6 00E7 00E8 00E9 00EA 00EB 00EC 00ED 00EE 00EF + 00F0 00F1 00F2 00F3 00F4 00F5 00F6 00F7 00F8 00F9 00FA 00FB 00FC 00FD 00FE 00FF +</map> +</unicode> + +<collation name="latin1_test"> +<map> + 00 01 02 03 37 2D 2E 2F 16 05 25 0B 0C 0D 0E 0F + 10 11 12 13 3C 3D 32 26 18 19 3F 27 1C 1D 1E 1F + 40 4F 7F 7B 5B 6C 50 7D 4D 5D 5C 4E 6B 60 4B 61 + F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 7A 5E 4C 7E 6E 6F + 7C C1 C2 C3 C4 C5 C6 C7 C8 C9 D1 D2 D3 D4 D5 D6 + D7 D8 D9 E2 E3 E4 E5 E6 E7 E8 E9 4A E0 5A 5F 6D + 79 81 82 83 84 85 86 87 88 89 91 92 93 94 95 96 + 97 98 99 A2 A3 A4 A5 A6 A7 A8 A9 C0 6A D0 A1 07 + 20 21 22 23 24 15 06 17 28 29 2A 2B 2C 09 0A 1B + 30 31 1A 33 34 35 36 08 38 39 3A 3B 04 14 3E E1 + 41 42 43 44 45 46 47 48 49 51 52 53 54 55 56 57 + 58 59 62 63 64 65 66 67 68 69 70 71 72 73 74 75 + 76 77 78 80 8A 8B 8C 8D 8E 8F 90 9A 9B 9C 9D 9E + 9F A0 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 + B8 B9 BA BB BC BD BE BF CA CB CC CD CE CF DA DB + DC DD DE DF EA EB EC ED EE EF FA FB FC FD FE FF +</map> +</collation> + +</charset> + +</charsets> diff --git a/mysql-test/suite/binlog/r/binlog_row_binlog.result b/mysql-test/suite/binlog/r/binlog_row_binlog.result index f6b5392dbc8..4d32a4f4739 100644 --- a/mysql-test/suite/binlog/r/binlog_row_binlog.result +++ b/mysql-test/suite/binlog/r/binlog_row_binlog.result @@ -1309,3 +1309,27 @@ INSERT INTO test.t1 VALUES (1), (2); CREATE TABLE test.t2 SELECT * FROM test.t1; USE test; DROP TABLES t1, t2; +RESET MASTER; +CREATE TABLE t1 (a INT PRIMARY KEY); +BINLOG ' +3u9kSA8KAAAAZgAAAGoAAAABAAQANS4xLjM1LW1hcmlhLWJldGExLWRlYnVnLWxvZwAAAAAAAAAA +AAAAAAAAAAAAAAAAAADe72RIEzgNAAgAEgAEBAQEEgAAUwAEGggAAAAICAgC +'; +INSERT INTO t1 VALUES (1); +BINLOG ' +3u9kSBMUAAAAKQAAAJEBAAAAABoAAAAAAAAABHRlc3QAAnQxAAEDAAA= +3u9kSBcUAAAAIgAAALMBAAAQABoAAAAAAAEAAf/+AgAAAA== +'; +SHOW BINLOG EVENTS; +Log_name Pos Event_type Server_id End_log_pos Info +# # Format_desc 1 # Server ver: #, Binlog ver: # +# # Query 1 # use `test`; CREATE TABLE t1 (a INT PRIMARY KEY) +# # Query 1 # BEGIN +# # Table_map 1 # table_id: # (test.t1) +# # Write_rows 1 # table_id: # flags: STMT_END_F +# # Query 1 # COMMIT +# # Query 1 # BEGIN +# # Table_map 1 # table_id: # (test.t1) +# # Write_rows 1 # table_id: # flags: STMT_END_F +# # Query 1 # COMMIT +DROP TABLE t1; diff --git a/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_verbose.result b/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_verbose.result new file mode 100644 index 00000000000..2687b21213a --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_verbose.result @@ -0,0 +1,161 @@ +Verbose statements from : write-partial-row.binlog +select replace(txt,'\r', '') as stmt from raw_binlog_rows where txt like '###%'; +stmt +### INSERT INTO mysql.ndb_apply_status +### SET +### @1=1 +### @2=25769803786 +### @3='' +### @4=0 +### @5=0 +### INSERT INTO test.ba +### SET +### @1=3 +### @2=3 +### @3=3 +### INSERT INTO test.ba +### SET +### @1=1 +### @2=1 +### @3=1 +### INSERT INTO test.ba +### SET +### @1=2 +### @2=2 +### @3=2 +### INSERT INTO test.ba +### SET +### @1=4 +### @2=4 +### @3=4 +### INSERT INTO test.ba +### SET +### @1=4 +### @3=40 +### DELETE FROM test.ba +### WHERE +### @1=2 +drop table raw_binlog_rows; +Verbose statements from : write-full-row.binlog +select replace(txt,'\r', '') as stmt from raw_binlog_rows where txt like '###%'; +stmt +### INSERT INTO mysql.ndb_apply_status +### SET +### @1=2 +### @2=25769803786 +### @3='' +### @4=0 +### @5=0 +### INSERT INTO test.ba +### SET +### @1=3 +### @2=3 +### @3=3 +### INSERT INTO test.ba +### SET +### @1=1 +### @2=1 +### @3=1 +### INSERT INTO test.ba +### SET +### @1=2 +### @2=2 +### @3=2 +### INSERT INTO test.ba +### SET +### @1=4 +### @2=4 +### @3=4 +### INSERT INTO test.ba +### SET +### @1=4 +### @2=4 +### @3=40 +### DELETE FROM test.ba +### WHERE +### @1=2 +drop table raw_binlog_rows; +Verbose statements from : update-partial-row.binlog +select replace(txt,'\r', '') as stmt from raw_binlog_rows where txt like '###%'; +stmt +### INSERT INTO mysql.ndb_apply_status +### SET +### @1=3 +### @2=25769803786 +### @3='' +### @4=0 +### @5=0 +### INSERT INTO test.ba +### SET +### @1=3 +### @2=3 +### @3=3 +### INSERT INTO test.ba +### SET +### @1=1 +### @2=1 +### @3=1 +### INSERT INTO test.ba +### SET +### @1=2 +### @2=2 +### @3=2 +### INSERT INTO test.ba +### SET +### @1=4 +### @2=4 +### @3=4 +### UPDATE test.ba +### WHERE +### @1=4 +### @3=4 +### SET +### @1=4 +### @3=40 +### DELETE FROM test.ba +### WHERE +### @1=2 +drop table raw_binlog_rows; +Verbose statements from : update-full-row.binlog +select replace(txt,'\r', '') as stmt from raw_binlog_rows where txt like '###%'; +stmt +### INSERT INTO mysql.ndb_apply_status +### SET +### @1=4 +### @2=25769803786 +### @3='' +### @4=0 +### @5=0 +### INSERT INTO test.ba +### SET +### @1=3 +### @2=3 +### @3=3 +### INSERT INTO test.ba +### SET +### @1=1 +### @2=1 +### @3=1 +### INSERT INTO test.ba +### SET +### @1=2 +### @2=2 +### @3=2 +### INSERT INTO test.ba +### SET +### @1=4 +### @2=4 +### @3=4 +### UPDATE test.ba +### WHERE +### @1=4 +### @2=4 +### @3=4 +### SET +### @1=4 +### @2=4 +### @3=40 +### DELETE FROM test.ba +### WHERE +### @1=2 +drop table raw_binlog_rows; diff --git a/mysql-test/suite/binlog/r/binlog_stm_binlog.result b/mysql-test/suite/binlog/r/binlog_stm_binlog.result index d05d3ccdb7a..eebcfceaa25 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_binlog.result +++ b/mysql-test/suite/binlog/r/binlog_stm_binlog.result @@ -784,3 +784,24 @@ INSERT INTO test.t1 VALUES (1), (2); CREATE TABLE test.t2 SELECT * FROM test.t1; USE test; DROP TABLES t1, t2; +RESET MASTER; +CREATE TABLE t1 (a INT PRIMARY KEY); +BINLOG ' +3u9kSA8KAAAAZgAAAGoAAAABAAQANS4xLjM1LW1hcmlhLWJldGExLWRlYnVnLWxvZwAAAAAAAAAA +AAAAAAAAAAAAAAAAAADe72RIEzgNAAgAEgAEBAQEEgAAUwAEGggAAAAICAgC +'; +INSERT INTO t1 VALUES (1); +BINLOG ' +3u9kSBMUAAAAKQAAAJEBAAAAABoAAAAAAAAABHRlc3QAAnQxAAEDAAA= +3u9kSBcUAAAAIgAAALMBAAAQABoAAAAAAAEAAf/+AgAAAA== +'; +SHOW BINLOG EVENTS; +Log_name Pos Event_type Server_id End_log_pos Info +# # Format_desc 1 # Server ver: #, Binlog ver: # +# # Query 1 # use `test`; CREATE TABLE t1 (a INT PRIMARY KEY) +# # Query 1 # use `test`; INSERT INTO t1 VALUES (1) +# # Query 1 # BEGIN +# # Table_map 1 # table_id: # (test.t1) +# # Write_rows 1 # table_id: # flags: STMT_END_F +# # Query 1 # COMMIT +DROP TABLE t1; diff --git a/mysql-test/suite/binlog/std_data/update-full-row.binlog b/mysql-test/suite/binlog/std_data/update-full-row.binlog Binary files differnew file mode 100644 index 00000000000..866a351033e --- /dev/null +++ b/mysql-test/suite/binlog/std_data/update-full-row.binlog diff --git a/mysql-test/suite/binlog/std_data/update-partial-row.binlog b/mysql-test/suite/binlog/std_data/update-partial-row.binlog Binary files differnew file mode 100644 index 00000000000..67e3611aa3a --- /dev/null +++ b/mysql-test/suite/binlog/std_data/update-partial-row.binlog diff --git a/mysql-test/suite/binlog/std_data/write-full-row.binlog b/mysql-test/suite/binlog/std_data/write-full-row.binlog Binary files differnew file mode 100644 index 00000000000..b9edb89e91a --- /dev/null +++ b/mysql-test/suite/binlog/std_data/write-full-row.binlog diff --git a/mysql-test/suite/binlog/std_data/write-partial-row.binlog b/mysql-test/suite/binlog/std_data/write-partial-row.binlog Binary files differnew file mode 100644 index 00000000000..7424ec4e940 --- /dev/null +++ b/mysql-test/suite/binlog/std_data/write-partial-row.binlog diff --git a/mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_verbose.test b/mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_verbose.test new file mode 100644 index 00000000000..42d92e1a44d --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_verbose.test @@ -0,0 +1,86 @@ +######################################################## +# Test mysqlbinlog command with Ndb produced Binlog +# variants +# +# WHAT +# ==== +# This test aims to check that the mysqlbinlog --verbose +# command can output binlogs in 4 format variants, currently +# used by Ndb +# +# 1) Updates logged as write_row events +# Only primary key and updated columns included in the +# event +# 2) Updates logged as write_row_events +# All columns included in the event +# 3) Updates logged as update_row events +# Only primary key and updated columns included in the +# event +# 4) Updates logged as update_row events +# All columns included in the event +# +# Format variant (1) is the Ndb default. +# Bug#47323 resulted in binlogs generated in format (1) +# being incorrectly parsed by the mysqlbinlog --verbose +# option +# +# HOW +# === +# Row-based binlog files in each format have been +# captured from an Ndb cluster +# These are output using the mysqlbinlog --verbose +# tool and the output is checked. +# +######################################################## + +# We require binlog_format_row as we're independent of binlog format +# and there's no point running the same test 3 times +-- source include/have_binlog_format_row.inc + +--disable_query_log +--let $binlog_file=write-partial-row.binlog +--exec $MYSQL_BINLOG --verbose suite/binlog/std_data/$binlog_file > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql +create table raw_binlog_rows (txt varchar(1000)); +--eval load data local infile '$MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql' into table raw_binlog_rows columns terminated by '\n'; +--remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql +--enable_query_log +--echo Verbose statements from : $binlog_file +# Output --verbose lines, with extra Windows CR's trimmed +select replace(txt,'\r', '') as stmt from raw_binlog_rows where txt like '###%'; +drop table raw_binlog_rows; + +--disable_query_log +--let $binlog_file=write-full-row.binlog +--exec $MYSQL_BINLOG --verbose suite/binlog/std_data/$binlog_file > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql +create table raw_binlog_rows (txt varchar(1000)); +--eval load data local infile '$MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql' into table raw_binlog_rows columns terminated by '\n'; +--remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql +--enable_query_log +--echo Verbose statements from : $binlog_file +# Output --verbose lines, with extra Windows CR's trimmed +select replace(txt,'\r', '') as stmt from raw_binlog_rows where txt like '###%'; +drop table raw_binlog_rows; + +--disable_query_log +--let $binlog_file=update-partial-row.binlog +--exec $MYSQL_BINLOG --verbose suite/binlog/std_data/$binlog_file > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql +create table raw_binlog_rows (txt varchar(1000)); +--eval load data local infile '$MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql' into table raw_binlog_rows columns terminated by '\n'; +--remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql +--enable_query_log +--echo Verbose statements from : $binlog_file +# Output --verbose lines, with extra Windows CR's trimmed +select replace(txt,'\r', '') as stmt from raw_binlog_rows where txt like '###%'; +drop table raw_binlog_rows; + +--disable_query_log +--let $binlog_file=update-full-row.binlog +--exec $MYSQL_BINLOG --verbose suite/binlog/std_data/$binlog_file > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql +create table raw_binlog_rows (txt varchar(1000)); +--eval load data local infile '$MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql' into table raw_binlog_rows columns terminated by '\n'; +--remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql +--enable_query_log +--echo Verbose statements from : $binlog_file +# Output --verbose lines, with extra Windows CR's trimmed +select replace(txt,'\r', '') as stmt from raw_binlog_rows where txt like '###%'; +drop table raw_binlog_rows; diff --git a/mysql-test/suite/binlog/t/binlog_stm_unsafe_warning.test b/mysql-test/suite/binlog/t/binlog_stm_unsafe_warning.test index a5472952f08..21c11d5a3df 100644 --- a/mysql-test/suite/binlog/t/binlog_stm_unsafe_warning.test +++ b/mysql-test/suite/binlog/t/binlog_stm_unsafe_warning.test @@ -94,15 +94,24 @@ DROP TABLE t1; SET GLOBAL log_warnings = @old_log_warnings; -let LOG_ERROR= `SELECT @@GLOBAL.log_error`; +let $log_error_= `SELECT @@GLOBAL.log_error`; +if(!`select LENGTH('$log_error_')`) +{ + # MySQL Server on windows is started with --console and thus + # does not know the location of its .err log, use default location + let $log_error_ = $MYSQLTEST_VARDIR/log/mysqld.1.err; +} +# Assign env variable LOG_ERROR +let LOG_ERROR=$log_error_; --echo # Count the number of times the "Unsafe" message was printed --echo # to the error log. perl; - $log_error= $ENV{'LOG_ERROR'}; + use strict; + my $log_error= $ENV{'LOG_ERROR'} or die "LOG_ERROR not set"; open(FILE, "$log_error") or die("Unable to open $log_error: $!\n"); - $count = () = grep(/Bug#46265/g,<FILE>); + my $count = () = grep(/Bug#46265/g,<FILE>); print "Occurrences: $count\n"; close(FILE); EOF diff --git a/mysql-test/t/ctype_ldml.test b/mysql-test/t/ctype_ldml.test index db9461bfbf7..bc04b93a935 100644 --- a/mysql-test/t/ctype_ldml.test +++ b/mysql-test/t/ctype_ldml.test @@ -86,3 +86,8 @@ select hex(c1) as h, c1 from t1 order by c1, h; select group_concat(hex(c1) order by hex(c1)) from t1 group by c1; select group_concat(c1 order by hex(c1) SEPARATOR '') from t1 group by c1; drop table t1; + +--echo Bug#46448 trailing spaces are not ignored when user collation maps space != 0x20 +set names latin1; +show collation like 'latin1_test'; +select "foo" = "foo " collate latin1_test; diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index b0a3d0feb79..6e39795a5d6 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -1006,3 +1006,51 @@ DROP TABLE t1; ### --echo End of 5.0 tests + +--echo # +--echo # BUG#47280 - strange results from count(*) with order by multiple +--echo # columns without where/group +--echo # + +--echo # +--echo # Initialize test +--echo # + +CREATE TABLE t1 ( + pk INT NOT NULL, + i INT, + PRIMARY KEY (pk) +); +INSERT INTO t1 VALUES (1,11),(2,12),(3,13); + +--echo # +--echo # Start test +--echo # All the following queries shall return 1 record +--echo # + +--echo +--echo # Masking all correct values {11...13} for column i in this result. +--replace_column 2 # +SELECT MAX(pk) as max, i +FROM t1 +ORDER BY max; + +--echo +EXPLAIN +SELECT MAX(pk) as max, i +FROM t1 +ORDER BY max; + +--echo +--echo # Only 11 is correct for collumn i in this result +SELECT MAX(pk) as max, i +FROM t1 +WHERE pk<2 +ORDER BY max; + +--echo # +--echo # Cleanup +--echo # +DROP TABLE t1; + +--echo End of 5.1 tests diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index 5de7c997a24..faeb5ee686a 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -1518,5 +1518,33 @@ CREATE TABLE t3 select * from t1; checksum table t3; drop table t1,t2,t3; + +# +# BUG#47073 - valgrind errs, corruption,failed repair of partition, +# low myisam_sort_buffer_size +# +CREATE TABLE t1(a INT, b CHAR(10), KEY(a), KEY(b)); +INSERT INTO t1 VALUES(1,'0'),(2,'0'),(3,'0'),(4,'0'),(5,'0'), + (6,'0'),(7,'0'); +INSERT INTO t1 SELECT a+10,b FROM t1; +INSERT INTO t1 SELECT a+20,b FROM t1; +INSERT INTO t1 SELECT a+40,b FROM t1; +INSERT INTO t1 SELECT a+80,b FROM t1; +INSERT INTO t1 SELECT a+160,b FROM t1; +INSERT INTO t1 SELECT a+320,b FROM t1; +INSERT INTO t1 SELECT a+640,b FROM t1; +INSERT INTO t1 SELECT a+1280,b FROM t1; +INSERT INTO t1 SELECT a+2560,b FROM t1; +INSERT INTO t1 SELECT a+5120,b FROM t1; +SET myisam_sort_buffer_size=4; +REPAIR TABLE t1; +SET myisam_repair_threads=2; +# May report different values depending on threads activity. +--replace_regex /changed from [0-9]+/changed from #/ +REPAIR TABLE t1; +SET myisam_repair_threads=@@global.myisam_repair_threads; +SET myisam_sort_buffer_size=@@global.myisam_sort_buffer_size; +DROP TABLE t1; + --echo End of 5.1 tests diff --git a/mysql-test/t/order_by.test b/mysql-test/t/order_by.test index cca1e3209cc..ac2bbaaeeac 100644 --- a/mysql-test/t/order_by.test +++ b/mysql-test/t/order_by.test @@ -1402,3 +1402,35 @@ SELECT DISTINCT a FROM t1 WHERE b = 1 ORDER BY c DESC LIMIT 0, 9; SELECT DISTINCT a FROM t1 WHERE b = 1 ORDER BY c DESC LIMIT 0, 9; DROP TABLE t1; + +--echo # +--echo # Bug #43029: FORCE INDEX FOR ORDER BY is ignored when join buffering +--echo # is used +--echo # + +CREATE TABLE t1 (a INT, b INT, KEY (a)); + +INSERT INTO t1 VALUES (0, NULL), (1, NULL), (2, NULL), (3, NULL); +INSERT INTO t1 SELECT a+4, b FROM t1; +INSERT INTO t1 SELECT a+8, b FROM t1; + +CREATE TABLE t2 (a INT, b INT); + +INSERT INTO t2 VALUES (0,NULL), (1,NULL), (2,NULL), (3,NULL), (4,NULL); +INSERT INTO t2 SELECT a+4, b FROM t2; + +--echo # shouldn't have "using filesort" +EXPLAIN +SELECT * FROM t1 FORCE INDEX FOR ORDER BY (a), t2 WHERE t1.a < 2 ORDER BY t1.a; + +--echo # should have "using filesort" +EXPLAIN +SELECT * FROM t1 USE INDEX FOR ORDER BY (a), t2 WHERE t1.a < 2 ORDER BY t1.a; + +--echo # should have "using filesort" +EXPLAIN +SELECT * FROM t1 FORCE INDEX FOR JOIN (a), t2 WHERE t1.a < 2 ORDER BY t1.a; + +DROP TABLE t1, t2; + +--echo End of 5.1 tests diff --git a/mysql-test/t/partition.test b/mysql-test/t/partition.test index c5ed098b678..1dfc53c6232 100644 --- a/mysql-test/t/partition.test +++ b/mysql-test/t/partition.test @@ -62,6 +62,19 @@ SHOW CREATE TABLE t1; DROP TABLE t1; # +# Bug#44059: rec_per_key on empty partition gives weird optimiser results +# +create table t1 (a int, b int, key(a)) +partition by list (a) +( partition p0 values in (1), + partition p1 values in (2)); +insert into t1 values (1,1),(2,1),(2,2),(2,3); +show indexes from t1; +analyze table t1; +show indexes from t1; +drop table t1; + +# # Bug#36001: Partitions: spelling and using some error messages # --error ER_FOREIGN_KEY_ON_PARTITIONED diff --git a/mysql-test/t/partition_open_files_limit-master.opt b/mysql-test/t/partition_open_files_limit-master.opt new file mode 100644 index 00000000000..4c1ed0c3da3 --- /dev/null +++ b/mysql-test/t/partition_open_files_limit-master.opt @@ -0,0 +1 @@ +--open-files-limit=5 --max_connections=2 --table_open_cache=1 diff --git a/mysql-test/t/partition_open_files_limit.test b/mysql-test/t/partition_open_files_limit.test new file mode 100644 index 00000000000..e62ebd0ade7 --- /dev/null +++ b/mysql-test/t/partition_open_files_limit.test @@ -0,0 +1,26 @@ +--source include/have_partition.inc + +--disable_warnings +DROP TABLE IF EXISTS `t1`; +--enable_warnings + +# On some platforms the lowest possible open_files_limit is too high... +let $max_open_files_limit= `SELECT @@open_files_limit > 511`; +if ($max_open_files_limit) +{ + skip Need open_files_limit to be lower than 512; +} + +# +--echo # Bug#46922: crash when adding partitions and open_files_limit is reached +# +CREATE TABLE t1 (a INT PRIMARY KEY) +ENGINE=MyISAM PARTITION BY KEY () PARTITIONS 1; +INSERT INTO t1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11); +--echo # if the bug exists, then crash will happen here +--replace_regex /file '.*'/file '<partition file>'/ +--error 23 +ALTER TABLE t1 ADD PARTITION PARTITIONS 511; +--sorted_result +SELECT * FROM t1; +DROP TABLE t1; diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index e1411e7fd46..dc119b6a77e 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -1046,3 +1046,128 @@ explain select * from t2 where a=1000 and b<11; drop table t1, t2; +# +# Bug#42846: wrong result returned for range scan when using covering index +# +CREATE TABLE t1( a INT, b INT, KEY( a, b ) ); + +CREATE TABLE t2( a INT, b INT, KEY( a, b ) ); + +CREATE TABLE t3( a INT, b INT, KEY( a, b ) ); + +INSERT INTO t1( a, b ) +VALUES (0, 1), (1, 2), (1, 4), (2, 3), (5, 0), (9, 7); + +INSERT INTO t2( a, b ) +VALUES ( 1, 1), ( 2, 1), ( 3, 1), ( 4, 1), ( 5, 1), + ( 6, 1), ( 7, 1), ( 8, 1), ( 9, 1), (10, 1), + (11, 1), (12, 1), (13, 1), (14, 1), (15, 1), + (16, 1), (17, 1), (18, 1), (19, 1), (20, 1); + +INSERT INTO t2 SELECT a, 2 FROM t2 WHERE b = 1; +INSERT INTO t2 SELECT a, 3 FROM t2 WHERE b = 1; + +# To make range scan compelling to the optimizer +INSERT INTO t2 SELECT -1, -1 FROM t2; +INSERT INTO t2 SELECT -1, -1 FROM t2; +INSERT INTO t2 SELECT -1, -1 FROM t2; + +INSERT INTO t3 +VALUES (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), + (6, 0), (7, 0), (8, 0), (9, 0), (10, 0); + +# To make range scan compelling to the optimizer +INSERT INTO t3 SELECT * FROM t3 WHERE a = 10; +INSERT INTO t3 SELECT * FROM t3 WHERE a = 10; + + +# +# Problem#1 Test queries. Will give missing results unless Problem#1 is fixed. +# With one exception, they are independent of Problem#2. +# +SELECT * FROM t1 WHERE +3 <= a AND a < 5 OR +5 < a AND b = 3 OR +3 <= a; + +EXPLAIN +SELECT * FROM t1 WHERE +3 <= a AND a < 5 OR +5 < a AND b = 3 OR +3 <= a; + +# Query below: Tests both Problem#1 and Problem#2 (EXPLAIN differs as well) +SELECT * FROM t1 WHERE +3 <= a AND a < 5 OR +5 <= a AND b = 3 OR +3 <= a; + +EXPLAIN +SELECT * FROM t1 WHERE +3 <= a AND a < 5 OR +5 <= a AND b = 3 OR +3 <= a; + +SELECT * FROM t1 WHERE +3 <= a AND a <= 5 OR +5 <= a AND b = 3 OR +3 <= a; + +EXPLAIN +SELECT * FROM t1 WHERE +3 <= a AND a <= 5 OR +5 <= a AND b = 3 OR +3 <= a; + +SELECT * FROM t1 WHERE +3 <= a AND a <= 5 OR +3 <= a; + +EXPLAIN +SELECT * FROM t1 WHERE +3 <= a AND a <= 5 OR +3 <= a; + +# +# Problem#2 Test queries. +# These queries will give missing results if Problem#1 is fixed. +# But Problem#1 also hides this bug. +# +SELECT * FROM t2 WHERE +5 <= a AND a < 10 AND b = 1 OR +15 <= a AND a < 20 AND b = 3 +OR +1 <= a AND b = 1; + +EXPLAIN +SELECT * FROM t2 WHERE +5 <= a AND a < 10 AND b = 1 OR +15 <= a AND a < 20 AND b = 3 +OR +1 <= a AND b = 1; + +SELECT * FROM t2 WHERE +5 <= a AND a < 10 AND b = 2 OR +15 <= a AND a < 20 AND b = 3 +OR +1 <= a AND b = 1; + +EXPLAIN +SELECT * FROM t2 WHERE +5 <= a AND a < 10 AND b = 2 OR +15 <= a AND a < 20 AND b = 3 +OR +1 <= a AND b = 1; + +SELECT * FROM t3 WHERE +5 <= a AND a < 10 AND b = 3 OR +a < 5 OR +a < 10; + +EXPLAIN +SELECT * FROM t3 WHERE +5 <= a AND a < 10 AND b = 3 OR +a < 5 OR +a < 10; + +DROP TABLE t1, t2, t3; diff --git a/mysql-test/t/type_bit.test b/mysql-test/t/type_bit.test index dc5120db430..530389b3ab9 100644 --- a/mysql-test/t/type_bit.test +++ b/mysql-test/t/type_bit.test @@ -397,6 +397,17 @@ insert into t2bit7 values (b'110011011111111'); select bin(a1) from t1bit7, t2bit7 where t1bit7.a1=t2bit7.b1; drop table t1bit7, t2bit7; + +--echo # +--echo # Bug42803: Field_bit does not have unsigned_flag field, +--echo # can lead to bad memory access +--echo # +CREATE TABLE t1 (a BIT(7), b BIT(9), KEY(a, b)); +INSERT INTO t1 VALUES(0, 0), (5, 3), (5, 6), (6, 4), (7, 0); +EXPLAIN SELECT a+0, b+0 FROM t1 WHERE a > 4 and b < 7 ORDER BY 2; +DROP TABLE t1; + + --echo End of 5.0 tests # diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt index 545278485d1..7afb800643c 100755 --- a/mysys/CMakeLists.txt +++ b/mysys/CMakeLists.txt @@ -29,7 +29,7 @@ SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c default.c default_ errors.c hash.c list.c md5.c mf_brkhant.c mf_cache.c mf_dirname.c mf_fn_ext.c mf_format.c mf_getdate.c mf_iocache.c mf_iocache2.c mf_keycache.c mf_keycaches.c mf_loadpath.c mf_pack.c mf_path.c mf_qsort.c mf_qsort2.c - mf_radix.c mf_same.c mf_sort.c mf_soundex.c mf_strip.c mf_arr_appstr.c mf_tempdir.c + mf_radix.c mf_same.c mf_sort.c mf_soundex.c mf_arr_appstr.c mf_tempdir.c mf_tempfile.c mf_unixpath.c mf_wcomp.c mf_wfile.c mulalloc.c my_access.c my_aes.c my_alarm.c my_alloc.c my_append.c my_bit.c my_bitmap.c my_chsize.c my_clock.c my_compress.c my_conio.c my_copy.c my_crc32.c my_create.c my_delete.c diff --git a/mysys/Makefile.am b/mysys/Makefile.am index aedd11dc824..a17b49c93ac 100644 --- a/mysys/Makefile.am +++ b/mysys/Makefile.am @@ -35,7 +35,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \ my_error.c errors.c my_div.c my_messnc.c \ mf_format.c mf_same.c mf_dirname.c mf_fn_ext.c \ my_symlink.c my_symlink2.c \ - mf_pack.c mf_unixpath.c mf_strip.c mf_arr_appstr.c \ + mf_pack.c mf_unixpath.c mf_arr_appstr.c \ mf_wcomp.c mf_wfile.c my_gethwaddr.c \ mf_qsort.c mf_qsort2.c mf_sort.c \ ptr_cmp.c mf_radix.c queues.c my_getncpus.c \ diff --git a/mysys/mf_strip.c b/mysys/mf_strip.c deleted file mode 100644 index b33620b1b2d..00000000000 --- a/mysys/mf_strip.c +++ /dev/null @@ -1,45 +0,0 @@ -/* Copyright (C) 2000 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 - the Free Software Foundation; version 2 of the License. - - 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 */ - -/* T|mmer en str{ng p{ slut_space */ - -#include "mysys_priv.h" - -/* - strip_sp(char * str) - Strips end-space from string and returns new length. -*/ - -size_t strip_sp(register char * str) -{ - reg2 char * found; - reg3 char * start; - - start=found=str; - - while (*str) - { - if (*str != ' ') - { - while (*++str && *str != ' ') {}; - if (!*str) - return (size_t) (str-start); /* Return stringlength */ - } - found=str; - while (*++str == ' ') {}; - } - *found= '\0'; /* Stripp at first space */ - return (size_t) (found-start); -} /* strip_sp */ diff --git a/regex/CMakeLists.txt b/regex/CMakeLists.txt index a3088c00357..2e3b18c7bb0 100755 --- a/regex/CMakeLists.txt +++ b/regex/CMakeLists.txt @@ -18,7 +18,7 @@ SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG -DSAFEMALLOC -DSAFE_MUT INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) -SET(REGEX_SOURCES debug.c regcomp.c regerror.c regexec.c regfree.c reginit.c split.c) +SET(REGEX_SOURCES regcomp.c regerror.c regexec.c regfree.c reginit.c) IF(NOT SOURCE_SUBLIBS) ADD_LIBRARY(regex ${REGEX_SOURCES}) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index df5badccb1e..451631ff373 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -1280,10 +1280,10 @@ void ha_partition::cleanup_new_partition(uint part_count) m_file= m_added_file; m_added_file= NULL; + external_lock(ha_thd(), F_UNLCK); /* delete_table also needed, a bit more complex */ close(); - m_added_file= m_file; m_file= save_m_file; } DBUG_VOID_RETURN; @@ -5011,8 +5011,9 @@ int ha_partition::info(uint flag) If the handler doesn't support statistics, it should set all of the above to 0. - We will allow the first handler to set the rec_per_key and use - this as an estimate on the total table. + We first scans through all partitions to get the one holding most rows. + We will then allow the handler with the most rows to set + the rec_per_key and use this as an estimate on the total table. max_data_file_length: Maximum data file length We ignore it, is only used in @@ -5024,14 +5025,33 @@ int ha_partition::info(uint flag) ref_length: We set this to the value calculated and stored in local object create_time: Creation time of table - Set by first handler - So we calculate these constants by using the variables on the first - handler. + So we calculate these constants by using the variables from the + handler with most rows. */ - handler *file; + handler *file, **file_array; + ulonglong max_records= 0; + uint32 i= 0; + uint32 handler_instance= 0; + + file_array= m_file; + do + { + file= *file_array; + /* Get variables if not already done */ + if (!(flag & HA_STATUS_VARIABLE) || + !bitmap_is_set(&(m_part_info->used_partitions), + (file_array - m_file))) + file->info(HA_STATUS_VARIABLE); + if (file->stats.records > max_records) + { + max_records= file->stats.records; + handler_instance= i; + } + i++; + } while (*(++file_array)); - file= m_file[0]; + file= m_file[handler_instance]; file->info(HA_STATUS_CONST); stats.create_time= file->stats.create_time; ref_length= m_ref_length; diff --git a/sql/log_event.cc b/sql/log_event.cc index d7921ad3c27..0e1500dac39 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1852,6 +1852,7 @@ Rows_log_event::print_verbose_one_row(IO_CACHE *file, table_def *td, { const uchar *value0= value; const uchar *null_bits= value; + uint null_bit_index= 0; char typestr[64]= ""; value+= (m_width + 7) / 8; @@ -1860,7 +1861,8 @@ Rows_log_event::print_verbose_one_row(IO_CACHE *file, table_def *td, for (size_t i= 0; i < td->size(); i ++) { - int is_null= (null_bits[i / 8] >> (i % 8)) & 0x01; + int is_null= (null_bits[null_bit_index / 8] + >> (null_bit_index % 8)) & 0x01; if (bitmap_is_set(cols_bitmap, i) == 0) continue; @@ -1897,6 +1899,8 @@ Rows_log_event::print_verbose_one_row(IO_CACHE *file, table_def *td, } my_b_printf(file, "\n"); + + null_bit_index++; } return value - value0; } @@ -3855,6 +3859,7 @@ bool Format_description_log_event::write(IO_CACHE* file) #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) int Format_description_log_event::do_apply_event(Relay_log_info const *rli) { + int ret= 0; DBUG_ENTER("Format_description_log_event::do_apply_event"); #ifdef USING_TRANSACTIONS @@ -3896,17 +3901,21 @@ int Format_description_log_event::do_apply_event(Relay_log_info const *rli) 0, then 96, then jump to first really asked event (which is >96). So this is ok. */ - DBUG_RETURN(Start_log_event_v3::do_apply_event(rli)); + ret= Start_log_event_v3::do_apply_event(rli); } - DBUG_RETURN(0); + + if (!ret) + { + /* Save the information describing this binlog */ + delete rli->relay_log.description_event_for_exec; + const_cast<Relay_log_info *>(rli)->relay_log.description_event_for_exec= this; + } + + DBUG_RETURN(ret); } int Format_description_log_event::do_update_pos(Relay_log_info *rli) { - /* save the information describing this binlog */ - delete rli->relay_log.description_event_for_exec; - rli->relay_log.description_event_for_exec= this; - if (server_id == (uint32) ::server_id) { /* @@ -7502,6 +7511,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) thd->reset_current_stmt_binlog_row_based(); const_cast<Relay_log_info*>(rli)->cleanup_context(thd, error); thd->is_slave_error= 1; + DBUG_RETURN(error); } /* This code would ideally be placed in do_update_pos() instead, but @@ -7530,6 +7540,14 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) const_cast<Relay_log_info*>(rli)->last_event_start_time= my_time(0); } + if (get_flags(STMT_END_F)) + if (error= rows_event_stmt_cleanup(rli, thd)) + rli->report(ERROR_LEVEL, error, + "Error in %s event: commit of row events failed, " + "table `%s`.`%s`", + get_type_str(), m_table->s->db.str, + m_table->s->table_name.str); + DBUG_RETURN(error); } @@ -7628,33 +7646,19 @@ Rows_log_event::do_update_pos(Relay_log_info *rli) if (get_flags(STMT_END_F)) { - if ((error= rows_event_stmt_cleanup(rli, thd)) == 0) - { - /* - Indicate that a statement is finished. - Step the group log position if we are not in a transaction, - otherwise increase the event log position. - */ - rli->stmt_done(log_pos, when); - - /* - Clear any errors pushed in thd->net.last_err* if for example "no key - found" (as this is allowed). This is a safety measure; apparently - those errors (e.g. when executing a Delete_rows_log_event of a - non-existing row, like in rpl_row_mystery22.test, - thd->net.last_error = "Can't find record in 't1'" and last_errno=1032) - do not become visible. We still prefer to wipe them out. - */ - thd->clear_error(); - } - else - { - rli->report(ERROR_LEVEL, error, - "Error in %s event: commit of row events failed, " - "table `%s`.`%s`", - get_type_str(), m_table->s->db.str, - m_table->s->table_name.str); - } + /* + Indicate that a statement is finished. + Step the group log position if we are not in a transaction, + otherwise increase the event log position. + */ + rli->stmt_done(log_pos, when); + /* + Clear any errors in thd->net.last_err*. It is not known if this is + needed or not. It is believed that any errors that may exist in + thd->net.last_err* are allowed. Examples of errors are "key not + found", which is produced in the test case rpl_row_conflicts.test + */ + thd->clear_error(); } else { diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index f14ebe49706..3389821a718 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -1814,33 +1814,6 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli) const_cast<Relay_log_info*>(rli)->last_event_start_time= my_time(0); } - DBUG_RETURN(0); -} - - -Log_event::enum_skip_reason -Old_rows_log_event::do_shall_skip(Relay_log_info *rli) -{ - /* - If the slave skip counter is 1 and this event does not end a - statement, then we should not start executing on the next event. - Otherwise, we defer the decision to the normal skipping logic. - */ - if (rli->slave_skip_counter == 1 && !get_flags(STMT_END_F)) - return Log_event::EVENT_SKIP_IGNORE; - else - return Log_event::do_shall_skip(rli); -} - -int -Old_rows_log_event::do_update_pos(Relay_log_info *rli) -{ - DBUG_ENTER("Old_rows_log_event::do_update_pos"); - int error= 0; - - DBUG_PRINT("info", ("flags: %s", - get_flags(STMT_END_F) ? "STMT_END_F " : "")); - if (get_flags(STMT_END_F)) { /* @@ -1869,7 +1842,12 @@ Old_rows_log_event::do_update_pos(Relay_log_info *rli) are involved, commit the transaction and flush the pending event to the binlog. */ - error= ha_autocommit_or_rollback(thd, 0); + if (error= ha_autocommit_or_rollback(thd, 0)) + rli->report(ERROR_LEVEL, error, + "Error in %s event: commit of row events failed, " + "table `%s`.`%s`", + get_type_str(), m_table->s->db.str, + m_table->s->table_name.str); /* Now what if this is not a transactional engine? we still need to @@ -1882,33 +1860,51 @@ Old_rows_log_event::do_update_pos(Relay_log_info *rli) */ thd->reset_current_stmt_binlog_row_based(); - rli->cleanup_context(thd, 0); - if (error == 0) - { - /* - Indicate that a statement is finished. - Step the group log position if we are not in a transaction, - otherwise increase the event log position. - */ - rli->stmt_done(log_pos, when); + const_cast<Relay_log_info*>(rli)->cleanup_context(thd, 0); + } - /* - Clear any errors pushed in thd->net.client_last_err* if for - example "no key found" (as this is allowed). This is a safety - measure; apparently those errors (e.g. when executing a - Delete_rows_log_event_old of a non-existing row, like in - rpl_row_mystery22.test, thd->net.last_error = "Can't - find record in 't1'" and last_errno=1032) do not become - visible. We still prefer to wipe them out. - */ - thd->clear_error(); - } - else - rli->report(ERROR_LEVEL, error, - "Error in %s event: commit of row events failed, " - "table `%s`.`%s`", - get_type_str(), m_table->s->db.str, - m_table->s->table_name.str); + DBUG_RETURN(error); +} + + +Log_event::enum_skip_reason +Old_rows_log_event::do_shall_skip(Relay_log_info *rli) +{ + /* + If the slave skip counter is 1 and this event does not end a + statement, then we should not start executing on the next event. + Otherwise, we defer the decision to the normal skipping logic. + */ + if (rli->slave_skip_counter == 1 && !get_flags(STMT_END_F)) + return Log_event::EVENT_SKIP_IGNORE; + else + return Log_event::do_shall_skip(rli); +} + +int +Old_rows_log_event::do_update_pos(Relay_log_info *rli) +{ + DBUG_ENTER("Old_rows_log_event::do_update_pos"); + int error= 0; + + DBUG_PRINT("info", ("flags: %s", + get_flags(STMT_END_F) ? "STMT_END_F " : "")); + + if (get_flags(STMT_END_F)) + { + /* + Indicate that a statement is finished. + Step the group log position if we are not in a transaction, + otherwise increase the event log position. + */ + rli->stmt_done(log_pos, when); + /* + Clear any errors in thd->net.last_err*. It is not known if this is + needed or not. It is believed that any errors that may exist in + thd->net.last_err* are allowed. Examples of errors are "key not + found", which is produced in the test case rpl_row_conflicts.test + */ + thd->clear_error(); } else { diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 1ce6bf0df8a..e4effd12af7 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -2435,6 +2435,7 @@ inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr) table->tablenr= tablenr; table->map= (table_map) 1 << tablenr; table->force_index= table_list->force_index; + table->force_index_order= table->force_index_group= 0; table->covering_keys= table->s->keys_for_keyread; table->merge_keys.clear_all(); } diff --git a/sql/mysql_priv.h.pp b/sql/mysql_priv.h.pp index 8bb31f64587..d874a2591d1 100644 --- a/sql/mysql_priv.h.pp +++ b/sql/mysql_priv.h.pp @@ -773,7 +773,6 @@ extern int wild_compare(const char *str,const char *wildstr, extern WF_PACK *wf_comp(char * str); extern int wf_test(struct wild_file_pack *wf_pack,const char *name); extern void wf_end(struct wild_file_pack *buffer); -extern size_t strip_sp(char * str); extern my_bool array_append_string_unique(const char *str, const char **array, size_t size); extern void get_date(char * to,int timeflag,time_t use_time); diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 05575e2744b..119f90bc97a 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -5876,6 +5876,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, if (type == Item_func::LT_FUNC && (value->val_int() > 0)) type = Item_func::LE_FUNC; else if (type == Item_func::GT_FUNC && + (field->type() != FIELD_TYPE_BIT) && !((Field_num*)field)->unsigned_flag && !((Item_int*)value)->unsigned_flag && (value->val_int() < 0)) @@ -5913,7 +5914,9 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, */ if (field->result_type() == INT_RESULT && value->result_type() == INT_RESULT && - ((Field_num*)field)->unsigned_flag && !((Item_int*)value)->unsigned_flag) + ((field->type() == FIELD_TYPE_BIT || + ((Field_num *) field)->unsigned_flag) && + !((Item_int*) value)->unsigned_flag)) { longlong item_val= value->val_int(); if (item_val < 0) @@ -6509,6 +6512,63 @@ get_range(SEL_ARG **e1,SEL_ARG **e2,SEL_ARG *root1) } +/** + Combine two range expression under a common OR. On a logical level, the + transformation is key_or( expr1, expr2 ) => expr1 OR expr2. + + Both expressions are assumed to be in the SEL_ARG format. In a logic sense, + theformat is reminiscent of DNF, since an expression such as the following + + ( 1 < kp1 < 10 AND p1 ) OR ( 10 <= kp2 < 20 AND p2 ) + + where there is a key consisting of keyparts ( kp1, kp2, ..., kpn ) and p1 + and p2 are valid SEL_ARG expressions over keyparts kp2 ... kpn, is a valid + SEL_ARG condition. The disjuncts appear ordered by the minimum endpoint of + the first range and ranges must not overlap. It follows that they are also + ordered by maximum endpoints. Thus + + ( 1 < kp1 <= 2 AND ( kp2 = 2 OR kp2 = 3 ) ) OR kp1 = 3 + + Is a a valid SER_ARG expression for a key of at least 2 keyparts. + + For simplicity, we will assume that expr2 is a single range predicate, + i.e. on the form ( a < x < b AND ... ). It is easy to generalize to a + disjunction of several predicates by subsequently call key_or for each + disjunct. + + The algorithm iterates over each disjunct of expr1, and for each disjunct + where the first keypart's range overlaps with the first keypart's range in + expr2: + + If the predicates are equal for the rest of the keyparts, or if there are + no more, the range in expr2 has its endpoints copied in, and the SEL_ARG + node in expr2 is deallocated. If more ranges became connected in expr1, the + surplus is also dealocated. If they differ, two ranges are created. + + - The range leading up to the overlap. Empty if endpoints are equal. + + - The overlapping sub-range. May be the entire range if they are equal. + + Finally, there may be one more range if expr2's first keypart's range has a + greater maximum endpoint than the last range in expr1. + + For the overlapping sub-range, we recursively call key_or. Thus in order to + compute key_or of + + (1) ( 1 < kp1 < 10 AND 1 < kp2 < 10 ) + + (2) ( 2 < kp1 < 20 AND 4 < kp2 < 20 ) + + We create the ranges 1 < kp <= 2, 2 < kp1 < 10, 10 <= kp1 < 20. For the + first one, we simply hook on the condition for the second keypart from (1) + : 1 < kp2 < 10. For the second range 2 < kp1 < 10, key_or( 1 < kp2 < 10, 4 + < kp2 < 20 ) is called, yielding 1 < kp2 < 20. For the last range, we reuse + the range 4 < kp2 < 20 from (2) for the second keypart. The result is thus + + ( 1 < kp1 <= 2 AND 1 < kp2 < 10 ) OR + ( 2 < kp1 < 10 AND 1 < kp2 < 20 ) OR + ( 10 <= kp1 < 20 AND 4 < kp2 < 20 ) +*/ static SEL_ARG * key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) { @@ -6660,7 +6720,21 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) key1=key1->tree_delete(save); } last->copy_min(tmp); - if (last->copy_min(key2) || last->copy_max(key2)) + bool full_range= last->copy_min(key2); + if (!full_range) + { + if (last->next && key2->cmp_max_to_min(last->next) >= 0) + { + last->max_value= last->next->min_value; + if (last->next->min_flag & NEAR_MIN) + last->max_flag&= ~NEAR_MAX; + else + last->max_flag|= NEAR_MAX; + } + else + full_range= last->copy_max(key2); + } + if (full_range) { // Full range key1->free_tree(); for (; key2 ; key2=key2->next) @@ -6670,8 +6744,6 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) return 0; } } - key2=key2->next; - continue; } if (cmp >= 0 && tmp->cmp_min_to_min(key2) < 0) diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index 8e7265ba1ad..e009cf1ca9f 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -97,7 +97,8 @@ static ulonglong get_exact_record_count(TABLE_LIST *tables) @note This function is only called for queries with sum functions and no - GROUP BY part. + GROUP BY part. This means that the result set shall contain a single + row only @retval 0 no errors diff --git a/sql/slave.cc b/sql/slave.cc index 82c9d035fd2..9718b54ea9e 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2082,8 +2082,7 @@ static int has_temporary_error(THD *thd) @retval 2 No error calling ev->apply_event(), but error calling ev->update_pos(). */ -int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli, - bool skip) +int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli) { int exec_res= 0; @@ -2128,37 +2127,33 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli, ev->when= my_time(0); ev->thd = thd; // because up to this point, ev->thd == 0 - if (skip) - { - int reason= ev->shall_skip(rli); - if (reason == Log_event::EVENT_SKIP_COUNT) - --rli->slave_skip_counter; - pthread_mutex_unlock(&rli->data_lock); - if (reason == Log_event::EVENT_SKIP_NOT) - exec_res= ev->apply_event(rli); + int reason= ev->shall_skip(rli); + if (reason == Log_event::EVENT_SKIP_COUNT) + --rli->slave_skip_counter; + pthread_mutex_unlock(&rli->data_lock); + if (reason == Log_event::EVENT_SKIP_NOT) + exec_res= ev->apply_event(rli); + #ifndef DBUG_OFF - /* - This only prints information to the debug trace. + /* + This only prints information to the debug trace. - TODO: Print an informational message to the error log? - */ - static const char *const explain[] = { - // EVENT_SKIP_NOT, - "not skipped", - // EVENT_SKIP_IGNORE, - "skipped because event should be ignored", - // EVENT_SKIP_COUNT - "skipped because event skip counter was non-zero" - }; - DBUG_PRINT("info", ("OPTION_BEGIN: %d; IN_STMT: %d", - thd->options & OPTION_BEGIN ? 1 : 0, - rli->get_flag(Relay_log_info::IN_STMT))); - DBUG_PRINT("skip_event", ("%s event was %s", - ev->get_type_str(), explain[reason])); + TODO: Print an informational message to the error log? + */ + static const char *const explain[] = { + // EVENT_SKIP_NOT, + "not skipped", + // EVENT_SKIP_IGNORE, + "skipped because event should be ignored", + // EVENT_SKIP_COUNT + "skipped because event skip counter was non-zero" + }; + DBUG_PRINT("info", ("OPTION_BEGIN: %d; IN_STMT: %d", + thd->options & OPTION_BEGIN ? 1 : 0, + rli->get_flag(Relay_log_info::IN_STMT))); + DBUG_PRINT("skip_event", ("%s event was %s", + ev->get_type_str(), explain[reason])); #endif - } - else - exec_res= ev->apply_event(rli); DBUG_PRINT("info", ("apply_event error = %d", exec_res)); if (exec_res == 0) @@ -2278,7 +2273,7 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) delete ev; DBUG_RETURN(1); } - exec_res= apply_event_and_update_pos(ev, thd, rli, TRUE); + exec_res= apply_event_and_update_pos(ev, thd, rli); /* Format_description_log_event should not be deleted because it will be diff --git a/sql/slave.h b/sql/slave.h index a44a7eed83e..f356d28b626 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -190,8 +190,7 @@ int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset, void set_slave_thread_options(THD* thd); void set_slave_thread_default_charset(THD *thd, Relay_log_info const *rli); void rotate_relay_log(Master_info* mi); -int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli, - bool skip); +int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli); pthread_handler_t handle_slave_io(void *arg); pthread_handler_t handle_slave_sql(void *arg); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index d1e96fcdbb3..e706bd04ea6 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2305,7 +2305,8 @@ bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list, bool link_in) table->tablenr=thd->current_tablenr++; table->used_fields=0; table->const_table=0; - table->null_row= table->maybe_null= table->force_index= 0; + table->null_row= table->maybe_null= 0; + table->force_index= table->force_index_order= table->force_index_group= 0; table->status=STATUS_NO_RECORD; DBUG_RETURN(FALSE); } @@ -2963,7 +2964,8 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, table->tablenr=thd->current_tablenr++; table->used_fields=0; table->const_table=0; - table->null_row= table->maybe_null= table->force_index= 0; + table->null_row= table->maybe_null= 0; + table->force_index= table->force_index_order= table->force_index_group= 0; table->status=STATUS_NO_RECORD; table->insert_values= 0; table->fulltext_searched= 0; diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc index 96e99b57e3c..ee51480411b 100644 --- a/sql/sql_binlog.cc +++ b/sql/sql_binlog.cc @@ -56,17 +56,20 @@ void mysql_client_binlog_statement(THD* thd) Format_description_event. */ my_bool have_fd_event= TRUE; - if (!thd->rli_fake) + int err; + Relay_log_info *rli; + rli= thd->rli_fake; + if (!rli) { - thd->rli_fake= new Relay_log_info; + rli= thd->rli_fake= new Relay_log_info; #ifdef HAVE_purify - thd->rli_fake->is_fake= TRUE; + rli->is_fake= TRUE; #endif have_fd_event= FALSE; } - if (thd->rli_fake && !thd->rli_fake->relay_log.description_event_for_exec) + if (rli && !rli->relay_log.description_event_for_exec) { - thd->rli_fake->relay_log.description_event_for_exec= + rli->relay_log.description_event_for_exec= new Format_description_log_event(4); have_fd_event= FALSE; } @@ -78,16 +81,16 @@ void mysql_client_binlog_statement(THD* thd) /* Out of memory check */ - if (!(thd->rli_fake && - thd->rli_fake->relay_log.description_event_for_exec && + if (!(rli && + rli->relay_log.description_event_for_exec && buf)) { my_error(ER_OUTOFMEMORY, MYF(0), 1); /* needed 1 bytes */ goto end; } - thd->rli_fake->sql_thd= thd; - thd->rli_fake->no_storage= TRUE; + rli->sql_thd= thd; + rli->no_storage= TRUE; for (char const *strptr= thd->lex->comment.str ; strptr < thd->lex->comment.str + thd->lex->comment.length ; ) @@ -170,8 +173,7 @@ void mysql_client_binlog_statement(THD* thd) } ev= Log_event::read_log_event(bufptr, event_len, &error, - thd->rli_fake->relay_log. - description_event_for_exec); + rli->relay_log.description_event_for_exec); DBUG_PRINT("info",("binlog base64 err=%s", error)); if (!ev) @@ -209,18 +211,10 @@ void mysql_client_binlog_statement(THD* thd) reporting. */ #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) - if (apply_event_and_update_pos(ev, thd, thd->rli_fake, FALSE)) - { - delete ev; - /* - TODO: Maybe a better error message since the BINLOG statement - now contains several events. - */ - my_error(ER_UNKNOWN_ERROR, MYF(0), "Error executing BINLOG statement"); - goto end; - } + err= ev->apply_event(rli); +#else + err= 0; #endif - /* Format_description_log_event should not be deleted because it will be used to read info about the relay log's format; it @@ -228,8 +222,17 @@ void mysql_client_binlog_statement(THD* thd) i.e. when this thread terminates. */ if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT) - delete ev; + delete ev; ev= 0; + if (err) + { + /* + TODO: Maybe a better error message since the BINLOG statement + now contains several events. + */ + my_error(ER_UNKNOWN_ERROR, MYF(0), "Error executing BINLOG statement"); + goto end; + } } } @@ -238,7 +241,7 @@ void mysql_client_binlog_statement(THD* thd) my_ok(thd); end: - thd->rli_fake->clear_tables_to_lock(); + rli->clear_tables_to_lock(); my_free(buf, MYF(MY_ALLOW_ZERO_PTR)); DBUG_VOID_RETURN; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 3dc6a49e964..bb5c700e4dc 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2647,7 +2647,32 @@ public: MI_COLUMNDEF *recinfo,*start_recinfo; KEY *keyinfo; ha_rows end_write_records; - uint field_count,sum_func_count,func_count; + /** + Number of normal fields in the query, including those referred to + from aggregate functions. Hence, "SELECT `field1`, + SUM(`field2`) from t1" sets this counter to 2. + + @see count_field_types + */ + uint field_count; + /** + Number of fields in the query that have functions. Includes both + aggregate functions (e.g., SUM) and non-aggregates (e.g., RAND). + Also counts functions referred to from aggregate functions, i.e., + "SELECT SUM(RAND())" sets this counter to 2. + + @see count_field_types + */ + uint func_count; + /** + Number of fields in the query that have aggregate functions. Note + that the optimizer may choose to optimize away these fields by + replacing them with constants, in which case sum_func_count will + need to be updated. + + @see opt_sum_query, count_field_types + */ + uint sum_func_count; uint hidden_field_count; uint group_parts,group_length,group_null_parts; uint quick_group; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 06220ffe8c0..eb9c726f6ef 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -6330,6 +6330,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, ptr->table_name_length=table->table.length; ptr->lock_type= lock_type; ptr->updating= test(table_options & TL_OPTION_UPDATING); + /* TODO: remove TL_OPTION_FORCE_INDEX as it looks like it's not used */ ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX); ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES); ptr->derived= table->sel; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 952d1b83ce6..22913c75d48 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -647,8 +647,11 @@ JOIN::prepare(Item ***rref_pointer_array, this->group= group_list != 0; unit= unit_arg; + if (tmp_table_param.sum_func_count && !group_list) + implicit_grouping= TRUE; + #ifdef RESTRICTED_GROUP - if (sum_func_count && !group_list && (func_count || field_count)) + if (implicit_grouping) { my_message(ER_WRONG_SUM_SELECT,ER(ER_WRONG_SUM_SELECT),MYF(0)); goto err; @@ -884,15 +887,23 @@ JOIN::optimize() } #endif - /* Optimize count(*), min() and max() */ - if (tables_list && tmp_table_param.sum_func_count && ! group_list) + /* + Try to optimize count(*), min() and max() to const fields if + there is implicit grouping (aggregate functions but no + group_list). In this case, the result set shall only contain one + row. + */ + if (tables_list && implicit_grouping) { int res; /* opt_sum_query() returns HA_ERR_KEY_NOT_FOUND if no rows match to the WHERE conditions, - or 1 if all items were resolved, + or 1 if all items were resolved (optimized away), or 0, or an error number HA_ERR_... + + If all items were resolved by opt_sum_query, there is no need to + open any tables. */ if ((res=opt_sum_query(select_lex->leaf_tables, all_fields, conds))) { @@ -1234,13 +1245,22 @@ JOIN::optimize() (!group_list && tmp_table_param.sum_func_count)) order=0; - // Can't use sort on head table if using row cache + // Can't use sort on head table if using join buffering if (full_join) { - if (group_list) - simple_group=0; - if (order) - simple_order=0; + TABLE *stable= (sort_by_table == (TABLE *) 1 ? + join_tab[const_tables].table : sort_by_table); + /* + FORCE INDEX FOR ORDER BY can be used to prevent join buffering when + sorting on the first table. + */ + if (!stable || !stable->force_index_order) + { + if (group_list) + simple_group= 0; + if (order) + simple_order= 0; + } } /* @@ -2018,7 +2038,8 @@ JOIN::exec() count_field_types(select_lex, &curr_join->tmp_table_param, *curr_all_fields, 0); - if (curr_join->group || curr_join->tmp_table_param.sum_func_count || + if (curr_join->group || curr_join->implicit_grouping || + curr_join->tmp_table_param.sum_func_count || (procedure && (procedure->flags & PROC_GROUP))) { if (make_group_fields(this, curr_join)) @@ -10805,6 +10826,12 @@ Next_select_func setup_end_select_func(JOIN *join) } else { + /* + Choose method for presenting result to user. Use end_send_group + if the query requires grouping (has a GROUP BY clause and/or one or + more aggregate functions). Use end_send if the query should not + be grouped. + */ if ((join->sort_and_group || (join->procedure && join->procedure->flags & PROC_GROUP)) && !tmp_tbl->precomputed_group_by) diff --git a/sql/sql_select.h b/sql/sql_select.h index a0366d47149..92356a4c96f 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -278,7 +278,14 @@ public: TABLE **table,**all_tables,*sort_by_table; uint tables,const_tables; uint send_group_parts; - bool sort_and_group,first_record,full_join,group, no_field_update; + /** + Indicates that grouping will be performed on the result set during + query execution. This field belongs to query execution. + + @see make_group_fields, alloc_group_fields, JOIN::exec + */ + bool sort_and_group; + bool first_record,full_join,group, no_field_update; bool do_send_rows; /** TRUE when we want to resume nested loop iterations when @@ -357,6 +364,8 @@ public: simple_xxxxx is set if ORDER/GROUP BY doesn't include any references to other tables than the first non-constant table in the JOIN. It's also set if ORDER/GROUP BY is empty. + Used for deciding for or against using a temporary table to compute + GROUP/ORDER BY. */ bool simple_order, simple_group; /** @@ -426,6 +435,7 @@ public: tables= 0; const_tables= 0; join_list= 0; + implicit_grouping= FALSE; sort_and_group= 0; first_record= 0; do_send_rows= 1; @@ -531,6 +541,11 @@ public: select_lex == unit->fake_select_lex)); } private: + /** + TRUE if the query contains an aggregate function but has no GROUP + BY clause. + */ + bool implicit_grouping; bool make_simple_join(JOIN *join, TABLE *tmp_table); }; diff --git a/sql/table.cc b/sql/table.cc index 9b27e1f8016..45099c1a4fb 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -4638,7 +4638,8 @@ Item_subselect *TABLE_LIST::containing_subselect() (TABLE_LIST::index_hints). Using the information in this tagged list this function sets the members st_table::keys_in_use_for_query, st_table::keys_in_use_for_group_by, st_table::keys_in_use_for_order_by, - st_table::force_index and st_table::covering_keys. + st_table::force_index, st_table::force_index_order, + st_table::force_index_group and st_table::covering_keys. Current implementation of the runtime does not allow mixing FORCE INDEX and USE INDEX, so this is checked here. Then the FORCE INDEX list @@ -4766,14 +4767,28 @@ bool TABLE_LIST::process_index_hints(TABLE *tbl) } /* process FORCE INDEX as USE INDEX with a flag */ + if (!index_order[INDEX_HINT_FORCE].is_clear_all()) + { + tbl->force_index_order= TRUE; + index_order[INDEX_HINT_USE].merge(index_order[INDEX_HINT_FORCE]); + } + + if (!index_group[INDEX_HINT_FORCE].is_clear_all()) + { + tbl->force_index_group= TRUE; + index_group[INDEX_HINT_USE].merge(index_group[INDEX_HINT_FORCE]); + } + + /* + TODO: get rid of tbl->force_index (on if any FORCE INDEX is specified) and + create tbl->force_index_join instead. + Then use the correct force_index_XX instead of the global one. + */ if (!index_join[INDEX_HINT_FORCE].is_clear_all() || - !index_order[INDEX_HINT_FORCE].is_clear_all() || - !index_group[INDEX_HINT_FORCE].is_clear_all()) + tbl->force_index_group || tbl->force_index_order) { tbl->force_index= TRUE; index_join[INDEX_HINT_USE].merge(index_join[INDEX_HINT_FORCE]); - index_order[INDEX_HINT_USE].merge(index_order[INDEX_HINT_FORCE]); - index_group[INDEX_HINT_USE].merge(index_group[INDEX_HINT_FORCE]); } /* apply USE INDEX */ diff --git a/sql/table.h b/sql/table.h index 40372fa91cf..e4a382c799f 100644 --- a/sql/table.h +++ b/sql/table.h @@ -752,6 +752,18 @@ struct st_table { bytes, it would take up 4. */ my_bool force_index; + + /** + Flag set when the statement contains FORCE INDEX FOR ORDER BY + See TABLE_LIST::process_index_hints(). + */ + my_bool force_index_order; + + /** + Flag set when the statement contains FORCE INDEX FOR GROUP BY + See TABLE_LIST::process_index_hints(). + */ + my_bool force_index_group; my_bool distinct,const_table,no_rows; /** diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index 1117a3d4e70..b5affc20fc3 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -1088,22 +1088,6 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool do_optimize) ha_rows rows= file->state->records; DBUG_ENTER("ha_myisam::repair"); - /* - Normally this method is entered with a properly opened table. If the - repair fails, it can be repeated with more elaborate options. Under - special circumstances it can happen that a repair fails so that it - closed the data file and cannot re-open it. In this case file->dfile - is set to -1. We must not try another repair without an open data - file. (Bug #25289) - */ - if (file->dfile == -1) - { - sql_print_information("Retrying repair of: '%s' failed. " - "Please try REPAIR EXTENDED or myisamchk", - table->s->path.str); - DBUG_RETURN(HA_ADMIN_FAILED); - } - param.db_name= table->s->db.str; param.table_name= table->alias; param.tmpfile_createflag = O_RDWR | O_TRUNC; diff --git a/storage/myisam/mi_check.c b/storage/myisam/mi_check.c index 1c33ffa90f5..8f7b1399aa2 100644 --- a/storage/myisam/mi_check.c +++ b/storage/myisam/mi_check.c @@ -2561,8 +2561,9 @@ err: VOID(my_close(new_file,MYF(0))); VOID(my_raid_delete(param->temp_filename,share->base.raid_chunks, MYF(MY_WME))); - if (info->dfile == new_file) - info->dfile= -1; + if (info->dfile == new_file) /* Retry with key cache */ + if (unlikely(mi_open_datafile(info, share, name, -1))) + param->retry_repair= 0; /* Safety */ } mi_mark_crashed_on_repair(info); } @@ -3095,8 +3096,9 @@ err: VOID(my_close(new_file,MYF(0))); VOID(my_raid_delete(param->temp_filename,share->base.raid_chunks, MYF(MY_WME))); - if (info->dfile == new_file) - info->dfile= -1; + if (info->dfile == new_file) /* Retry with key cache */ + if (unlikely(mi_open_datafile(info, share, name, -1))) + param->retry_repair= 0; /* Safety */ } mi_mark_crashed_on_repair(info); } diff --git a/storage/myisam/sort.c b/storage/myisam/sort.c index f31edbe1249..fb16af9cddf 100644 --- a/storage/myisam/sort.c +++ b/storage/myisam/sort.c @@ -788,7 +788,11 @@ static int NEAR_F merge_many_buff(MI_SORT_PARAM *info, uint keys, cleanup: close_cached_file(to_file); /* This holds old result */ if (to_file == t_file) + { *t_file=t_file2; /* Copy result file */ + t_file->current_pos= &t_file->write_pos; + t_file->current_end= &t_file->write_end; + } DBUG_RETURN(*maxbuffer >= MERGEBUFF2); /* Return 1 if interrupted */ } /* merge_many_buff */ diff --git a/storage/mysql_storage_engine.cmake b/storage/mysql_storage_engine.cmake index bb368494898..af8c3a85cd1 100644 --- a/storage/mysql_storage_engine.cmake +++ b/storage/mysql_storage_engine.cmake @@ -7,6 +7,8 @@ # Remarks: # ${engine}_SOURCES variable containing source files to produce the library must set before # calling this macro +# ${engine}_LIBS variable containing extra libraries to link with may be set + MACRO(MYSQL_STORAGE_ENGINE engine) IF(NOT SOURCE_SUBLIBS) @@ -22,6 +24,9 @@ IF(NOT SOURCE_SUBLIBS) #Create static library. The name of the library is <storage_engine>.lib ADD_LIBRARY(${libname} ${${engine}_SOURCES}) ADD_DEPENDENCIES(${libname} GenError) + IF(${engine}_LIBS) + TARGET_LINK_LIBRARIES(${libname} ${${engine}_LIBS}) + ENDIF(${engine}_LIBS) MESSAGE("build ${engine} as static library") ELSEIF(${ENGINE_BUILD_TYPE} STREQUAL "DYNAMIC") ADD_DEFINITIONS(-DMYSQL_DYNAMIC_PLUGIN) @@ -30,6 +35,9 @@ IF(NOT SOURCE_SUBLIBS) SET(dyn_libname ha_${libname}) ADD_LIBRARY(${dyn_libname} SHARED ${${engine}_SOURCES}) TARGET_LINK_LIBRARIES (${dyn_libname} mysqld) + IF(${engine}_LIBS) + TARGET_LINK_LIBRARIES(${dyn_libname} ${${engine}_LIBS}) + ENDIF(${engine}_LIBS) MESSAGE("build ${engine} as DLL") ENDIF(${ENGINE_BUILD_TYPE} STREQUAL "STATIC") ENDIF(NOT SOURCE_SUBLIBS) diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index 7de00025eda..4f3aaa6f668 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -185,8 +185,8 @@ int my_strnncollsp_simple(CHARSET_INFO * cs, const uchar *a, size_t a_length, } for (end= a + a_length-length; a < end ; a++) { - if (map[*a] != ' ') - return (map[*a] < ' ') ? -swap : swap; + if (map[*a] != map[' ']) + return (map[*a] < map[' ']) ? -swap : swap; } } return res; |