maria-developers team mailing list archive
-
maria-developers team
-
Mailing list archive
-
Message #11148
MDEV-15620 Crash when using "SET @@NEW.a=expr" inside a trigger
Hello Sanja,
Please review a patch for MDEV-15620.
Thanks!
commit 8306aaec113a061e5e1a576ff9f932f9cac1850a
Author: Alexander Barkov <bar@xxxxxxxxxxx>
Date: Fri Mar 23 14:23:48 2018 +0400
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
diff --git a/mysql-test/r/parser.result b/mysql-test/r/parser.result
index f197fbe..1a65f8f 100644
--- a/mysql-test/r/parser.result
+++ b/mysql-test/r/parser.result
@@ -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'
diff --git a/mysql-test/r/set_statement.result b/mysql-test/r/set_statement.result
index 5bcf825..c34e117 100644
--- a/mysql-test/r/set_statement.result
+++ b/mysql-test/r/set_statement.result
@@ -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
''
diff --git a/mysql-test/suite/compat/oracle/r/func_misc.result b/mysql-test/suite/compat/oracle/r/func_misc.result
index 0e2ba0c..f285423 100644
--- a/mysql-test/suite/compat/oracle/r/func_misc.result
+++ b/mysql-test/suite/compat/oracle/r/func_misc.result
@@ -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
diff --git a/mysql-test/suite/compat/oracle/r/parser.result b/mysql-test/suite/compat/oracle/r/parser.result
new file mode 100644
index 0000000..29588a6
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/parser.result
@@ -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'
diff --git a/mysql-test/suite/compat/oracle/r/trigger.result b/mysql-test/suite/compat/oracle/r/trigger.result
index f77a565..7c24c78 100644
--- a/mysql-test/suite/compat/oracle/r/trigger.result
+++ b/mysql-test/suite/compat/oracle/r/trigger.result
@@ -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;
diff --git a/mysql-test/suite/compat/oracle/t/parser.test b/mysql-test/suite/compat/oracle/t/parser.test
new file mode 100644
index 0000000..5aa37c1
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/parser.test
@@ -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 ;$$
diff --git a/mysql-test/t/parser.test b/mysql-test/t/parser.test
index 98eaa7a..08b6d34 100644
--- a/mysql-test/t/parser.test
+++ b/mysql-test/t/parser.test
@@ -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 ;$$
diff --git a/mysql-test/t/set_statement.test b/mysql-test/t/set_statement.test
index 32f56e4..cc36155 100644
--- a/mysql-test/t/set_statement.test
+++ b/mysql-test/t/set_statement.test
@@ -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);
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 1bdbd4e..bf373dd 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -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.
diff --git a/sql/set_var.h b/sql/set_var.h
index d0143e1..9014a9c 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -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) \
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index b169b9e..dcf0b7a 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -41,12 +41,6 @@ void LEX::parse_error(uint err_number)
static int lex_one_token(YYSTYPE *yylval, THD *thd);
-/*
- We are using pointer to this variable for distinguishing between assignment
- to NEW row field (when parsing trigger definition) and structured variable.
-*/
-
-sys_var *trg_new_row_fake_var= (sys_var*) 0x01;
/**
LEX_STRING constant for null-string to be used in parser and other places.
@@ -5253,36 +5247,7 @@ LEX::find_variable(const LEX_CSTRING *name,
}
-bool LEX::init_internal_variable(struct sys_var_with_base *variable,
- const LEX_CSTRING *name)
-{
- sp_variable *spv;
- const Sp_rcontext_handler *rh;
-
- /* Best effort lookup for system variable. */
- if (!(spv= find_variable(name, &rh)))
- {
- struct sys_var_with_base tmp= {NULL, *name};
-
- /* Not an SP local variable */
- if (find_sys_var_null_base(thd, &tmp))
- return true;
-
- *variable= tmp;
- return false;
- }
-
- /*
- Possibly an SP local variable (or a shadowed sysvar).
- Will depend on the context of the SET statement.
- */
- variable->var= NULL;
- variable->base_name= *name;
- return false;
-}
-
-
-bool LEX::is_trigger_new_or_old_reference(const LEX_CSTRING *name)
+bool LEX::is_trigger_new_or_old_reference(const LEX_CSTRING *name) const
{
return sphead && sphead->m_handler->type() == TYPE_ENUM_TRIGGER &&
name->length == 3 &&
@@ -5291,68 +5256,6 @@ bool LEX::is_trigger_new_or_old_reference(const LEX_CSTRING *name)
}
-bool LEX::init_internal_variable(struct sys_var_with_base *variable,
- const LEX_CSTRING *dbname,
- const LEX_CSTRING *name)
-{
- if (check_reserved_words(dbname))
- {
- my_error(ER_UNKNOWN_STRUCTURED_VARIABLE, MYF(0),
- (int) dbname->length, dbname->str);
- return true;
- }
- if (is_trigger_new_or_old_reference(dbname))
- {
- if (dbname->str[0]=='O' || dbname->str[0]=='o')
- {
- my_error(ER_TRG_CANT_CHANGE_ROW, MYF(0), "OLD", "");
- return true;
- }
- if (trg_chistics.event == TRG_EVENT_DELETE)
- {
- my_error(ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "NEW", "on DELETE");
- return true;
- }
- if (trg_chistics.action_time == TRG_ACTION_AFTER)
- {
- my_error(ER_TRG_CANT_CHANGE_ROW, MYF(0), "NEW", "after ");
- return true;
- }
- /* This special combination will denote field of NEW row */
- variable->var= trg_new_row_fake_var;
- variable->base_name= *name;
- return false;
- }
-
- sys_var *tmp= find_sys_var_ex(thd, name->str, name->length, true, false);
- if (!tmp)
- {
- my_error(ER_UNKNOWN_STRUCTURED_VARIABLE, MYF(0),
- (int) dbname->length, dbname->str);
- return true;
- }
- if (!tmp->is_struct())
- my_error(ER_VARIABLE_IS_NOT_STRUCT, MYF(0), name->str);
- variable->var= tmp;
- variable->base_name= *dbname;
- return false;
-}
-
-
-bool LEX::init_default_internal_variable(struct sys_var_with_base *variable,
- LEX_CSTRING name)
-{
- sys_var *tmp= find_sys_var(thd, name.str, name.length);
- if (!tmp)
- return true;
- if (!tmp->is_struct())
- my_error(ER_VARIABLE_IS_NOT_STRUCT, MYF(0), name.str);
- variable->var= tmp;
- variable->base_name.str= (char*) "default";
- variable->base_name.length= 7;
- return false;
-}
-
void LEX::sp_variable_declarations_init(THD *thd, int nvars)
{
sp_variable *spvar= spcont->get_last_context_variable();
@@ -6994,38 +6897,6 @@ bool LEX::set_user_variable(THD *thd, const LEX_CSTRING *name, Item *val)
}
-/*
- Perform assignment for a trigger, a system variable, or an SP variable.
- "variable" be previously set by init_internal_variable(variable, name).
-*/
-bool LEX::set_variable(struct sys_var_with_base *variable, Item *item)
-{
- if (variable->var == trg_new_row_fake_var)
- {
- /* We are in trigger and assigning value to field of new row */
- return set_trigger_new_row(&variable->base_name, item);
- }
- if (variable->var)
- {
- /* It is a system variable. */
- return set_system_variable(variable, option_type, item);
- }
-
- /*
- spcont and spv should not be NULL, as the variable
- was previously checked by init_internal_variable().
- */
- DBUG_ASSERT(spcont);
- const Sp_rcontext_handler *rh;
- sp_pcontext *ctx;
- sp_variable *spv= find_variable(&variable->base_name, &ctx, &rh);
- DBUG_ASSERT(spv);
- DBUG_ASSERT(ctx);
- DBUG_ASSERT(rh);
- return sphead->set_local_variable(thd, ctx, rh, spv, item, this, true);
-}
-
-
Item *LEX::create_item_ident_nosp(THD *thd, LEX_CSTRING *name)
{
if (current_select->parsing_place != IN_HAVING ||
@@ -7084,6 +6955,17 @@ Item *LEX::create_item_ident_sp(THD *thd, LEX_CSTRING *name,
}
+
+bool LEX::set_variable(const LEX_CSTRING *name, Item *item)
+{
+ 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) :
+ set_system_variable(option_type, name, item);
+}
+
+
/**
Generate instructions for:
SET x.y= expr;
@@ -7111,10 +6993,76 @@ bool LEX::set_variable(const LEX_CSTRING *name1,
item, this);
}
- // A trigger field or a system variable
- sys_var_with_base sysvar;
- return init_internal_variable(&sysvar, name1, name2) ||
- set_variable(&sysvar, item);
+ if (is_trigger_new_or_old_reference(name1))
+ return set_trigger_field(name1, name2, item);
+
+ return set_system_variable(thd, option_type, name1, name2, item);
+}
+
+
+bool LEX::set_default_system_variable(enum_var_type var_type,
+ const LEX_CSTRING *name,
+ Item *val)
+{
+ static LEX_CSTRING default_base_name= {STRING_WITH_LEN("default")};
+ sys_var *var= find_sys_var(thd, name->str, name->length);
+ if (!var)
+ return true;
+ if (!var->is_struct())
+ my_error(ER_VARIABLE_IS_NOT_STRUCT, MYF(0), name->str);
+ return set_system_variable(var_type, var, &default_base_name, val);
+}
+
+
+bool LEX::set_system_variable(enum_var_type var_type,
+ const LEX_CSTRING *name,
+ Item *val)
+{
+ sys_var *var= find_sys_var(thd, name->str, name->length);
+ DBUG_ASSERT(thd->is_error() || var != NULL);
+ return var ? set_system_variable(var_type, var, &null_clex_str, val) : true;
+}
+
+
+bool LEX::set_system_variable(THD *thd, enum_var_type var_type,
+ const LEX_CSTRING *name1,
+ const LEX_CSTRING *name2,
+ Item *val)
+{
+ sys_var *tmp;
+ if (check_reserved_words(name1) ||
+ !(tmp= find_sys_var_ex(thd, name2->str, name2->length, true, false)))
+ {
+ my_error(ER_UNKNOWN_STRUCTURED_VARIABLE, MYF(0),
+ (int) name1->length, name1->str);
+ return true;
+ }
+ if (!tmp->is_struct())
+ my_error(ER_VARIABLE_IS_NOT_STRUCT, MYF(0), name2->str);
+ return set_system_variable(var_type, tmp, name1, val);
+}
+
+
+bool LEX::set_trigger_field(const LEX_CSTRING *name1, const LEX_CSTRING *name2,
+ Item *val)
+{
+ DBUG_ASSERT(is_trigger_new_or_old_reference(name1));
+ if (name1->str[0]=='O' || name1->str[0]=='o')
+ {
+ my_error(ER_TRG_CANT_CHANGE_ROW, MYF(0), "OLD", "");
+ return true;
+ }
+ if (trg_chistics.event == TRG_EVENT_DELETE)
+ {
+ my_error(ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "NEW", "on DELETE");
+ return true;
+ }
+ if (trg_chistics.action_time == TRG_ACTION_AFTER)
+ {
+ my_error(ER_TRG_CANT_CHANGE_ROW, MYF(0), "NEW", "after ");
+ return true;
+ }
+ return set_trigger_new_row(name2, val);
}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index f0241a3..9856ca1 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -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 @@ struct LEX: public Query_tables_list
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 @@ struct LEX: public Query_tables_list
sp_pcontext *not_used_ctx;
return find_variable(name, ¬_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 @@ struct LEX: public Query_tables_list
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);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 35ec2d2..e3ceb3b 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -288,27 +288,28 @@ int LEX::case_stmt_action_then()
*/
bool
-LEX::set_system_variable(struct sys_var_with_base *tmp,
- enum enum_var_type var_type, Item *val)
+LEX::set_system_variable(enum enum_var_type var_type,
+ sys_var *sysvar, const LEX_CSTRING *base_name,
+ Item *val)
{
- set_var *var;
+ set_var *setvar;
/* No AUTOCOMMIT from a stored function or trigger. */
- if (spcont && tmp->var == Sys_autocommit_ptr)
+ if (spcont && sysvar == Sys_autocommit_ptr)
sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
if (val && val->type() == Item::FIELD_ITEM &&
((Item_field*)val)->table_name)
{
- my_error(ER_WRONG_TYPE_FOR_VAR, MYF(0), tmp->var->name.str);
+ my_error(ER_WRONG_TYPE_FOR_VAR, MYF(0), sysvar->name.str);
return TRUE;
}
- if (! (var= new (thd->mem_root)
- set_var(thd, var_type, tmp->var, &tmp->base_name, val)))
+ if (!(setvar= new (thd->mem_root) set_var(thd, var_type, sysvar,
+ base_name, val)))
return TRUE;
- return var_list.push_back(var, thd->mem_root);
+ return var_list.push_back(setvar, thd->mem_root);
}
@@ -322,7 +323,7 @@ LEX::set_system_variable(struct sys_var_with_base *tmp,
@return TRUE if error, FALSE otherwise.
*/
-bool LEX::set_trigger_new_row(LEX_CSTRING *name, Item *val)
+bool LEX::set_trigger_new_row(const LEX_CSTRING *name, Item *val)
{
Item_trigger_field *trg_fld;
sp_instr_set_trigger_field *sp_fld;
@@ -778,7 +779,6 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr)
LEX_CSTRING lex_str;
LEX_SYMBOL symbol;
Lex_string_with_metadata_st lex_string_with_metadata;
- struct sys_var_with_base variable;
Lex_string_with_pos_st lex_string_with_pos;
Lex_spblock_st spblock;
Lex_spblock_handlers_st spblock_handlers;
@@ -1869,8 +1869,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
opt_load_data_charset
UNDERSCORE_CHARSET
-%type <variable> internal_variable_name
-
%type <select_lex> subselect
get_select_lex get_select_lex_derived
simple_table
@@ -15960,25 +15958,20 @@ opt_var_ident_type:
/* Option values with preceding option_type. */
option_value_following_option_type:
- internal_variable_name equal set_expr_or_default
+ ident equal set_expr_or_default
{
- LEX *lex= Lex;
-
- if ($1.var && $1.var != trg_new_row_fake_var)
- {
- /* It is a system variable. */
- if (lex->set_system_variable(&$1, lex->option_type, $3))
- MYSQL_YYABORT;
- }
- else
- {
- /*
- Not in trigger assigning value to new row,
- and option_type preceding local variable is illegal.
- */
- thd->parse_error();
+ if (Lex->set_system_variable(Lex->option_type, &$1, $3))
+ MYSQL_YYABORT;
+ }
+ | ident '.' ident equal set_expr_or_default
+ {
+ if (Lex->set_system_variable(thd, Lex->option_type, &$1, &$3, $5))
+ MYSQL_YYABORT;
+ }
+ | DEFAULT '.' ident equal set_expr_or_default
+ {
+ if (Lex->set_default_system_variable(Lex->option_type, &$3, $5))
MYSQL_YYABORT;
- }
}
;
@@ -15986,9 +15979,7 @@ option_value_following_option_type:
option_value_no_option_type:
ident equal set_expr_or_default
{
- struct sys_var_with_base var;
- if (Lex->init_internal_variable(&var, &$1) ||
- Lex->set_variable(&var, $3))
+ if (Lex->set_variable(&$1, $3))
MYSQL_YYABORT;
}
| ident '.' ident equal set_expr_or_default
@@ -15999,9 +15990,7 @@ option_value_no_option_type:
}
| DEFAULT '.' ident equal set_expr_or_default
{
- struct sys_var_with_base var;
- if (Lex->init_default_internal_variable(&var, $3) ||
- Lex->set_variable(&var, $5))
+ if (Lex->set_default_system_variable(Lex->option_type, &$3, $5))
MYSQL_YYABORT;
}
| '@' ident_or_text equal expr
@@ -16009,16 +15998,19 @@ option_value_no_option_type:
if (Lex->set_user_variable(thd, &$2, $4))
MYSQL_YYABORT;
}
- | '@' '@' opt_var_ident_type internal_variable_name equal set_expr_or_default
+ | '@' '@' opt_var_ident_type ident equal set_expr_or_default
{
- struct sys_var_with_base tmp= $4;
- /* Lookup if necessary: must be a system variable. */
- if (tmp.var == NULL)
- {
- if (find_sys_var_null_base(thd, &tmp))
- MYSQL_YYABORT;
- }
- if (Lex->set_system_variable(&tmp, $3, $6))
+ if (Lex->set_system_variable($3, &$4, $6))
+ MYSQL_YYABORT;
+ }
+ | '@' '@' opt_var_ident_type ident '.' ident equal set_expr_or_default
+ {
+ if (Lex->set_system_variable(thd, $3, &$4, &$6, $8))
+ MYSQL_YYABORT;
+ }
+ | '@' '@' opt_var_ident_type DEFAULT '.' ident equal set_expr_or_default
+ {
+ if (Lex->set_default_system_variable($3, &$6, $8))
MYSQL_YYABORT;
}
| charset old_or_new_charset_name_or_default
@@ -16116,25 +16108,6 @@ option_value_no_option_type:
}
;
-
-internal_variable_name:
- ident
- {
- if (Lex->init_internal_variable(&$$, &$1))
- MYSQL_YYABORT;
- }
- | ident '.' ident
- {
- if (Lex->init_internal_variable(&$$, &$1, &$3))
- MYSQL_YYABORT;
- }
- | DEFAULT '.' ident
- {
- if (Lex->init_default_internal_variable(&$$, $3))
- MYSQL_YYABORT;
- }
- ;
-
transaction_characteristics:
transaction_access_mode
| isolation_level
diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy
index c8f93c1..bdc4694 100644
--- a/sql/sql_yacc_ora.yy
+++ b/sql/sql_yacc_ora.yy
@@ -171,7 +171,6 @@ void ORAerror(THD *thd, const char *s)
LEX_CSTRING lex_str;
LEX_SYMBOL symbol;
Lex_string_with_metadata_st lex_string_with_metadata;
- struct sys_var_with_base variable;
Lex_string_with_pos_st lex_string_with_pos;
Lex_spblock_st spblock;
Lex_spblock_handlers_st spblock_handlers;
@@ -1271,9 +1270,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
opt_load_data_charset
UNDERSCORE_CHARSET
-%type <variable> internal_variable_name
- internal_variable_name_directly_assignable
-
%type <select_lex> subselect
get_select_lex get_select_lex_derived
query_specification
@@ -14809,9 +14805,9 @@ simple_ident_q2:
if (lex->is_trigger_new_or_old_reference(&$2))
{
bool new_row= ($2.str[0]=='N' || $2.str[0]=='n');
- if (!($$= Lex->create_and_link_Item_trigger_field(thd,
- &$4,
- new_row)))
+ if (!($$= lex->create_and_link_Item_trigger_field(thd,
+ &$4,
+ new_row)))
MYSQL_YYABORT;
}
else
@@ -15659,7 +15655,7 @@ set:
;
set_assign:
- internal_variable_name_directly_assignable SET_VAR
+ ident_directly_assignable SET_VAR
{
LEX *lex=Lex;
lex->set_stmt_init();
@@ -15687,6 +15683,25 @@ set_assign:
lex->sphead->restore_lex(thd))
MYSQL_YYABORT;
}
+ | colon_with_pos ident '.' ident SET_VAR
+ {
+ LEX *lex= Lex;
+ if (!lex->is_trigger_new_or_old_reference(&$2))
+ {
+ thd->parse_error(ER_SYNTAX_ERROR, $1);
+ MYSQL_YYABORT;
+ }
+ lex->set_stmt_init();
+ lex->var_list.empty();
+ sp_create_assignment_lex(thd, yychar == YYEMPTY);
+ }
+ set_expr_or_default
+ {
+ LEX_CSTRING tmp= { $2.str, $2.length };
+ if (Lex->set_trigger_field(&tmp, &$4, $7) ||
+ sp_create_assignment_instr(thd, yychar == YYEMPTY))
+ MYSQL_YYABORT;
+ }
;
set_stmt_option_value_following_option_type_list:
@@ -15798,25 +15813,20 @@ opt_var_ident_type:
/* Option values with preceding option_type. */
option_value_following_option_type:
- internal_variable_name equal set_expr_or_default
+ ident equal set_expr_or_default
{
- LEX *lex= Lex;
-
- if ($1.var && $1.var != trg_new_row_fake_var)
- {
- /* It is a system variable. */
- if (lex->set_system_variable(&$1, lex->option_type, $3))
- MYSQL_YYABORT;
- }
- else
- {
- /*
- Not in trigger assigning value to new row,
- and option_type preceding local variable is illegal.
- */
- thd->parse_error();
+ if (Lex->set_system_variable(Lex->option_type, &$1, $3))
+ MYSQL_YYABORT;
+ }
+ | ident '.' ident equal set_expr_or_default
+ {
+ if (Lex->set_system_variable(thd, Lex->option_type, &$1, &$3, $5))
+ MYSQL_YYABORT;
+ }
+ | DEFAULT '.' ident equal set_expr_or_default
+ {
+ if (Lex->set_default_system_variable(Lex->option_type, &$3, $5))
MYSQL_YYABORT;
- }
}
;
@@ -15824,9 +15834,7 @@ option_value_following_option_type:
option_value_no_option_type:
ident equal set_expr_or_default
{
- struct sys_var_with_base var;
- if (Lex->init_internal_variable(&var, &$1) ||
- Lex->set_variable(&var, $3))
+ if (Lex->set_variable(&$1, $3))
MYSQL_YYABORT;
}
| ident '.' ident equal set_expr_or_default
@@ -15837,9 +15845,7 @@ option_value_no_option_type:
}
| DEFAULT '.' ident equal set_expr_or_default
{
- struct sys_var_with_base var;
- if (Lex->init_default_internal_variable(&var, $3) ||
- Lex->set_variable(&var, $5))
+ if (Lex->set_default_system_variable(Lex->option_type, &$3, $5))
MYSQL_YYABORT;
}
| '@' ident_or_text equal expr
@@ -15847,16 +15853,19 @@ option_value_no_option_type:
if (Lex->set_user_variable(thd, &$2, $4))
MYSQL_YYABORT;
}
- | '@' '@' opt_var_ident_type internal_variable_name equal set_expr_or_default
+ | '@' '@' opt_var_ident_type ident equal set_expr_or_default
{
- struct sys_var_with_base tmp= $4;
- /* Lookup if necessary: must be a system variable. */
- if (tmp.var == NULL)
- {
- if (find_sys_var_null_base(thd, &tmp))
- MYSQL_YYABORT;
- }
- if (Lex->set_system_variable(&tmp, $3, $6))
+ if (Lex->set_system_variable($3, &$4, $6))
+ MYSQL_YYABORT;
+ }
+ | '@' '@' opt_var_ident_type ident '.' ident equal set_expr_or_default
+ {
+ if (Lex->set_system_variable(thd, $3, &$4, &$6, $8))
+ MYSQL_YYABORT;
+ }
+ | '@' '@' opt_var_ident_type DEFAULT '.' ident equal set_expr_or_default
+ {
+ if (Lex->set_default_system_variable($3, &$6, $8))
MYSQL_YYABORT;
}
| charset old_or_new_charset_name_or_default
@@ -15955,48 +15964,6 @@ option_value_no_option_type:
;
-internal_variable_name:
- ident
- {
- if (Lex->init_internal_variable(&$$, &$1))
- MYSQL_YYABORT;
- }
- | ident '.' ident
- {
- if (Lex->init_internal_variable(&$$, &$1, &$3))
- MYSQL_YYABORT;
- }
- | DEFAULT '.' ident
- {
- if (Lex->init_default_internal_variable(&$$, $3))
- MYSQL_YYABORT;
- }
- ;
-
-
-internal_variable_name_directly_assignable:
- ident_directly_assignable
- {
- if (Lex->init_internal_variable(&$$, &$1))
- MYSQL_YYABORT;
- }
- | DEFAULT '.' ident
- {
- if (Lex->init_default_internal_variable(&$$, $3))
- MYSQL_YYABORT;
- }
- | colon_with_pos ident_directly_assignable '.' ident
- {
- if (!Lex->is_trigger_new_or_old_reference(&$2))
- {
- thd->parse_error();
- MYSQL_YYABORT;
- }
- if (Lex->init_internal_variable(&$$, &$2, &$4))
- MYSQL_YYABORT;
- }
- ;
-
transaction_characteristics:
transaction_access_mode
| isolation_level