mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
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.
This commit is contained in:
parent
ec23949158
commit
7999f40a99
4 changed files with 118 additions and 2 deletions
|
@ -1133,3 +1133,55 @@ SELECT * FROM t1 WHERE (2, 0) NOT IN (SELECT min(f3)+f3, min(f4)+f3+max(f4) FROM
|
|||
f1 f2
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
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
|
|||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
|
||||
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)
|
|||
{
|
||||
List<Item> *columns_list= (procedure ? &join->procedure_fields_list :
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -954,8 +954,8 @@ public:
|
|||
bool init_save_join_tab();
|
||||
bool send_row_on_empty_set()
|
||||
{
|
||||
return (do_send_rows && tmp_table_param.sum_func_count != 0 &&
|
||||
!group_list && having_value != Item::COND_FALSE);
|
||||
return (do_send_rows && implicit_grouping &&
|
||||
having_value != Item::COND_FALSE);
|
||||
}
|
||||
bool change_result(select_result *result);
|
||||
bool is_top_level_join() const
|
||||
|
|
Loading…
Reference in a new issue