diff --git a/mysql-test/main/fulltext_order_by.result b/mysql-test/main/fulltext_order_by.result index a350a55c75d..35ae8789c7d 100644 --- a/mysql-test/main/fulltext_order_by.result +++ b/mysql-test/main/fulltext_order_by.result @@ -126,7 +126,7 @@ group by a.text, b.id, b.betreff order by match(b.betreff) against ('+abc' in boolean mode) desc; -ERROR 42000: Table 'b' from one of the SELECTs cannot be used in ORDER clause +ERROR 42000: Table 'b' from one of the SELECTs cannot be used in order clause select a.text, b.id, b.betreff from t2 a inner join t3 b on a.id = b.forum inner join @@ -142,7 +142,7 @@ where match(c.beitrag) against ('+abc' in boolean mode) order by match(b.betreff) against ('+abc' in boolean mode) desc; -ERROR 42000: Table 'b' from one of the SELECTs cannot be used in ORDER clause +ERROR 42000: Table 'b' from one of the SELECTs cannot be used in order clause select a.text, b.id, b.betreff from t2 a inner join t3 b on a.id = b.forum inner join diff --git a/mysql-test/main/name_const_replacement.result b/mysql-test/main/name_const_replacement.result new file mode 100644 index 00000000000..bfce1dd46c1 --- /dev/null +++ b/mysql-test/main/name_const_replacement.result @@ -0,0 +1,87 @@ +create table t1 (a int, b int); +insert into t1 values (1,1),(2,2); +explain format=json +select * from t1 where a=name_const('varname',1); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 2, + "filtered": 100, + "attached_condition": "t1.a = 1" + } + } +} +explain format=json +select * from t1 left join t1 as t2 on t1.a=name_const('varname',1) and t1.b=t2.b; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "const_condition": "1", + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 2, + "filtered": 100 + }, + "block-nl-join": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 2, + "filtered": 100 + }, + "buffer_type": "flat", + "buffer_size": "141", + "join_type": "BNL", + "attached_condition": "trigcond(t2.b = t1.b and trigcond(t1.a = 1))" + } + } +} +create table t2 ( +a varchar(100) collate utf8_unicode_ci, +b int +); +insert into t2 values ('foo', 1),('bar', 1); +create procedure p1(var1 varchar(10)) +update t2 set b=b+1 where a=var1; +call p1('foo'); +call p1('foo'); +call p1('foo'); +select * from t2; +a b +foo 4 +bar 1 +create table t3 ( +a varchar(100) collate utf8_unicode_ci, +b int +); +insert into t3 values ('foo', 1),('bar', 1); +select * from t3; +a b +foo 1 +bar 1 +explain format=json +update t3 set b=b+1 where a= NAME_CONST('var1',_latin1'foo' COLLATE 'latin1_swedish_ci'); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "update": 1, + "table_name": "t3", + "access_type": "ALL", + "rows": 2, + "attached_condition": "t3.a = convert(_latin1'foo' collate latin1_swedish_ci using utf8mb3)" + } + } +} +select * from t3 where a= NAME_CONST('var1',_latin1'foo' COLLATE 'latin1_swedish_ci'); +a b +foo 1 +drop procedure p1; +drop table t1, t2, t3; diff --git a/mysql-test/main/name_const_replacement.test b/mysql-test/main/name_const_replacement.test new file mode 100644 index 00000000000..b9770d65bb0 --- /dev/null +++ b/mysql-test/main/name_const_replacement.test @@ -0,0 +1,38 @@ +# +# MDEV-33971 Using NAME_CONST() changes the plan +# + +create table t1 (a int, b int); +insert into t1 values (1,1),(2,2); +explain format=json +select * from t1 where a=name_const('varname',1); +explain format=json +select * from t1 left join t1 as t2 on t1.a=name_const('varname',1) and t1.b=t2.b; + + +create table t2 ( + a varchar(100) collate utf8_unicode_ci, + b int +); +insert into t2 values ('foo', 1),('bar', 1); +create procedure p1(var1 varchar(10)) + update t2 set b=b+1 where a=var1; +call p1('foo'); +call p1('foo'); +call p1('foo'); +select * from t2; + + +create table t3 ( + a varchar(100) collate utf8_unicode_ci, + b int +); +insert into t3 values ('foo', 1),('bar', 1); +select * from t3; +explain format=json +update t3 set b=b+1 where a= NAME_CONST('var1',_latin1'foo' COLLATE 'latin1_swedish_ci'); +select * from t3 where a= NAME_CONST('var1',_latin1'foo' COLLATE 'latin1_swedish_ci'); + + +drop procedure p1; +drop table t1, t2, t3; diff --git a/mysql-test/main/union.result b/mysql-test/main/union.result index aab13d191a4..cd1c9022960 100644 --- a/mysql-test/main/union.result +++ b/mysql-test/main/union.result @@ -80,7 +80,7 @@ a b 2 b 1 a (select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by t1.b; -ERROR 42000: Table 't1' from one of the SELECTs cannot be used in ORDER clause +ERROR 42000: Table 't1' from one of the SELECTs cannot be used in order clause explain extended (select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by b desc; id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 4 100.00 @@ -493,7 +493,7 @@ drop temporary table t1; create table t1 select a from t1 union select a from t2; ERROR 42S01: Table 't1' already exists select a from t1 union select a from t2 order by t2.a; -ERROR 42000: Table 't2' from one of the SELECTs cannot be used in ORDER clause +ERROR 42000: Table 't2' from one of the SELECTs cannot be used in order clause drop table t1,t2; select length(version()) > 1 as `*` UNION select 2; * diff --git a/mysql-test/suite/innodb_fts/r/fulltext_order_by.result b/mysql-test/suite/innodb_fts/r/fulltext_order_by.result index 0d3a4a85b86..02142016d40 100644 --- a/mysql-test/suite/innodb_fts/r/fulltext_order_by.result +++ b/mysql-test/suite/innodb_fts/r/fulltext_order_by.result @@ -129,7 +129,7 @@ group by a.text, b.id, b.betreff order by match(b.betreff) against ('+abc' in boolean mode) desc; -ERROR 42000: Table 'b' from one of the SELECTs cannot be used in ORDER clause +ERROR 42000: Table 'b' from one of the SELECTs cannot be used in order clause select a.text, b.id, b.betreff from t2 a inner join t3 b on a.id = b.forum inner join @@ -145,7 +145,7 @@ where match(c.beitrag) against ('+abc' in boolean mode) order by match(b.betreff) against ('+abc' in boolean mode) desc; -ERROR 42000: Table 'b' from one of the SELECTs cannot be used in ORDER clause +ERROR 42000: Table 'b' from one of the SELECTs cannot be used in order clause select a.text, b.id, b.betreff from t2 a inner join t3 b on a.id = b.forum inner join diff --git a/sql/item.cc b/sql/item.cc index ad76b461847..d1879367e0f 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2184,6 +2184,36 @@ bool Item_name_const::fix_fields(THD *thd, Item **ref) my_error(ER_RESERVED_SYNTAX, MYF(0), "NAME_CONST"); return TRUE; } + + /* + If we have either of the following: + ... WHERE foo=NAME_CONST(...) + ... JOIN ... ON foo=NAME_CONST(...) + then we have an opportunity to unwrap the NAME_CONST and + use the enclosed value directly, replacing NAME_CONST in + the parse tree with the value it encloses. + */ + if ((thd->where == THD_WHERE::WHERE_CLAUSE || + thd->where == THD_WHERE::ON_CLAUSE) && + (value_item->type() == FUNC_ITEM || + value_item->type() == CONST_ITEM)) + { + thd->change_item_tree(ref, value_item); + + /* + We're replacing NAME_CONST('name', value_item) with value_item. + Only a few constants and functions are possible as value_item, see + Create_func_name_const::create_2_arg. + Set the value_item's coercibility to be the same as NAME_CONST(...) + would have (see how it's set a few lines below). + */ + if (value_item->collation.derivation != DERIVATION_NUMERIC) + value_item->collation.set(value_item->collation.collation, + DERIVATION_IMPLICIT); + return FALSE; + } + // else, could not unwrap, fall back to default handling below. + if (value_item->collation.derivation == DERIVATION_NUMERIC) collation= DTCollation_numeric(); else @@ -5528,7 +5558,7 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list) is ambiguous. */ my_error(ER_NON_UNIQ_ERROR, MYF(0), - find_item->full_name(), current_thd->where); + find_item->full_name(), thd_where(current_thd)); return NULL; } } @@ -5613,7 +5643,7 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select) push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_NON_UNIQ_ERROR, ER_THD(thd,ER_NON_UNIQ_ERROR), ref->full_name(), - thd->where); + thd_where(thd)); } } @@ -5947,7 +5977,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) if (upward_lookup) { // We can't say exactly what absent table or field - my_error(ER_BAD_FIELD_ERROR, MYF(0), full_name(), thd->where); + my_error(ER_BAD_FIELD_ERROR, MYF(0), full_name(), thd_where(thd)); } else { @@ -6174,7 +6204,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) { /* The column to which we link isn't valid. */ my_error(ER_BAD_FIELD_ERROR, MYF(0), (*res)->name.str, - thd->where); + thd_where(thd)); return(1); } @@ -6219,7 +6249,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) if (unlikely(!select)) { - my_error(ER_BAD_FIELD_ERROR, MYF(0), full_name(), thd->where); + my_error(ER_BAD_FIELD_ERROR, MYF(0), full_name(), thd_where(thd)); goto error; } if ((ret= fix_outer_field(thd, &from_field, reference)) < 0) @@ -8163,7 +8193,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) if (unlikely(!outer_context)) { /* The current reference cannot be resolved in this query. */ - my_error(ER_BAD_FIELD_ERROR,MYF(0), full_name(), thd->where); + my_error(ER_BAD_FIELD_ERROR,MYF(0), full_name(), thd_where(thd)); goto error; } @@ -8314,7 +8344,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) { /* The item was not a table field and not a reference */ my_error(ER_BAD_FIELD_ERROR, MYF(0), - this->full_name(), thd->where); + this->full_name(), thd_where(thd)); goto error; } /* Should be checked in resolve_ref_in_select_and_group(). */ diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index af9a57f751e..dc6453f42c5 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -241,7 +241,7 @@ Item_subselect::select_transformer(JOIN *join) bool Item_subselect::fix_fields(THD *thd_param, Item **ref) { - char const *save_where= thd_param->where; + THD_WHERE save_where= thd_param->where; uint8 uncacheable; bool res; @@ -320,7 +320,7 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref) if (have_to_be_excluded) engine->exclude(); substitution= 0; - thd->where= "checking transformed subquery"; + thd->where= THD_WHERE::CHECKING_TRANSFORMED_SUBQUERY; res= (*ref)->fix_fields_if_needed(thd, ref); goto end; @@ -3403,13 +3403,13 @@ Item_in_subselect::select_in_like_transformer(JOIN *join) { Query_arena *arena= 0, backup; SELECT_LEX *current= thd->lex->current_select; - const char *save_where= thd->where; + THD_WHERE save_where= thd->where; bool trans_res= true; bool result; DBUG_ENTER("Item_in_subselect::select_in_like_transformer"); DBUG_ASSERT(thd == join->thd); - thd->where= "IN/ALL/ANY subquery"; + thd->where= THD_WHERE::IN_ALL_ANY_SUBQUERY; /* In some optimisation cases we will not need this Item_in_optimizer @@ -3496,7 +3496,7 @@ bool Item_in_subselect::fix_fields(THD *thd_arg, Item **ref) { uint outer_cols_num; List *inner_cols; - char const *save_where= thd_arg->where; + THD_WHERE save_where= thd_arg->where; DBUG_ENTER("Item_in_subselect::fix_fields"); thd= thd_arg; @@ -3505,7 +3505,7 @@ bool Item_in_subselect::fix_fields(THD *thd_arg, Item **ref) if (test_strategy(SUBS_SEMI_JOIN)) DBUG_RETURN( !( (*ref)= new (thd->mem_root) Item_int(thd, 1)) ); - thd->where= "IN/ALL/ANY subquery"; + thd->where= THD_WHERE::IN_ALL_ANY_SUBQUERY; /* Check if the outer and inner IN operands match in those cases when we will not perform IN=>EXISTS transformation. Currently this is when we @@ -4016,7 +4016,7 @@ int join_read_next_same_or_null(READ_RECORD *info); int subselect_single_select_engine::exec() { - char const *save_where= thd->where; + THD_WHERE save_where= thd->where; SELECT_LEX *save_select= thd->lex->current_select; thd->lex->current_select= select_lex; DBUG_ENTER("subselect_single_select_engine::exec"); @@ -4137,7 +4137,7 @@ int subselect_single_select_engine::exec() int subselect_union_engine::exec() { - char const *save_where= thd->where; + THD_WHERE save_where= thd->where; int res= unit->exec(); thd->where= save_where; return res; diff --git a/sql/json_table.cc b/sql/json_table.cc index 65fe3c9a659..d4ba9f88a78 100644 --- a/sql/json_table.cc +++ b/sql/json_table.cc @@ -1146,7 +1146,7 @@ bool push_table_function_arg_context(LEX *lex, MEM_ROOT *alloc) bool Table_function_json_table::setup(THD *thd, TABLE_LIST *sql_table, SELECT_LEX *s_lex) { - thd->where= "JSON_TABLE argument"; + thd->where= THD_WHERE::JSON_TABLE_ARGUMENT; if (!m_context_setup_done) { diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 8690acded99..3dc281bca10 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -638,8 +638,8 @@ int check_and_do_in_subquery_rewrites(JOIN *join) { SELECT_LEX *current= thd->lex->current_select; thd->lex->current_select= current->return_after_parsing(); - char const *save_where= thd->where; - thd->where= "IN/ALL/ANY subquery"; + THD_WHERE save_where= thd->where; + thd->where= THD_WHERE::IN_ALL_ANY_SUBQUERY; Item **left= in_subs->left_exp_ptr(); bool failure= (*left)->fix_fields_if_needed(thd, left); diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 3af7e97db2b..3cefeae32b6 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -1824,7 +1824,7 @@ bool partition_info::add_column_list_value(THD *thd, Item *item) part_column_list_val *col_val; Name_resolution_context *context= &thd->lex->current_select->context; TABLE_LIST *save_list= context->table_list; - const char *save_where= thd->where; + THD_WHERE save_where= thd->where; DBUG_ENTER("partition_info::add_column_list_value"); if (part_type == LIST_PARTITION && @@ -1838,9 +1838,9 @@ bool partition_info::add_column_list_value(THD *thd, Item *item) context->table_list= 0; if (column_list) - thd->where= "field list"; + thd->where= THD_WHERE::FIELD_LIST; else - thd->where= "partition function"; + thd->where= THD_WHERE::PARTITION_FUNCTION; if (item->walk(&Item::check_partition_func_processor, 0, NULL)) { diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 70c5b4ffbf6..f27868c83e8 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -5957,7 +5957,7 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, si { if (nj_col) { - my_error(ER_NON_UNIQ_ERROR, MYF(0), name, thd->where); + my_error(ER_NON_UNIQ_ERROR, MYF(0), name, thd_where(thd)); DBUG_RETURN(NULL); } nj_col= curr_nj_col; @@ -6604,7 +6604,7 @@ find_field_in_tables(THD *thd, Item_ident *item, item->cached_field_index= NO_CACHED_FIELD_INDEX; } - DBUG_ASSERT(thd->where); + DBUG_ASSERT(thd->where != THD_WHERE::NOWHERE); /* If we found a fully qualified field we return it directly as it can't have duplicates. @@ -6617,7 +6617,7 @@ find_field_in_tables(THD *thd, Item_ident *item, if (report_error == REPORT_ALL_ERRORS || report_error == IGNORE_EXCEPT_NON_UNIQUE) my_error(ER_NON_UNIQ_ERROR, MYF(0), - table_name ? item->full_name() : name, thd->where); + table_name ? item->full_name() : name, thd_where(thd)); return (Field*) 0; } found= cur_field; @@ -6645,13 +6645,13 @@ find_field_in_tables(THD *thd, Item_ident *item, strxnmov(buff,sizeof(buff)-1,db,".",table_name,NullS); table_name=buff; } - my_error(ER_UNKNOWN_TABLE, MYF(0), table_name, thd->where); + my_error(ER_UNKNOWN_TABLE, MYF(0), table_name, thd_where(thd)); } else { if (report_error == REPORT_ALL_ERRORS || report_error == REPORT_EXCEPT_NON_UNIQUE) - my_error(ER_BAD_FIELD_ERROR, MYF(0), item->full_name(), thd->where); + my_error(ER_BAD_FIELD_ERROR, MYF(0), item->full_name(), thd_where(thd)); else found= not_found_field; } @@ -6784,7 +6784,7 @@ find_item_in_list(Item *find, List &items, uint *counter, */ if (report_error != IGNORE_ERRORS) my_error(ER_NON_UNIQ_ERROR, MYF(0), - find->full_name(), current_thd->where); + find->full_name(), thd_where(current_thd)); return (Item**) 0; } found_unaliased= li.ref(); @@ -6815,7 +6815,7 @@ find_item_in_list(Item *find, List &items, uint *counter, continue; // Same field twice if (report_error != IGNORE_ERRORS) my_error(ER_NON_UNIQ_ERROR, MYF(0), - find->full_name(), current_thd->where); + find->full_name(), thd_where(current_thd)); return (Item**) 0; } found= li.ref(); @@ -6870,7 +6870,7 @@ find_item_in_list(Item *find, List &items, uint *counter, { if (report_error != IGNORE_ERRORS) my_error(ER_NON_UNIQ_ERROR, MYF(0), - find->full_name(), current_thd->where); + find->full_name(), thd_where(current_thd)); return (Item **) 0; } if (found_unaliased) @@ -6887,7 +6887,7 @@ find_item_in_list(Item *find, List &items, uint *counter, { if (report_error == REPORT_ALL_ERRORS) my_error(ER_BAD_FIELD_ERROR, MYF(0), - find->full_name(), current_thd->where); + find->full_name(), thd_where(current_thd)); return (Item **) 0; } else @@ -7093,7 +7093,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, DBUG_PRINT ("info", ("match c1.is_common=%d", nj_col_1->is_common)); if (cur_nj_col_2->is_common || found) { - my_error(ER_NON_UNIQ_ERROR, MYF(0), field_name_1->str, thd->where); + my_error(ER_NON_UNIQ_ERROR, MYF(0), field_name_1->str, thd_where(thd)); goto err; } if ((!using_fields && !field_2_invisible) || is_using_column_1) @@ -7307,7 +7307,7 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join, if (!(common_field= it++)) { my_error(ER_BAD_FIELD_ERROR, MYF(0), using_field_name_ptr, - current_thd->where); + thd_where(current_thd)); goto err; } if (!my_strcasecmp(system_charset_info, @@ -7561,7 +7561,7 @@ static bool setup_natural_join_row_types(THD *thd, Name_resolution_context *context) { DBUG_ENTER("setup_natural_join_row_types"); - thd->where= "from clause"; + thd->where= THD_WHERE::FROM_CLAUSE; if (from_clause->elements == 0) DBUG_RETURN(false); /* We come here in the case of UNIONs. */ @@ -7732,7 +7732,7 @@ bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array, thd->lex->current_select->nest_level); if (allow_sum_func) thd->lex->allow_sum_func.set_bit(thd->lex->current_select->nest_level); - thd->where= THD::DEFAULT_WHERE; + thd->where= THD_WHERE::DEFAULT_WHERE; save_is_item_list_lookup= thd->lex->current_select->is_item_list_lookup; thd->lex->current_select->is_item_list_lookup= 0; @@ -8491,7 +8491,7 @@ bool setup_on_expr(THD *thd, TABLE_LIST *table, bool is_update) embedded= embedding; if (embedded->on_expr) { - thd->where="on clause"; + thd->where= THD_WHERE::ON_CLAUSE; embedded->on_expr->mark_as_condition_AND_part(embedded); if (embedded->on_expr->fix_fields_if_needed_for_bool(thd, &embedded->on_expr)) @@ -8592,7 +8592,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, List &leaves, if (*conds) { - thd->where="where clause"; + thd->where= THD_WHERE::WHERE_CLAUSE; DBUG_EXECUTE("where", print_where(*conds, "WHERE in setup_conds", diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 7272ee2531b..6419a58fbe4 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -83,8 +83,6 @@ char internal_table_name[2]= "*"; char empty_c_string[1]= {0}; /* used for not defined db */ -const char * const THD::DEFAULT_WHERE= "field list"; - /**************************************************************************** ** User variables ****************************************************************************/ @@ -629,6 +627,64 @@ extern "C" void thd_kill_timeout(THD* thd) thd->awake(KILL_TIMEOUT); } +const char *thd_where(THD *thd) +{ + switch(thd->where) { + case THD_WHERE::CHECKING_TRANSFORMED_SUBQUERY: + return "checking transformed subquery"; + break; + case THD_WHERE::IN_ALL_ANY_SUBQUERY: + return "IN/ALL/ANY subquery"; + break; + case THD_WHERE::JSON_TABLE_ARGUMENT: + return "JSON_TABLE argument"; + break; + case THD_WHERE::DEFAULT_WHERE: // same as FIELD_LIST + case THD_WHERE::FIELD_LIST: + return "field list"; + break; + case THD_WHERE::PARTITION_FUNCTION: + return "partition function"; + break; + case THD_WHERE::FROM_CLAUSE: + return "from clause"; + break; + case THD_WHERE::ON_CLAUSE: + return "on clause"; + break; + case THD_WHERE::WHERE_CLAUSE: + return "where clause"; + break; + case THD_WHERE::CONVERT_CHARSET_CONST: + return "convert character set partition constant"; + break; + case THD_WHERE::FOR_SYSTEM_TIME: + return "FOR SYSTEM_TIME"; + break; + case THD_WHERE::ORDER_CLAUSE: + return "order clause"; + break; + case THD_WHERE::HAVING_CLAUSE: + return "having clause"; + break; + case THD_WHERE::GROUP_STATEMENT: + return "group statement"; + break; + case THD_WHERE::PROCEDURE_LIST: + return "procedure list"; + break; + case THD_WHERE::CHECK_OPTION: + return "check option"; + break; + case THD_WHERE::USE_WHERE_STRING: + return thd->where_str; + default: + break; // "fall-through" to default return below + }; + DBUG_ASSERT(false); + return "UNKNOWN"; +} + THD::THD(my_thread_id id, bool is_wsrep_applier) :Statement(&main_lex, &main_mem_root, STMT_CONVENTIONAL_EXECUTION, /* statement id */ 0), @@ -838,7 +894,7 @@ THD::THD(my_thread_id id, bool is_wsrep_applier) /* Variables with default values */ proc_info="login"; - where= THD::DEFAULT_WHERE; + where= THD_WHERE::DEFAULT_WHERE; slave_net = 0; m_command=COM_CONNECT; *scramble= '\0'; @@ -2328,7 +2384,7 @@ void THD::cleanup_after_query() /* Free Items that were created during this execution */ free_items(); /* Reset where. */ - where= THD::DEFAULT_WHERE; + where= THD_WHERE::DEFAULT_WHERE; /* reset table map for multi-table update */ table_map_for_update= 0; m_binlog_invoker= INVOKER_NONE; diff --git a/sql/sql_class.h b/sql/sql_class.h index bcc300a8f2c..a9d89871025 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2668,6 +2668,33 @@ struct thd_async_state }; +enum class THD_WHERE +{ + NOWHERE = 0, + CHECKING_TRANSFORMED_SUBQUERY, + IN_ALL_ANY_SUBQUERY, + JSON_TABLE_ARGUMENT, + FIELD_LIST, + PARTITION_FUNCTION, + FROM_CLAUSE, + DEFAULT_WHERE, + ON_CLAUSE, + WHERE_CLAUSE, + CONVERT_CHARSET_CONST, + FOR_SYSTEM_TIME, + ORDER_CLAUSE, + HAVING_CLAUSE, + GROUP_STATEMENT, + PROCEDURE_LIST, + CHECK_OPTION, + USE_WHERE_STRING, // ugh, a compromise for vcol... +}; + + +class THD; +const char *thd_where(THD *thd); + + /** @class THD For each client connection we create a separate thread with THD serving as @@ -2720,13 +2747,6 @@ public: MDL_request *backup_commit_lock; void reset_for_next_command(bool do_clear_errors= 1); - /* - Constant for THD::where initialization in the beginning of every query. - - It's needed because we do not save/restore THD::where normally during - primary (non subselect) query execution. - */ - static const char * const DEFAULT_WHERE; #ifdef EMBEDDED_LIBRARY struct st_mysql *mysql; @@ -2882,12 +2902,15 @@ public: const char *get_proc_info() const { return proc_info; } + // Used by thd_where() when where==USE_WHERE_STRING + const char *where_str; + /* Used in error messages to tell user in what part of MySQL we found an error. E. g. when where= "having clause", if fix_fields() fails, user will know that the error was in having clause. */ - const char *where; + THD_WHERE where; /* Needed by MariaDB semi sync replication */ Trans_binlog_info *semisync_info; diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index de5a1f63019..78ec80ccad6 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -431,7 +431,7 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived) derived->on_expr= expr; derived->prep_on_expr= expr->copy_andor_structure(thd); } - thd->where= "on clause"; + thd->where= THD_WHERE::ON_CLAUSE; if (derived->on_expr && derived->on_expr->fix_fields_if_needed_for_bool(thd, &derived->on_expr)) { diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index f8acaa24278..e3dc7b7ee8b 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -8147,7 +8147,7 @@ bool LEX::check_expr_allows_fields_or_error(THD *thd, const char *name) const { if (select_stack_top > 0) return false; // OK, fields are allowed - my_error(ER_BAD_FIELD_ERROR, MYF(0), name, thd->where); + my_error(ER_BAD_FIELD_ERROR, MYF(0), name, thd_where(thd)); return true; // Error, fields are not allowed } @@ -8170,7 +8170,7 @@ Item *LEX::create_item_ident_nospvar(THD *thd, if (unlikely(current_select->no_table_names_allowed)) { - my_error(ER_TABLENAME_NOT_ALLOWED_HERE, MYF(0), a->str, thd->where); + my_error(ER_TABLENAME_NOT_ALLOWED_HERE, MYF(0), a->str, thd_where(thd)); return NULL; } @@ -8385,7 +8385,7 @@ Item *LEX::create_item_ident(THD *thd, if (current_select->no_table_names_allowed) { - my_error(ER_TABLENAME_NOT_ALLOWED_HERE, MYF(0), b->str, thd->where); + my_error(ER_TABLENAME_NOT_ALLOWED_HERE, MYF(0), b->str, thd_where(thd)); return NULL; } diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 20ab2da10a6..1006c18ae11 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -142,11 +142,11 @@ Item* convert_charset_partition_constant(Item *item, CHARSET_INFO *cs) THD *thd= current_thd; Name_resolution_context *context= &thd->lex->current_select->context; TABLE_LIST *save_list= context->table_list; - const char *save_where= thd->where; + THD_WHERE save_where= thd->where; item= item->safe_charset_converter(thd, cs); context->table_list= NULL; - thd->where= "convert character set partition constant"; + thd->where= THD_WHERE::CONVERT_CHARSET_CONST; if (item && item->fix_fields_if_needed(thd, (Item**)NULL)) item= NULL; thd->where= save_where; @@ -841,7 +841,7 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, func_expr->walk(&Item::change_context_processor, 0, &lex.first_select_lex()->context); - thd->where= "partition function"; + thd->where= THD_WHERE::PARTITION_FUNCTION; /* In execution we must avoid the use of thd->change_item_tree since we might release memory before statement is completed. We do this diff --git a/sql/sql_select.cc b/sql/sql_select.cc index cf5a2983551..4e109d634ca 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1245,7 +1245,7 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables) if (vers_conditions.is_set() && vers_conditions.type != SYSTEM_TIME_HISTORY) { - thd->where= "FOR SYSTEM_TIME"; + thd->where= THD_WHERE::FOR_SYSTEM_TIME; /* TODO: do resolve fix_length_and_dec(), fix_fields(). This requires storing vers_conditions as Item and make some magic related to vers_system_time_t/VERS_TRX_ID at stage of fix_fields() @@ -1530,7 +1530,7 @@ JOIN::prepare(TABLE_LIST *tables_init, COND *conds_init, uint og_num, { nesting_map save_allow_sum_func= thd->lex->allow_sum_func; thd->lex->allow_sum_func.set_bit(select_lex->nest_level); - thd->where= "order clause"; + thd->where= THD_WHERE::ORDER_CLAUSE; for (ORDER *order= select_lex->order_list.first; order; order= order->next) { /* Don't add the order items to all fields. Just resolve them to ensure @@ -1546,7 +1546,7 @@ JOIN::prepare(TABLE_LIST *tables_init, COND *conds_init, uint og_num, if (having) { nesting_map save_allow_sum_func= thd->lex->allow_sum_func; - thd->where="having clause"; + thd->where= THD_WHERE::HAVING_CLAUSE; thd->lex->allow_sum_func.set_bit(select_lex_arg->nest_level); select_lex->having_fix_field= 1; /* @@ -25986,7 +25986,7 @@ find_order_in_list(THD *thd, Ref_ptr_array ref_pointer_array, if (!count || count > fields.elements) { my_error(ER_BAD_FIELD_ERROR, MYF(0), - order_item->full_name(), thd->where); + order_item->full_name(), thd_where(thd)); return TRUE; } thd->change_item_tree((Item **)&order->item, (Item *)&ref_pointer_array[count - 1]); @@ -26065,7 +26065,7 @@ find_order_in_list(THD *thd, Ref_ptr_array ref_pointer_array, ER_NON_UNIQ_ERROR, ER_THD(thd, ER_NON_UNIQ_ERROR), ((Item_ident*) order_item)->field_name.str, - thd->where); + thd_where(thd)); } } else if (from_window_spec) @@ -26135,7 +26135,7 @@ int setup_order(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables, SELECT_LEX *select = thd->lex->current_select; enum_parsing_place context_analysis_place= thd->lex->current_select->context_analysis_place; - thd->where="order clause"; + thd->where= THD_WHERE::ORDER_CLAUSE; const bool for_union= select->master_unit()->is_unit_op() && select == select->master_unit()->fake_select_lex; for (uint number = 1; order; order=order->next, number++) @@ -26214,7 +26214,7 @@ setup_group(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables, uint org_fields=all_fields.elements; - thd->where="group statement"; + thd->where= THD_WHERE::GROUP_STATEMENT; for (ord= order; ord; ord= ord->next) { if (find_order_in_list(thd, ref_pointer_array, tables, ord, fields, @@ -26332,7 +26332,7 @@ setup_new_fields(THD *thd, List &fields, new_field->item=item; /* Change to shared Item */ else { - thd->where="procedure list"; + thd->where= THD_WHERE::PROCEDURE_LIST; if ((*new_field->item)->fix_fields(thd, new_field->item)) DBUG_RETURN(1); /* purecov: inspected */ all_fields.push_front(*new_field->item, thd->mem_root); diff --git a/sql/sql_tvc.cc b/sql/sql_tvc.cc index 3d3dd2135f2..2e7a5e1c9d8 100644 --- a/sql/sql_tvc.cc +++ b/sql/sql_tvc.cc @@ -312,7 +312,7 @@ bool table_value_constr::prepare(THD *thd, SELECT_LEX *sl, (thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW) */ - thd->where="order clause"; + thd->where= THD_WHERE::ORDER_CLAUSE; ORDER *order= sl->order_list.first; for (; order; order=order->next) { @@ -327,7 +327,7 @@ bool table_value_constr::prepare(THD *thd, SELECT_LEX *sl, if (!count || count > first_elem->elements) { my_error(ER_BAD_FIELD_ERROR, MYF(0), - order_item->full_name(), thd->where); + order_item->full_name(), thd_where(thd)); DBUG_RETURN(true); } order->in_field_list= 1; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 023af109a3f..ed2bcd5deb9 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -12520,7 +12520,7 @@ opt_order_clause: order_clause: ORDER_SYM BY { - thd->where= "ORDER clause"; + thd->where= THD_WHERE::ORDER_CLAUSE; } order_list { diff --git a/sql/table.cc b/sql/table.cc index 2c2ae5b5e22..1906acd14e2 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1212,7 +1212,8 @@ bool parse_vcol_defs(THD *thd, MEM_ROOT *mem_root, TABLE *table, expr_str.length(parse_vcol_keyword.length); expr_str.append((char*)pos, expr_length); - thd->where= vcol_type_name(static_cast(type)); + thd->where= THD_WHERE::USE_WHERE_STRING; + thd->where_str= vcol_type_name(static_cast(type)); switch (type) { case VCOL_GENERATED_VIRTUAL: @@ -6282,8 +6283,8 @@ bool TABLE_LIST::prep_check_option(THD *thd, uint8 check_opt_type) if (check_option) { - const char *save_where= thd->where; - thd->where= "check option"; + THD_WHERE save_where= thd->where; + thd->where= THD_WHERE::CHECK_OPTION; if (check_option->fix_fields_if_needed_for_bool(thd, &check_option)) DBUG_RETURN(TRUE); thd->where= save_where;