diff options
author | Oleksandr Byelkin <sanja@mariadb.com> | 2021-07-23 11:14:13 +0200 |
---|---|---|
committer | Oleksandr Byelkin <sanja@mariadb.com> | 2021-09-27 11:00:51 +0200 |
commit | 3690c549c6e72646ba74f6b4c83813ee4ac3aea4 (patch) | |
tree | e619941de38c42f99b6377e8af00a78700bcfbb1 /sql | |
parent | 1a62c878970fea6d2013c432bbd5aae30dbaca89 (diff) | |
download | mariadb-git-bb-10.2-MDEV-24454.tar.gz |
MDEV-24454 Crash at change_item_treebb-10.2-MDEV-24454
Use in_sum_func (and so nest_level) only in LEX to which SELECT lex belong to
Reduce usage of current_select (because it does not always point on the correct
SELECT_LEX, for example with prepare.
Change context for all classes inherited from Item_ident (was only for Item_field) in case of pushing down it to HAVING.
Now name resolution context have to have SELECT_LEX reference if the context is present.
Fixed feedback plugin stack usage.
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item.cc | 104 | ||||
-rw-r--r-- | sql/item.h | 1 | ||||
-rw-r--r-- | sql/item_subselect.cc | 3 | ||||
-rw-r--r-- | sql/item_sum.cc | 8 | ||||
-rw-r--r-- | sql/sql_base.cc | 1 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 2 |
6 files changed, 80 insertions, 39 deletions
diff --git a/sql/item.cc b/sql/item.cc index 96e118e6365..2a7c620b864 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -61,11 +61,12 @@ bool cmp_items(Item *a, Item *b) /** Set max_sum_func_level if it is needed */ -inline void set_max_sum_func_level(THD *thd, SELECT_LEX *select) +inline void set_max_sum_func_level(SELECT_LEX *select) { - if (thd->lex->in_sum_func && - thd->lex->in_sum_func->nest_level >= select->nest_level) - set_if_bigger(thd->lex->in_sum_func->max_sum_func_level, + LEX *lex_s= select->parent_lex; + if (lex_s->in_sum_func && + lex_s->in_sum_func->nest_level >= select->nest_level) + set_if_bigger(lex_s->in_sum_func->max_sum_func_level, select->nest_level - 1); } @@ -780,6 +781,7 @@ Item_ident::Item_ident(THD *thd, Name_resolution_context *context_arg, { name = (char*) field_name_arg; name_length= name ? strlen(name) : 0; + DBUG_ASSERT(!context || context->select_lex); } @@ -794,6 +796,7 @@ Item_ident::Item_ident(THD *thd, TABLE_LIST *view_arg, const char *field_name_ar { name = (char*) field_name_arg; name_length= name ? strlen(name) : 0; + DBUG_ASSERT(!context || context->select_lex); } @@ -815,7 +818,9 @@ Item_ident::Item_ident(THD *thd, Item_ident *item) cached_table(item->cached_table), depended_from(item->depended_from), can_be_depended(item->can_be_depended) -{} +{ + DBUG_ASSERT(!context || context->select_lex); +} void Item_ident::cleanup() { @@ -5117,7 +5122,14 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) */ Name_resolution_context *last_checked_context= context; Item **ref= (Item **) not_found_item; - SELECT_LEX *current_sel= thd->lex->current_select; + /* + There are cases when name resolution context is absent (when we are not + doing name resolution), but here the name resolution context should + be present because we are doing name resolution + */ + DBUG_ASSERT(context); + SELECT_LEX *current_sel= context->select_lex; + LEX *lex_s= context->select_lex->parent_lex; Name_resolution_context *outer_context= 0; SELECT_LEX *select= 0; /* Currently derived tables cannot be correlated */ @@ -5218,18 +5230,18 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) return -1; thd->change_item_tree(reference, rf); select->inner_refs_list.push_back(rf, thd->mem_root); - rf->in_sum_func= thd->lex->in_sum_func; + rf->in_sum_func= lex_s->in_sum_func; } /* 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 max_arg_level for the function if it's needed. */ - if (thd->lex->in_sum_func && - thd->lex->in_sum_func->nest_level >= select->nest_level) + if (lex_s->in_sum_func && + lex_s->in_sum_func->nest_level >= select->nest_level) { Item::Type ref_type= (*reference)->type(); - set_if_bigger(thd->lex->in_sum_func->max_arg_level, + set_if_bigger(lex_s->in_sum_func->max_arg_level, select->nest_level); set_field(*from_field); fixed= 1; @@ -5250,10 +5262,10 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) ((ref_type == REF_ITEM || ref_type == FIELD_ITEM) ? (Item_ident*) (*reference) : 0), false); - if (thd->lex->in_sum_func && - thd->lex->in_sum_func->nest_level >= select->nest_level) + if (lex_s->in_sum_func && + lex_s->in_sum_func->nest_level >= select->nest_level) { - set_if_bigger(thd->lex->in_sum_func->max_arg_level, + set_if_bigger(lex_s->in_sum_func->max_arg_level, select->nest_level); } /* @@ -5345,7 +5357,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) { outer_context->select_lex->inner_refs_list.push_back((Item_outer_ref*)rf, thd->mem_root); - ((Item_outer_ref*)rf)->in_sum_func= thd->lex->in_sum_func; + ((Item_outer_ref*)rf)->in_sum_func= lex_s->in_sum_func; } thd->change_item_tree(reference, rf); /* @@ -5360,7 +5372,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) We can not "move" aggregate function in the place where its arguments are not defined. */ - set_max_sum_func_level(thd, select); + set_max_sum_func_level(select); mark_as_dependent(thd, last_checked_context->select_lex, context->select_lex, rf, rf, false); @@ -5373,7 +5385,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) We can not "move" aggregate function in the place where its arguments are not defined. */ - set_max_sum_func_level(thd, select); + set_max_sum_func_level(select); mark_as_dependent(thd, last_checked_context->select_lex, context->select_lex, this, (Item_ident*)*reference, false); @@ -5450,7 +5462,20 @@ bool Item_field::fix_fields(THD *thd, Item **reference) DBUG_ASSERT(fixed == 0); Field *from_field= (Field *)not_found_field; bool outer_fixed= false; - SELECT_LEX *select= thd->lex->current_select; + SELECT_LEX *select; + LEX *lex_s; + if (context) + { + select= context->select_lex; + lex_s= context->select_lex->parent_lex; + } + else + { + // No real name resolution, used somewhere in SP + DBUG_ASSERT(field); + select= NULL; + lex_s= NULL; + } if (!field) // If field is not checked { @@ -5511,7 +5536,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) We can not "move" aggregate function in the place where its arguments are not defined. */ - set_max_sum_func_level(thd, select); + set_max_sum_func_level(select); set_field(new_field); depended_from= (*((Item_field**)res))->depended_from; return 0; @@ -5540,7 +5565,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) We can not "move" aggregate function in the place where its arguments are not defined. */ - set_max_sum_func_level(thd, select); + set_max_sum_func_level(select); return FALSE; } } @@ -5577,10 +5602,11 @@ bool Item_field::fix_fields(THD *thd, Item **reference) goto mark_non_agg_field; } - if (thd->lex->in_sum_func && - thd->lex->in_sum_func->nest_level == + if (lex_s && + lex_s->in_sum_func && + lex_s->in_sum_func->nest_level == select->nest_level) - set_if_bigger(thd->lex->in_sum_func->max_arg_level, + set_if_bigger(lex_s->in_sum_func->max_arg_level, select->nest_level); /* if it is not expression from merged VIEW we will set this field. @@ -5646,8 +5672,9 @@ bool Item_field::fix_fields(THD *thd, Item **reference) if (field->vcol_info) fix_session_vcol_expr_for_read(thd, field, field->vcol_info); if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY && - !outer_fixed && !thd->lex->in_sum_func && + !outer_fixed && select && + !lex_s->in_sum_func && select->cur_pos_in_select_list != UNDEF_POS && select->join) { @@ -5682,13 +5709,13 @@ mark_non_agg_field: */ select_lex= context->select_lex; } - if (!thd->lex->in_sum_func) + if (!lex_s || !lex_s->in_sum_func) select_lex->set_non_agg_field_used(true); else { if (outer_fixed) - thd->lex->in_sum_func->outer_fields.push_back(this, thd->mem_root); - else if (thd->lex->in_sum_func->nest_level != + lex_s->in_sum_func->outer_fields.push_back(this, thd->mem_root); + else if (lex_s->in_sum_func->nest_level != select->nest_level) select_lex->set_non_agg_field_used(true); } @@ -7181,6 +7208,12 @@ Item *get_field_item_for_having(THD *thd, Item *item, st_select_lex *sel) return NULL; } +Item *Item_ident::derived_field_transformer_for_having(THD *thd, uchar *arg) +{ + st_select_lex *sel= (st_select_lex *)arg; + context= &sel->context; + return this; +} Item *Item_field::derived_field_transformer_for_having(THD *thd, uchar *arg) { @@ -7200,12 +7233,13 @@ Item *Item_field::derived_field_transformer_for_having(THD *thd, uchar *arg) Item *Item_direct_view_ref::derived_field_transformer_for_having(THD *thd, uchar *arg) { + st_select_lex *sel= (st_select_lex *)arg; + context= &sel->context; if ((*ref)->marker & SUBSTITUTION_FL) { this->marker|= SUBSTITUTION_FL; return this; } - st_select_lex *sel= (st_select_lex *)arg; table_map tab_map= sel->master_unit()->derived->table->map; if ((item_equal && !(item_equal->used_tables() & tab_map)) || !item_equal) @@ -7501,7 +7535,9 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) { enum_parsing_place place= NO_MATTER; DBUG_ASSERT(fixed == 0); - SELECT_LEX *current_sel= thd->lex->current_select; + + SELECT_LEX *current_sel= context->select_lex; + LEX *lex_s= context->select_lex->parent_lex; if (set_properties_only) { @@ -7662,10 +7698,10 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) the nest level of the enclosing set function : adjust the value of max_arg_level for the function if it's needed. */ - if (thd->lex->in_sum_func && - thd->lex->in_sum_func->nest_level >= + if (lex_s->in_sum_func && + lex_s->in_sum_func->nest_level >= last_checked_context->select_lex->nest_level) - set_if_bigger(thd->lex->in_sum_func->max_arg_level, + set_if_bigger(lex_s->in_sum_func->max_arg_level, last_checked_context->select_lex->nest_level); return FALSE; } @@ -7685,10 +7721,10 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) the nest level of the enclosing set function : adjust the value of max_arg_level for the function if it's needed. */ - if (thd->lex->in_sum_func && - thd->lex->in_sum_func->nest_level >= + if (lex_s->in_sum_func && + lex_s->in_sum_func->nest_level >= last_checked_context->select_lex->nest_level) - set_if_bigger(thd->lex->in_sum_func->max_arg_level, + set_if_bigger(lex_s->in_sum_func->max_arg_level, last_checked_context->select_lex->nest_level); } } diff --git a/sql/item.h b/sql/item.h index 8be9a7fe417..35700129243 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2630,6 +2630,7 @@ public: Collect outer references */ virtual bool collect_outer_ref_processor(void *arg); + Item *derived_field_transformer_for_having(THD *thd, uchar *arg); friend bool insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, const char *table_name, List_iterator<Item> *it, diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 25621dfe104..3f9a760ce09 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -5190,8 +5190,9 @@ bool subselect_hash_sj_engine::make_semi_join_conds() NULL, TL_READ); tmp_table_ref->table= tmp_table; - context= new Name_resolution_context; + context= new (thd->mem_root) Name_resolution_context; context->init(); + context->select_lex= item_in->unit->first_select(); context->first_name_resolution_table= context->last_name_resolution_table= tmp_table_ref; semi_join_conds_context= context; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index dd65f04a652..f20be3b5226 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -68,6 +68,7 @@ size_t Item_sum::ram_limitation(THD *thd) bool Item_sum::init_sum_func_check(THD *thd) { SELECT_LEX *curr_sel= thd->lex->current_select; + LEX *lex_s= (curr_sel ? curr_sel->parent_lex : thd->lex); if (curr_sel && !curr_sel->name_visibility_map) { for (SELECT_LEX *sl= curr_sel; sl; sl= sl->context.outer_select()) @@ -82,9 +83,9 @@ bool Item_sum::init_sum_func_check(THD *thd) return TRUE; } /* Set a reference to the nesting set function if there is any */ - in_sum_func= thd->lex->in_sum_func; + in_sum_func= lex_s->in_sum_func; /* Save a pointer to object to be used in items for nested set functions */ - thd->lex->in_sum_func= this; + lex_s->in_sum_func= this; nest_level= thd->lex->current_select->nest_level; ref_by= 0; aggr_level= -1; @@ -151,6 +152,7 @@ bool Item_sum::init_sum_func_check(THD *thd) bool Item_sum::check_sum_func(THD *thd, Item **ref) { SELECT_LEX *curr_sel= thd->lex->current_select; + LEX *lex_s= curr_sel->parent_lex; nesting_map allow_sum_func= (thd->lex->allow_sum_func & curr_sel->name_visibility_map); bool invalid= FALSE; @@ -310,7 +312,7 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref) } aggr_sel->set_agg_func_used(true); update_used_tables(); - thd->lex->in_sum_func= in_sum_func; + lex_s->in_sum_func= in_sum_func; return FALSE; } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 9a66b27a454..5173df260d5 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -6440,6 +6440,7 @@ set_new_item_local_context(THD *thd, Item_ident *item, TABLE_LIST *table_ref) if (!(context= new (thd->mem_root) Name_resolution_context)) return TRUE; context->init(); + context->select_lex= table_ref->select_lex; context->first_name_resolution_table= context->last_name_resolution_table= table_ref; item->context= context; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 624bcb90cd5..9339cb925e5 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -3060,6 +3060,7 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) } for (; sl; sl= sl->next_select_in_list()) { + sl->parent_lex->in_sum_func= NULL; if (sl->changed_elements & TOUCHED_SEL_COND) { /* remove option which was put by mysql_explain_union() */ @@ -3190,7 +3191,6 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) lex->result->set_thd(thd); } lex->allow_sum_func= 0; - lex->in_sum_func= NULL; DBUG_VOID_RETURN; } |