diff --git a/sql/item.cc b/sql/item.cc index 9dcc81bbae7..ce9f258612e 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1542,6 +1542,45 @@ bool mark_unsupported_function(const char *w1, const char *w2, return mark_unsupported_function(ptr, store, result); } + +Query_fragment::Query_fragment(THD *thd, sp_head *sphead, + const char *start, const char *end) +{ + DBUG_ASSERT(start <= end); + if (sphead) + { + if (sphead->m_tmp_query) + { + // Normal SP statement + DBUG_ASSERT(sphead->m_tmp_query <= start); + set(start - sphead->m_tmp_query, end - start); + } + else + { + /* + We're in the "if" expression of a compound query: + if (expr) + do_something; + end if; + sphead->m_tmp_query is not set yet at this point, because + the "if" part of such statements is never put into the binary log. + Values of Rewritable_query_parameter::pos_in_query and + Rewritable_query_parameter:len_in_query will not be important, + so setting both to 0 should be fine. + */ + set(0, 0); + } + } + else + { + // Non-SP statement + DBUG_ASSERT(thd->query() <= start); + DBUG_ASSERT(end <= thd->query_end()); + set(start - thd->query(), end - start); + } +} + + /***************************************************************************** Item_sp_variable methods *****************************************************************************/ diff --git a/sql/item.h b/sql/item.h index 04dad5265d3..13f6f2019e4 100644 --- a/sql/item.h +++ b/sql/item.h @@ -89,6 +89,7 @@ public: const char *dbug_print_item(Item *item); +class sp_head; class Protocol; struct TABLE_LIST; void item_init(void); /* Init item functions */ @@ -391,6 +392,31 @@ public: { return NULL; } }; + +/* + A helper class to calculate offset and length of a query fragment + - outside of SP + - inside an SP + - inside a compound block +*/ +class Query_fragment +{ + uint m_pos; + uint m_length; + void set(size_t pos, size_t length) + { + DBUG_ASSERT(pos < UINT_MAX32); + DBUG_ASSERT(length < UINT_MAX32); + m_pos= (uint) pos; + m_length= (uint) length; + } +public: + Query_fragment(THD *thd, sp_head *sphead, const char *start, const char *end); + uint pos() const { return m_pos; } + uint length() const { return m_length; } +}; + + /** This is used for items in the query that needs to be rewritten before binlogging @@ -2100,7 +2126,6 @@ public: Field_enumerator() {} /* Remove gcc warning */ }; -class sp_head; class Item_string; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index b83195b8c71..faf208f549f 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -545,6 +545,7 @@ sp_head::sp_head(const Sp_handler *sph) Database_qualified_name(&null_clex_str, &null_clex_str), m_handler(sph), m_flags(0), + m_tmp_query(NULL), m_explicit_name(false), /* FIXME: the only use case when name is NULL is events, and it should diff --git a/sql/sql_class.h b/sql/sql_class.h index 1c4e657cf5a..8e87b3b41f9 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1069,6 +1069,10 @@ public: { return static_cast(query_string.length()); } + inline char *query_end() const + { + return query_string.str() + query_string.length(); + } CHARSET_INFO *query_charset() const { return query_string.charset(); } void set_query_inner(const CSET_STRING &string_arg) { diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 64b24ad7846..b080fb7f822 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -6287,15 +6287,17 @@ Item *LEX::create_and_link_Item_trigger_field(THD *thd, Item_param *LEX::add_placeholder(THD *thd, const LEX_CSTRING *name, - uint pos_in_query, uint len_in_query) + const char *start, const char *end) { if (!parsing_options.allows_variable) { my_error(ER_VIEW_SELECT_VARIABLE, MYF(0)); return NULL; } + + Query_fragment pos(thd, sphead, start, end); Item_param *item= new (thd->mem_root) Item_param(thd, name, - pos_in_query, len_in_query); + pos.pos(), pos.length()); if (!item || param_list.push_back(item, thd->mem_root)) { my_error(ER_OUT_OF_RESOURCES, MYF(0)); @@ -6305,12 +6307,6 @@ Item_param *LEX::add_placeholder(THD *thd, const LEX_CSTRING *name, } -const char *LEX::substatement_query(THD *thd) const -{ - return sphead ? sphead->m_tmp_query : thd->query(); -} - - bool LEX::add_signal_statement(THD *thd, const sp_condition_value *v) { Yacc_state *state= &thd->m_parser_state->m_yacc; @@ -6364,8 +6360,8 @@ Item_splocal *LEX::create_item_spvar_row_field(THD *thd, const LEX_CSTRING *a, const LEX_CSTRING *b, sp_variable *spv, - uint pos_in_q, - uint length_in_q) + const char *start, + const char *end) { if (!parsing_options.allows_variable) { @@ -6373,6 +6369,7 @@ Item_splocal *LEX::create_item_spvar_row_field(THD *thd, return NULL; } + Query_fragment pos(thd, sphead, start, end); Item_splocal *item; if (spv->field_def.is_table_rowtype_ref() || spv->field_def.is_cursor_rowtype_ref()) @@ -6380,7 +6377,7 @@ Item_splocal *LEX::create_item_spvar_row_field(THD *thd, if (!(item= new (thd->mem_root) Item_splocal_row_field_by_name(thd, a, b, spv->offset, MYSQL_TYPE_NULL, - pos_in_q, length_in_q))) + pos.pos(), pos.length()))) return NULL; } else @@ -6394,7 +6391,7 @@ Item_splocal *LEX::create_item_spvar_row_field(THD *thd, Item_splocal_row_field(thd, a, b, spv->offset, row_field_offset, def->real_field_type(), - pos_in_q, length_in_q))) + pos.pos(), pos.length()))) return NULL; } #ifndef DBUG_OFF @@ -6489,14 +6486,14 @@ Item *LEX::create_item_func_setval(THD *thd, Table_ident *table_ident, Item *LEX::create_item_ident(THD *thd, const LEX_CSTRING *a, const LEX_CSTRING *b, - uint pos_in_q, uint length_in_q) + const char *start, const char *end) { sp_variable *spv; if (spcont && (spv= spcont->find_variable(a, false)) && (spv->field_def.is_row() || spv->field_def.is_table_rowtype_ref() || spv->field_def.is_cursor_rowtype_ref())) - return create_item_spvar_row_field(thd, a, b, spv, pos_in_q, length_in_q); + return create_item_spvar_row_field(thd, a, b, spv, start, end); if ((thd->variables.sql_mode & MODE_ORACLE) && b->length == 7) { @@ -6550,7 +6547,7 @@ Item *LEX::create_item_ident(THD *thd, Item *LEX::create_item_limit(THD *thd, const LEX_CSTRING *a, - uint pos_in_q, uint length_in_q) + const char *start, const char *end) { sp_variable *spv; if (!spcont || !(spv= spcont->find_variable(a, false))) @@ -6559,10 +6556,11 @@ Item *LEX::create_item_limit(THD *thd, return NULL; } + Query_fragment pos(thd, sphead, start, end); Item_splocal *item; if (!(item= new (thd->mem_root) Item_splocal(thd, a, spv->offset, spv->sql_type(), - pos_in_q, length_in_q))) + pos.pos(), pos.length()))) return NULL; #ifndef DBUG_OFF item->m_sp= sphead; @@ -6582,7 +6580,7 @@ Item *LEX::create_item_limit(THD *thd, Item *LEX::create_item_limit(THD *thd, const LEX_CSTRING *a, const LEX_CSTRING *b, - uint pos_in_q, uint length_in_q) + const char *start, const char *end) { sp_variable *spv; if (!spcont || !(spv= spcont->find_variable(a, false))) @@ -6593,8 +6591,7 @@ Item *LEX::create_item_limit(THD *thd, // Qualified %TYPE variables are not possible DBUG_ASSERT(!spv->field_def.column_type_ref()); Item_splocal *item; - if (!(item= create_item_spvar_row_field(thd, a, b, spv, - pos_in_q, length_in_q))) + if (!(item= create_item_spvar_row_field(thd, a, b, spv, start, end))) return NULL; if (item->type() != Item::INT_ITEM) { @@ -6660,11 +6657,12 @@ Item *LEX::create_item_ident_nosp(THD *thd, LEX_CSTRING *name) Item *LEX::create_item_ident_sp(THD *thd, LEX_CSTRING *name, - uint start_in_q, - uint length_in_q) + const char *start, + const char *end) { sp_variable *spv; DBUG_ASSERT(spcont); + DBUG_ASSERT(sphead); if ((spv= spcont->find_variable(name, false))) { /* We're compiling a stored procedure and found a variable */ @@ -6674,17 +6672,18 @@ Item *LEX::create_item_ident_sp(THD *thd, LEX_CSTRING *name, return NULL; } + Query_fragment pos(thd, sphead, start, end); Item_splocal *splocal= spv->field_def.is_column_type_ref() ? new (thd->mem_root) Item_splocal_with_delayed_data_type(thd, name, spv->offset, - start_in_q, - length_in_q) : + pos.pos(), + pos.length()) : spv->field_def.is_row() || spv->field_def.is_table_rowtype_ref() ? new (thd->mem_root) Item_splocal_row(thd, name, spv->offset, - start_in_q, length_in_q) : + pos.pos(), pos.length()) : new (thd->mem_root) Item_splocal(thd, name, spv->offset, spv->sql_type(), - start_in_q, length_in_q); + pos.pos(), pos.length()); if (splocal == NULL) return NULL; #ifndef DBUG_OFF @@ -6705,16 +6704,6 @@ Item *LEX::create_item_ident_sp(THD *thd, LEX_CSTRING *name, } -Item *LEX::create_item_ident_sp(THD *thd, LEX_CSTRING *name, - const char *start_in_q, - const char *end_in_q) -{ - DBUG_ASSERT(sphead); - return create_item_ident_sp(thd, name, start_in_q - sphead->m_tmp_query, - end_in_q - start_in_q); -} - - /** Generate instructions for: SET x.y= expr; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 38ce41e43dd..7be918f2c0b 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -2994,8 +2994,6 @@ public: void start(THD *thd); - const char *substatement_query(THD *thd) const; - inline bool is_ps_or_view_context_analysis() { return (context_analysis_only & @@ -3226,22 +3224,16 @@ public: bool sp_open_cursor(THD *thd, const LEX_CSTRING *name, List *parameters); Item_splocal *create_item_for_sp_var(LEX_CSTRING *name, sp_variable *spvar, - const char *start_in_q, - const char *end_in_q); + const char *start, const char *end); Item *create_item_ident_nosp(THD *thd, LEX_CSTRING *name); Item *create_item_ident_sp(THD *thd, LEX_CSTRING *name, - uint start_in_q, - uint length_in_q); - Item *create_item_ident_sp(THD *thd, LEX_CSTRING *name, - const char *start_in_q, - const char *end_in_q); + const char *start, const char *end); Item *create_item_ident(THD *thd, LEX_CSTRING *name, - const char *start_in_q, - const char *end_in_q) + const char *start, const char *end) { return sphead ? - create_item_ident_sp(thd, name, start_in_q, end_in_q) : + create_item_ident_sp(thd, name, start, end) : create_item_ident_nosp(thd, name); } @@ -3268,15 +3260,15 @@ public: @param field - the ROW variable field name @param spvar - the variable that was previously found by name using "var_name". - @pos_in_q - position in the query (for binary log) - @length_in_q - length in the query (for binary log) + @param start - position in the query (for binary log) + @param end - end in the query (for binary log) */ Item_splocal *create_item_spvar_row_field(THD *thd, const LEX_CSTRING *var, const LEX_CSTRING *field, sp_variable *spvar, - uint pos_in_q, - uint length_in_q); + const char *start, + const char *end); /* Create an item from its qualified name. Depending on context, it can be either a ROW variable field, @@ -3286,15 +3278,15 @@ public: @param thd - THD, for mem_root @param a - the first name @param b - the second name - @param pos_in_q - position in the query (for binary log) - @param length_in_q - length in the query (for binary log) + @param start - position in the query (for binary log) + @param end - end in the query (for binary log) @retval - NULL on error, or a pointer to a new Item. */ Item *create_item_ident(THD *thd, const LEX_CSTRING *a, const LEX_CSTRING *b, - uint pos_in_q, uint length_in_q); - + const char *start, + const char *end); /* Create an item from its qualified name. Depending on context, it can be a table field, a table field reference, @@ -3333,23 +3325,24 @@ public: Create an item for a name in LIMIT clause: LIMIT var @param THD - THD, for mem_root @param var_name - the variable name - @param pos_in_q - position in the query (for binary log) - @param length_in_q - length in the query (for binary log) + @param start - position in the query (for binary log) + @param end - end in the query (for binary log) @retval - a new Item corresponding to the SP variable, or NULL on error (non in SP, unknown variable, wrong data type). */ Item *create_item_limit(THD *thd, const LEX_CSTRING *var_name, - uint pos_in_q, uint length_in_q); + const char *start, + const char *end); /* Create an item for a qualified name in LIMIT clause: LIMIT var.field @param THD - THD, for mem_root @param var_name - the variable name @param field_name - the variable field name - @param pos_in_q - position in the query (for binary log) - @param length_in_q - length in the query (for binary log) + @param start - start in the query (for binary log) + @param end - end in the query (for binary log) @retval - a new Item corresponding to the SP variable, or NULL on error (non in SP, unknown variable, unknown ROW field, @@ -3358,7 +3351,8 @@ public: Item *create_item_limit(THD *thd, const LEX_CSTRING *var_name, const LEX_CSTRING *field_name, - uint pos_in_q, uint length_in_q); + const char *start, + const char *end); Item *make_item_func_replace(THD *thd, Item *org, Item *find, Item *replace); @@ -3441,16 +3435,7 @@ public: bool sp_push_goto_label(THD *thd, const LEX_CSTRING *label_name); Item_param *add_placeholder(THD *thd, const LEX_CSTRING *name, - uint pos_in_query, uint len_in_query); - Item_param *add_placeholder(THD *thd, const LEX_CSTRING *name, - const char *start, const char *end) - { - size_t pos= start - substatement_query(thd); - size_t len= end - start; - DBUG_ASSERT(pos < UINT_MAX32); - DBUG_ASSERT(len < UINT_MAX32); - return add_placeholder(thd, name, (uint) pos, (uint) len); - } + const char *start, const char *end); /* Integer range FOR LOOP methods */ sp_variable *sp_add_for_loop_variable(THD *thd, const LEX_CSTRING *name, diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 17d6f016b2c..24fee1548cb 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -11926,9 +11926,7 @@ limit_option: LEX *lex= thd->lex; Lex_input_stream *lip= & thd->m_parser_state->m_lip; if (!($$= lex->create_item_limit(thd, &$1, - $1.m_pos - - lex->substatement_query(thd), - lip->get_tok_end() - $1.m_pos))) + $1.m_pos, lip->get_tok_end()))) MYSQL_YYABORT; } | ident_with_tok_start '.' ident @@ -11936,9 +11934,7 @@ limit_option: LEX *lex= thd->lex; Lex_input_stream *lip= & thd->m_parser_state->m_lip; if (!($$= lex->create_item_limit(thd, &$1, &$3, - $1.m_pos - - lex->substatement_query(thd), - lip->get_ptr() - $1.m_pos))) + $1.m_pos, lip->get_ptr()))) MYSQL_YYABORT; } | param_marker @@ -14239,9 +14235,7 @@ simple_ident: { LEX *lex= thd->lex; if (!($$= lex->create_item_ident(thd, &$1, &$3, - $1.m_pos - - lex->substatement_query(thd), - YYLIP->get_tok_end() - $1.m_pos))) + $1.m_pos, YYLIP->get_tok_end()))) MYSQL_YYABORT; } ; diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index 052c219a7a4..053c2625da1 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -11983,9 +11983,7 @@ limit_option: LEX *lex= thd->lex; Lex_input_stream *lip= & thd->m_parser_state->m_lip; if (!($$= lex->create_item_limit(thd, &$1, - $1.m_pos - - lex->substatement_query(thd), - lip->get_tok_end() - $1.m_pos))) + $1.m_pos, lip->get_tok_end()))) MYSQL_YYABORT; } | ident_with_tok_start '.' ident @@ -11993,9 +11991,7 @@ limit_option: LEX *lex= thd->lex; Lex_input_stream *lip= & thd->m_parser_state->m_lip; if (!($$= lex->create_item_limit(thd, &$1, &$3, - $1.m_pos - - lex->substatement_query(thd), - lip->get_ptr() - $1.m_pos))) + $1.m_pos, lip->get_ptr()))) MYSQL_YYABORT; } | param_marker @@ -14315,9 +14311,7 @@ simple_ident: { LEX *lex= thd->lex; if (!($$= lex->create_item_ident(thd, &$1, &$3, - $1.m_pos - - lex->substatement_query(thd), - YYLIP->get_tok_end() - $1.m_pos))) + $1.m_pos, YYLIP->get_tok_end()))) MYSQL_YYABORT; } ;