Commit 5a8b9a16 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 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.
parent 6840af6e
......@@ -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,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;
......
......@@ -391,7 +391,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);
......@@ -411,16 +412,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;
......@@ -450,7 +454,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:
......
......@@ -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
*/
......
This diff is collapsed.
......@@ -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};
}
......@@ -8035,5 +8035,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 */
This diff is collapsed.
......@@ -3318,7 +3318,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);
......@@ -3333,7 +3334,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);
......@@ -3888,9 +3890,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,
......@@ -3946,40 +3949,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,
......@@ -4267,8 +4282,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);
......@@ -4281,7 +4297,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);
......@@ -4291,11 +4308,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,
......@@ -4894,6 +4913,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;
}
};
......@@ -5118,10 +5146,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)
{
......@@ -5137,10 +5167,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;
}
};
......@@ -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 @@ 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;
}
};
......
This diff is collapsed.
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