#At file:///work/bzrroot/43600-bug-azalea/ based on revid:alik@stripped
2825 Evgeny Potemkin 2009-07-28
Bug#43600: Incorrect type conversion caused wrong result.
The index_cond_func_xxx function is used to evaluate pushed index condition or
return an error if the tuple being checked is out of range.
And there are two bugs in it:
1) The function result type is my_bool, but actually it can return 3
values - TRUE/FALSE/OUT OF RANGE.
2) The type of the pushed condition evaluation is converted to my_bool, but
since the evaluation result isn't checked it's possible to return values
other that 0/1, thus falsely returning OUT OF RANGE.
The fix for this bug introduces the enum for the index_cond_func_xxx's
result called ICP_RESULT. It has three values:
0=ICP_NO_MATCH - index tuple doesn't satisfy the pushed index condition (the
engine should discard the tuple and go to the next one)
1=ICP_MATCH - index tuple satisfies the pushed index condition (the engine
should fetch and return the record)
2=ICP_OUT_OF_RANGE - index tuple is out range that we're scanning, e.g. this
if we're scanning "t.key BETWEEN 10 AND 20" and got a
"t.key=21" tuple (the engine should stop scanning and return
HA_ERR_END_OF_FILE right away).
The index_cond_func_myisam and index_cond_func_innodb functions now checking
the pushed condition evaluation result, and making sure that only 0/1 are
returned.
@ include/my_handler.h
Bug#43600: Incorrect type conversion caused wrong result.
The enum for the index_cond_func_xxx's result is introduced.
It's called ICP_RESULT.
@ mysql-test/include/mix1.inc
A test case added for the bug#43600.
@ mysql-test/r/innodb_mysql.result
A test case added for the bug#43600.
@ mysql-test/r/myisam.result
A test case added for the bug#43600.
@ mysql-test/t/myisam.test
A test case added for the bug#43600.
@ storage/innobase/handler/ha_innodb.cc
Bug#43600: Incorrect type conversion caused wrong result.
The result type of the index_cond_func_innodb function
is changed to uint and the result of the pushed condition
evaluation now is checked to make sure that only 0/1 are returned.
@ storage/innobase/include/row0mysql.h
Bug#43600: Incorrect type conversion caused wrong result.
The result type of the index_cond_func_innodb function
is changed to uint.
@ storage/myisam/ha_myisam.cc
Bug#43600: Incorrect type conversion caused wrong result.
The index_cond_func_myisam function now checks the pushed
condition evaluation result, and makes sure that only 0/1 are
returned.
@ storage/myisam/ha_myisam.h
Bug#43600: Incorrect type conversion caused wrong result.
Result type of the index_cond_func_xxx function is changed to the
ICP_RESULT enum.
@ storage/myisam/myisamdef.h
Bug#43600: Incorrect type conversion caused wrong result.
Result type of the index_cond_func_xxx function is changed to the
ICP_RESULT enum.
modified:
include/my_handler.h
mysql-test/include/mix1.inc
mysql-test/r/innodb_mysql.result
mysql-test/r/myisam.result
mysql-test/t/myisam.test
storage/innobase/handler/ha_innodb.cc
storage/innobase/include/row0mysql.h
storage/myisam/ha_myisam.cc
storage/myisam/ha_myisam.h
storage/myisam/myisamdef.h
=== modified file 'include/my_handler.h'
--- a/include/my_handler.h 2008-11-12 15:23:22 +0000
+++ b/include/my_handler.h 2009-07-28 11:37:42 +0000
@@ -123,8 +123,29 @@ extern void my_handler_error_unregister(
this amount of bytes.
*/
#define portable_sizeof_char_ptr 8
+
+/*
+ Return values of index_cond_func_xxx functions.
+
+ 0=ICP_NO_MATCH - index tuple doesn't satisfy the pushed index condition (the
+ engine should discard the tuple and go to the next one)
+ 1=ICP_MATCH - index tuple satisfies the pushed index condition (the engine
+ should fetch and return the record)
+ 2=ICP_OUT_OF_RANGE - index tuple is out range that we're scanning, e.g. this
+ if we're scanning "t.key BETWEEN 10 AND 20" and got a
+ "t.key=21" tuple (the engine should stop scanning and return
+ HA_ERR_END_OF_FILE right away).
+*/
+
+typedef enum icp_result {
+ ICP_NO_MATCH,
+ ICP_MATCH,
+ ICP_OUT_OF_RANGE
+} ICP_RESULT;
+
#ifdef __cplusplus
}
#endif
+
#endif /* _my_handler_h */
=== modified file 'mysql-test/include/mix1.inc'
--- a/mysql-test/include/mix1.inc 2009-07-09 16:11:01 +0000
+++ b/mysql-test/include/mix1.inc 2009-07-28 11:37:42 +0000
@@ -1585,3 +1585,27 @@ SELECT 1 FROM (SELECT COUNT(DISTINCT c1)
DROP TABLE t1;
--echo End of 5.1 tests
+
+--echo #
+--echo # Bug#43600: Incorrect type conversion caused wrong result.
+--echo #
+CREATE TABLE t1 (
+ a int NOT NULL
+) engine= innodb;
+
+CREATE TABLE t2 (
+ a int NOT NULL,
+ b int NOT NULL,
+ filler char(100) DEFAULT NULL,
+ KEY a (a,b)
+) engine= innodb;
+
+insert into t1 values (0),(1),(2),(3),(4);
+insert into t2 select A.a + 10 *B.a, 1, 'filler' from t1 A, t1 B;
+
+explain select * from t1, t2 where t2.a=t1.a and t2.b + 1;
+select * from t1, t2 where t2.a=t1.a and t2.b + 1;
+
+drop table t1,t2;
+--echo # End of test case for the bug#43600
+
=== modified file 'mysql-test/r/innodb_mysql.result'
--- a/mysql-test/r/innodb_mysql.result 2009-07-09 16:11:01 +0000
+++ b/mysql-test/r/innodb_mysql.result 2009-07-28 11:37:42 +0000
@@ -1764,6 +1764,33 @@ id select_type table type possible_keys
2 DERIVED t1 index c3,c2 c2 14 NULL 5
DROP TABLE t1;
End of 5.1 tests
+#
+# Bug#43600: Incorrect type conversion caused wrong result.
+#
+CREATE TABLE t1 (
+a int NOT NULL
+) engine= innodb;
+CREATE TABLE t2 (
+a int NOT NULL,
+b int NOT NULL,
+filler char(100) DEFAULT NULL,
+KEY a (a,b)
+) engine= innodb;
+insert into t1 values (0),(1),(2),(3),(4);
+insert into t2 select A.a + 10 *B.a, 1, 'filler' from t1 A, t1 B;
+explain select * from t1, t2 where t2.a=t1.a and t2.b + 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5
+1 SIMPLE t2 ref a a 4 test.t1.a 1 Using where
+select * from t1, t2 where t2.a=t1.a and t2.b + 1;
+a a b filler
+0 0 1 filler
+1 1 1 filler
+2 2 1 filler
+3 3 1 filler
+4 4 1 filler
+drop table t1,t2;
+# End of test case for the bug#43600
drop table if exists t1, t2, t3;
create table t1(a int);
insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
=== modified file 'mysql-test/r/myisam.result'
--- a/mysql-test/r/myisam.result 2009-06-02 13:04:43 +0000
+++ b/mysql-test/r/myisam.result 2009-07-28 11:37:42 +0000
@@ -2295,3 +2295,30 @@ h+0 d + 0 e g + 0
1 1 4 0
DROP TABLE t1;
End of 5.1 tests
+#
+# Bug#43600: Incorrect type conversion caused wrong result.
+#
+CREATE TABLE t1 (
+a int NOT NULL
+) engine= myisam;
+CREATE TABLE t2 (
+a int NOT NULL,
+b int NOT NULL,
+filler char(100) DEFAULT NULL,
+KEY a (a,b)
+) engine= myisam;
+insert into t1 values (0),(1),(2),(3),(4);
+insert into t2 select A.a + 10 *B.a, 1, 'filler' from t1 A, t1 B;
+explain select * from t1, t2 where t2.a=t1.a and t2.b + 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5
+1 SIMPLE t2 ref a a 4 test.t1.a 1 Using index condition
+select * from t1, t2 where t2.a=t1.a and t2.b + 1;
+a a b filler
+0 0 1 filler
+1 1 1 filler
+2 2 1 filler
+3 3 1 filler
+4 4 1 filler
+drop table t1,t2;
+# End of test case for the bug#43600
=== modified file 'mysql-test/t/myisam.test'
--- a/mysql-test/t/myisam.test 2009-04-30 10:27:29 +0000
+++ b/mysql-test/t/myisam.test 2009-07-28 11:37:42 +0000
@@ -1542,3 +1542,27 @@ SELECT h+0, d + 0, e, g + 0 FROM t1;
DROP TABLE t1;
--echo End of 5.1 tests
+
+--echo #
+--echo # Bug#43600: Incorrect type conversion caused wrong result.
+--echo #
+CREATE TABLE t1 (
+ a int NOT NULL
+) engine= myisam;
+
+CREATE TABLE t2 (
+ a int NOT NULL,
+ b int NOT NULL,
+ filler char(100) DEFAULT NULL,
+ KEY a (a,b)
+) engine= myisam;
+
+insert into t1 values (0),(1),(2),(3),(4);
+insert into t2 select A.a + 10 *B.a, 1, 'filler' from t1 A, t1 B;
+
+explain select * from t1, t2 where t2.a=t1.a and t2.b + 1;
+select * from t1, t2 where t2.a=t1.a and t2.b + 1;
+
+drop table t1,t2;
+--echo # End of test case for the bug#43600
+
=== modified file 'storage/innobase/handler/ha_innodb.cc'
--- a/storage/innobase/handler/ha_innodb.cc 2009-06-25 09:55:58 +0000
+++ b/storage/innobase/handler/ha_innodb.cc 2009-07-28 11:37:42 +0000
@@ -63,7 +63,7 @@ static bool innodb_inited = 0;
static handlerton *innodb_hton_ptr;
C_MODE_START
-static my_bool index_cond_func_innodb(void *arg);
+static uint index_cond_func_innodb(void *arg);
C_MODE_END
@@ -8573,9 +8573,12 @@ ha_rows ha_innobase::multi_range_read_in
C_MODE_START
-/* Index condition check function to be called from within Innobase */
+/*
+ Index condition check function to be called from within Innobase.
+ See note on ICP_RESULT for return values description.
+*/
-static my_bool index_cond_func_innodb(void *arg)
+static uint index_cond_func_innodb(void *arg)
{
ha_innobase *h= (ha_innobase*)arg;
if (h->end_range)
@@ -8583,7 +8586,7 @@ static my_bool index_cond_func_innodb(vo
if (h->compare_key2(h->end_range) > 0)
return 2; /* caller should return HA_ERR_END_OF_FILE already */
}
- return (my_bool)h->pushed_idx_cond->val_int();
+ return test(h->pushed_idx_cond->val_int());
}
C_MODE_END
=== modified file 'storage/innobase/include/row0mysql.h'
--- a/storage/innobase/include/row0mysql.h 2009-06-25 09:55:58 +0000
+++ b/storage/innobase/include/row0mysql.h 2009-07-28 11:37:42 +0000
@@ -524,7 +524,7 @@ struct mysql_row_templ_struct {
#define ROW_PREBUILT_ALLOCATED 78540783
#define ROW_PREBUILT_FREED 26423527
-typedef my_bool (*index_cond_func_t)(void *param);
+typedef uint (*index_cond_func_t)(void *param);
/* A struct for (sometimes lazily) prebuilt structures in an Innobase table
handle used within MySQL; these are used to save CPU time. */
=== modified file 'storage/myisam/ha_myisam.cc'
--- a/storage/myisam/ha_myisam.cc 2009-07-08 12:46:36 +0000
+++ b/storage/myisam/ha_myisam.cc 2009-07-28 11:37:42 +0000
@@ -1522,15 +1522,15 @@ int ha_myisam::delete_row(const uchar *b
C_MODE_START
-my_bool index_cond_func_myisam(void *arg)
+ICP_RESULT index_cond_func_myisam(void *arg)
{
ha_myisam *h= (ha_myisam*)arg;
if (h->end_range)
{
if (h->compare_key2(h->end_range) > 0)
- return 2; /* caller should return HA_ERR_END_OF_FILE already */
+ return ICP_OUT_OF_RANGE; /* caller should return HA_ERR_END_OF_FILE already */
}
- return (my_bool)h->pushed_idx_cond->val_int();
+ return (ICP_RESULT) test(h->pushed_idx_cond->val_int());
}
C_MODE_END
=== modified file 'storage/myisam/ha_myisam.h'
--- a/storage/myisam/ha_myisam.h 2009-07-08 12:46:36 +0000
+++ b/storage/myisam/ha_myisam.h 2009-07-28 11:37:42 +0000
@@ -35,7 +35,7 @@ extern TYPELIB myisam_recover_typelib;
extern ulong myisam_recover_options;
C_MODE_START
-my_bool index_cond_func_myisam(void *arg);
+ICP_RESULT index_cond_func_myisam(void *arg);
C_MODE_END
class ha_myisam: public handler
@@ -168,7 +168,7 @@ public:
Item *idx_cond_push(uint keyno, Item* idx_cond);
private:
DsMrr_impl ds_mrr;
- friend my_bool index_cond_func_myisam(void *arg);
+ friend ICP_RESULT index_cond_func_myisam(void *arg);
};
#if !defined(EMBEDDED_LIBRARY) && defined(HAVE_MYISAM_PHYSICAL_LOGGING)
=== modified file 'storage/myisam/myisamdef.h'
--- a/storage/myisam/myisamdef.h 2009-04-01 21:36:07 +0000
+++ b/storage/myisam/myisamdef.h 2009-07-28 11:37:42 +0000
@@ -256,8 +256,7 @@ typedef struct st_mi_isam_share
my_bool MI_LOG_OPEN_stored_in_physical_log;
} MYISAM_SHARE;
-
-typedef my_bool (*index_cond_func_t)(void *param);
+typedef ICP_RESULT (*index_cond_func_t)(void *param);
/** Information local to the table's instance */
struct st_myisam_info
Attachment: [text/bzr-bundle] bzr/epotemkin@mysql.com-20090728113742-llw1j8l8h66k36xu.bundle