1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

MDEV-15620 Crash when using "SET @@NEW.a=expr" inside a trigger

The problem resided in this branch of the "option_value_no_option_type" rule:

| '@' '@' opt_var_ident_type internal_variable_name equal set_expr_or_default

Summary:

1. internal_variable_name initialized tmp.var to trg_new_row_fake_var (0x01).
2. The condition "if (tmp.var == NULL)" did not check
   the special case with trg_new_row_fake_var,
   so Lex->set_system_variable(&tmp, $3, $6) was
   called with tmp.var pointing to trg_new_row_fake_var,
   which created a sys_var instance pointing to 0x01 instead of
   a real system variable.
3. Later, at the trigger invocation time, this method was called:
   sys_var::do_deprecated_warning (this=0x1, thd=0x7ffe6c000a98)
   Notice, "this" is equal to trg_new_row_fake_var (0x01)

Solution:

The old implementation with separate rules
internal_variable_name (in sql_yacc.yy and sql_yacc_ora.yy) and
internal_variable_name_directly_assignable (in sql_yacc_ora.yy only)
was too complex and hard to follow.

Rewriting the code in a more straightforward way.

1. Changing LEX::set_system_variable()

from:

bool set_system_variable(struct sys_var_with_base *, enum_var_type, Item *);

to:

bool set_system_variable(enum_var_type, sys_var *, const LEX_CSTRING *, Item *);

2. Adding new methods in LEX, which operate with variable names:

bool set_trigger_field(const LEX_CSTRING *, const LEX_CSTRING *, Item *);
bool set_system_variable(enum_var_type var_type, const LEX_CSTRING *name,
                         Item *val);
bool set_system_variable(THD *thd, enum_var_type var_type,
                         const LEX_CSTRING *name1,
                         const LEX_CSTRING *name2,
                         Item *val);
bool set_default_system_variable(enum_var_type var_type,
                                 const LEX_CSTRING *name,
                                 Item *val);
bool set_variable(const LEX_CSTRING *name, Item *item);

3. Changing the grammar to call the new methods directly
   in option_value_no_option_type,
   Removing rules internal_variable_name and
   internal_variable_name_directly_assignable.

4. Removing "struct sys_var_with_base" and trg_new_row_fake_var.

Good side effect:

- The code in /sql reduced from 314 to 183 lines.
- MDEV-15615 Unexpected syntax error instead of "Unknown system variable" ...
  was also fixed automatically
This commit is contained in:
Alexander Barkov
2018-03-23 14:23:48 +04:00
parent ad647cc84e
commit 902ace0968
14 changed files with 270 additions and 320 deletions

View File

@ -155,15 +155,6 @@ extern uint binlog_unsafe_map[256];
void binlog_unsafe_map_init();
#endif
/**
used by the parser to store internal variable name
*/
struct sys_var_with_base
{
sys_var *var;
LEX_CSTRING base_name;
};
struct LEX_TYPE
{
enum enum_field_types type;
@ -1338,8 +1329,6 @@ struct st_trg_chistics: public st_trg_execution_order
};
extern sys_var *trg_new_row_fake_var;
enum xa_option_words {XA_NONE, XA_JOIN, XA_RESUME, XA_ONE_PHASE,
XA_SUSPEND, XA_FOR_MIGRATE};
@ -3220,9 +3209,20 @@ public:
enum sub_select_type type,
bool is_top_level);
bool setup_select_in_parentheses();
bool set_trigger_new_row(LEX_CSTRING *name, Item *val);
bool set_system_variable(struct sys_var_with_base *tmp,
enum enum_var_type var_type, Item *val);
bool set_trigger_new_row(const LEX_CSTRING *name, Item *val);
bool set_trigger_field(const LEX_CSTRING *name1, const LEX_CSTRING *name2,
Item *val);
bool set_system_variable(enum_var_type var_type, sys_var *var,
const LEX_CSTRING *base_name, Item *val);
bool set_system_variable(enum_var_type var_type, const LEX_CSTRING *name,
Item *val);
bool set_system_variable(THD *thd, enum_var_type var_type,
const LEX_CSTRING *name1,
const LEX_CSTRING *name2,
Item *val);
bool set_default_system_variable(enum_var_type var_type,
const LEX_CSTRING *name,
Item *val);
bool set_user_variable(THD *thd, const LEX_CSTRING *name, Item *val);
void set_stmt_init();
sp_name *make_sp_name(THD *thd, const LEX_CSTRING *name);
@ -3265,14 +3265,7 @@ public:
sp_pcontext *not_used_ctx;
return find_variable(name, &not_used_ctx, rh);
}
bool init_internal_variable(struct sys_var_with_base *variable,
const LEX_CSTRING *name);
bool init_internal_variable(struct sys_var_with_base *variable,
const LEX_CSTRING *dbname,
const LEX_CSTRING *name);
bool init_default_internal_variable(struct sys_var_with_base *variable,
LEX_CSTRING name);
bool set_variable(struct sys_var_with_base *variable, Item *item);
bool set_variable(const LEX_CSTRING *name, Item *item);
bool set_variable(const LEX_CSTRING *name1, const LEX_CSTRING *name2,
Item *item);
void sp_variable_declarations_init(THD *thd, int nvars);
@ -3464,7 +3457,7 @@ public:
const LEX_CSTRING *var_name,
const LEX_CSTRING *field_name);
bool is_trigger_new_or_old_reference(const LEX_CSTRING *name);
bool is_trigger_new_or_old_reference(const LEX_CSTRING *name) const;
Item *create_and_link_Item_trigger_field(THD *thd, const LEX_CSTRING *name,
bool new_row);