Skip to content
Permalink
Browse files
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
  • Loading branch information
abarkov committed Mar 27, 2018
1 parent ad647cc commit 902ace0
Show file tree
Hide file tree
Showing 14 changed files with 270 additions and 320 deletions.
@@ -1328,3 +1328,19 @@ CREATE TABLE raw (raw int);
DROP TABLE raw;
CREATE TABLE varchar2 (varchar2 int);
DROP TABLE varchar2;
#
# MDEV-15620 Crash when using "SET @@NEW.a=expr" inside a trigger
#
CREATE TABLE t1 (a INT);
CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET @@NEW.a=0;
ERROR HY000: Unknown structured system variable or ROW routine variable 'NEW'
DROP TABLE t1;
#
# MDEV-15615 Unexpected syntax error instead of "Unknown system variable" inside an SP
#
BEGIN NOT ATOMIC
DECLARE a INT;
SET GLOBAL a=10;
END;
$$
ERROR HY000: Unknown system variable 'a'
@@ -881,7 +881,7 @@ ERROR 42000: You have an error in your SQL syntax; check the manual that corresp
SET max_error_count=100 FOR INSERT INTO t1 VALUES (1,2);
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'FOR INSERT INTO t1 VALUES (1,2)' at line 1
SET STATEMENT GLOBAL max_error_count=100 FOR INSERT INTO t1 VALUES (1,2);
ERROR HY000: Unknown system variable 'GLOBAL'
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'max_error_count=100 FOR INSERT INTO t1 VALUES (1,2)' at line 1
SET STATEMENT @@global.max_error_count=100 FOR INSERT INTO t1 VALUES (1,2);
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '@@global.max_error_count=100 FOR INSERT INTO t1 VALUES (1,2)' at line 1
''
@@ -35,7 +35,7 @@ CALL p1('SELECT 1');
Error1: 0 normal, successful completition
CALL p1('xxx');
'Error2: ' || SQLCODE || ' ' || SQLERRM
Error2: 1193 Unknown system variable 'xxx'
Error2: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '' at line 1
CALL p1('SELECT 1');
1
1
@@ -0,0 +1,18 @@
SET sql_mode=ORACLE;
#
# MDEV-15620 Crash when using "SET @@NEW.a=expr" inside a trigger
#
CREATE TABLE t1 (a INT);
CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET @@NEW.a=0;
ERROR HY000: Unknown structured system variable or ROW routine variable 'NEW'
DROP TABLE t1;
#
# MDEV-15615 Unexpected syntax error instead of "Unknown system variable" inside an SP
#
DECLARE
a INT;
BEGIN
SET GLOBAL a=10;
END;
$$
ERROR HY000: Unknown system variable 'a'
@@ -1,10 +1,10 @@
set sql_mode=ORACLE;
:NEW.a := 1;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'a := 1' at line 1
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ':NEW.a := 1' at line 1
:OLD.a := 1;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'a := 1' at line 1
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ':OLD.a := 1' at line 1
:OLa.a := 1;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'a := 1' at line 1
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ':OLa.a := 1' at line 1
SELECT :NEW.a;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'a' at line 1
SELECT :OLD.a;
@@ -0,0 +1,24 @@
SET sql_mode=ORACLE;

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

CREATE TABLE t1 (a INT);
--error ER_UNKNOWN_STRUCTURED_VARIABLE
CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET @@NEW.a=0;
DROP TABLE t1;

--echo #
--echo # MDEV-15615 Unexpected syntax error instead of "Unknown system variable" inside an SP
--echo #

DELIMITER $$;
--error ER_UNKNOWN_SYSTEM_VARIABLE
DECLARE
a INT;
BEGIN
SET GLOBAL a=10;
END;
$$
DELIMITER ;$$
@@ -1349,3 +1349,26 @@ DROP TABLE raw;

CREATE TABLE varchar2 (varchar2 int);
DROP TABLE varchar2;


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

CREATE TABLE t1 (a INT);
--error ER_UNKNOWN_STRUCTURED_VARIABLE
CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET @@NEW.a=0;
DROP TABLE t1;

--echo #
--echo # MDEV-15615 Unexpected syntax error instead of "Unknown system variable" inside an SP
--echo #

DELIMITER $$;
--error ER_UNKNOWN_SYSTEM_VARIABLE
BEGIN NOT ATOMIC
DECLARE a INT;
SET GLOBAL a=10;
END;
$$
DELIMITER ;$$
@@ -828,7 +828,7 @@ SET STATEMENT max_error_count=100 INSERT t1 VALUES (1,2);
SET STATEMENT FOR INSERT INTO t1 VALUES (1,2);
--error ER_PARSE_ERROR
SET max_error_count=100 FOR INSERT INTO t1 VALUES (1,2);
--error ER_UNKNOWN_SYSTEM_VARIABLE
--error ER_PARSE_ERROR
SET STATEMENT GLOBAL max_error_count=100 FOR INSERT INTO t1 VALUES (1,2);
--error ER_PARSE_ERROR
SET STATEMENT @@global.max_error_count=100 FOR INSERT INTO t1 VALUES (1,2);
@@ -688,17 +688,6 @@ sys_var *intern_find_sys_var(const char *str, size_t length)
}


bool find_sys_var_null_base(THD *thd, struct sys_var_with_base *tmp)
{
tmp->var= find_sys_var(thd, tmp->base_name.str, tmp->base_name.length);

if (tmp->var != NULL)
tmp->base_name= null_clex_str;

return thd->is_error();
}


/**
Execute update of all variables.
@@ -393,7 +393,6 @@ SHOW_VAR* enumerate_sys_vars(THD *thd, bool sorted, enum enum_var_type type);
int fill_sysvars(THD *thd, TABLE_LIST *tables, COND *cond);

sys_var *find_sys_var(THD *thd, const char *str, size_t length=0);
bool find_sys_var_null_base(THD *thd, struct sys_var_with_base *tmp);
int sql_set_variables(THD *thd, List<set_var_base> *var_list, bool free);

#define SYSVAR_AUTOSIZE(VAR,VAL) \

0 comments on commit 902ace0

Please sign in to comment.