Fixed LP bug #802860.
This crashing bug could manifest itself at execution of join queries over materialized derived tables with IN subquery predicates in the where clause. If for such a query the optimizer chose to use duplicate weed-out with duplicates in a materialized derived table and chose to employ join cache the the execution could cause a crash of the server. It happened because the JOIN_CACHE::init method assumed that the value of TABLE::file::ref is set at the moment when the method was called for the employed join cache. It's true for regular tables, but it's not true for materialized derived tables that are filled now at the first access to them, i.e. after the JOIN_CACHE::init has done its job. To fix this problem for any ROWID field of materialized derived table the procedure that copies fields from record buffers into the employed join buffer first checks whether the value of TABLE::file::ref has been set for the table, and if it's not so the procedure sets this value.
This commit is contained in:
parent
5ce5e8db92
commit
31edda66fd
@ -4964,4 +4964,40 @@ a
|
||||
SET SESSION join_cache_level = DEFAULT;
|
||||
SET SESSION join_buffer_size = DEFAULT;
|
||||
DROP TABLE t1,t2;
|
||||
#
|
||||
# Bug #802860: crash on join cache + derived + duplicate_weedout
|
||||
#
|
||||
SET SESSION optimizer_switch=
|
||||
'semijoin=on,materialization=off,firstmatch=off,loosescan=off';
|
||||
CREATE TABLE t1 (a int) ;
|
||||
INSERT IGNORE INTO t1 VALUES (0), (1), (0);
|
||||
CREATE TABLE t2 (a int) ;
|
||||
INSERT IGNORE INTO t2 VALUES (0), (3), (0), (2);
|
||||
SET SESSION join_cache_level = 0;
|
||||
EXPLAIN
|
||||
SELECT * FROM (SELECT DISTINCT * FROM t1) t
|
||||
WHERE t.a IN (SELECT t2.a FROM t2);
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t2 ALL NULL NULL NULL NULL 4 Using where; Start temporary
|
||||
1 PRIMARY <derived2> ref key0 key0 5 test.t2.a 2 End temporary
|
||||
2 DERIVED t1 ALL NULL NULL NULL NULL 3 Using temporary
|
||||
SELECT * FROM (SELECT DISTINCT * FROM t1) t
|
||||
WHERE t.a IN (SELECT t2.a FROM t2);
|
||||
a
|
||||
0
|
||||
SET SESSION join_cache_level = 1;
|
||||
EXPLAIN
|
||||
SELECT * FROM (SELECT DISTINCT * FROM t1) t
|
||||
WHERE t.a IN (SELECT t2.a FROM t2);
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY <derived2> ALL key0 NULL NULL NULL 3 Start temporary
|
||||
1 PRIMARY t2 ALL NULL NULL NULL NULL 4 Using where; End temporary; Using join buffer (flat, BNL join)
|
||||
2 DERIVED t1 ALL NULL NULL NULL NULL 3 Using temporary
|
||||
SELECT * FROM (SELECT DISTINCT * FROM t1) t
|
||||
WHERE t.a IN (SELECT t2.a FROM t2);
|
||||
a
|
||||
0
|
||||
SET SESSION join_cache_level = DEFAULT;
|
||||
DROP TABLE t1, t2;
|
||||
SET SESSION optimizer_switch=default;
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
|
@ -3100,5 +3100,40 @@ SET SESSION join_buffer_size = DEFAULT;
|
||||
|
||||
DROP TABLE t1,t2;
|
||||
|
||||
--echo #
|
||||
--echo # Bug #802860: crash on join cache + derived + duplicate_weedout
|
||||
--echo #
|
||||
|
||||
SET SESSION optimizer_switch=
|
||||
'semijoin=on,materialization=off,firstmatch=off,loosescan=off';
|
||||
|
||||
CREATE TABLE t1 (a int) ;
|
||||
INSERT IGNORE INTO t1 VALUES (0), (1), (0);
|
||||
|
||||
CREATE TABLE t2 (a int) ;
|
||||
INSERT IGNORE INTO t2 VALUES (0), (3), (0), (2);
|
||||
|
||||
SET SESSION join_cache_level = 0;
|
||||
|
||||
EXPLAIN
|
||||
SELECT * FROM (SELECT DISTINCT * FROM t1) t
|
||||
WHERE t.a IN (SELECT t2.a FROM t2);
|
||||
SELECT * FROM (SELECT DISTINCT * FROM t1) t
|
||||
WHERE t.a IN (SELECT t2.a FROM t2);
|
||||
|
||||
SET SESSION join_cache_level = 1;
|
||||
|
||||
EXPLAIN
|
||||
SELECT * FROM (SELECT DISTINCT * FROM t1) t
|
||||
WHERE t.a IN (SELECT t2.a FROM t2);
|
||||
SELECT * FROM (SELECT DISTINCT * FROM t1) t
|
||||
WHERE t.a IN (SELECT t2.a FROM t2);
|
||||
|
||||
SET SESSION join_cache_level = DEFAULT;
|
||||
|
||||
DROP TABLE t1, t2;
|
||||
|
||||
SET SESSION optimizer_switch=default;
|
||||
|
||||
# this must be the last command in the file
|
||||
set @@optimizer_switch=@save_optimizer_switch;
|
||||
|
@ -609,8 +609,15 @@ void JOIN_CACHE::create_remaining_fields()
|
||||
if (tab->keep_current_rowid)
|
||||
{
|
||||
copy->str= table->file->ref;
|
||||
if (copy->str)
|
||||
copy->length= table->file->ref_length;
|
||||
copy->type= 0;
|
||||
else
|
||||
{
|
||||
/* This may happen only for materialized derived tables and views */
|
||||
copy->length= 0;
|
||||
copy->str= (uchar *) table;
|
||||
}
|
||||
copy->type= CACHE_ROWID;
|
||||
copy->field= 0;
|
||||
copy->referenced_field_no= 0;
|
||||
length+= copy->length;
|
||||
@ -1326,7 +1333,6 @@ uint JOIN_CACHE::write_record_data(uchar * link, bool *is_full)
|
||||
Field *field= copy->field;
|
||||
if (field && field->maybe_null() && field->is_null())
|
||||
{
|
||||
/* Do not copy a field if its value is null */
|
||||
if (copy->referenced_field_no)
|
||||
copy->offset= 0;
|
||||
continue;
|
||||
@ -1386,6 +1392,18 @@ uint JOIN_CACHE::write_record_data(uchar * link, bool *is_full)
|
||||
cp+= len+2;
|
||||
break;
|
||||
}
|
||||
case CACHE_ROWID:
|
||||
if (!copy->length)
|
||||
{
|
||||
/*
|
||||
This may happen only for ROWID fields of materialized
|
||||
derived tables and views.
|
||||
*/
|
||||
TABLE *table= (TABLE *) copy->str;
|
||||
copy->str= table->file->ref;
|
||||
copy->length= table->file->ref_length;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
/* Copy the entire image of the field from the record buffer */
|
||||
memcpy(cp, copy->str, copy->length);
|
||||
@ -1455,7 +1473,6 @@ uint JOIN_CACHE::write_record_data(uchar * link, bool *is_full)
|
||||
RETURN VALUE
|
||||
none
|
||||
*/
|
||||
|
||||
void JOIN_CACHE::reset(bool for_writing)
|
||||
{
|
||||
pos= buff;
|
||||
|
@ -16,6 +16,7 @@
|
||||
#define CACHE_STRIPPED 2 /* field stripped of trailing spaces */
|
||||
#define CACHE_VARSTR1 3 /* short string value (length takes 1 byte) */
|
||||
#define CACHE_VARSTR2 4 /* long string value (length takes 2 bytes) */
|
||||
#define CACHE_ROWID 5 /* ROWID field */
|
||||
|
||||
/*
|
||||
The CACHE_FIELD structure used to describe fields of records that
|
||||
|
Loading…
x
Reference in New Issue
Block a user