Commit 5ebff759 authored by Dmitry Shulga's avatar Dmitry Shulga

MDEV-5816: Stored programs: validation of stored program statements

For those SP instructions that need to get access to LEX object on execution,
added storing of their original sql expressions inside classes derived
from the class sp_lex_instr.

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 could be non valid
SQL statement in general case (not parseable statement), the virtual method
sp_lex_instr::get_query() has been 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.
parent 4669fe5f
......@@ -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);
}
......
......@@ -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 @@ class Sp_handler
}
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 @@ class Sp_handler_function: public Sp_handler
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;
};
......
......@@ -3077,7 +3077,7 @@ 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,
......@@ -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;
......
......@@ -392,7 +392,8 @@ class sp_head :private Query_arena,
}
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);
......@@ -412,16 +413,19 @@ class sp_head :private Query_arena,
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;
......@@ -451,7 +455,8 @@ class sp_head :private Query_arena,
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:
......
......@@ -419,6 +419,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.str, expr_query.length);
}
/*
sp_instr_stmt class functions
*/
......
......@@ -18,12 +18,14 @@ 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_cursor(THD *thd, const LEX *oldlex)
:sp_lex_local(thd, oldlex),
Query_arena(thd->lex->sphead->get_main_mem_root(), STMT_INITIALIZED_FOR_SP)
Query_arena(thd->lex->sphead->get_main_mem_root(), STMT_INITIALIZED_FOR_SP),
m_expr_str(empty_clex_str)
{}
~sp_lex_cursor()
{
......@@ -51,6 +53,19 @@ class sp_lex_cursor: public sp_lex_local, public Query_arena
thd->free_list= nullptr;
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;
};
......@@ -287,7 +302,21 @@ class sp_lex_instr : public sp_instr
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;
};
......@@ -307,17 +336,13 @@ 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)
{}
int execute(THD *thd, uint *nextp) override;
......@@ -335,6 +360,17 @@ class sp_instr_stmt : public sp_lex_instr
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;
......@@ -352,9 +388,10 @@ class sp_instr_set : public sp_lex_instr
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_rcontext_handler(rh), m_offset(offset), m_value(val),
m_expr_str(expr_str)
{}
int execute(THD *thd, uint *nextp) override;
......@@ -374,11 +411,19 @@ class sp_instr_set : public sp_lex_instr
}
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;
......@@ -403,8 +448,9 @@ class sp_instr_set_row_field : public sp_instr_set
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)
{}
......@@ -444,8 +490,9 @@ class sp_instr_set_row_field_by_name : public sp_instr_set
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)
{}
......@@ -468,10 +515,12 @@ class sp_instr_set_trigger_field : public sp_lex_instr
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)
{}
int execute(THD *thd, uint *nextp) override;
......@@ -490,9 +539,19 @@ class sp_instr_set_trigger_field : public sp_lex_instr
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; }
......@@ -593,16 +652,18 @@ class sp_instr_jump_if_not : public sp_lex_instr, public sp_instr_opt_meta
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)
{}
int execute(THD *thd, uint *nextp) override;
......@@ -651,10 +712,20 @@ class sp_instr_jump_if_not : public sp_lex_instr, public sp_instr_opt_meta
m_expr= nullptr;
}
protected:
LEX_CSTRING get_expr_query() const override
{
return m_expr_str;
}
private:
Item *m_expr; ///< The condition
/**
SQL clause corresponding to the expression value.
*/
LEX_CSTRING m_expr_str;
public:
PSI_statement_info* get_psi_info() override { return & psi_info; }
static PSI_statement_info psi_info;
......@@ -696,9 +767,10 @@ 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_value(val), m_type_handler(handler),
m_expr_str(lex->get_expr_str())
{}
int execute(THD *thd, uint *nextp) override;
......@@ -715,6 +787,11 @@ class sp_instr_freturn : public sp_lex_instr
protected:
LEX_CSTRING get_expr_query() const override
{
return m_expr_str;
}
Item *m_value;
const Type_handler *m_type_handler;
......@@ -727,6 +804,13 @@ class sp_instr_freturn : public sp_lex_instr
{
m_value= nullptr;
}
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;
......@@ -914,6 +998,16 @@ class sp_instr_cpush : public sp_lex_instr, public sp_cursor
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 empty_clex_str;
}
private:
uint m_cursor; /**< Frame offset (for debugging) */
......@@ -922,6 +1016,7 @@ class sp_instr_cpush : public sp_lex_instr, public sp_cursor
on depending database objects used in the statement.
*/
bool m_metadata_changed;
public:
PSI_statement_info* get_psi_info() override { return & psi_info; }
static PSI_statement_info psi_info;
......@@ -1024,6 +1119,12 @@ class sp_instr_cursor_copy_struct: public sp_lex_instr
m_valid= true;
}
protected:
LEX_CSTRING get_expr_query() const override
{
return empty_clex_str;
}
public:
PSI_statement_info* get_psi_info() override { return & psi_info; }
static PSI_statement_info psi_info;
......@@ -1152,9 +1253,11 @@ 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_id(case_expr_id), m_case_expr(case_expr),
m_expr_str(case_expr_query)
{}
int execute(THD *thd, uint *nextp) override;
......@@ -1188,10 +1291,17 @@ class sp_instr_set_case_expr : public sp_lex_instr, public sp_instr_opt_meta
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; }
......
......@@ -8382,3 +8382,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};
}
......@@ -7952,5 +7952,21 @@ class Write_log_with_flags
}
};
/**
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 */
......@@ -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.
......@@ -6483,7 +6487,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 &&
......@@ -6519,7 +6524,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;
}
......@@ -6531,7 +6536,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++)
{
......@@ -6545,7 +6551,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);
......@@ -6554,20 +6560,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);
/*
......@@ -6593,7 +6601,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);
......@@ -6612,7 +6621,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 :
......@@ -6620,7 +6630,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),
......@@ -6635,7 +6646,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);
}
......@@ -6643,7 +6654,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=
......@@ -6656,7 +6668,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;
......@@ -6668,7 +6680,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);
......@@ -6688,7 +6701,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;
......@@ -6706,18 +6720,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++)
{
......@@ -6726,7 +6744,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);
......@@ -6736,7 +6754,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)))
......@@ -6750,14 +6769,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())
......@@ -6766,7 +6787,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
......@@ -6774,7 +6796,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);
}
......@@ -6803,7 +6826,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);
......@@ -6819,7 +6843,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);
......@@ -6918,7 +6942,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));
}
......@@ -6950,7 +6975,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);
}
......@@ -6975,13 +7000,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;
......@@ -7074,7 +7104,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;
}
......@@ -7133,6 +7164,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;
......@@ -7582,7 +7614,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)
......@@ -7650,7 +7682,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);
......@@ -7660,7 +7693,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)))
......@@ -7670,7 +7703,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))
......@@ -7679,11 +7712,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))
......@@ -7691,7 +7725,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);
}
......@@ -7748,7 +7782,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);
......@@ -7756,7 +7791,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)))
......@@ -7775,7 +7810,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);
}
......@@ -7788,7 +7823,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);
}
......@@ -7853,10 +7888,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())) ||
......@@ -8481,12 +8517,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);
}
......@@ -8497,7 +8535,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;
......@@ -8509,17 +8547,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);
}
......@@ -8576,7 +8615,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'))
......@@ -8594,7 +8633,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);
}
......@@ -10544,7 +10583,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)
......@@ -10552,17 +10598,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);
}
......@@ -11632,7 +11678,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;
......@@ -11646,7 +11692,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,
......
......@@ -3260,7 +3260,8 @@ struct LEX: public Query_tables_list
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);
......@@ -3275,7 +3276,8 @@ struct LEX: public Query_tables_list
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);
......@@ -3829,9 +3831,10 @@ struct LEX: public Query_tables_list
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,
......@@ -3887,40 +3890,52 @@ struct LEX: public Query_tables_list
sp_pcontext *not_used_ctx;
return find_variable(name, &not_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,
......@@ -4211,8 +4226,9 @@ struct LEX: public Query_tables_list
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);
......@@ -4225,7 +4241,8 @@ struct LEX: public Query_tables_list
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);
......@@ -4235,11 +4252,13 @@ struct LEX: public Query_tables_list
/* 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,
......@@ -4834,6 +4853,15 @@ struct LEX: public Query_tables_list
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;
}
};
......@@ -5060,10 +5088,12 @@ class sp_lex_set_var: public sp_lex_local
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)
{
......@@ -5079,10 +5109,18 @@ class sp_expr_lex: public sp_lex_local
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;
}
};
......@@ -5113,11 +5151,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)
{
......@@ -5132,6 +5172,14 @@ class sp_assignment_lex: public sp_lex_local
{
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;
}
};
......
......@@ -330,6 +330,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;
}
%{
......@@ -1359,7 +1364,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%type <simple_string>
remember_name remember_end
remember_tok_start
remember_cpp_ptr
wild_and_where
remember_start_opt
%type <const_simple_string>
field_length_str
......@@ -1483,9 +1490,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
......@@ -1505,6 +1511,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
simple_target_specification
condition_number
opt_versioning_interval_start
set_expr_misc
%type <num> opt_vers_auto_part
......@@ -1529,6 +1536,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%type <expr_lex>
expr_lex
%type <expr_and_query_str> sp_opt_default set_expr_or_default
%type <assignment_lex>
assignment_source_lex
assignment_source_expr
......@@ -3200,7 +3209,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);
}
......@@ -3208,7 +3218,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);
}
......@@ -3253,13 +3265,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;
}
;
......@@ -3753,22 +3775,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;
}
;
......@@ -3832,11 +3857,21 @@ expr_lex:
if (Lex->main_select_push(true))
MYSQL_YYABORT;
}
expr
remember_start_opt expr remember_end
{
$$= $<expr_lex>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;
......@@ -3863,12 +3898,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))
......@@ -3884,12 +3929,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;
......@@ -9010,6 +9065,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; }
......@@ -16446,7 +16516,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
}
......@@ -16460,7 +16531,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
}
......@@ -16472,7 +16543,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
}
......@@ -16490,7 +16561,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;
}
......@@ -16503,7 +16575,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;
}
......@@ -16514,7 +16587,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;
}
......@@ -16530,8 +16604,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;
}
......@@ -16543,8 +16618,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;
}
......@@ -16555,7 +16631,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;
......@@ -16571,9 +16648,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;
}
......@@ -16584,7 +16669,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;
}
......@@ -16595,7 +16680,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;
}
......@@ -16606,7 +16692,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;
}
......@@ -16712,8 +16798,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;
}
......@@ -16820,28 +16907,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))
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;
}
| ALL
$$= { $2, expr_str };
}
| 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:
......@@ -18131,8 +18227,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:
......@@ -18140,7 +18248,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);
}
......@@ -18148,7 +18257,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);
}
......@@ -18588,9 +18698,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:
......@@ -18654,8 +18788,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;
......@@ -18672,8 +18807,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;
......@@ -18693,7 +18829,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;
......@@ -19018,7 +19155,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);
}
......@@ -19026,7 +19164,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);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment