Skip to content

Commit d049cc1

Browse files
committed
Bug#21606400: Segfault in Item_ident::fix_after_pullout with semijoin
The problem here occurs when a subquery's query block is removed during transformation of an IN subquery or a scalar subquery, and semi-join is not applicable, and Item::remove_dependence_processor() is used to modify items below the subquery to be removed. One such item is an Item_direct_ref which is added in the transformation of an IN subquery, see e.g Item_in_subselect::single_value_transformer(). The Item_direct_ref may be created with a dependent_from field pointing to the subquery to be removed. In this case, dependent_from most be moved to the outer query block, but remove_dependence_processor() fails to handle this situation. Luckily, Item_ident::fix_after_pullout() does exactly this, when first making sure that the name resolution contexts of the eliminated query block are merged with its parent. The code snippet that merges name resolution contexts is made into a new member function of SELECT_LEX, named merge_contexts(). Item::remove_dependence_processor() was also deleted.
1 parent f7036e1 commit d049cc1

File tree

5 files changed

+44
-53
lines changed

5 files changed

+44
-53
lines changed

sql/item.cc

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -942,15 +942,6 @@ void Item_ident::cleanup()
942942
DBUG_VOID_RETURN;
943943
}
944944

945-
bool Item_ident::remove_dependence_processor(uchar * arg)
946-
{
947-
DBUG_ENTER("Item_ident::remove_dependence_processor");
948-
if (depended_from == (st_select_lex *) arg)
949-
depended_from= 0;
950-
context= &((st_select_lex *) arg)->context;
951-
DBUG_RETURN(0);
952-
}
953-
954945

955946
/**
956947
Store the pointer to this item field into a list if not already there.

sql/item.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1815,7 +1815,6 @@ class Item : public Parse_tree_node
18151815
*/
18161816
virtual bool intro_version(uchar *int_arg) { return false; }
18171817

1818-
virtual bool remove_dependence_processor(uchar * arg) { return false; }
18191818
virtual bool remove_fixed(uchar * arg) { fixed= 0; return false; }
18201819
virtual bool cleanup_processor(uchar *arg);
18211820
virtual bool collect_item_field_processor(uchar * arg) { return 0; }
@@ -2628,7 +2627,6 @@ class Item_ident :public Item
26282627
virtual void fix_after_pullout(st_select_lex *parent_select,
26292628
st_select_lex *removed_select);
26302629
void cleanup();
2631-
bool remove_dependence_processor(uchar * arg);
26322630
virtual bool aggregate_check_distinct(uchar *arg);
26332631
virtual bool aggregate_check_group(uchar *arg);
26342632
Bool3 local_column(const st_select_lex *sl) const;

sql/item_subselect.cc

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,6 +1073,7 @@ Item_singlerow_subselect::select_transformer(SELECT_LEX *select)
10731073

10741074
THD * const thd= unit->thd;
10751075
Query_arena *arena= thd->stmt_arena;
1076+
SELECT_LEX *outer= select->outer_select();
10761077

