From: Jorgen Loland Date: May 18 2011 11:25am Subject: bzr push into mysql-trunk branch (jorgen.loland:3307 to 3308) Bug#12430646 List-Archive: http://lists.mysql.com/commits/137582 X-Bug: 12430646 Message-Id: <20110518112541.EA01810A3@atum21.norway.sun.com> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 3308 Jorgen Loland 2011-05-18 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 right 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 3307 Jorgen Loland 2011-05-18 Bug#12551047: ASSERTION NO_ASSERT_ON_SYNTAX_ERROR FAILED IN OPT_TRACE_STMT::SYNTAX_ERROR Optimizer tracing: get_best_covering_ror_intersect() was not tested by any existing mtr test case so we had no test case to use with optimizer tracing either. John found a case when doing RQG testing, so now tracing could be fixed and a few test cases added to optimizer_trace_range*.test @ sql/opt_range.cc Fix optimizer tracing in previously untested function get_best_covering_ror_intersect() modified: mysql-test/include/optimizer_trace_range.inc mysql-test/r/optimizer_trace_range_no_prot.result mysql-test/r/optimizer_trace_range_ps_prot.result 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-18 11:25:27 +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-18 11:25:27 +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-18 10:37:05 +0000 +++ b/sql/opt_range.cc 2011-05-18 11:25:27 +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 require that left == right == NULL + 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,10 +398,17 @@ 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 construct MAYBE_KEY and IMPOSSIBLE SEL_ARGs. left and + right is NULL, so this ctor must not be used to create other + SEL_ARG types. 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), - color(BLACK), type(type_arg) - {} + :min_flag(0),elements(1),use_count(1),left(NULL),right(NULL), + next_key_part(0), color(BLACK), type(type_arg) + { + DBUG_ASSERT(type_arg == MAYBE_KEY || type_arg == IMPOSSIBLE); + } inline bool is_same(SEL_ARG *arg) { if (type != arg->type || part != arg->part) @@ -1797,6 +1806,9 @@ QUICK_RANGE::QUICK_RANGE() SEL_ARG::SEL_ARG(SEL_ARG &arg) :Sql_alloc() { + DBUG_ASSERT(arg.type != 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 +1827,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,8 +1835,8 @@ 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), - next_key_part(0),color(BLACK),type(KEY_RANGE) + 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 +1847,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; } @@ -6972,7 +6984,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) No bundle (reason: useless for push emails).