From 5a8b9a16d16b48968f0824db4b6589d4714de916 Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Wed, 19 Jul 2023 17:53:55 +0700 Subject: [PATCH] MDEV-5816: Stored programs: validation of stored program statements For those SP instructions that need to get access to ia LEX object on execution, added storing of their original sql expressions inside classes derived from the class sp_lex_instr. A stored sql expression is returned by the abstract method sp_lex_instr::get_expr_query redefined in derived classes. Since an expression constituting a SP instruction can be invalid SQL statement in general case (not parseable statement), the virtual method sp_lex_instr::get_query() is introduced to return a valid string for a statement that corresponds to the given instruction. Additionally, introduced the rule remember_start_opt in the grammar. The new rule intended to get correct position of a current token taking into attention the fact whether lookahead was done or not. --- sql/sp.cc | 4 +- sql/sp.h | 5 +- sql/sp_head.cc | 25 +++-- sql/sp_head.h | 15 ++- sql/sp_instr.cc | 21 ++++ sql/sp_instr.h | 177 +++++++++++++++++++++++++++------ sql/sql_class.cc | 8 ++ sql/sql_class.h | 16 +++ sql/sql_lex.cc | 177 +++++++++++++++++++++------------ sql/sql_lex.h | 98 +++++++++++++----- sql/sql_yacc.yy | 253 ++++++++++++++++++++++++++++++++++++----------- 11 files changed, 606 insertions(+), 193 deletions(-) diff --git a/sql/sp.cc b/sql/sp.cc index de8de97c91c..ce62b5849c5 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -65,7 +65,7 @@ ulong Sp_handler_procedure::recursion_depth(THD *thd) const bool Sp_handler::add_instr_freturn(THD *thd, sp_head *sp, sp_pcontext *spcont, - Item *item, LEX *lex) const + Item *item, sp_expr_lex *lex) const { my_error(ER_SP_BADRETURN, MYF(0)); return true; @@ -82,7 +82,7 @@ bool Sp_handler::add_instr_preturn(THD *thd, sp_head *sp, bool Sp_handler_function::add_instr_freturn(THD *thd, sp_head *sp, sp_pcontext *spcont, - Item *item, LEX *lex) const + Item *item, sp_expr_lex *lex) const { return sp->add_instr_freturn(thd, spcont, item, lex); } diff --git a/sql/sp.h b/sql/sp.h index c73ff2877b0..45e2ebc6385 100644 --- a/sql/sp.h +++ b/sql/sp.h @@ -35,6 +35,7 @@ class sp_head; class sp_package; class sp_pcontext; class sp_name; +class sp_expr_lex; class Database_qualified_name; struct st_sp_chistics; class Stored_program_creation_ctx; @@ -185,7 +186,7 @@ public: } virtual bool add_instr_freturn(THD *thd, sp_head *sp, sp_pcontext *spcont, - Item *item, LEX *lex) const; + Item *item, sp_expr_lex *lex) const; virtual bool add_instr_preturn(THD *thd, sp_head *sp, sp_pcontext *spcont) const; @@ -324,7 +325,7 @@ public: HASH *get_priv_hash() const; #endif bool add_instr_freturn(THD *thd, sp_head *sp, sp_pcontext *spcont, - Item *item, LEX *lex) const; + Item *item, sp_expr_lex *lex) const; }; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 58396f2a3b3..002f7883c0e 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -3077,11 +3077,11 @@ bool sp_head::add_instr_jump_forward_with_backpatch(THD *thd, bool sp_head::add_instr_freturn(THD *thd, sp_pcontext *spcont, - Item *item, LEX *lex) + Item *item, sp_expr_lex *lex) { sp_instr_freturn *i= new (thd->mem_root) sp_instr_freturn(instructions(), spcont, item, - m_return_field_def.type_handler(), lex); + m_return_field_def.type_handler(), lex); if (i == NULL || add_instr(i)) return true; m_flags|= sp_head::HAS_RETURN; @@ -3594,7 +3594,8 @@ bool sp_head::set_local_variable(THD *thd, sp_pcontext *spcont, const Sp_rcontext_handler *rh, sp_variable *spv, Item *val, LEX *lex, - bool responsible_to_free_lex) + bool responsible_to_free_lex, + const LEX_CSTRING &value_query) { if (!(val= adjust_assignment_source(thd, val, spv->default_value))) return true; @@ -3605,7 +3606,8 @@ sp_head::set_local_variable(THD *thd, sp_pcontext *spcont, sp_instr_set *sp_set= new (thd->mem_root) sp_instr_set(instructions(), spcont, rh, spv->offset, val, lex, - responsible_to_free_lex); + responsible_to_free_lex, + value_query); return sp_set == NULL || add_instr(sp_set); } @@ -3619,7 +3621,8 @@ bool sp_head::set_local_variable_row_field(THD *thd, sp_pcontext *spcont, const Sp_rcontext_handler *rh, sp_variable *spv, uint field_idx, - Item *val, LEX *lex) + Item *val, LEX *lex, + const LEX_CSTRING &value_query) { if (!(val= adjust_assignment_source(thd, val, NULL))) return true; @@ -3629,7 +3632,8 @@ sp_head::set_local_variable_row_field(THD *thd, sp_pcontext *spcont, spcont, rh, spv->offset, field_idx, val, - lex, true); + lex, true, + value_query); return sp_set == NULL || add_instr(sp_set); } @@ -3639,7 +3643,8 @@ sp_head::set_local_variable_row_field_by_name(THD *thd, sp_pcontext *spcont, const Sp_rcontext_handler *rh, sp_variable *spv, const LEX_CSTRING *field_name, - Item *val, LEX *lex) + Item *val, LEX *lex, + const LEX_CSTRING &value_query) { if (!(val= adjust_assignment_source(thd, val, NULL))) return true; @@ -3650,7 +3655,8 @@ sp_head::set_local_variable_row_field_by_name(THD *thd, sp_pcontext *spcont, spv->offset, *field_name, val, - lex, true); + lex, true, + value_query); return sp_set == NULL || add_instr(sp_set); } @@ -3729,7 +3735,8 @@ sp_head::add_set_for_loop_cursor_param_variables(THD *thd, if (set_local_variable(thd, param_spcont, &sp_rcontext_handler_local, spvar, parameters->arguments()[idx], - param_lex, last)) + param_lex, last, + param_lex->get_expr_str())) return true; } return false; diff --git a/sql/sp_head.h b/sql/sp_head.h index 0e4bc952c93..69e7838b25a 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -391,7 +391,8 @@ public: } bool - add_instr_freturn(THD *thd, sp_pcontext *spcont, Item *item, LEX *lex); + add_instr_freturn(THD *thd, sp_pcontext *spcont, Item *item, + sp_expr_lex *lex); bool add_instr_preturn(THD *thd, sp_pcontext *spcont); @@ -411,16 +412,19 @@ public: bool set_local_variable(THD *thd, sp_pcontext *spcont, const Sp_rcontext_handler *rh, sp_variable *spv, Item *val, LEX *lex, - bool responsible_to_free_lex); + bool responsible_to_free_lex, + const LEX_CSTRING &value_query); bool set_local_variable_row_field(THD *thd, sp_pcontext *spcont, const Sp_rcontext_handler *rh, sp_variable *spv, uint field_idx, - Item *val, LEX *lex); + Item *val, LEX *lex, + const LEX_CSTRING &value_query); bool set_local_variable_row_field_by_name(THD *thd, sp_pcontext *spcont, const Sp_rcontext_handler *rh, sp_variable *spv, const LEX_CSTRING *field_name, - Item *val, LEX *lex); + Item *val, LEX *lex, + const LEX_CSTRING &value_query); bool check_package_routine_end_name(const LEX_CSTRING &end_name) const; bool check_standalone_routine_end_name(const sp_name *end_name) const; bool check_group_aggregate_instructions_function() const; @@ -450,7 +454,8 @@ private: m_thd->free_list= prm->get_free_list(); if (set_local_variable(thd, param_spcont, &sp_rcontext_handler_local, - spvar, prm->get_item(), prm, true)) + spvar, prm->get_item(), prm, true, + prm->get_expr_str())) return true; /* Safety: diff --git a/sql/sp_instr.cc b/sql/sp_instr.cc index bc1394ac942..208ed5ccd7d 100644 --- a/sql/sp_instr.cc +++ b/sql/sp_instr.cc @@ -417,6 +417,27 @@ int sp_instr::exec_core(THD *thd, uint *nextp) return 0; } +void sp_lex_instr::get_query(String *sql_query) const +{ + LEX_CSTRING expr_query= get_expr_query(); + + /* + the expression string must me initialized in constructor of a derived class + */ + DBUG_ASSERT(expr_query.str != null_clex_str.str && + expr_query.length != null_clex_str.length); + + /* + Leave the method in case of empty query string. + */ + if (!expr_query.length) + return; + + sql_query->append(C_STRING_WITH_LEN("SELECT ")); + sql_query->append(expr_query); +} + + /* sp_instr_stmt class functions */ diff --git a/sql/sp_instr.h b/sql/sp_instr.h index 6bffd6efa6b..b1d9b95be5b 100644 --- a/sql/sp_instr.h +++ b/sql/sp_instr.h @@ -19,13 +19,15 @@ class sp_lex_cursor: public sp_lex_local, public Query_arena public: sp_lex_cursor(THD *thd, const LEX *oldlex, MEM_ROOT *mem_root_arg) : sp_lex_local(thd, oldlex), - Query_arena(mem_root_arg, STMT_INITIALIZED_FOR_SP) + Query_arena(mem_root_arg, STMT_INITIALIZED_FOR_SP), + m_expr_str(empty_clex_str) {} sp_lex_cursor(THD *thd, const LEX *oldlex) : sp_lex_local(thd, oldlex), Query_arena(thd->lex->sphead->get_main_mem_root(), - STMT_INITIALIZED_FOR_SP) + STMT_INITIALIZED_FOR_SP), + m_expr_str(empty_clex_str) {} ~sp_lex_cursor() { free_items(); } @@ -63,6 +65,19 @@ public: return false; } + + void set_expr_str(const LEX_CSTRING &expr_str) + { + m_expr_str= expr_str; + } + + const LEX_CSTRING &get_expr_str() const + { + return m_expr_str; + } + +private: + LEX_CSTRING m_expr_str; }; @@ -296,7 +311,21 @@ public: virtual void invalidate() = 0; + /** + Return the query string, which can be passed to the parser, + that is a valid SQL-statement. + + @param[out] sql_query SQL-statement query string. + */ + virtual void get_query(String *sql_query) const; + protected: + /** + @return the expression query string. This string can't be passed directly + to the parser as it is most likely not a valid SQL-statement. + */ + virtual LEX_CSTRING get_expr_query() const = 0; + sp_lex_keeper m_lex_keeper; }; @@ -316,16 +345,14 @@ class sp_instr_stmt : public sp_lex_instr */ bool m_valid; -public: LEX_STRING m_query; ///< For thd->query - sp_instr_stmt(uint ip, sp_pcontext *ctx, LEX *lex) +public: + sp_instr_stmt(uint ip, sp_pcontext *ctx, LEX *lex, const LEX_STRING& query) : sp_lex_instr(ip, ctx, lex, true), - m_valid(true) - { - m_query.str= 0; - m_query.length= 0; - } + m_valid(true), + m_query(query) + {} virtual ~sp_instr_stmt() = default; @@ -345,6 +372,17 @@ public: m_valid= false; } + void get_query(String *sql_query) const override + { + sql_query->append(get_expr_query()); + } + +protected: + LEX_CSTRING get_expr_query() const override + { + return LEX_CSTRING{m_query.str, m_query.length}; + } + public: PSI_statement_info* get_psi_info() override { return & psi_info; } static PSI_statement_info psi_info; @@ -360,11 +398,13 @@ public: sp_instr_set(uint ip, sp_pcontext *ctx, const Sp_rcontext_handler *rh, uint offset, Item *val, - LEX *lex, bool lex_resp) + LEX *lex, bool lex_resp, + const LEX_CSTRING &expr_str) : sp_lex_instr(ip, ctx, lex, lex_resp), m_rcontext_handler(rh), m_offset(offset), - m_value(val) + m_value(val), + m_expr_str(expr_str) {} virtual ~sp_instr_set() = default; @@ -386,11 +426,19 @@ public: } protected: + LEX_CSTRING get_expr_query() const override + { + return m_expr_str; + } + sp_rcontext *get_rcontext(THD *thd) const; const Sp_rcontext_handler *m_rcontext_handler; uint m_offset; ///< Frame offset Item *m_value; +private: + LEX_CSTRING m_expr_str; + public: PSI_statement_info* get_psi_info() override { return & psi_info; } static PSI_statement_info psi_info; @@ -414,8 +462,9 @@ public: const Sp_rcontext_handler *rh, uint offset, uint field_offset, Item *val, - LEX *lex, bool lex_resp) - : sp_instr_set(ip, ctx, rh, offset, val, lex, lex_resp), + LEX *lex, bool lex_resp, + const LEX_CSTRING &value_query) + : sp_instr_set(ip, ctx, rh, offset, val, lex, lex_resp, value_query), m_field_offset(field_offset) {} @@ -457,8 +506,9 @@ public: const Sp_rcontext_handler *rh, uint offset, const LEX_CSTRING &field_name, Item *val, - LEX *lex, bool lex_resp) - : sp_instr_set(ip, ctx, rh, offset, val, lex, lex_resp), + LEX *lex, bool lex_resp, + const LEX_CSTRING &value_query) + : sp_instr_set(ip, ctx, rh, offset, val, lex, lex_resp, value_query), m_field_name(field_name) {} @@ -482,10 +532,12 @@ class sp_instr_set_trigger_field : public sp_lex_instr public: sp_instr_set_trigger_field(uint ip, sp_pcontext *ctx, Item_trigger_field *trg_fld, - Item *val, LEX *lex) + Item *val, LEX *lex, + const LEX_CSTRING &value_query) : sp_lex_instr(ip, ctx, lex, true), trigger_field(trg_fld), - value(val) + value(val), + m_expr_str(value_query) {} virtual ~sp_instr_set_trigger_field() = default; @@ -506,9 +558,19 @@ public: value= nullptr; } +protected: + LEX_CSTRING get_expr_query() const override + { + return m_expr_str; + } + private: Item_trigger_field *trigger_field; Item *value; + /** + SQL clause corresponding to the expression value. + */ + LEX_CSTRING m_expr_str; public: PSI_statement_info* get_psi_info() override { return & psi_info; } @@ -609,16 +671,20 @@ class sp_instr_jump_if_not : public sp_lex_instr, public sp_instr_opt_meta void operator=(sp_instr_jump_if_not &); public: - sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i, LEX *lex) + sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i, LEX *lex, + const LEX_CSTRING &expr_query) : sp_lex_instr(ip, ctx, lex, true), sp_instr_opt_meta(0), - m_expr(i) + m_expr(i), + m_expr_str(expr_query) {} - sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i, uint dest, LEX *lex) + sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i, uint dest, LEX *lex, + const LEX_CSTRING &expr_query) : sp_lex_instr(ip, ctx, lex, true), sp_instr_opt_meta(dest), - m_expr(i) + m_expr(i), + m_expr_str(expr_query) {} virtual ~sp_instr_jump_if_not() = default; @@ -669,8 +735,15 @@ public: m_expr= nullptr; } +protected: + LEX_CSTRING get_expr_query() const override + { + return m_expr_str; + } + private: Item *m_expr; ///< The condition + LEX_CSTRING m_expr_str; public: PSI_statement_info* get_psi_info() override { return & psi_info; } @@ -713,10 +786,11 @@ class sp_instr_freturn : public sp_lex_instr public: sp_instr_freturn(uint ip, sp_pcontext *ctx, - Item *val, const Type_handler *handler, LEX *lex) + Item *val, const Type_handler *handler, sp_expr_lex *lex) : sp_lex_instr(ip, ctx, lex, true), m_value(val), - m_type_handler(handler) + m_type_handler(handler), + m_expr_str(lex->get_expr_str()) {} virtual ~sp_instr_freturn() = default; @@ -744,9 +818,20 @@ public: } protected: + LEX_CSTRING get_expr_query() const override + { + return m_expr_str; + } + Item *m_value; const Type_handler *m_type_handler; +private: + /** + SQL-query corresponding to the RETURN-expression. + */ + LEX_CSTRING m_expr_str; + public: PSI_statement_info* get_psi_info() override { return & psi_info; } static PSI_statement_info psi_info; @@ -899,10 +984,11 @@ class sp_instr_cpush : public sp_lex_instr, public sp_cursor void operator=(sp_instr_cpush &); public: - sp_instr_cpush(uint ip, sp_pcontext *ctx, LEX *lex, uint offset) + sp_instr_cpush(uint ip, sp_pcontext *ctx, sp_lex_cursor *lex, uint offset) : sp_lex_instr(ip, ctx, lex, true), m_cursor(offset), - m_metadata_changed(false) + m_metadata_changed(false), + m_cursor_stmt(lex->get_expr_str()) {} virtual ~sp_instr_cpush() = default; @@ -936,6 +1022,17 @@ public: return &m_lex_keeper; } + void get_query(String *sql_query) const override + { + sql_query->append(get_expr_query()); + } + +protected: + LEX_CSTRING get_expr_query() const override + { + return m_cursor_stmt; + } + private: uint m_cursor; /**< Frame offset (for debugging) */ /** @@ -944,6 +1041,8 @@ private: */ bool m_metadata_changed; + LEX_CSTRING m_cursor_stmt; + public: PSI_statement_info* get_psi_info() override { return & psi_info; } static PSI_statement_info psi_info; @@ -1026,6 +1125,7 @@ class sp_instr_cursor_copy_struct: public sp_lex_instr be reinitialized. */ bool m_valid; + LEX_CSTRING m_cursor_stmt; public: sp_instr_cursor_copy_struct(uint ip, sp_pcontext *ctx, uint coffs, @@ -1033,7 +1133,8 @@ public: : sp_lex_instr(ip, ctx, lex, false), m_cursor(coffs), m_var(voffs), - m_valid(true) + m_valid(true), + m_cursor_stmt(lex->get_expr_str()) {} virtual ~sp_instr_cursor_copy_struct() = default; int execute(THD *thd, uint *nextp) override; @@ -1049,6 +1150,17 @@ public: m_valid= false; } + void get_query(String *sql_query) const override + { + sql_query->append(get_expr_query()); + } + +protected: + LEX_CSTRING get_expr_query() const override + { + return m_cursor_stmt; + } + public: PSI_statement_info* get_psi_info() override { return & psi_info; } static PSI_statement_info psi_info; @@ -1181,11 +1293,13 @@ class sp_instr_set_case_expr : public sp_lex_instr, public sp_instr_opt_meta { public: sp_instr_set_case_expr(uint ip, sp_pcontext *ctx, uint case_expr_id, - Item *case_expr, LEX *lex) + Item *case_expr, LEX *lex, + const LEX_CSTRING &case_expr_query) : sp_lex_instr(ip, ctx, lex, true), sp_instr_opt_meta(0), m_case_expr_id(case_expr_id), - m_case_expr(case_expr) + m_case_expr(case_expr), + m_expr_str(case_expr_query) {} virtual ~sp_instr_set_case_expr() = default; @@ -1221,9 +1335,16 @@ public: m_case_expr= nullptr; } +protected: + LEX_CSTRING get_expr_query() const override + { + return m_expr_str; + } + private: uint m_case_expr_id; Item *m_case_expr; + LEX_CSTRING m_expr_str; public: PSI_statement_info* get_psi_info() override { return & psi_info; } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 962ad8ebc7c..a36ca367c0d 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -8417,3 +8417,11 @@ void Charset_loader_server::raise_not_applicable_error(const char *cs, { my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0), cl, cs); } + + +LEX_CSTRING make_string(THD *thd, const char *start_ptr, + const char *end_ptr) +{ + size_t length= end_ptr - start_ptr; + return {strmake_root(thd->mem_root, start_ptr, length), length}; +} diff --git a/sql/sql_class.h b/sql/sql_class.h index fcada2d7ace..06cb6b7e3f1 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -8035,5 +8035,21 @@ public: } }; + +/** + Make a new string allocated on THD's mem-root. + + @param thd thread handler. + @param start_ptr start of the new string. + @param end_ptr end of the new string. + + @return LEX_CSTRING object, containing a pointer to a newly + constructed/allocated string, and its length. The data member + LEX_CSTRING::str has the value nullptr in case of out-of-memory error. +*/ + +LEX_CSTRING make_string(THD *thd, const char *start_ptr, + const char *end_ptr); + #endif /* MYSQL_SERVER */ #endif /* SQL_CLASS_INCLUDED */ diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 3c13bb1e68f..34d08736fd3 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -77,7 +77,7 @@ int sp_expr_lex::case_stmt_action_expr() i= new (thd->mem_root) sp_instr_set_case_expr(sphead->instructions(), spcont, case_expr_id, - get_item(), this); + get_item(), this, m_expr_str); sphead->add_cont_backpatch(i); return sphead->add_instr(i); @@ -111,10 +111,12 @@ int sp_expr_lex::case_stmt_action_when(bool simple) #endif expr= new (thd->mem_root) Item_func_eq(thd, var, get_item()); - i= new (thd->mem_root) sp_instr_jump_if_not(ip, spcont, expr, this); + i= new (thd->mem_root) sp_instr_jump_if_not(ip, spcont, expr, this, + m_expr_str); } else - i= new (thd->mem_root) sp_instr_jump_if_not(ip, spcont, get_item(), this); + i= new (thd->mem_root) sp_instr_jump_if_not(ip, spcont, get_item(), this, + m_expr_str); /* BACKPATCH: Registering forward jump from @@ -207,7 +209,8 @@ LEX::set_system_variable(enum enum_var_type var_type, @return TRUE if error, FALSE otherwise. */ -bool LEX::set_trigger_new_row(const LEX_CSTRING *name, Item *val) +bool LEX::set_trigger_new_row(const LEX_CSTRING *name, Item *val, + const LEX_CSTRING &expr_str) { Item_trigger_field *trg_fld; sp_instr_set_trigger_field *sp_fld; @@ -230,7 +233,7 @@ bool LEX::set_trigger_new_row(const LEX_CSTRING *name, Item *val) sp_fld= new (thd->mem_root) sp_instr_set_trigger_field(sphead->instructions(), - spcont, trg_fld, val, this); + spcont, trg_fld, val, this, expr_str); if (unlikely(sp_fld == NULL)) return TRUE; @@ -420,6 +423,7 @@ bool sp_create_assignment_lex(THD *thd, const char *pos) @param thd - Thread context @param no_lookahead - True if the parser has no lookahead + @param rhs_value_str - a string value for right hand side of assignment @param need_set_keyword - if a SET statement "SET a=10", or a direct assignment overwise "a:=10" @return false if success, true otherwise. @@ -6453,7 +6457,8 @@ void LEX::sp_variable_declarations_init(THD *thd, int nvars) bool LEX::sp_variable_declarations_set_default(THD *thd, int nvars, - Item *dflt_value_item) + Item *dflt_value_item, + const LEX_CSTRING &expr_str) { bool has_default_clause= dflt_value_item != NULL; if (!has_default_clause && @@ -6489,7 +6494,7 @@ bool LEX::sp_variable_declarations_set_default(THD *thd, int nvars, sp_instr_set(sphead->instructions(), spcont, &sp_rcontext_handler_local, spvar->offset, dflt_value_item, - this, last); + this, last, expr_str); if (unlikely(is == NULL || sphead->add_instr(is))) return true; } @@ -6501,7 +6506,8 @@ bool LEX::sp_variable_declarations_copy_type_finalize(THD *thd, int nvars, const Column_definition &ref, Row_definition_list *fields, - Item *default_value) + Item *default_value, + const LEX_CSTRING &expr_str) { for (uint i= 0 ; i < (uint) nvars; i++) { @@ -6515,7 +6521,7 @@ LEX::sp_variable_declarations_copy_type_finalize(THD *thd, int nvars, spvar->field_def.field_name= spvar->name; } if (unlikely(sp_variable_declarations_set_default(thd, nvars, - default_value))) + default_value, expr_str))) return true; spcont->declare_var_boundary(0); return sphead->restore_lex(thd); @@ -6524,20 +6530,22 @@ LEX::sp_variable_declarations_copy_type_finalize(THD *thd, int nvars, bool LEX::sp_variable_declarations_finalize(THD *thd, int nvars, const Column_definition *cdef, - Item *dflt_value_item) + Item *dflt_value_item, + const LEX_CSTRING &expr_str) { DBUG_ASSERT(cdef); Column_definition tmp(*cdef); if (sphead->fill_spvar_definition(thd, &tmp)) return true; return sp_variable_declarations_copy_type_finalize(thd, nvars, tmp, NULL, - dflt_value_item); + dflt_value_item, expr_str); } bool LEX::sp_variable_declarations_row_finalize(THD *thd, int nvars, Row_definition_list *row, - Item *dflt_value_item) + Item *dflt_value_item, + const LEX_CSTRING &expr_str) { DBUG_ASSERT(row); /* @@ -6563,7 +6571,8 @@ bool LEX::sp_variable_declarations_row_finalize(THD *thd, int nvars, return true; } - if (sp_variable_declarations_set_default(thd, nvars, dflt_value_item)) + if (sp_variable_declarations_set_default(thd, nvars, dflt_value_item, + expr_str)) return true; spcont->declare_var_boundary(0); return sphead->restore_lex(thd); @@ -6582,7 +6591,8 @@ bool LEX::sp_variable_declarations_row_finalize(THD *thd, int nvars, bool LEX::sp_variable_declarations_rowtype_finalize(THD *thd, int nvars, Qualified_column_ident *ref, - Item *def) + Item *def, + const LEX_CSTRING &expr_str) { uint coffp; const sp_pcursor *pcursor= ref->table.str && ref->db.str ? NULL : @@ -6590,7 +6600,8 @@ LEX::sp_variable_declarations_rowtype_finalize(THD *thd, int nvars, false); if (pcursor) return sp_variable_declarations_cursor_rowtype_finalize(thd, nvars, - coffp, def); + coffp, def, + expr_str); /* When parsing a qualified identifier chain, the parser does not know yet if it's going to be a qualified column name (for %TYPE), @@ -6605,7 +6616,7 @@ LEX::sp_variable_declarations_rowtype_finalize(THD *thd, int nvars, return sp_variable_declarations_table_rowtype_finalize(thd, nvars, ref->table, ref->m_column, - def); + def, expr_str); } @@ -6613,7 +6624,8 @@ bool LEX::sp_variable_declarations_table_rowtype_finalize(THD *thd, int nvars, const LEX_CSTRING &db, const LEX_CSTRING &table, - Item *def) + Item *def, + const LEX_CSTRING &expr_str) { Table_ident *table_ref; if (unlikely(!(table_ref= @@ -6626,7 +6638,7 @@ LEX::sp_variable_declarations_table_rowtype_finalize(THD *thd, int nvars, spvar->field_def.set_table_rowtype_ref(table_ref); sphead->fill_spvar_definition(thd, &spvar->field_def, &spvar->name); } - if (sp_variable_declarations_set_default(thd, nvars, def)) + if (sp_variable_declarations_set_default(thd, nvars, def, expr_str)) return true; // Make sure sp_rcontext is created using the invoker security context: sphead->m_flags|= sp_head::HAS_COLUMN_TYPE_REFS; @@ -6638,7 +6650,8 @@ LEX::sp_variable_declarations_table_rowtype_finalize(THD *thd, int nvars, bool LEX::sp_variable_declarations_cursor_rowtype_finalize(THD *thd, int nvars, uint offset, - Item *def) + Item *def, + const LEX_CSTRING &expr_str) { const sp_pcursor *pcursor= spcont->find_cursor(offset); @@ -6658,7 +6671,8 @@ LEX::sp_variable_declarations_cursor_rowtype_finalize(THD *thd, int nvars, sphead->fill_spvar_definition(thd, &spvar->field_def, &spvar->name); } - if (unlikely(sp_variable_declarations_set_default(thd, nvars, def))) + if (unlikely(sp_variable_declarations_set_default(thd, nvars, def, + expr_str))) return true; // Make sure sp_rcontext is created using the invoker security context: sphead->m_flags|= sp_head::HAS_COLUMN_TYPE_REFS; @@ -6676,18 +6690,22 @@ LEX::sp_variable_declarations_cursor_rowtype_finalize(THD *thd, int nvars, bool LEX::sp_variable_declarations_with_ref_finalize(THD *thd, int nvars, Qualified_column_ident *ref, - Item *def) + Item *def, + const LEX_CSTRING &expr_str) { return ref->db.length == 0 && ref->table.length == 0 ? - sp_variable_declarations_vartype_finalize(thd, nvars, ref->m_column, def) : - sp_variable_declarations_column_type_finalize(thd, nvars, ref, def); + sp_variable_declarations_vartype_finalize(thd, nvars, ref->m_column, def, + expr_str) : + sp_variable_declarations_column_type_finalize(thd, nvars, ref, def, + expr_str); } bool LEX::sp_variable_declarations_column_type_finalize(THD *thd, int nvars, Qualified_column_ident *ref, - Item *def) + Item *def, + const LEX_CSTRING &expr_str) { for (uint i= 0 ; i < (uint) nvars; i++) { @@ -6696,7 +6714,7 @@ LEX::sp_variable_declarations_column_type_finalize(THD *thd, int nvars, spvar->field_def.field_name= spvar->name; } sphead->m_flags|= sp_head::HAS_COLUMN_TYPE_REFS; - if (sp_variable_declarations_set_default(thd, nvars, def)) + if (sp_variable_declarations_set_default(thd, nvars, def, expr_str)) return true; spcont->declare_var_boundary(0); return sphead->restore_lex(thd); @@ -6706,7 +6724,8 @@ LEX::sp_variable_declarations_column_type_finalize(THD *thd, int nvars, bool LEX::sp_variable_declarations_vartype_finalize(THD *thd, int nvars, const LEX_CSTRING &ref, - Item *default_value) + Item *default_value, + const LEX_CSTRING &expr_str) { sp_variable *t; if (!spcont || !(t= spcont->find_variable(&ref, false))) @@ -6720,14 +6739,16 @@ LEX::sp_variable_declarations_vartype_finalize(THD *thd, int nvars, uint offset= t->field_def.cursor_rowtype_offset(); return sp_variable_declarations_cursor_rowtype_finalize(thd, nvars, offset, - default_value); + default_value, + expr_str); } if (t->field_def.is_column_type_ref()) { Qualified_column_ident *tmp= t->field_def.column_type_ref(); return sp_variable_declarations_column_type_finalize(thd, nvars, tmp, - default_value); + default_value, + expr_str); } if (t->field_def.is_table_rowtype_ref()) @@ -6736,7 +6757,8 @@ LEX::sp_variable_declarations_vartype_finalize(THD *thd, int nvars, return sp_variable_declarations_table_rowtype_finalize(thd, nvars, tmp->db, tmp->table, - default_value); + default_value, + expr_str); } // A reference to a scalar or a row variable with an explicit data type @@ -6744,7 +6766,8 @@ LEX::sp_variable_declarations_vartype_finalize(THD *thd, int nvars, t->field_def, t->field_def. row_field_definitions(), - default_value); + default_value, + expr_str); } @@ -6773,7 +6796,8 @@ LEX::sp_variable_declarations_vartype_finalize(THD *thd, int nvars, sp_variable *LEX::sp_add_for_loop_variable(THD *thd, const LEX_CSTRING *name, - Item *value) + Item *value, + const LEX_CSTRING &expr_str) { sp_variable *spvar= spcont->add_variable(thd, name); spcont->declare_var_boundary(1); @@ -6789,7 +6813,7 @@ sp_variable *LEX::sp_add_for_loop_variable(THD *thd, const LEX_CSTRING *name, sp_instr_set(sphead->instructions(), spcont, &sp_rcontext_handler_local, spvar->offset, value, - this, true); + this, true, expr_str); if (unlikely(is == NULL || sphead->add_instr(is))) return NULL; spcont->declare_var_boundary(0); @@ -6888,7 +6912,8 @@ bool LEX::sp_for_loop_condition(THD *thd, const Lex_for_loop_st &loop) Item *expr= loop.m_direction > 0 ? (Item *) new (thd->mem_root) Item_func_le(thd, args[0], args[1]) : (Item *) new (thd->mem_root) Item_func_ge(thd, args[0], args[1]); - return unlikely(!expr) || unlikely(sp_while_loop_expression(thd, expr)); + return unlikely(!expr) || unlikely(sp_while_loop_expression(thd, expr, + empty_clex_str)); } @@ -6920,7 +6945,7 @@ bool LEX::sp_for_loop_cursor_condition_test(THD *thd, Item_func_cursor_found(thd, cursor_name, loop.m_cursor_offset)))) return true; - if (thd->lex->sp_while_loop_expression(thd, expr)) + if (thd->lex->sp_while_loop_expression(thd, expr, empty_clex_str)) return true; return thd->lex->sphead->restore_lex(thd); } @@ -6945,13 +6970,18 @@ bool LEX::sp_for_loop_intrange_declarations(THD *thd, Lex_for_loop_st *loop, } if (!(loop->m_index= bounds.m_index->sp_add_for_loop_variable(thd, index, - bounds.m_index->get_item()))) + bounds.m_index->get_item(), + bounds.m_index->get_expr_str()) + )) return true; if (unlikely(!(loop->m_target_bound= bounds.m_target_bound-> sp_add_for_loop_target_bound(thd, bounds. - m_target_bound->get_item())))) + m_target_bound->get_item(), + bounds. + m_target_bound->get_expr_str() + )))) return true; loop->m_direction= bounds.m_direction; loop->m_implicit_cursor= 0; @@ -7044,7 +7074,8 @@ bool LEX::sp_for_loop_increment(THD *thd, const Lex_for_loop_st &loop) if (unlikely(!expr) || unlikely(sphead->set_local_variable(thd, spcont, &sp_rcontext_handler_local, - loop.m_index, expr, this, true))) + loop.m_index, expr, this, true, + empty_clex_str))) return true; return false; } @@ -7103,6 +7134,7 @@ bool LEX::sp_for_loop_outer_block_finalize(THD *thd, bool LEX::sp_declare_cursor(THD *thd, const LEX_CSTRING *name, sp_lex_cursor *cursor_stmt, sp_pcontext *param_ctx, bool add_cpush_instr) + { uint offp; sp_instr_cpush *i; @@ -7552,7 +7584,7 @@ bool LEX::sp_leave_statement(THD *thd, const LEX_CSTRING *label_name) my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "LEAVE", label_name->str); return true; } - return sp_exit_block(thd, lab, NULL); + return sp_exit_block(thd, lab, NULL, empty_clex_str); } bool LEX::sp_goto_statement(THD *thd, const LEX_CSTRING *label_name) @@ -7620,7 +7652,8 @@ bool LEX::sp_exit_block(THD *thd, sp_label *lab) } -bool LEX::sp_exit_block(THD *thd, sp_label *lab, Item *when) +bool LEX::sp_exit_block(THD *thd, sp_label *lab, Item *when, + const LEX_CSTRING &expr_str) { if (!when) return sp_exit_block(thd, lab); @@ -7630,7 +7663,7 @@ bool LEX::sp_exit_block(THD *thd, sp_label *lab, Item *when) sp_instr_jump_if_not *i= new (thd->mem_root) sp_instr_jump_if_not(sphead->instructions(), spcont, - when, this); + when, this, expr_str); if (unlikely(i == NULL) || unlikely(sphead->add_instr(i)) || unlikely(sp_exit_block(thd, lab))) @@ -7640,7 +7673,7 @@ bool LEX::sp_exit_block(THD *thd, sp_label *lab, Item *when) } -bool LEX::sp_exit_statement(THD *thd, Item *item) +bool LEX::sp_exit_statement(THD *thd, Item *item, const LEX_CSTRING &expr_str) { sp_label *lab= spcont->find_label_current_loop_start(); if (unlikely(!lab)) @@ -7649,11 +7682,12 @@ bool LEX::sp_exit_statement(THD *thd, Item *item) return true; } DBUG_ASSERT(lab->type == sp_label::ITERATION); - return sp_exit_block(thd, lab, item); + return sp_exit_block(thd, lab, item, expr_str); } -bool LEX::sp_exit_statement(THD *thd, const LEX_CSTRING *label_name, Item *item) +bool LEX::sp_exit_statement(THD *thd, const LEX_CSTRING *label_name, + Item *item, const LEX_CSTRING &expr_str) { sp_label *lab= spcont->find_label(label_name); if (unlikely(!lab || lab->type != sp_label::ITERATION)) @@ -7661,7 +7695,7 @@ bool LEX::sp_exit_statement(THD *thd, const LEX_CSTRING *label_name, Item *item) my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "EXIT", label_name->str); return true; } - return sp_exit_block(thd, lab, item); + return sp_exit_block(thd, lab, item, expr_str); } @@ -7718,7 +7752,8 @@ bool LEX::sp_continue_statement(THD *thd, const LEX_CSTRING *label_name) } -bool LEX::sp_continue_loop(THD *thd, sp_label *lab, Item *when) +bool LEX::sp_continue_loop(THD *thd, sp_label *lab, Item *when, + const LEX_CSTRING &expr_str) { DBUG_ASSERT(when); DBUG_ASSERT(sphead == thd->lex->sphead); @@ -7726,7 +7761,7 @@ bool LEX::sp_continue_loop(THD *thd, sp_label *lab, Item *when) sp_instr_jump_if_not *i= new (thd->mem_root) sp_instr_jump_if_not(sphead->instructions(), spcont, - when, this); + when, this, expr_str); if (unlikely(i == NULL) || unlikely(sphead->add_instr(i)) || unlikely(sp_continue_loop(thd, lab))) @@ -7745,7 +7780,7 @@ bool sp_expr_lex::sp_continue_when_statement(THD *thd) return true; } DBUG_ASSERT(lab->type == sp_label::ITERATION); - return sp_continue_loop(thd, lab, get_item()); + return sp_continue_loop(thd, lab, get_item(), m_expr_str); } @@ -7758,7 +7793,7 @@ bool sp_expr_lex::sp_continue_when_statement(THD *thd, my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "CONTINUE", label_name->str); return true; } - return sp_continue_loop(thd, lab, get_item()); + return sp_continue_loop(thd, lab, get_item(), m_expr_str); } @@ -7823,10 +7858,11 @@ void LEX::sp_pop_loop_empty_label(THD *thd) } -bool LEX::sp_while_loop_expression(THD *thd, Item *item) +bool LEX::sp_while_loop_expression(THD *thd, Item *item, + const LEX_CSTRING &expr_str) { sp_instr_jump_if_not *i= new (thd->mem_root) - sp_instr_jump_if_not(sphead->instructions(), spcont, item, this); + sp_instr_jump_if_not(sphead->instructions(), spcont, item, this, expr_str); return (unlikely(i == NULL) || /* Jumping forward */ unlikely(sphead->push_backpatch(thd, i, spcont->last_label())) || @@ -8451,12 +8487,14 @@ Item *LEX::create_item_ident_sp(THD *thd, Lex_ident_sys_st *name, -bool LEX::set_variable(const Lex_ident_sys_st *name, Item *item) +bool LEX::set_variable(const Lex_ident_sys_st *name, Item *item, + const LEX_CSTRING &expr_str) { sp_pcontext *ctx; const Sp_rcontext_handler *rh; sp_variable *spv= find_variable(name, &ctx, &rh); - return spv ? sphead->set_local_variable(thd, ctx, rh, spv, item, this, true) : + return spv ? sphead->set_local_variable(thd, ctx, rh, spv, item, this, true, + expr_str) : set_system_variable(option_type, name, item); } @@ -8467,7 +8505,7 @@ bool LEX::set_variable(const Lex_ident_sys_st *name, Item *item) */ bool LEX::set_variable(const Lex_ident_sys_st *name1, const Lex_ident_sys_st *name2, - Item *item) + Item *item, const LEX_CSTRING &expr_str) { const Sp_rcontext_handler *rh; sp_pcontext *ctx; @@ -8479,17 +8517,18 @@ bool LEX::set_variable(const Lex_ident_sys_st *name1, return sphead->set_local_variable_row_field_by_name(thd, ctx, rh, spv, name2, - item, this); + item, this, + expr_str); // A field of a ROW variable uint row_field_offset; return !spv->find_row_field(name1, name2, &row_field_offset) || sphead->set_local_variable_row_field(thd, ctx, rh, spv, row_field_offset, - item, this); + item, this, expr_str); } if (is_trigger_new_or_old_reference(name1)) - return set_trigger_field(name1, name2, item); + return set_trigger_field(name1, name2, item, expr_str); return set_system_variable(thd, option_type, name1, name2, item); } @@ -8546,7 +8585,7 @@ bool LEX::set_system_variable(THD *thd, enum_var_type var_type, bool LEX::set_trigger_field(const LEX_CSTRING *name1, const LEX_CSTRING *name2, - Item *val) + Item *val, const LEX_CSTRING &expr_str) { DBUG_ASSERT(is_trigger_new_or_old_reference(name1)); if (unlikely(name1->str[0]=='O' || name1->str[0]=='o')) @@ -8564,7 +8603,7 @@ bool LEX::set_trigger_field(const LEX_CSTRING *name1, const LEX_CSTRING *name2, my_error(ER_TRG_CANT_CHANGE_ROW, MYF(0), "NEW", "after "); return true; } - return set_trigger_new_row(name2, val); + return set_trigger_new_row(name2, val, expr_str); } @@ -10487,7 +10526,14 @@ bool SELECT_LEX::make_unique_derived_name(THD *thd, LEX_CSTRING *alias) /* Make a new sp_instr_stmt and set its m_query to a concatenation of two strings. + + @param thd Thread context + @param prefix the first part of a concatenated string value + @param suffix the second part of a concatenated string value + + @return false on success, else return true */ + bool LEX::new_sp_instr_stmt(THD *thd, const LEX_CSTRING &prefix, const LEX_CSTRING &suffix) @@ -10495,17 +10541,17 @@ bool LEX::new_sp_instr_stmt(THD *thd, LEX_STRING qbuff; sp_instr_stmt *i; - if (!(i= new (thd->mem_root) sp_instr_stmt(sphead->instructions(), - spcont, this))) - return true; - qbuff.length= prefix.length + suffix.length; if (!(qbuff.str= (char*) alloc_root(thd->mem_root, qbuff.length + 1))) return true; if (prefix.length) memcpy(qbuff.str, prefix.str, prefix.length); strmake(qbuff.str + prefix.length, suffix.str, suffix.length); - i->m_query= qbuff; + + if (!(i= new (thd->mem_root) sp_instr_stmt(sphead->instructions(), + spcont, this, qbuff))) + return true; + return sphead->add_instr(i); } @@ -11575,7 +11621,7 @@ bool sp_expr_lex::sp_repeat_loop_finalize(THD *thd) uint ip= sphead->instructions(); sp_label *lab= spcont->last_label(); /* Jumping back */ sp_instr_jump_if_not *i= new (thd->mem_root) - sp_instr_jump_if_not(ip, spcont, get_item(), lab->ip, this); + sp_instr_jump_if_not(ip, spcont, get_item(), lab->ip, this, m_expr_str); if (unlikely(i == NULL) || unlikely(sphead->add_instr(i))) return true; @@ -11589,7 +11635,8 @@ bool sp_expr_lex::sp_if_expr(THD *thd) { uint ip= sphead->instructions(); sp_instr_jump_if_not *i= new (thd->mem_root) - sp_instr_jump_if_not(ip, spcont, get_item(), this); + sp_instr_jump_if_not(ip, spcont, get_item(), this, + m_expr_str); return (unlikely(i == NULL) || unlikely(sphead->push_backpatch(thd, i, diff --git a/sql/sql_lex.h b/sql/sql_lex.h index a243848b683..7e8a8bb2be7 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3318,7 +3318,8 @@ private: class sp_label **splabel); bool sp_change_context(THD *thd, const sp_pcontext *ctx, bool exclusive); bool sp_exit_block(THD *thd, sp_label *lab); - bool sp_exit_block(THD *thd, sp_label *lab, Item *when); + bool sp_exit_block(THD *thd, sp_label *lab, Item *when, + const LEX_CSTRING &expr_str); bool sp_continue_loop(THD *thd, sp_label *lab); @@ -3333,7 +3334,8 @@ private: bool check_expr_allows_fields_or_error(THD *thd, const char *name) const; protected: - bool sp_continue_loop(THD *thd, sp_label *lab, Item *when); + bool sp_continue_loop(THD *thd, sp_label *lab, Item *when, + const LEX_CSTRING &expr_str); public: void parse_error(uint err_number= ER_SYNTAX_ERROR); @@ -3888,9 +3890,10 @@ public: bool set_names(const char *pos, const Lex_exact_charset_opt_extended_collate &cs, bool no_lookahead); - bool set_trigger_new_row(const LEX_CSTRING *name, Item *val); + bool set_trigger_new_row(const LEX_CSTRING *name, Item *val, + const LEX_CSTRING &expr_str); bool set_trigger_field(const LEX_CSTRING *name1, const LEX_CSTRING *name2, - Item *val); + Item *val, const LEX_CSTRING &expr_str); bool set_system_variable(enum_var_type var_type, sys_var *var, const Lex_ident_sys_st *base_name, Item *val); bool set_system_variable(enum_var_type var_type, @@ -3946,40 +3949,52 @@ public: sp_pcontext *not_used_ctx; return find_variable(name, ¬_used_ctx, rh); } - bool set_variable(const Lex_ident_sys_st *name, Item *item); + bool set_variable(const Lex_ident_sys_st *name, Item *item, + const LEX_CSTRING &expr_str); bool set_variable(const Lex_ident_sys_st *name1, - const Lex_ident_sys_st *name2, Item *item); + const Lex_ident_sys_st *name2, Item *item, + const LEX_CSTRING &expr_str); void sp_variable_declarations_init(THD *thd, int nvars); bool sp_variable_declarations_finalize(THD *thd, int nvars, const Column_definition *cdef, - Item *def); - bool sp_variable_declarations_set_default(THD *thd, int nvars, Item *def); + Item *def, + const LEX_CSTRING &expr_str); + bool sp_variable_declarations_set_default(THD *thd, int nvars, Item *def, + const LEX_CSTRING &expr_str); bool sp_variable_declarations_row_finalize(THD *thd, int nvars, Row_definition_list *row, - Item *def); + Item *def, + const LEX_CSTRING &expr_str); bool sp_variable_declarations_with_ref_finalize(THD *thd, int nvars, Qualified_column_ident *col, - Item *def); + Item *def, + const LEX_CSTRING &expr_str); bool sp_variable_declarations_rowtype_finalize(THD *thd, int nvars, Qualified_column_ident *, - Item *def); + Item *def, + const LEX_CSTRING &expr_str); bool sp_variable_declarations_cursor_rowtype_finalize(THD *thd, int nvars, uint offset, - Item *def); + Item *def, + const LEX_CSTRING &expr_str); bool sp_variable_declarations_table_rowtype_finalize(THD *thd, int nvars, const LEX_CSTRING &db, const LEX_CSTRING &table, - Item *def); + Item *def, + const LEX_CSTRING &expr_str); bool sp_variable_declarations_column_type_finalize(THD *thd, int nvars, Qualified_column_ident *ref, - Item *def); + Item *def, + const LEX_CSTRING &expr_str); bool sp_variable_declarations_vartype_finalize(THD *thd, int nvars, const LEX_CSTRING &name, - Item *def); + Item *def, + const LEX_CSTRING &expr_str); bool sp_variable_declarations_copy_type_finalize(THD *thd, int nvars, const Column_definition &ref, Row_definition_list *fields, - Item *def); + Item *def, + const LEX_CSTRING &expr_str); LEX_USER *current_user_for_set_password(THD *thd); bool sp_create_set_password_instr(THD *thd, @@ -4267,8 +4282,9 @@ public: uint executable_section_ip, uint exception_count); bool sp_block_with_exceptions_add_empty(THD *thd); - bool sp_exit_statement(THD *thd, Item *when); - bool sp_exit_statement(THD *thd, const LEX_CSTRING *label_name, Item *item); + bool sp_exit_statement(THD *thd, Item *when, const LEX_CSTRING &expr_str); + bool sp_exit_statement(THD *thd, const LEX_CSTRING *label_name, Item *item, + const LEX_CSTRING &expr_str); bool sp_leave_statement(THD *thd, const LEX_CSTRING *label_name); bool sp_goto_statement(THD *thd, const LEX_CSTRING *label_name); @@ -4281,7 +4297,8 @@ public: bool sp_push_loop_empty_label(THD *thd); bool sp_pop_loop_label(THD *thd, const LEX_CSTRING *label_name); void sp_pop_loop_empty_label(THD *thd); - bool sp_while_loop_expression(THD *thd, Item *expr); + bool sp_while_loop_expression(THD *thd, Item *expr, + const LEX_CSTRING &expr_str); bool sp_while_loop_finalize(THD *thd); bool sp_if_after_statements(THD *thd); bool sp_push_goto_label(THD *thd, const LEX_CSTRING *label_name); @@ -4291,11 +4308,13 @@ public: /* Integer range FOR LOOP methods */ sp_variable *sp_add_for_loop_variable(THD *thd, const LEX_CSTRING *name, - Item *value); - sp_variable *sp_add_for_loop_target_bound(THD *thd, Item *value) + Item *value, + const LEX_CSTRING &expr_str); + sp_variable *sp_add_for_loop_target_bound(THD *thd, Item *value, + const LEX_CSTRING &expr_str) { LEX_CSTRING name= { STRING_WITH_LEN("[target_bound]") }; - return sp_add_for_loop_variable(thd, &name, value); + return sp_add_for_loop_variable(thd, &name, value, expr_str); } bool sp_for_loop_intrange_declarations(THD *thd, Lex_for_loop_st *loop, const LEX_CSTRING *index, @@ -4894,6 +4913,15 @@ public: builtin_select.options |= SELECT_DESCRIBE; } + + /** + Check if the current statement uses meta-data (uses a table or a stored + routine). + */ + bool is_metadata_used() const + { + return query_tables != nullptr || sroutines.records > 0; + } }; @@ -5118,10 +5146,12 @@ public: class sp_expr_lex: public sp_lex_local { Item *m_item; // The expression + LEX_CSTRING m_expr_str; public: sp_expr_lex(THD *thd, LEX *oldlex) :sp_lex_local(thd, oldlex), - m_item(NULL) + m_item(nullptr), + m_expr_str(empty_clex_str) { } void set_item(Item *item) { @@ -5137,10 +5167,18 @@ public: int case_stmt_action_when(bool simple); bool sp_while_loop_expression(THD *thd) { - return LEX::sp_while_loop_expression(thd, get_item()); + return LEX::sp_while_loop_expression(thd, get_item(), m_expr_str); } bool sp_repeat_loop_finalize(THD *thd); bool sp_if_expr(THD *thd); + void set_expr_str(const LEX_CSTRING &expr_str) + { + m_expr_str= expr_str; + } + const LEX_CSTRING &get_expr_str() const + { + return m_expr_str; + } }; @@ -5171,11 +5209,13 @@ class sp_assignment_lex: public sp_lex_local { Item *m_item; // The expression Item *m_free_list; // The associated free_list (sub-expressions) + LEX_CSTRING m_expr_str; public: sp_assignment_lex(THD *thd, LEX *oldlex) :sp_lex_local(thd, oldlex), m_item(NULL), - m_free_list(NULL) + m_free_list(nullptr), + m_expr_str(empty_clex_str) { } void set_item_and_free_list(Item *item, Item *free_list) { @@ -5190,6 +5230,14 @@ public: { return m_free_list; } + void set_expr_str(const LEX_CSTRING &expr_str) + { + m_expr_str= expr_str; + } + const LEX_CSTRING &get_expr_str() const + { + return m_expr_str; + } }; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c0215a73e8c..a015a6ed48f 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -333,6 +333,11 @@ void _CONCAT_UNDERSCORED(turn_parser_debug_on,yyparse)() enum Column_definition::enum_column_versioning vers_column_versioning; enum plsql_cursor_attr_t plsql_cursor_attr; privilege_t privilege; + struct + { + Item *expr; + LEX_CSTRING expr_str; + } expr_and_query_str; } %{ @@ -1386,7 +1391,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); %type remember_name remember_end remember_tok_start + remember_cpp_ptr wild_and_where + remember_start_opt %type field_length_str @@ -1511,9 +1518,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); table_wild simple_expr column_default_non_parenthesized_expr udf_expr primary_expr string_factor_expr mysql_concatenation_expr select_sublist_qualified_asterisk - expr_or_ignore expr_or_ignore_or_default set_expr_or_default + expr_or_ignore expr_or_ignore_or_default signed_literal expr_or_literal - sp_opt_default simple_ident_nospvar field_or_var limit_option part_func_expr @@ -1533,6 +1539,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); simple_target_specification condition_number opt_versioning_interval_start + set_expr_misc %type opt_vers_auto_part @@ -1557,6 +1564,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); %type expr_lex +%type sp_opt_default set_expr_or_default + %type assignment_source_lex assignment_source_expr @@ -3229,7 +3238,8 @@ sp_decl_variable_list: { if (unlikely(Lex->sp_variable_declarations_finalize(thd, $1, &Lex->last_field[0], - $4))) + $4.expr, + $4.expr_str))) MYSQL_YYABORT; $$.init_using_vars($1); } @@ -3237,7 +3247,9 @@ sp_decl_variable_list: ROW_SYM row_type_body sp_opt_default { - if (unlikely(Lex->sp_variable_declarations_row_finalize(thd, $1, $3, $4))) + if (unlikely(Lex->sp_variable_declarations_row_finalize(thd, $1, $3, + $4.expr, + $4.expr_str))) MYSQL_YYABORT; $$.init_using_vars($1); } @@ -3282,13 +3294,23 @@ sp_cursor_stmt: if (Lex->main_select_push(true)) MYSQL_YYABORT; } - select + remember_name select remember_end { DBUG_ASSERT(Lex == $1); Lex->pop_select(); //main select - if (unlikely($1->stmt_finalize(thd)) || - unlikely($1->sphead->restore_lex(thd))) + if (unlikely($1->stmt_finalize(thd))) MYSQL_YYABORT; + if (Lex->is_metadata_used()) + { + LEX_CSTRING expr_str= make_string(thd, $3, $5); + + if (expr_str.str == nullptr) + MYSQL_YYABORT; + $1->set_expr_str(expr_str); + } + if (unlikely($1->sphead->restore_lex(thd))) + MYSQL_YYABORT; + $$= $1; } ; @@ -3782,22 +3804,25 @@ sp_proc_stmt_return: sp_proc_stmt_exit_oracle: EXIT_ORACLE_SYM { - if (unlikely(Lex->sp_exit_statement(thd, NULL))) + if (unlikely(Lex->sp_exit_statement(thd, nullptr, empty_clex_str))) MYSQL_YYABORT; } | EXIT_ORACLE_SYM label_ident { - if (unlikely(Lex->sp_exit_statement(thd, &$2, NULL))) + if (unlikely(Lex->sp_exit_statement(thd, &$2, nullptr, + empty_clex_str))) MYSQL_YYABORT; } | EXIT_ORACLE_SYM WHEN_SYM expr_lex { - if (unlikely($3->sp_exit_statement(thd, $3->get_item()))) + if (unlikely($3->sp_exit_statement(thd, $3->get_item(), + $3->get_expr_str()))) MYSQL_YYABORT; } | EXIT_ORACLE_SYM label_ident WHEN_SYM expr_lex { - if (unlikely($4->sp_exit_statement(thd, &$2, $4->get_item()))) + if (unlikely($4->sp_exit_statement(thd, &$2, $4->get_item(), + $4->get_expr_str()))) MYSQL_YYABORT; } ; @@ -3861,11 +3886,21 @@ expr_lex: if (Lex->main_select_push(true)) MYSQL_YYABORT; } - expr + remember_start_opt expr remember_end { $$= $1; $$->sp_lex_in_use= true; - $$->set_item($2); + $$->set_item($3); + + if (Lex->is_metadata_used()) + { + LEX_CSTRING expr_str= make_string(thd, $2, $4); + + if (expr_str.str == nullptr) + MYSQL_YYABORT; + $$->set_expr_str(expr_str); + } + Lex->pop_select(); //min select if (Lex->check_cte_dependencies_and_resolve_references()) MYSQL_YYABORT; @@ -3892,12 +3927,22 @@ assignment_source_expr: if (Lex->main_select_push(true)) MYSQL_YYABORT; } - expr + remember_cpp_ptr expr remember_end { DBUG_ASSERT($1 == thd->lex); $$= $1; $$->sp_lex_in_use= true; - $$->set_item_and_free_list($3, thd->free_list); + $$->set_item_and_free_list($4, thd->free_list); + + if (Lex->is_metadata_used()) + { + LEX_CSTRING expr_str= make_string(thd, $3, $5); + + if (expr_str.str == nullptr) + MYSQL_YYABORT; + $$->set_expr_str(expr_str); + } + thd->free_list= NULL; Lex->pop_select(); //min select if ($$->sphead->restore_lex(thd)) @@ -3913,12 +3958,22 @@ for_loop_bound_expr: MYSQL_YYABORT; Lex->current_select->parsing_place= FOR_LOOP_BOUND; } - expr + remember_cpp_ptr expr remember_end { DBUG_ASSERT($1 == thd->lex); $$= $1; $$->sp_lex_in_use= true; - $$->set_item_and_free_list($3, NULL); + $$->set_item_and_free_list($4, nullptr); + + if (Lex->is_metadata_used()) + { + LEX_CSTRING expr_str= make_string(thd, $3, $5); + + if (expr_str.str == nullptr) + MYSQL_YYABORT; + $$->set_expr_str(expr_str); + } + Lex->pop_select(); //main select if (unlikely($$->sphead->restore_lex(thd))) MYSQL_YYABORT; @@ -9056,6 +9111,21 @@ remember_end: } ; +remember_cpp_ptr: + { + $$= (char*) YYLIP->get_cpp_ptr(); + } + ; + +remember_start_opt: + { + if (yychar == YYEMPTY) + $$= (char*) YYLIP->get_cpp_ptr(); + else + $$= (char*) YYLIP->get_cpp_tok_start(); + } + ; + select_alias: /* empty */ { $$=null_clex_str;} | AS ident { $$=$2; } @@ -16526,7 +16596,8 @@ set_stmt_option: { Lex_ident_sys tmp(thd, &$1); if (unlikely(!tmp.str) || - unlikely(Lex->set_system_variable(Lex->option_type, &tmp, $4))) + unlikely(Lex->set_system_variable(Lex->option_type, &tmp, + $4.expr))) MYSQL_YYABORT; Lex->pop_select(); //min select } @@ -16540,7 +16611,7 @@ set_stmt_option: Lex_ident_sys tmp(thd, &$1); if (unlikely(!tmp.str) || unlikely(Lex->set_system_variable(thd, Lex->option_type, - &tmp, &$3, $6))) + &tmp, &$3, $6.expr))) MYSQL_YYABORT; Lex->pop_select(); //min select } @@ -16552,7 +16623,7 @@ set_stmt_option: set_expr_or_default { if (unlikely(Lex->set_default_system_variable(Lex->option_type, - &$3, $6))) + &$3, $6.expr))) MYSQL_YYABORT; Lex->pop_select(); //min select } @@ -16570,7 +16641,8 @@ option_value_following_option_type: { Lex_ident_sys tmp(thd, &$1); if (unlikely(!tmp.str) || - unlikely(Lex->set_system_variable(Lex->option_type, &tmp, $4)) || + unlikely(Lex->set_system_variable(Lex->option_type, &tmp, + $4.expr)) || unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) MYSQL_YYABORT; } @@ -16583,7 +16655,8 @@ option_value_following_option_type: { Lex_ident_sys tmp(thd, &$1); if (unlikely(!tmp.str) || - unlikely(Lex->set_system_variable(thd, Lex->option_type, &tmp, &$3, $6)) || + unlikely(Lex->set_system_variable(thd, Lex->option_type, &tmp, + &$3, $6.expr)) || unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) MYSQL_YYABORT; } @@ -16594,7 +16667,8 @@ option_value_following_option_type: } set_expr_or_default { - if (unlikely(Lex->set_default_system_variable(Lex->option_type, &$3, $6)) || + if (unlikely(Lex->set_default_system_variable(Lex->option_type, + &$3, $6.expr)) || unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) MYSQL_YYABORT; } @@ -16610,8 +16684,9 @@ option_value_no_option_type: set_expr_or_default { Lex_ident_sys tmp(thd, &$1); + if (unlikely(!tmp.str) || - unlikely(Lex->set_variable(&tmp, $4)) || + unlikely(Lex->set_variable(&tmp, $4.expr, $4.expr_str)) || unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) MYSQL_YYABORT; } @@ -16623,8 +16698,9 @@ option_value_no_option_type: set_expr_or_default { Lex_ident_sys tmp(thd, &$1); + if (unlikely(!tmp.str) || - unlikely(Lex->set_variable(&tmp, &$3, $6)) || + unlikely(Lex->set_variable(&tmp, &$3, $6.expr, $6.expr_str)) || unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) MYSQL_YYABORT; } @@ -16635,7 +16711,8 @@ option_value_no_option_type: } set_expr_or_default { - if (unlikely(Lex->set_default_system_variable(Lex->option_type, &$3, $6))) + if (unlikely(Lex->set_default_system_variable(Lex->option_type, + &$3, $6.expr))) MYSQL_YYABORT; if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) MYSQL_YYABORT; @@ -16651,9 +16728,17 @@ option_value_no_option_type: if (sp_create_assignment_lex(thd, $1.str)) MYSQL_YYABORT; } - expr + remember_cpp_ptr expr remember_end { - if (unlikely(Lex->set_user_variable(thd, &$2, $5)) || + LEX_CSTRING expr_str= empty_clex_str; + + if (Lex->is_metadata_used()) + { + expr_str= make_string(thd, $5, $7); + if (expr_str.str == nullptr) + MYSQL_YYABORT; + } + if (unlikely(Lex->set_user_variable(thd, &$2, $6)) || unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) MYSQL_YYABORT; } @@ -16664,7 +16749,7 @@ option_value_no_option_type: } set_expr_or_default { - if (unlikely(Lex->set_system_variable($3, &$4, $7)) || + if (unlikely(Lex->set_system_variable($3, &$4, $7.expr)) || unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) MYSQL_YYABORT; } @@ -16675,7 +16760,8 @@ option_value_no_option_type: } set_expr_or_default { - if (unlikely(Lex->set_system_variable(thd, $3, &$4, &$6, $9)) || + if (unlikely(Lex->set_system_variable(thd, $3, &$4, &$6, + $9.expr)) || unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) MYSQL_YYABORT; } @@ -16686,7 +16772,7 @@ option_value_no_option_type: } set_expr_or_default { - if (unlikely(Lex->set_default_system_variable($3, &$6, $9)) || + if (unlikely(Lex->set_default_system_variable($3, &$6, $9.expr)) || unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) MYSQL_YYABORT; } @@ -16797,8 +16883,9 @@ option_value_no_option_type: set_expr_or_default { Lex_ident_sys tmp(thd, &$1); + if (unlikely(!tmp.str) || - unlikely(Lex->set_variable(&tmp, $4)) || + unlikely(Lex->set_variable(&tmp, $4.expr, $4.expr_str)) || unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) MYSQL_YYABORT; } @@ -16905,28 +16992,37 @@ text_or_password: ; set_expr_or_default: - expr { $$=$1; } - | DEFAULT { $$=0; } - | ON + remember_cpp_ptr expr remember_end { - $$=new (thd->mem_root) Item_string_sys(thd, "ON", 2); - if (unlikely($$ == NULL)) - MYSQL_YYABORT; + LEX_CSTRING expr_str= empty_clex_str; + + if (Lex->is_metadata_used()) + { + expr_str= make_string(thd, $1, $3); + if (expr_str.str == nullptr) + MYSQL_YYABORT; + } + + $$= { $2, expr_str }; } - | ALL + | remember_cpp_ptr set_expr_misc remember_end { - $$=new (thd->mem_root) Item_string_sys(thd, "ALL", 3); - if (unlikely($$ == NULL)) + if (unlikely($2 == nullptr)) MYSQL_YYABORT; + $$= {$2, empty_clex_str}; } - | BINARY + | remember_cpp_ptr DEFAULT remember_end { - $$=new (thd->mem_root) Item_string_sys(thd, "binary", 6); - if (unlikely($$ == NULL)) - MYSQL_YYABORT; + $$= { nullptr, empty_clex_str }; } ; +set_expr_misc: + ON { $$= new (thd->mem_root) Item_string_sys(thd, "ON", 2); } + | ALL { $$= new (thd->mem_root) Item_string_sys(thd, "ALL", 3); } + | BINARY { $$= new (thd->mem_root) Item_string_sys(thd, "binary", 6); } + ; + /* Lock function */ lock: @@ -18216,8 +18312,20 @@ sp_block_label: ; sp_opt_default: - _empty { $$ = NULL; } - | DEFAULT expr { $$ = $2; } + _empty { $$= { nullptr, empty_clex_str}; } + | DEFAULT remember_cpp_ptr expr remember_end + { + LEX_CSTRING expr_str= empty_clex_str; + + if (Lex->is_metadata_used()) + { + expr_str= make_string(thd, $2, $4); + if (expr_str.str == nullptr) + MYSQL_YYABORT; + } + + $$= { $3, expr_str }; + } ; sp_decl_variable_list_anchored: @@ -18225,7 +18333,8 @@ sp_decl_variable_list_anchored: TYPE_SYM OF_SYM optionally_qualified_column_ident sp_opt_default { - if (unlikely(Lex->sp_variable_declarations_with_ref_finalize(thd, $1, $4, $5))) + if (unlikely(Lex->sp_variable_declarations_with_ref_finalize( + thd, $1, $4, $5.expr, $5.expr_str))) MYSQL_YYABORT; $$.init_using_vars($1); } @@ -18233,7 +18342,8 @@ sp_decl_variable_list_anchored: ROW_SYM TYPE_SYM OF_SYM optionally_qualified_column_ident sp_opt_default { - if (unlikely(Lex->sp_variable_declarations_rowtype_finalize(thd, $1, $5, $6))) + if (unlikely(Lex->sp_variable_declarations_rowtype_finalize( + thd, $1, $5, $6.expr, $6.expr_str))) MYSQL_YYABORT; $$.init_using_vars($1); } @@ -18673,9 +18783,33 @@ remember_end_opt: ; sp_opt_default: - _empty { $$ = NULL; } - | DEFAULT expr { $$ = $2; } - | SET_VAR expr { $$ = $2; } + _empty { $$= { nullptr, empty_clex_str}; } + | DEFAULT remember_cpp_ptr expr remember_end + { + LEX_CSTRING expr_str= empty_clex_str; + + if (Lex->is_metadata_used()) + { + expr_str= make_string(thd, $2, $4); + if (expr_str.str == nullptr) + MYSQL_YYABORT; + } + + $$= { $3, expr_str }; + } + | SET_VAR remember_cpp_ptr expr remember_end + { + LEX_CSTRING expr_str= empty_clex_str; + + if (Lex->is_metadata_used()) + { + expr_str= make_string(thd, $2, $4 ); + if (expr_str.str == nullptr) + MYSQL_YYABORT; + } + + $$= { $3, expr_str }; + } ; sp_opt_inout: @@ -18739,8 +18873,9 @@ set_assign: set_expr_or_default { Lex_ident_sys tmp(thd, &$1); + if (unlikely(!tmp.str) || - unlikely(Lex->set_variable(&tmp, $4)) || + unlikely(Lex->set_variable(&tmp, $4.expr, $4.expr_str)) || unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY, false))) MYSQL_YYABORT; @@ -18757,8 +18892,9 @@ set_assign: LEX *lex= Lex; DBUG_ASSERT(lex->var_list.is_empty()); Lex_ident_sys tmp(thd, &$1); + if (unlikely(!tmp.str) || - unlikely(lex->set_variable(&tmp, &$3, $6)) || + unlikely(lex->set_variable(&tmp, &$3, $6.expr, $6.expr_str)) || unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY, false))) MYSQL_YYABORT; @@ -18778,7 +18914,8 @@ set_assign: set_expr_or_default { LEX_CSTRING tmp= { $2.str, $2.length }; - if (unlikely(Lex->set_trigger_field(&tmp, &$4, $7)) || + if (unlikely(Lex->set_trigger_field(&tmp, &$4, $7.expr, + $7.expr_str)) || unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY, false))) MYSQL_YYABORT; @@ -19103,7 +19240,8 @@ sp_decl_variable_list_anchored: optionally_qualified_column_ident PERCENT_ORACLE_SYM TYPE_SYM sp_opt_default { - if (unlikely(Lex->sp_variable_declarations_with_ref_finalize(thd, $1, $2, $5))) + if (unlikely(Lex->sp_variable_declarations_with_ref_finalize(thd, $1, $2, + $5.expr, $5.expr_str))) MYSQL_YYABORT; $$.init_using_vars($1); } @@ -19111,7 +19249,8 @@ sp_decl_variable_list_anchored: optionally_qualified_column_ident PERCENT_ORACLE_SYM ROWTYPE_ORACLE_SYM sp_opt_default { - if (unlikely(Lex->sp_variable_declarations_rowtype_finalize(thd, $1, $2, $5))) + if (unlikely(Lex->sp_variable_declarations_rowtype_finalize(thd, $1, + $2, $5.expr, $5.expr_str))) MYSQL_YYABORT; $$.init_using_vars($1); }