Skip to content

Commit ffbc972

Browse files
committed
Bug#35201901: Server failure of MySQL #3
Two problems were identified for this bug. The first is seen by looking at the reduced query: select subq_1.c1 as c1 from (select subq_0.c0 as c0, subq_0.c0 as c1, 90 as c2, subq_0.c1 as c3 from (select (select v2 from table1) as c0, ref_0.v4 as c1 from table1 as ref_0 ) as subq_0 ) as subq_1 where EXISTS (select subq_1.c0 as c2, case when EXISTS (select (select v0 from table1) as c1 from table1 as ref_8 where EXISTS (select subq_1.c2 as c7 from table1 as ref_9 ) ) then subq_1.c3 end as c5 from table1 as ref_7); In the innermost EXISTS predicate, a column subq_1.c2 is looked up. It is erroneously found as the column subq_1.c0 with alias c2 in the query block of the outermost EXISTS predicate. But this resolving is not according to SQL standard: A table name cannot be part of a column alias, it has to be a simple identifier, and any referencing column must also be a simple identifier. By changing item_ref->item_name to item_ref->field_name in a test in find_item_in_list, we ensure that the match is against a table (view) name and column name and not an alias. But there is also another problem. The EXISTS predicate contains a few selected columns that are resolved and then immediately deleted since they are redundant in EXISTS processing. But if these columns are outer references and defined in a derived table, we may actually de-reference them before the initial reference increment. Thus, those columns are removed before they are possibly used later. This happens to subq_1.c2 which is resolved in the outer-most query block and coming from a derived table. We prevent this problem by incrementing the reference count of selected expressions from derived tables earlier, and we try to prevent this problem from re-occuring by adding an "m_abandoned" field in class Item, which is set to true when the reference count is decremented to zero and prevents the reference count from ever be incremented after that. Change-Id: Idda48ae726a580c1abdc000371b49a753e197bc6
1 parent 2e0d1e3 commit ffbc972

File tree

3 files changed

+14
-8
lines changed

3 files changed

+14
-8
lines changed

sql/item.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3203,12 +3203,16 @@ class Item : public Parse_tree_node {
32033203
bool is_blob_field() const;
32043204

32053205
/// Increment reference count
3206-
void increment_ref_count() { ++m_ref_count; }
3206+
void increment_ref_count() {
3207+
assert(!m_abandoned);
3208+
++m_ref_count;
3209+
}
32073210

32083211
/// Decrement reference count
32093212
uint decrement_ref_count() {
32103213
assert(m_ref_count > 0);
3211-
return --m_ref_count;
3214+
if (--m_ref_count == 0) m_abandoned = true;
3215+
return m_ref_count;
32123216
}
32133217

32143218
protected:
@@ -3428,6 +3432,7 @@ class Item : public Parse_tree_node {
34283432
be unused and can be removed.
34293433
*/
34303434
uint m_ref_count{0};
3435+
bool m_abandoned{false}; ///< true if item has been fully de-referenced
34313436
const bool is_parser_item; ///< true if allocated directly by parser
34323437
int8 is_expensive_cache; ///< Cache of result of is_expensive()
34333438
uint8 m_data_type; ///< Data type assigned to Item

sql/sql_base.cc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8234,7 +8234,8 @@ bool find_item_in_list(THD *thd, Item *find, mem_root_deque<Item *> *items,
82348234
Item_field for tables.
82358235
*/
82368236
Item_ident *item_ref = down_cast<Item_ident *>(item);
8237-
if (item_ref->item_name.eq_safe(find_ident->field_name) &&
8237+
if (!my_strcasecmp(system_charset_info, item_ref->field_name,
8238+
find_ident->field_name) &&
82388239
item_ref->table_name != nullptr &&
82398240
!my_strcasecmp(table_alias_charset, item_ref->table_name,
82408241
find_ident->table_name) &&
@@ -9027,6 +9028,11 @@ bool setup_fields(THD *thd, ulong want_privilege, bool allow_sum_func,
90279028
if (!ref.is_null()) {
90289029
ref[0] = item;
90299030
ref.pop_front();
9031+
/*
9032+
Items present in ref_array have a positive reference count since
9033+
removal of unused columns from derived tables depends on this.
9034+
*/
9035+
item->increment_ref_count();
90309036
}
90319037
Item *typed_item = nullptr;
90329038
if (typed_items != nullptr && typed_it != typed_items->end()) {

sql/sql_resolver.cc

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -281,11 +281,6 @@ bool Query_block::prepare(THD *thd, mem_root_deque<Item *> *insert_field_list) {
281281
insert_field_list, &fields, base_ref_items))
282282
return true;
283283

284-
// Ensure that all selected expressions have a positive reference count
285-
for (auto it : fields) {
286-
it->increment_ref_count();
287-
}
288-
289284
resolve_place = RESOLVE_NONE;
290285

291286
const nesting_map save_allow_sum_func = thd->lex->allow_sum_func;

0 commit comments

Comments
 (0)