Skip to content

Commit 98cd109

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 2d44cc3 commit 98cd109

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
@@ -3210,12 +3210,16 @@ class Item : public Parse_tree_node {
32103210
bool is_blob_field() const;
32113211

32123212
/// Increment reference count
3213-
void increment_ref_count() { ++m_ref_count; }
3213+
void increment_ref_count() {
3214+
assert(!m_abandoned);
3215+
++m_ref_count;
3216+
}
32143217

32153218
/// Decrement reference count
32163219
uint decrement_ref_count() {
32173220
assert(m_ref_count > 0);
3218-
return --m_ref_count;
3221+
if (--m_ref_count == 0) m_abandoned = true;
3222+
return m_ref_count;
32193223
}
32203224

32213225
protected:
@@ -3435,6 +3439,7 @@ class Item : public Parse_tree_node {
34353439
be unused and can be removed.
34363440
*/
34373441
uint m_ref_count{0};
3442+
bool m_abandoned{false}; ///< true if item has been fully de-referenced
34383443
const bool is_parser_item; ///< true if allocated directly by parser
34393444
int8 is_expensive_cache; ///< Cache of result of is_expensive()
34403445
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
@@ -8268,7 +8268,8 @@ bool find_item_in_list(THD *thd, Item *find, mem_root_deque<Item *> *items,
82688268
Item_field for tables.
82698269
*/
82708270
Item_ident *item_ref = down_cast<Item_ident *>(item);
8271-
if (item_ref->item_name.eq_safe(find_ident->field_name) &&
8271+
if (!my_strcasecmp(system_charset_info, item_ref->field_name,
8272+
find_ident->field_name) &&
82728273
item_ref->table_name != nullptr &&
82738274
!my_strcasecmp(table_alias_charset, item_ref->table_name,
82748275
find_ident->table_name) &&
@@ -9061,6 +9062,11 @@ bool setup_fields(THD *thd, ulong want_privilege, bool allow_sum_func,
90619062
if (!ref.is_null()) {
90629063
ref[0] = item;
90639064
ref.pop_front();
9065+
/*
9066+
Items present in ref_array have a positive reference count since
9067+
removal of unused columns from derived tables depends on this.
9068+
*/
9069+
item->increment_ref_count();
90649070
}
90659071
Item *typed_item = nullptr;
90669072
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)