#At file:///export/home/jl208045/mysql/wl4800/mysql-next-mr-opt-backporting-wl4800-12430646/ based on revid:guilhem.bichot@stripped
3307 Jorgen Loland 2011-05-16
BUG#12430646 - SEL_ARG::LEFT AND RIGHT POINTERS INCORRECTLY USED.
CRASHES OPTIMIZER TRACING
SEL_ARGs are the building blocks of range conditions. Multiple
conditions are stored as SEL_ARGs in a RedBlack tree, in which
left and righ points to children SEL_ARGs.
When a SEL_ARG does not have a left or right child, left/right
normally points to null_element. This is, however, not the case
with a special SEL_ARG of type MAYBE_KEY. For this type, the
left and right pointers are required to be NULL pointers. This
is inconsistent, but many functions rely on this fact
(e.g. eq_tree(), SEL_ARG::first()).
Two bugs are fixed by this changeset:
1) One of the SEL_ARG constructors did not initialize
prev, next, left and right pointers.
2) and_all_keys() sets left and right pointers to
&null_element for SEL_ARG::MAYBE_KEY even though it is
explicitly stated that these shall be NULL.
@ mysql-test/r/optimizer_trace_bugs.result
New regression test result file for statements that failed with
optimizer tracing enabled.
Added test for BUG#12430646
@ mysql-test/t/optimizer_trace_bugs.test
New regression test file for statements that failed with
optimizer tracing enabled.
Added test for BUG#12430646
@ sql/opt_range.cc
* One of the SEL_ARG constructors did not initialize prev,
next, left and right pointers.
* and_all_keys() sets left and right pointers to &null_element
for SEL_ARG::MAYBE_KEY even though it is explicitly stated
that these shall be NULL.
added:
mysql-test/r/optimizer_trace_bugs.result
mysql-test/t/optimizer_trace_bugs.test
modified:
sql/opt_range.cc
=== added file 'mysql-test/r/optimizer_trace_bugs.result'
--- a/mysql-test/r/optimizer_trace_bugs.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/optimizer_trace_bugs.result 2011-05-16 08:00:59 +0000
@@ -0,0 +1,33 @@
+SET optimizer_trace="enabled=on,end_marker=on,one_line=off";
+#
+# BUG#12430646 - SEL_ARG::LEFT AND RIGHT POINTERS INCORRECTLY
+# USED. CRASHES OPTIMIZER TRACING
+#
+CREATE TABLE t1 (
+a INT,
+b CHAR(2),
+c INT,
+d INT,
+KEY ( c ),
+KEY ( d, a, b ( 2 ) ),
+KEY ( b ( 1 ) )
+);
+INSERT INTO t1 VALUES ( NULL, 'a', 1, 2 ), ( NULL, 'a', 1, 2 ),
+( 1, 'a', 1, 2 ), ( 1, 'a', 1, 2 );
+CREATE TABLE t2 (
+a INT,
+c INT,
+e INT,
+KEY ( e )
+);
+INSERT INTO t2 VALUES ( 1, 1, NULL ), ( 1, 1, NULL );
+SELECT 1
+FROM t1, t2
+WHERE t1.d <> '1' AND t1.b > '1'
+AND t1.a = t2.a AND t1.c = t2.c;
+1
+1
+1
+1
+1
+DROP TABLE t1, t2;
=== added file 'mysql-test/t/optimizer_trace_bugs.test'
--- a/mysql-test/t/optimizer_trace_bugs.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/optimizer_trace_bugs.test 2011-05-16 08:00:59 +0000
@@ -0,0 +1,38 @@
+# Regressiontest for statements that failed with optimizer tracing enabled.
+
+--source include/have_optimizer_trace.inc
+SET optimizer_trace="enabled=on,end_marker=on,one_line=off";
+
+--echo #
+--echo # BUG#12430646 - SEL_ARG::LEFT AND RIGHT POINTERS INCORRECTLY
+--echo # USED. CRASHES OPTIMIZER TRACING
+--echo #
+
+CREATE TABLE t1 (
+ a INT,
+ b CHAR(2),
+ c INT,
+ d INT,
+ KEY ( c ),
+ KEY ( d, a, b ( 2 ) ),
+ KEY ( b ( 1 ) )
+);
+
+INSERT INTO t1 VALUES ( NULL, 'a', 1, 2 ), ( NULL, 'a', 1, 2 ),
+ ( 1, 'a', 1, 2 ), ( 1, 'a', 1, 2 );
+
+CREATE TABLE t2 (
+ a INT,
+ c INT,
+ e INT,
+ KEY ( e )
+);
+
+INSERT INTO t2 VALUES ( 1, 1, NULL ), ( 1, 1, NULL );
+
+SELECT 1
+FROM t1, t2
+WHERE t1.d <> '1' AND t1.b > '1'
+AND t1.a = t2.a AND t1.c = t2.c;
+
+DROP TABLE t1, t2;
=== modified file 'sql/opt_range.cc'
--- a/sql/opt_range.cc 2011-05-13 14:17:54 +0000
+++ b/sql/opt_range.cc 2011-05-16 08:00:59 +0000
@@ -376,7 +376,9 @@ public:
uchar *min_value,*max_value; // Pointer to range
/*
- eq_tree() requires that left == right == 0 if the type is MAYBE_KEY.
+ eq_tree(), first(), last() etc requires that left == right == 0 if the type
+ is MAYBE_KEY. Todo: fix this so SEL_ARGs without R-B children are handled
+ consistently. See related WL#5894
*/
SEL_ARG *left,*right; /* R-B tree children */
SEL_ARG *next,*prev; /* Links for bi-directional interval list */
@@ -396,8 +398,12 @@ public:
SEL_ARG(Field *,const uchar *, const uchar *);
SEL_ARG(Field *field, uint8 part, uchar *min_value, uchar *max_value,
uint8 min_flag, uint8 max_flag, uint8 maybe_flag);
+ /*
+ Used to consturct MAYBE_KEY SEL_ARGs, so left and right must be
+ NULL. See todo for left/right pointers.
+ */
SEL_ARG(enum Type type_arg)
- :min_flag(0),elements(1),use_count(1),left(0),right(0),next_key_part(0),
+ :min_flag(0),elements(1),use_count(1),left(NULL),right(NULL),next_key_part(0),
color(BLACK), type(type_arg)
{}
inline bool is_same(SEL_ARG *arg)
@@ -1797,6 +1803,9 @@ QUICK_RANGE::QUICK_RANGE()
SEL_ARG::SEL_ARG(SEL_ARG &arg) :Sql_alloc()
{
+ DBUG_ASSERT(arg.type != SEL_ARG::MAYBE_KEY); // Would need left=right=NULL
+ left=right= &null_element;
+ prev=next= NULL;
type=arg.type;
min_flag=arg.min_flag;
max_flag=arg.max_flag;
@@ -1815,7 +1824,7 @@ inline void SEL_ARG::make_root()
{
left=right= &null_element;
color=BLACK;
- next=prev=0;
+ next=prev= NULL;
use_count=0; elements=1;
}
@@ -1823,7 +1832,7 @@ SEL_ARG::SEL_ARG(Field *f,const uchar *m
const uchar *max_value_arg)
:min_flag(0), max_flag(0), maybe_flag(0), maybe_null(f->real_maybe_null()),
elements(1), use_count(1), field(f), min_value((uchar*) min_value_arg),
- max_value((uchar*) max_value_arg), next(0),prev(0),
+ max_value((uchar*) max_value_arg), next(NULL),prev(NULL),
next_key_part(0),color(BLACK),type(KEY_RANGE)
{
left=right= &null_element;
@@ -1835,7 +1844,7 @@ SEL_ARG::SEL_ARG(Field *field_,uint8 par
:min_flag(min_flag_),max_flag(max_flag_),maybe_flag(maybe_flag_),
part(part_),maybe_null(field_->real_maybe_null()), elements(1),use_count(1),
field(field_), min_value(min_value_), max_value(max_value_),
- next(0),prev(0),next_key_part(0),color(BLACK),type(KEY_RANGE)
+ next(NULL),prev(NULL),next_key_part(0),color(BLACK),type(KEY_RANGE)
{
left=right= &null_element;
}
@@ -6950,7 +6959,9 @@ and_all_keys(RANGE_OPT_PARAM *param, SEL
}
if (key1->type == SEL_ARG::MAYBE_KEY)
{
- key1->right= key1->left= &null_element;
+ // See todo for left/right pointers
+ DBUG_ASSERT(!key1->left);
+ DBUG_ASSERT(!key1->right);
key1->next= key1->prev= 0;
}
for (next=key1->first(); next ; next=next->next)
Attachment: [text/bzr-bundle] bzr/jorgen.loland@oracle.com-20110516080059-h26nfwvis16hw816.bundle