Commit fef6682b authored by unknown's avatar unknown

Fix LP BUG#613029

Analysis:
There are two code paths through which JOIN::exec may produce
an all-NULL row for an empty result set. One goes via the
function return_zero_rows(), when query processing detectes
early that the where clause is false, the other one is via
do_select() in the case of join execution.

In the case of do_select(), the problem was that the executioner
didn't set TABLE::null_row to 1. As result when sending the only
result row, the evaluation of each field didn't detect that all
non-aggregated fields are NULL, because Field::is_null returned
true, after checking that field->table->null_row was false.

Given that the each non-aggregated field was not considered NULL,
select_result::send_data sent whatever was in the buffer of each
field. However, since there was no actual data in the field buffer,
send_data() accessed and sent whatever junk was in the field's
data buffer.

Solution:
Similar to the analogous case in return_zero_rows() mark all
tables that their current row is NULL before sending the
artificailly created NULL row.
parent dc9ba672
...@@ -1133,3 +1133,55 @@ SELECT * FROM t1 WHERE (2, 0) NOT IN (SELECT min(f3)+f3, min(f4)+f3+max(f4) FROM ...@@ -1133,3 +1133,55 @@ SELECT * FROM t1 WHERE (2, 0) NOT IN (SELECT min(f3)+f3, min(f4)+f3+max(f4) FROM
f1 f2 f1 f2
set @@optimizer_switch=@save_optimizer_switch; set @@optimizer_switch=@save_optimizer_switch;
drop table t1,t2; drop table t1,t2;
#
# LP BUG#613029 Wrong result with materialization and semijoin, and
# valgrind warnings in Protocol::net_store_data with materialization
# for implicit grouping
#
CREATE TABLE t1 (
pk int(11) NOT NULL AUTO_INCREMENT,
f2 int(11) NOT NULL,
f3 varchar(1) NOT NULL,
PRIMARY KEY (pk),
KEY f2 (f2));
INSERT INTO t1 VALUES (1,9,'x');
INSERT INTO t1 VALUES (2,5,'g');
CREATE TABLE t2 (
pk int(11) NOT NULL AUTO_INCREMENT,
f2 int(11) NOT NULL,
f3 varchar(1) NOT NULL,
PRIMARY KEY (pk),
KEY f2 (f2));
INSERT INTO t2 VALUES (1,7,'p');
set @save_optimizer_switch=@@optimizer_switch;
set @@optimizer_switch='materialization=off,semijoin=off';
EXPLAIN
SELECT t1.f3, MAX(t1.f2)
FROM t1, t2
WHERE (t2.pk = t1.pk) AND t2.pk IN (SELECT f2 FROM t1);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
2 DEPENDENT SUBQUERY t1 index_subquery f2 f2 4 func 2 Using index
SELECT t1.f3, MAX(t1.f2)
FROM t1, t2
WHERE (t2.pk = t1.pk) AND t2.pk IN (SELECT f2 FROM t1);
f3 MAX(t1.f2)
NULL NULL
set @@optimizer_switch='materialization=on,semijoin=off';
EXPLAIN
SELECT t1.f3, MAX(t1.f2)
FROM t1, t2
WHERE (t2.pk = t1.pk) AND t2.pk IN (SELECT f2 FROM t1);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 system PRIMARY NULL NULL NULL 1
1 PRIMARY t1 const PRIMARY PRIMARY 4 const 1
2 SUBQUERY t1 index NULL f2 4 NULL 2 Using index
SELECT t1.f3, MAX(t1.f2)
FROM t1, t2
WHERE (t2.pk = t1.pk) AND t2.pk IN (SELECT f2 FROM t1);
f3 MAX(t1.f2)
NULL NULL
TODO: add a test case for semijoin when the wrong result is fixed
set @@optimizer_switch='materialization=off,semijoin=on';
set @@optimizer_switch=@save_optimizer_switch;
drop table t1, t2;
...@@ -906,3 +906,60 @@ SELECT * FROM t1 WHERE (2, 0) NOT IN (SELECT min(f3)+f3, min(f4)+f3+max(f4) FROM ...@@ -906,3 +906,60 @@ SELECT * FROM t1 WHERE (2, 0) NOT IN (SELECT min(f3)+f3, min(f4)+f3+max(f4) FROM
set @@optimizer_switch=@save_optimizer_switch; set @@optimizer_switch=@save_optimizer_switch;
drop table t1,t2; drop table t1,t2;
--echo #
--echo # LP BUG#613029 Wrong result with materialization and semijoin, and
--echo # valgrind warnings in Protocol::net_store_data with materialization
--echo # for implicit grouping
--echo #
CREATE TABLE t1 (
pk int(11) NOT NULL AUTO_INCREMENT,
f2 int(11) NOT NULL,
f3 varchar(1) NOT NULL,
PRIMARY KEY (pk),
KEY f2 (f2));
INSERT INTO t1 VALUES (1,9,'x');
INSERT INTO t1 VALUES (2,5,'g');
CREATE TABLE t2 (
pk int(11) NOT NULL AUTO_INCREMENT,
f2 int(11) NOT NULL,
f3 varchar(1) NOT NULL,
PRIMARY KEY (pk),
KEY f2 (f2));
INSERT INTO t2 VALUES (1,7,'p');
set @save_optimizer_switch=@@optimizer_switch;
set @@optimizer_switch='materialization=off,semijoin=off';
EXPLAIN
SELECT t1.f3, MAX(t1.f2)
FROM t1, t2
WHERE (t2.pk = t1.pk) AND t2.pk IN (SELECT f2 FROM t1);
SELECT t1.f3, MAX(t1.f2)
FROM t1, t2
WHERE (t2.pk = t1.pk) AND t2.pk IN (SELECT f2 FROM t1);
set @@optimizer_switch='materialization=on,semijoin=off';
EXPLAIN
SELECT t1.f3, MAX(t1.f2)
FROM t1, t2
WHERE (t2.pk = t1.pk) AND t2.pk IN (SELECT f2 FROM t1);
SELECT t1.f3, MAX(t1.f2)
FROM t1, t2
WHERE (t2.pk = t1.pk) AND t2.pk IN (SELECT f2 FROM t1);
-- echo TODO: add a test case for semijoin when the wrong result is fixed
-- echo set @@optimizer_switch='materialization=off,semijoin=on';
set @@optimizer_switch=@save_optimizer_switch;
drop table t1, t2;
...@@ -13452,6 +13452,13 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure) ...@@ -13452,6 +13452,13 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
{ {
List<Item> *columns_list= (procedure ? &join->procedure_fields_list : List<Item> *columns_list= (procedure ? &join->procedure_fields_list :
fields); fields);
/*
With implicit grouping all fields of special row produced for an
empty result are NULL. See return_zero_rows() for the same behavior.
*/
for (TABLE_LIST *table= join->select_lex->leaf_tables;
table; table= table->next_leaf)
mark_as_null_row(table->table);
rc= join->result->send_data(*columns_list); rc= join->result->send_data(*columns_list);
} }
} }
......
...@@ -954,8 +954,8 @@ class JOIN :public Sql_alloc ...@@ -954,8 +954,8 @@ class JOIN :public Sql_alloc
bool init_save_join_tab(); bool init_save_join_tab();
bool send_row_on_empty_set() bool send_row_on_empty_set()
{ {
return (do_send_rows && tmp_table_param.sum_func_count != 0 && return (do_send_rows && implicit_grouping &&
!group_list && having_value != Item::COND_FALSE); having_value != Item::COND_FALSE);
} }
bool change_result(select_result *result); bool change_result(select_result *result);
bool is_top_level_join() const bool is_top_level_join() const
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment