Commit 5721ea6a authored by Alexander Barkov's avatar Alexander Barkov

MDEV-10579 sql_mode=ORACLE: Triggers: Understand :NEW.c1 and :OLD.c1 instead of NEW.c1 and OLD.c1

parent ca242117
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
: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
: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
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;
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 :OLa.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
CREATE TABLE t1 (a INT);
CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW NEW.a:= 10;
INSERT INTO t1 VALUES ();
SELECT * FROM t1;
a
10
DROP TRIGGER tr1;
DROP TABLE t1;
CREATE TABLE t1 (a INT);
CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW :NEW.a:= 10;
INSERT INTO t1 VALUES ();
SELECT * FROM t1;
a
10
DROP TRIGGER tr1;
DROP TABLE t1;
CREATE TABLE t1 (a INT);
CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW
BEGIN
IF :NEW.a IS NULL
THEN
:NEW.a:= 10;
END IF;
END;
/
INSERT INTO t1 VALUES (NULL);
SELECT * FROM t1;
a
10
DROP TRIGGER tr1;
DROP TABLE t1;
CREATE TABLE t1 (a INT);
CREATE TRIGGER tr1 BEFORE UPDATE ON t1 FOR EACH ROW
BEGIN
IF :OLD.a IS NULL
THEN
:NEW.a:= 10;
END IF;
END;
/
INSERT INTO t1 VALUES (NULL);
UPDATE t1 SET a=NULL;
SELECT * FROM t1;
a
10
DROP TRIGGER tr1;
DROP TABLE t1;
CREATE TABLE t1 (a INT, b INT, c INT);
CREATE TRIGGER tr1 BEFORE INSERT ON t1
FOR EACH ROW
DECLARE
cnt INT := 0;
BEGIN
IF :NEW.a IS NULL THEN cnt:=cnt+1; END IF;
IF :NEW.b IS NULL THEN cnt:=cnt+1; END IF;
IF :NEW.c IS NULL THEN :NEW.c:=cnt; END IF;
END;
/
INSERT INTO t1 VALUES ();
INSERT INTO t1 VALUES (1, NULL, NULL);
INSERT INTO t1 VALUES (NULL, 1, NULL);
INSERT INTO t1 VALUES (1, 1, NULL);
SELECT * FROM t1;
a b c
NULL NULL 2
1 NULL 1
NULL 1 1
1 1 0
DROP TABLE t1;
set sql_mode=ORACLE;
--error ER_PARSE_ERROR
:NEW.a := 1;
--error ER_PARSE_ERROR
:OLD.a := 1;
--error ER_PARSE_ERROR
:OLa.a := 1;
--error ER_PARSE_ERROR
SELECT :NEW.a;
--error ER_PARSE_ERROR
SELECT :OLD.a;
--error ER_PARSE_ERROR
SELECT :OLa.a;
CREATE TABLE t1 (a INT);
CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW NEW.a:= 10;
INSERT INTO t1 VALUES ();
SELECT * FROM t1;
DROP TRIGGER tr1;
DROP TABLE t1;
CREATE TABLE t1 (a INT);
CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW :NEW.a:= 10;
INSERT INTO t1 VALUES ();
SELECT * FROM t1;
DROP TRIGGER tr1;
DROP TABLE t1;
CREATE TABLE t1 (a INT);
DELIMITER /;
CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW
BEGIN
IF :NEW.a IS NULL
THEN
:NEW.a:= 10;
END IF;
END;
/
DELIMITER ;/
INSERT INTO t1 VALUES (NULL);
SELECT * FROM t1;
DROP TRIGGER tr1;
DROP TABLE t1;
CREATE TABLE t1 (a INT);
DELIMITER /;
CREATE TRIGGER tr1 BEFORE UPDATE ON t1 FOR EACH ROW
BEGIN
IF :OLD.a IS NULL
THEN
:NEW.a:= 10;
END IF;
END;
/
DELIMITER ;/
INSERT INTO t1 VALUES (NULL);
UPDATE t1 SET a=NULL;
SELECT * FROM t1;
DROP TRIGGER tr1;
DROP TABLE t1;
CREATE TABLE t1 (a INT, b INT, c INT);
DELIMITER /;
CREATE TRIGGER tr1 BEFORE INSERT ON t1
FOR EACH ROW
DECLARE
cnt INT := 0;
BEGIN
IF :NEW.a IS NULL THEN cnt:=cnt+1; END IF;
IF :NEW.b IS NULL THEN cnt:=cnt+1; END IF;
IF :NEW.c IS NULL THEN :NEW.c:=cnt; END IF;
END;
/
DELIMITER ;/
INSERT INTO t1 VALUES ();
INSERT INTO t1 VALUES (1, NULL, NULL);
INSERT INTO t1 VALUES (NULL, 1, NULL);
INSERT INTO t1 VALUES (1, 1, NULL);
SELECT * FROM t1;
DROP TABLE t1;
...@@ -5132,6 +5132,15 @@ bool LEX::init_internal_variable(struct sys_var_with_base *variable, ...@@ -5132,6 +5132,15 @@ bool LEX::init_internal_variable(struct sys_var_with_base *variable,
} }
bool LEX::is_trigger_new_or_old_reference(const LEX_STRING name)
{
return sphead && sphead->m_type == TYPE_ENUM_TRIGGER &&
name.length == 3 &&
(!my_strcasecmp(system_charset_info, name.str, "NEW") ||
!my_strcasecmp(system_charset_info, name.str, "OLD"));
}
bool LEX::init_internal_variable(struct sys_var_with_base *variable, bool LEX::init_internal_variable(struct sys_var_with_base *variable,
LEX_STRING dbname, LEX_STRING name) LEX_STRING dbname, LEX_STRING name)
{ {
...@@ -5140,9 +5149,7 @@ bool LEX::init_internal_variable(struct sys_var_with_base *variable, ...@@ -5140,9 +5149,7 @@ bool LEX::init_internal_variable(struct sys_var_with_base *variable,
thd->parse_error(); thd->parse_error();
return true; return true;
} }
if (sphead && sphead->m_type == TYPE_ENUM_TRIGGER && if (is_trigger_new_or_old_reference(dbname))
(!my_strcasecmp(system_charset_info, dbname.str, "NEW") ||
!my_strcasecmp(system_charset_info, dbname.str, "OLD")))
{ {
if (dbname.str[0]=='O' || dbname.str[0]=='o') if (dbname.str[0]=='O' || dbname.str[0]=='o')
{ {
...@@ -5828,6 +5835,46 @@ bool LEX::sp_while_loop_finalize(THD *thd) ...@@ -5828,6 +5835,46 @@ bool LEX::sp_while_loop_finalize(THD *thd)
} }
Item *LEX::create_and_link_Item_trigger_field(THD *thd, const char *name,
bool new_row)
{
Item_trigger_field *trg_fld;
if (trg_chistics.event == TRG_EVENT_INSERT && !new_row)
{
my_error(ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "OLD", "on INSERT");
return NULL;
}
if (trg_chistics.event == TRG_EVENT_DELETE && new_row)
{
my_error(ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "NEW", "on DELETE");
return NULL;
}
DBUG_ASSERT(!new_row ||
(trg_chistics.event == TRG_EVENT_INSERT ||
trg_chistics.event == TRG_EVENT_UPDATE));
const bool tmp_read_only=
!(new_row && trg_chistics.action_time == TRG_ACTION_BEFORE);
trg_fld= new (thd->mem_root)
Item_trigger_field(thd, current_context(),
new_row ?
Item_trigger_field::NEW_ROW:
Item_trigger_field::OLD_ROW,
name, SELECT_ACL, tmp_read_only);
/*
Let us add this item to list of all Item_trigger_field objects
in trigger.
*/
if (trg_fld)
trg_table_fields.link_in_list(trg_fld, &trg_fld->next_trg_field);
return trg_fld;
}
#ifdef MYSQL_SERVER #ifdef MYSQL_SERVER
uint binlog_unsafe_map[256]; uint binlog_unsafe_map[256];
......
...@@ -3117,6 +3117,11 @@ struct LEX: public Query_tables_list ...@@ -3117,6 +3117,11 @@ struct LEX: public Query_tables_list
const char *start_in_q, const char *start_in_q,
const char *end_in_q); const char *end_in_q);
bool is_trigger_new_or_old_reference(const LEX_STRING name);
Item *create_and_link_Item_trigger_field(THD *thd, const char *name,
bool new_row);
void sp_block_init(THD *thd, const LEX_STRING label); void sp_block_init(THD *thd, const LEX_STRING label);
void sp_block_init(THD *thd) void sp_block_init(THD *thd)
{ {
......
...@@ -13829,45 +13829,13 @@ simple_ident_q: ...@@ -13829,45 +13829,13 @@ simple_ident_q:
we can't meet simple_ident_nospvar in trigger now. But it we can't meet simple_ident_nospvar in trigger now. But it
should be changed in future. should be changed in future.
*/ */
if (lex->sphead && lex->sphead->m_type == TYPE_ENUM_TRIGGER && if (lex->is_trigger_new_or_old_reference($1))
(!my_strcasecmp(system_charset_info, $1.str, "NEW") ||
!my_strcasecmp(system_charset_info, $1.str, "OLD")))
{ {
Item_trigger_field *trg_fld;
bool new_row= ($1.str[0]=='N' || $1.str[0]=='n'); bool new_row= ($1.str[0]=='N' || $1.str[0]=='n');
if (lex->trg_chistics.event == TRG_EVENT_INSERT && if (!($$= lex->create_and_link_Item_trigger_field(thd, $3.str,
!new_row) new_row)))
my_yyabort_error((ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "OLD", "on INSERT"));
if (lex->trg_chistics.event == TRG_EVENT_DELETE &&
new_row)
my_yyabort_error((ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "NEW", "on DELETE"));
DBUG_ASSERT(!new_row ||
(lex->trg_chistics.event == TRG_EVENT_INSERT ||
lex->trg_chistics.event == TRG_EVENT_UPDATE));
const bool tmp_read_only=
!(new_row && lex->trg_chistics.action_time == TRG_ACTION_BEFORE);
trg_fld= new (thd->mem_root)
Item_trigger_field(thd, Lex->current_context(),
new_row ?
Item_trigger_field::NEW_ROW:
Item_trigger_field::OLD_ROW,
$3.str,
SELECT_ACL,
tmp_read_only);
if (trg_fld == NULL)
MYSQL_YYABORT; MYSQL_YYABORT;
/*
Let us add this item to list of all Item_trigger_field objects
in trigger.
*/
lex->trg_table_fields.link_in_list(trg_fld,
&trg_fld->next_trg_field);
$$= trg_fld;
} }
else else
{ {
......
...@@ -13482,45 +13482,13 @@ simple_ident_q: ...@@ -13482,45 +13482,13 @@ simple_ident_q:
we can't meet simple_ident_nospvar in trigger now. But it we can't meet simple_ident_nospvar in trigger now. But it
should be changed in future. should be changed in future.
*/ */
if (lex->sphead && lex->sphead->m_type == TYPE_ENUM_TRIGGER && if (lex->is_trigger_new_or_old_reference($1))
(!my_strcasecmp(system_charset_info, $1.str, "NEW") ||
!my_strcasecmp(system_charset_info, $1.str, "OLD")))
{ {
Item_trigger_field *trg_fld;
bool new_row= ($1.str[0]=='N' || $1.str[0]=='n'); bool new_row= ($1.str[0]=='N' || $1.str[0]=='n');
if (lex->trg_chistics.event == TRG_EVENT_INSERT && if (!($$= lex->create_and_link_Item_trigger_field(thd, $3.str,
!new_row) new_row)))
my_yyabort_error((ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "OLD", "on INSERT"));
if (lex->trg_chistics.event == TRG_EVENT_DELETE &&
new_row)
my_yyabort_error((ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "NEW", "on DELETE"));
DBUG_ASSERT(!new_row ||
(lex->trg_chistics.event == TRG_EVENT_INSERT ||
lex->trg_chistics.event == TRG_EVENT_UPDATE));
const bool tmp_read_only=
!(new_row && lex->trg_chistics.action_time == TRG_ACTION_BEFORE);
trg_fld= new (thd->mem_root)
Item_trigger_field(thd, Lex->current_context(),
new_row ?
Item_trigger_field::NEW_ROW:
Item_trigger_field::OLD_ROW,
$3.str,
SELECT_ACL,
tmp_read_only);
if (trg_fld == NULL)
MYSQL_YYABORT; MYSQL_YYABORT;
/*
Let us add this item to list of all Item_trigger_field objects
in trigger.
*/
lex->trg_table_fields.link_in_list(trg_fld,
&trg_fld->next_trg_field);
$$= trg_fld;
} }
else else
{ {
...@@ -13545,6 +13513,23 @@ simple_ident_q: ...@@ -13545,6 +13513,23 @@ simple_ident_q:
MYSQL_YYABORT; MYSQL_YYABORT;
} }
} }
| ':' ident '.' ident
{
LEX *lex= Lex;
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.str,
new_row)))
MYSQL_YYABORT;
}
else
{
thd->parse_error();
MYSQL_YYABORT;
}
}
| '.' ident '.' ident | '.' ident '.' ident
{ {
LEX *lex= thd->lex; LEX *lex= thd->lex;
...@@ -14342,6 +14327,15 @@ set_assign: ...@@ -14342,6 +14327,15 @@ set_assign:
sp_create_assignment_lex(thd, yychar == YYEMPTY); sp_create_assignment_lex(thd, yychar == YYEMPTY);
} }
set_expr_or_default set_expr_or_default
{
if ($1.var == trg_new_row_fake_var)
{
/* We are in trigger and assigning value to field of new row */
if (Lex->set_trigger_new_row(&$1.base_name, $4) ||
Lex->sphead->restore_lex(thd))
MYSQL_YYABORT;
}
else
{ {
sp_pcontext *spc= Lex->spcont; sp_pcontext *spc= Lex->spcont;
sp_variable *spv= spc->find_variable($1.base_name, false); sp_variable *spv= spc->find_variable($1.base_name, false);
...@@ -14353,6 +14347,7 @@ set_assign: ...@@ -14353,6 +14347,7 @@ set_assign:
if (sp_create_assignment_instr(thd, yychar == YYEMPTY)) if (sp_create_assignment_instr(thd, yychar == YYEMPTY))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
}
; ;
set_stmt_option_value_following_option_type_list: set_stmt_option_value_following_option_type_list:
...@@ -14671,6 +14666,16 @@ internal_variable_name_directly_assignable: ...@@ -14671,6 +14666,16 @@ internal_variable_name_directly_assignable:
if (Lex->init_default_internal_variable(&$$, $3)) if (Lex->init_default_internal_variable(&$$, $3))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| ':' 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_characteristics:
......
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