Bug #19434916: FATAL_SIGNAL IN ADD_KEY_EQUAL_FIELDS() WITH

               UPDATE VIEW USING OUTER SUBQUERY

Issue:
-----
While resolving a column which refers to a table/view in an
outer query, it's respecitve item object is marked with the
outer query's select_lex object. But when the column refers
to a view or if the column is part of a subquery in the
HAVING clause, an Item_ref object is created. While the
reference to the outer query is stored by the Item_ref
object, the same is not stored in it's real_item.

This creates a problem with the IN-TO-EXISTS optmization.
When there is an index over the column in the inner query,
it will be considered since the column's real_item object
will be mistaken for a local field. This will lead to a
crash.

SOLUTION:
---------
Under the current design, the only way to fix this issue is
to check the reginfo.join_tab for a NULL value. If yes, the
query should not be worrying about the key use.

The testcase and comments added as part of the fix for
Bug#17766653 have been backported.
parent f83d9e42
/* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. /* Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
...@@ -1072,6 +1072,27 @@ Item_in_subselect::single_value_transformer(JOIN *join, ...@@ -1072,6 +1072,27 @@ Item_in_subselect::single_value_transformer(JOIN *join,
runtime created Ref item which is deleted at the end runtime created Ref item which is deleted at the end
of the statement. Thus one of 'substitution' arguments of the statement. Thus one of 'substitution' arguments
can be broken in case of PS. can be broken in case of PS.
@todo
Why do we use real_item()/substitutional_item() instead of the plain
left_expr?
Because left_expr might be a rollbackable item, and we fail to properly
rollback all copies of left_expr at end of execution, so we want to
avoid creating copies of left_expr as much as possible, so we use
real_item() instead.
Doing a proper rollback is difficult: the change was registered for the
original item which was the left argument of IN. Then this item was
copied to left_expr, which is copied below to substitution->args[0]. To
do a proper rollback, we would have to restore the content
of both copies as well as the original item. There might be more copies,
if AND items have been constructed.
The same applies to the right expression.
However, using real_item()/substitutional_item() brings its own
problems: for example, we lose information that the item is an outer
reference; the item can thus wrongly be considered for a Keyuse (causing
bug#17766653).
When WL#6570 removes the "rolling back" system, all
real_item()/substitutional_item() in this file should be removed.
*/ */
substitution= func->create(left_expr->real_item(), subs); substitution= func->create(left_expr->real_item(), subs);
DBUG_RETURN(RES_OK); DBUG_RETURN(RES_OK);
...@@ -1157,6 +1178,9 @@ Item_in_subselect::single_value_transformer(JOIN *join, ...@@ -1157,6 +1178,9 @@ Item_in_subselect::single_value_transformer(JOIN *join,
} }
else else
{ {
/*
Grep for "WL#6570" to see the relevant comment about real_item.
*/
Item *item= (Item*) select_lex->item_list.head()->real_item(); Item *item= (Item*) select_lex->item_list.head()->real_item();
if (select_lex->table_list.elements) if (select_lex->table_list.elements)
......
...@@ -3335,6 +3335,18 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond, ...@@ -3335,6 +3335,18 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond,
table_map usable_tables, SARGABLE_PARAM **sargables) table_map usable_tables, SARGABLE_PARAM **sargables)
{ {
uint exists_optimize= 0; uint exists_optimize= 0;
if (field->table->reginfo.join_tab == NULL)
{
/*
Due to a bug in IN-to-EXISTS (grep for real_item() in item_subselect.cc
for more info), an index over a field from an outer query might be
considered here, which is incorrect. Their query has been fully
optimized already so their reginfo.join_tab is NULL and we reject them.
*/
return;
}
if (!(field->flags & PART_KEY_FLAG)) if (!(field->flags & PART_KEY_FLAG))
{ {
// Don't remove column IS NULL on a LEFT JOIN table // Don't remove column IS NULL on a LEFT JOIN table
......
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