10771078
if (!unit->is_union() &&
10781079
!select->table_list.elements &&
@@ -1111,12 +1112,11 @@ Item_singlerow_subselect::select_transformer(SELECT_LEX *select)
11111112
Item_subselect *subs= (Item_subselect*)substitution;
11121113
subs->unit->set_explain_marker_from(unit);
11131114
}
1114-
/*
1115-
as far as we moved content to upper level, field which depend of
1116-
'upper' select is not really dependent => we remove this dependence
1117-
*/
1118-
substitution->walk(&Item::remove_dependence_processor, WALK_POSTFIX,
1119-
(uchar *) select->outer_select());
1115+
// Merge subquery's name resolution contexts into parent's
1116+
outer->merge_contexts(select);
1117+
1118+
// Fix query block contexts after merging the subquery
1119+
substitution->fix_after_pullout(outer, select);
11201120
DBUG_RETURN(RES_REDUCE);
11211121
}
11221122
DBUG_RETURN(RES_OK);
@@ -1953,6 +1953,8 @@ Item_in_subselect::single_value_in_to_exists_transformer(SELECT_LEX *select,
19531953
THD * const thd= unit->thd;
19541954
DBUG_ENTER("Item_in_subselect::single_value_in_to_exists_transformer");
19551955

1956+
SELECT_LEX *outer= select->outer_select();
1957+
19561958
OPT_TRACE_TRANSFORM(&thd->opt_trace, oto0, oto1, select->select_number,
19571959
"IN (SELECT)", "EXISTS (CORRELATED SELECT)");
19581960
oto1.add("chosen", true);
@@ -2148,8 +2150,9 @@ Item_in_subselect::single_value_in_to_exists_transformer(SELECT_LEX *select,
21482150
The expression is moved to the immediately outer query block, so it
21492151
may no longer contain outer references.
21502152
*/
2151-
orig_item->walk(&Item::remove_dependence_processor, WALK_POSTFIX,
2152-
(uchar *) select->outer_select());
2153+
outer->merge_contexts(select);
2154+
orig_item->fix_after_pullout(outer, select);
2155+
21532156
/*
21542157
fix_field of substitution item will be done in time of
21552158
substituting.

sql/sql_lex.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1399,6 +1399,9 @@ class st_select_lex: public Sql_alloc
13991399
void reset_nj_counters(List<TABLE_LIST> *join_list= NULL);
14001400
bool check_only_full_group_by(THD *thd);
14011401

1402+
/// Merge name resolution context objects of a subquery into its parent
1403+
void merge_contexts(SELECT_LEX *inner);
1404+
14021405
/**
14031406
Returns which subquery execution strategies can be used for this query block.
14041407

sql/sql_resolver.cc

Lines changed: 30 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2147,23 +2147,8 @@ SELECT_LEX::convert_subquery_to_semijoin(Item_exists_subselect *subq_pred)
21472147
// Unlink the subquery's query expression:
21482148
subq_select->master_unit()->exclude_level();
21492149

2150-
/*
2151-
Add Name res objects belonging to subquery to parent query block.
2152-
Update all name res objects to have this base query block.
2153-
*/
2154-
for (Name_resolution_context *ctx= subq_select->first_context;
2155-
ctx != NULL;
2156-
ctx= ctx->next_context)
2157-
{
2158-
ctx->select_lex= this;
2159-
if (ctx->next_context == NULL)
2160-
{
2161-
ctx->next_context= first_context;
2162-
first_context= subq_select->first_context;
2163-
subq_select->first_context= NULL;
2164-
break;
2165-
}
2166-
}
2150+
// Merge subquery's name resolution contexts into parent's
2151+
merge_contexts(subq_select);
21672152

21682153
repoint_contexts_of_join_nests(subq_select->top_join_list);
21692154

@@ -2377,23 +2362,8 @@ bool SELECT_LEX::merge_derived(THD *thd, TABLE_LIST *derived_table)
23772362
// Don't try to access it:
23782363
derived_table->set_derived_unit((SELECT_LEX_UNIT *)1);
23792364

2380-
/*
2381-
Add Name res objects belonging to subquery to parent query block.
2382-
Update all name res objects to have this base query block.
2383-
*/
2384-
for (Name_resolution_context *ctx= derived_select->first_context;
2385-
ctx != NULL;
2386-
ctx= ctx->next_context)
2387-
{
2388-
ctx->select_lex= this;
2389-
if (ctx->next_context == NULL)
2390-
{
2391-
ctx->next_context= first_context;
2392-
first_context= derived_select->first_context;
2393-
derived_select->first_context= NULL;
2394-
break;
2395-
}
2396-
}
2365+
// Merge subquery's name resolution contexts into parent's
2366+
merge_contexts(derived_select);
23972367

23982368
repoint_contexts_of_join_nests(derived_select->top_join_list);
23992369

@@ -2782,6 +2752,32 @@ void SELECT_LEX::repoint_contexts_of_join_nests(List<TABLE_LIST> join_list)
27822752
}
27832753

27842754

2755+
/**
2756+
Merge name resolution context objects belonging to an inner subquery
2757+
to parent query block.
2758+
Update all context objects to have this base query block.
2759+
Used when a subquery's query block is merged into its parent.
2760+
2761+
@param inner Subquery for which context objects are to be merged.
2762+
*/
2763+
void SELECT_LEX::merge_contexts(SELECT_LEX *inner)
2764+
{
2765+
for (Name_resolution_context *ctx= inner->first_context;
2766+
ctx != NULL;
2767+
ctx= ctx->next_context)
2768+
{
2769+
ctx->select_lex= this;
2770+
if (ctx->next_context == NULL)
2771+
{
2772+
ctx->next_context= first_context;
2773+
first_context= inner->first_context;
2774+
inner->first_context= NULL;
2775+
break;
2776+
}
2777+
}
2778+
}
2779+
2780+
27852781
/**
27862782
Fix fields referenced from inner query blocks.
27872783

0 commit comments

Comments
 (0)