mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
MDEV-25108: Running of the EXPLAIN EXTENDED statement produces extra warning in case it is executed in PS (prepared statement) mode
The EXPLAIN EXTENDED statement run as a prepared statement can produce extra warning comparing with a case when EXPLAIN EXTENDED statement is run as a regular statement. For example, the following test case CREATE TABLE t1 (c int); CREATE TABLE t2 (d int); EXPLAIN EXTENDED SELECT (SELECT 1 FROM t2 WHERE d = c) FROM t1; produces the extra warning "Field or reference 'c' of SELECT #2 was resolved in SELECT #1" in case the above mentioned "EXPLAIN EXTENDED" statement is executed in PS mode, that is by submitting the following statements: PREPARE stmt FROM "EXPLAIN EXTENDED SELECT (SELECT 1 FROM t2 WHERE d = c) FROM t1"; EXECUTE stmt; The reason of the extra warning emittion is in a way items are handled (being fixed) during execution of the JOIN::prepare() method. The method Item_field::fix_fields() calls the find_field_in_tables() function in case a field hasn't been associated yet with the item. Implementation of the find_field_in_tables() function first checks whether a table containing the required field was already opened and cached. It is done by checking the data member item->cached_table. This data member is set on handling the PRERARE FROM statement and checked on executing the EXECUTE statement. If the data member item->cached_table is set the find_field_in_tables() function invoked and the mark_select_range_as_dependent() function called if the field is an outer referencee. The mark_select_range_as_dependent() function calls the mark_as_dependent() function that finally invokes the push_warning_printf() function that produces extra warning. To fix the issue, calling of push_warning_printf() is elimited in case it was run indirectly in result of hanlding already opened table from the Item_field::fix_fields() method.
This commit is contained in:
@ -5419,5 +5419,42 @@ id select_type table type possible_keys key key_len ref rows Extra
|
|||||||
DEALLOCATE PREPARE stmt;
|
DEALLOCATE PREPARE stmt;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
#
|
#
|
||||||
|
# MDEV-25108: Running of the EXPLAIN EXTENDED statement produces extra warning
|
||||||
|
# in case it is executed in PS (prepared statement) mode
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (c int);
|
||||||
|
CREATE TABLE t2 (d int);
|
||||||
|
# EXPLAIN EXTENDED in regular way (not PS mode)
|
||||||
|
EXPLAIN EXTENDED SELECT (SELECT 1 FROM t2 WHERE d = c) FROM t1;
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 PRIMARY t1 system NULL NULL NULL NULL 0 0.00 const row not found
|
||||||
|
2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
|
||||||
|
Warnings:
|
||||||
|
Note 1276 Field or reference 'test.t1.c' of SELECT #2 was resolved in SELECT #1
|
||||||
|
Note 1003 select (select 1 from `test`.`t2` where 0) AS `(SELECT 1 FROM t2 WHERE d = c)` from `test`.`t1`
|
||||||
|
SHOW WARNINGS;
|
||||||
|
Level Code Message
|
||||||
|
Note 1276 Field or reference 'test.t1.c' of SELECT #2 was resolved in SELECT #1
|
||||||
|
Note 1003 select (select 1 from `test`.`t2` where 0) AS `(SELECT 1 FROM t2 WHERE d = c)` from `test`.`t1`
|
||||||
|
# Now run the same EXPLAIN EXTENDED in PS mode. Number of warnings
|
||||||
|
# and their content must be the same as in case running the statement
|
||||||
|
# in regular way
|
||||||
|
PREPARE stmt FROM "EXPLAIN EXTENDED SELECT (SELECT 1 FROM t2 WHERE d = c) FROM t1";
|
||||||
|
Warnings:
|
||||||
|
Note 1276 Field or reference 'test.t1.c' of SELECT #2 was resolved in SELECT #1
|
||||||
|
EXECUTE stmt;
|
||||||
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
|
1 PRIMARY t1 system NULL NULL NULL NULL 0 0.00 const row not found
|
||||||
|
2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
|
||||||
|
Warnings:
|
||||||
|
Note 1276 Field or reference 'test.t1.c' of SELECT #2 was resolved in SELECT #1
|
||||||
|
Note 1003 select (select 1 from `test`.`t2` where 0) AS `(SELECT 1 FROM t2 WHERE d = c)` from `test`.`t1`
|
||||||
|
SHOW WARNINGS;
|
||||||
|
Level Code Message
|
||||||
|
Note 1276 Field or reference 'test.t1.c' of SELECT #2 was resolved in SELECT #1
|
||||||
|
Note 1003 select (select 1 from `test`.`t2` where 0) AS `(SELECT 1 FROM t2 WHERE d = c)` from `test`.`t1`
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
DROP TABLE t1, t2;
|
||||||
|
#
|
||||||
# End of 10.2 tests
|
# End of 10.2 tests
|
||||||
#
|
#
|
||||||
|
@ -4926,6 +4926,26 @@ EXECUTE stmt;
|
|||||||
DEALLOCATE PREPARE stmt;
|
DEALLOCATE PREPARE stmt;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-25108: Running of the EXPLAIN EXTENDED statement produces extra warning
|
||||||
|
--echo # in case it is executed in PS (prepared statement) mode
|
||||||
|
--echo #
|
||||||
|
CREATE TABLE t1 (c int);
|
||||||
|
CREATE TABLE t2 (d int);
|
||||||
|
|
||||||
|
--echo # EXPLAIN EXTENDED in regular way (not PS mode)
|
||||||
|
EXPLAIN EXTENDED SELECT (SELECT 1 FROM t2 WHERE d = c) FROM t1;
|
||||||
|
SHOW WARNINGS;
|
||||||
|
|
||||||
|
--echo # Now run the same EXPLAIN EXTENDED in PS mode. Number of warnings
|
||||||
|
--echo # and their content must be the same as in case running the statement
|
||||||
|
--echo # in regular way
|
||||||
|
PREPARE stmt FROM "EXPLAIN EXTENDED SELECT (SELECT 1 FROM t2 WHERE d = c) FROM t1";
|
||||||
|
EXECUTE stmt;
|
||||||
|
SHOW WARNINGS;
|
||||||
|
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
DROP TABLE t1, t2;
|
||||||
--echo #
|
--echo #
|
||||||
--echo # End of 10.2 tests
|
--echo # End of 10.2 tests
|
||||||
--echo #
|
--echo #
|
||||||
|
30
sql/item.cc
30
sql/item.cc
@ -4668,11 +4668,14 @@ bool Item_ref_null_helper::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
|
|||||||
@param resolved_item item which was resolved in outer SELECT(for warning)
|
@param resolved_item item which was resolved in outer SELECT(for warning)
|
||||||
@param mark_item item which should be marked (can be differ in case of
|
@param mark_item item which should be marked (can be differ in case of
|
||||||
substitution)
|
substitution)
|
||||||
|
@param suppress_warning_output flag specifying whether to suppress output of
|
||||||
|
a warning message
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static bool mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
|
static bool mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
|
||||||
Item_ident *resolved_item,
|
Item_ident *resolved_item,
|
||||||
Item_ident *mark_item)
|
Item_ident *mark_item,
|
||||||
|
bool suppress_warning_output)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("mark_as_dependent");
|
DBUG_ENTER("mark_as_dependent");
|
||||||
|
|
||||||
@ -4685,7 +4688,7 @@ static bool mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
|
|||||||
if (current->mark_as_dependent(thd, last,
|
if (current->mark_as_dependent(thd, last,
|
||||||
/** resolved_item psergey-thu **/ mark_item))
|
/** resolved_item psergey-thu **/ mark_item))
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
if (thd->lex->describe & DESCRIBE_EXTENDED)
|
if ((thd->lex->describe & DESCRIBE_EXTENDED) && !suppress_warning_output)
|
||||||
{
|
{
|
||||||
const char *db_name= (resolved_item->db_name ?
|
const char *db_name= (resolved_item->db_name ?
|
||||||
resolved_item->db_name : "");
|
resolved_item->db_name : "");
|
||||||
@ -4714,6 +4717,8 @@ static bool mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
|
|||||||
@param found_item Item which was found during resolving (if resolved
|
@param found_item Item which was found during resolving (if resolved
|
||||||
identifier belongs to VIEW)
|
identifier belongs to VIEW)
|
||||||
@param resolved_item Identifier which was resolved
|
@param resolved_item Identifier which was resolved
|
||||||
|
@param suppress_warning_output flag specifying whether to suppress output of
|
||||||
|
a warning message
|
||||||
|
|
||||||
@note
|
@note
|
||||||
We have to mark all items between current_sel (including) and
|
We have to mark all items between current_sel (including) and
|
||||||
@ -4727,7 +4732,8 @@ void mark_select_range_as_dependent(THD *thd,
|
|||||||
SELECT_LEX *last_select,
|
SELECT_LEX *last_select,
|
||||||
SELECT_LEX *current_sel,
|
SELECT_LEX *current_sel,
|
||||||
Field *found_field, Item *found_item,
|
Field *found_field, Item *found_item,
|
||||||
Item_ident *resolved_item)
|
Item_ident *resolved_item,
|
||||||
|
bool suppress_warning_output)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Go from current SELECT to SELECT where field was resolved (it
|
Go from current SELECT to SELECT where field was resolved (it
|
||||||
@ -4762,7 +4768,7 @@ void mark_select_range_as_dependent(THD *thd,
|
|||||||
found_field->table->map;
|
found_field->table->map;
|
||||||
prev_subselect_item->const_item_cache= 0;
|
prev_subselect_item->const_item_cache= 0;
|
||||||
mark_as_dependent(thd, last_select, current_sel, resolved_item,
|
mark_as_dependent(thd, last_select, current_sel, resolved_item,
|
||||||
dependent);
|
dependent, suppress_warning_output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5228,7 +5234,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
|
|||||||
context->select_lex, this,
|
context->select_lex, this,
|
||||||
((ref_type == REF_ITEM ||
|
((ref_type == REF_ITEM ||
|
||||||
ref_type == FIELD_ITEM) ?
|
ref_type == FIELD_ITEM) ?
|
||||||
(Item_ident*) (*reference) : 0));
|
(Item_ident*) (*reference) : 0), false);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5240,7 +5246,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
|
|||||||
context->select_lex, this,
|
context->select_lex, this,
|
||||||
((ref_type == REF_ITEM || ref_type == FIELD_ITEM) ?
|
((ref_type == REF_ITEM || ref_type == FIELD_ITEM) ?
|
||||||
(Item_ident*) (*reference) :
|
(Item_ident*) (*reference) :
|
||||||
0));
|
0), false);
|
||||||
if (thd->lex->in_sum_func &&
|
if (thd->lex->in_sum_func &&
|
||||||
thd->lex->in_sum_func->nest_level >= select->nest_level)
|
thd->lex->in_sum_func->nest_level >= select->nest_level)
|
||||||
{
|
{
|
||||||
@ -5354,7 +5360,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
|
|||||||
set_max_sum_func_level(thd, select);
|
set_max_sum_func_level(thd, select);
|
||||||
mark_as_dependent(thd, last_checked_context->select_lex,
|
mark_as_dependent(thd, last_checked_context->select_lex,
|
||||||
context->select_lex, rf,
|
context->select_lex, rf,
|
||||||
rf);
|
rf, false);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -5367,7 +5373,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
|
|||||||
set_max_sum_func_level(thd, select);
|
set_max_sum_func_level(thd, select);
|
||||||
mark_as_dependent(thd, last_checked_context->select_lex,
|
mark_as_dependent(thd, last_checked_context->select_lex,
|
||||||
context->select_lex,
|
context->select_lex,
|
||||||
this, (Item_ident*)*reference);
|
this, (Item_ident*)*reference, false);
|
||||||
if (last_checked_context->select_lex->having_fix_field)
|
if (last_checked_context->select_lex->having_fix_field)
|
||||||
{
|
{
|
||||||
Item_ref *rf;
|
Item_ref *rf;
|
||||||
@ -7401,7 +7407,7 @@ public:
|
|||||||
if (tbl->table == item->field->table)
|
if (tbl->table == item->field->table)
|
||||||
{
|
{
|
||||||
if (sel != current_select)
|
if (sel != current_select)
|
||||||
mark_as_dependent(thd, sel, current_select, item, item);
|
mark_as_dependent(thd, sel, current_select, item, item, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7596,7 +7602,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
|
|||||||
((refer_type == REF_ITEM ||
|
((refer_type == REF_ITEM ||
|
||||||
refer_type == FIELD_ITEM) ?
|
refer_type == FIELD_ITEM) ?
|
||||||
(Item_ident*) (*reference) :
|
(Item_ident*) (*reference) :
|
||||||
0));
|
0), false);
|
||||||
/*
|
/*
|
||||||
view reference found, we substituted it instead of this
|
view reference found, we substituted it instead of this
|
||||||
Item, so can quit
|
Item, so can quit
|
||||||
@ -7646,7 +7652,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
|
|||||||
goto error;
|
goto error;
|
||||||
thd->change_item_tree(reference, fld);
|
thd->change_item_tree(reference, fld);
|
||||||
mark_as_dependent(thd, last_checked_context->select_lex,
|
mark_as_dependent(thd, last_checked_context->select_lex,
|
||||||
current_sel, fld, fld);
|
current_sel, fld, fld, false);
|
||||||
/*
|
/*
|
||||||
A reference is resolved to a nest level that's outer or the same as
|
A reference is resolved to a nest level that's outer or the same as
|
||||||
the nest level of the enclosing set function : adjust the value of
|
the nest level of the enclosing set function : adjust the value of
|
||||||
@ -7669,7 +7675,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
|
|||||||
/* Should be checked in resolve_ref_in_select_and_group(). */
|
/* Should be checked in resolve_ref_in_select_and_group(). */
|
||||||
DBUG_ASSERT(*ref && (*ref)->fixed);
|
DBUG_ASSERT(*ref && (*ref)->fixed);
|
||||||
mark_as_dependent(thd, last_checked_context->select_lex,
|
mark_as_dependent(thd, last_checked_context->select_lex,
|
||||||
context->select_lex, this, this);
|
context->select_lex, this, this, false);
|
||||||
/*
|
/*
|
||||||
A reference is resolved to a nest level that's outer or the same as
|
A reference is resolved to a nest level that's outer or the same as
|
||||||
the nest level of the enclosing set function : adjust the value of
|
the nest level of the enclosing set function : adjust the value of
|
||||||
|
@ -6088,7 +6088,8 @@ void mark_select_range_as_dependent(THD *thd,
|
|||||||
st_select_lex *last_select,
|
st_select_lex *last_select,
|
||||||
st_select_lex *current_sel,
|
st_select_lex *current_sel,
|
||||||
Field *found_field, Item *found_item,
|
Field *found_field, Item *found_item,
|
||||||
Item_ident *resolved_item);
|
Item_ident *resolved_item,
|
||||||
|
bool suppress_warning_output);
|
||||||
|
|
||||||
extern Cached_item *new_Cached_item(THD *thd, Item *item,
|
extern Cached_item *new_Cached_item(THD *thd, Item *item,
|
||||||
bool pass_through_ref);
|
bool pass_through_ref);
|
||||||
|
@ -283,7 +283,8 @@ public:
|
|||||||
friend bool Item_ref::fix_fields(THD *, Item **);
|
friend bool Item_ref::fix_fields(THD *, Item **);
|
||||||
friend void mark_select_range_as_dependent(THD*,
|
friend void mark_select_range_as_dependent(THD*,
|
||||||
st_select_lex*, st_select_lex*,
|
st_select_lex*, st_select_lex*,
|
||||||
Field*, Item*, Item_ident*);
|
Field*, Item*, Item_ident*,
|
||||||
|
bool);
|
||||||
friend bool convert_join_subqueries_to_semijoins(JOIN *join);
|
friend bool convert_join_subqueries_to_semijoins(JOIN *join);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -6046,7 +6046,7 @@ find_field_in_tables(THD *thd, Item_ident *item,
|
|||||||
if (!all_merged && current_sel != last_select)
|
if (!all_merged && current_sel != last_select)
|
||||||
{
|
{
|
||||||
mark_select_range_as_dependent(thd, last_select, current_sel,
|
mark_select_range_as_dependent(thd, last_select, current_sel,
|
||||||
found, *ref, item);
|
found, *ref, item, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return found;
|
return found;
|
||||||
|
Reference in New Issue
Block a user