mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
MDEV-10579 sql_mode=ORACLE: Triggers: Understand :NEW.c1 and :OLD.c1 instead of NEW.c1 and OLD.c1
This commit is contained in:
82
mysql-test/suite/compat/oracle/r/trigger.result
Normal file
82
mysql-test/suite/compat/oracle/r/trigger.result
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
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;
|
86
mysql-test/suite/compat/oracle/t/trigger.test
Normal file
86
mysql-test/suite/compat/oracle/t/trigger.test
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
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,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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,
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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 @@ public:
|
|||||||
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:
|
|||||||
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:
|
|||||||
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:
|
|||||||
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:
|
|||||||
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:
|
|||||||
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:
|
|||||||
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:
|
||||||
|
Reference in New Issue
Block a user