Commit a32bf7fb authored by unknown's avatar unknown

Fix for bugs #5892/6182/8751/8758/10994 (based on Antony's patch)

  "Triggers have the wrong namespace"
  "Triggers: duplicate names allowed"
  "Triggers: CREATE TRIGGER does not accept fully qualified names"
  "SHOW TRIGGERS"


mysql-test/r/information_schema.result:
  Added tests for new INFORMATION_SCHEMA.TRIGGERS view and SHOW TRIGGERS command.
mysql-test/r/information_schema_db.result:
  INFORMATION_SCHEMA.TRIGGERS view was added.
mysql-test/r/rpl_sp.result:
  Now DROP TRIGGER interprets first part of trigger identifier as database
  name and not as table name. Adjusted tests properly.
mysql-test/r/trigger.result:
  Now DROP TRIGGER interprets first part of trigger identifier as database
  name and not as table name. Adjusted tests properly.
  Added test checking that triggers have database wide namespace.
  Added test for bug #8791 "Triggers: Allowed to create triggers on a subject
  table in a different DB".
mysql-test/r/view.result:
  Now DROP TRIGGER interprets first part of trigger identifier as database
  name and not as table name. Adjusted tests properly.
mysql-test/t/information_schema.test:
  Added tests for new INFORMATION_SCHEMA.TRIGGERS view and SHOW TRIGGERS command.
mysql-test/t/rpl_sp.test:
  Now DROP TRIGGER interprets first part of trigger identifier as database
  name and not as table name. Adjusted tests properly.
mysql-test/t/trigger.test:
  Now DROP TRIGGER interprets first part of trigger identifier as database
  name and not as table name. Adjusted tests properly.
  Added test checking that triggers have database wide namespace.
  Added test for bug #8791 "Triggers: Allowed to create triggers on a subject
  table in a different DB".
mysql-test/t/view.test:
  Now DROP TRIGGER interprets first part of trigger identifier as database
  name and not as table name. Adjusted tests properly.
sql/handler.cc:
  Added .TRN tho the list of known file extensions assoicated with tables.
sql/item.h:
  trg_action_time_type/trg_event_type enums:
    Added TRG_ACTION_MAX/TRG_EVENT_MAX elements which should be used instead of
    magical values in various loops where we iterate through all types of trigger
    action times or/and trigger event types.
sql/lex.h:
  Added new symbol "TRIGGERS".
sql/mysql_priv.h:
  Added declaration of constant holding extension for trigger name (.TRN) files.
sql/mysqld.cc:
  Added statistical variable for SHOW TRIGGERS command.
sql/share/errmsg.txt:
  Added error message saying that one attempts to create trigger in wrong schema.
sql/sp.cc:
  Replaced magical values with TRG_EVENT_MAX/TRG_ACTION_MAX constants.
sql/sql_base.cc:
  open_unireg_entry():
    Now Table_triggers_list::check_n_load() has one more argument which
    controls whether we should prepare Table_triggers_list with fully functional
    triggers or load only their names.
sql/sql_lex.h:
  Added element for new SHOW TRIGGERS command to enum_sql_command enum.
sql/sql_parse.cc:
  prepare_schema_table():
    Added support for SHOW TRIGGERS statement.
sql/sql_show.cc:
  Added new INFORMATION_SCHEMA.TRIGGERS view and SHOW TRIGGERS command.
sql/sql_table.cc:
  mysql_rm_table_part2():
    Replaced simple deletion of .TRG file with call to
    Table_triggers_list::drop_all_triggers which will also delete .TRN files
    for all triggers associated with table.
sql/sql_trigger.cc:
  Now triggers have database wide namespace. To support it we create special .TRN
  file with same name as trigger for each trigger. This file contains name of
  trigger's table so one does not need to specify it explicitly in DROP TRIGGER.
  Moreover DROP TRIGGER treats first part of trigger identifier as database name
  now. Updated mysql_create_or_drop_trigger() routine and
  Table_triggers_list::create_trigger()/drop_trigger()/check_n_load() methods
  accordingly. Added add_table_for_trigger() routine and
  Table_triggers_list::drop_all_triggers() method.
  
  Added Table_triggers_list::get_trigger_info() for obtaining trigger metadata.
sql/sql_trigger.h:
  Table_triggers_list:
    Use TRG_EVENT_MAX, TRG_ACTION_MAX instead of magic values.
    Added get_trigger_info() method for obtaining trigger's meta-data.
    Added drop_all_triggers() method which drops all triggers for table.
    Added declarations of trg_action_time_type_names/trg_event_type_names
    arrays which hold names of triggers action time types  and event types.
sql/sql_yacc.yy:
  Changed grammar for CREATE/DROP TRIGGER to support database wide trigger
  namespace. Added new SHOW TRIGGERS statement.
sql/table.h:
  enum enum_schema_tables:
    Added constant for new INFORMATION_SCHEMA.TRIGGERS view.
parent e155a0c0
...@@ -48,6 +48,7 @@ TABLE_PRIVILEGES ...@@ -48,6 +48,7 @@ TABLE_PRIVILEGES
COLUMN_PRIVILEGES COLUMN_PRIVILEGES
TABLE_CONSTRAINTS TABLE_CONSTRAINTS
KEY_COLUMN_USAGE KEY_COLUMN_USAGE
TRIGGERS
columns_priv columns_priv
db db
func func
...@@ -77,6 +78,7 @@ c table_name ...@@ -77,6 +78,7 @@ c table_name
TABLES TABLES TABLES TABLES
TABLE_PRIVILEGES TABLE_PRIVILEGES TABLE_PRIVILEGES TABLE_PRIVILEGES
TABLE_CONSTRAINTS TABLE_CONSTRAINTS TABLE_CONSTRAINTS TABLE_CONSTRAINTS
TRIGGERS TRIGGERS
tables_priv tables_priv tables_priv tables_priv
time_zone time_zone time_zone time_zone
time_zone_leap_second time_zone_leap_second time_zone_leap_second time_zone_leap_second
...@@ -94,6 +96,7 @@ c table_name ...@@ -94,6 +96,7 @@ c table_name
TABLES TABLES TABLES TABLES
TABLE_PRIVILEGES TABLE_PRIVILEGES TABLE_PRIVILEGES TABLE_PRIVILEGES
TABLE_CONSTRAINTS TABLE_CONSTRAINTS TABLE_CONSTRAINTS TABLE_CONSTRAINTS
TRIGGERS TRIGGERS
tables_priv tables_priv tables_priv tables_priv
time_zone time_zone time_zone time_zone
time_zone_leap_second time_zone_leap_second time_zone_leap_second time_zone_leap_second
...@@ -111,6 +114,7 @@ c table_name ...@@ -111,6 +114,7 @@ c table_name
TABLES TABLES TABLES TABLES
TABLE_PRIVILEGES TABLE_PRIVILEGES TABLE_PRIVILEGES TABLE_PRIVILEGES
TABLE_CONSTRAINTS TABLE_CONSTRAINTS TABLE_CONSTRAINTS TABLE_CONSTRAINTS
TRIGGERS TRIGGERS
tables_priv tables_priv tables_priv tables_priv
time_zone time_zone time_zone time_zone
time_zone_leap_second time_zone_leap_second time_zone_leap_second time_zone_leap_second
...@@ -577,6 +581,7 @@ Tables_in_information_schema (T%) ...@@ -577,6 +581,7 @@ Tables_in_information_schema (T%)
TABLES TABLES
TABLE_PRIVILEGES TABLE_PRIVILEGES
TABLE_CONSTRAINTS TABLE_CONSTRAINTS
TRIGGERS
create database information_schema; create database information_schema;
ERROR HY000: Can't create database 'information_schema'; database exists ERROR HY000: Can't create database 'information_schema'; database exists
use information_schema; use information_schema;
...@@ -585,6 +590,7 @@ Tables_in_information_schema (T%) Table_type ...@@ -585,6 +590,7 @@ Tables_in_information_schema (T%) Table_type
TABLES TEMPORARY TABLES TEMPORARY
TABLE_PRIVILEGES TEMPORARY TABLE_PRIVILEGES TEMPORARY
TABLE_CONSTRAINTS TEMPORARY TABLE_CONSTRAINTS TEMPORARY
TRIGGERS TEMPORARY
create table t1(a int); create table t1(a int);
ERROR 42S02: Unknown table 't1' in information_schema ERROR 42S02: Unknown table 't1' in information_schema
use test; use test;
...@@ -596,6 +602,7 @@ Tables_in_information_schema (T%) ...@@ -596,6 +602,7 @@ Tables_in_information_schema (T%)
TABLES TABLES
TABLE_PRIVILEGES TABLE_PRIVILEGES
TABLE_CONSTRAINTS TABLE_CONSTRAINTS
TRIGGERS
select table_name from tables where table_name='user'; select table_name from tables where table_name='user';
table_name table_name
user user
...@@ -690,7 +697,7 @@ CREATE TABLE t_crashme ( f1 BIGINT); ...@@ -690,7 +697,7 @@ CREATE TABLE t_crashme ( f1 BIGINT);
CREATE VIEW a1 (t_CRASHME) AS SELECT f1 FROM t_crashme GROUP BY f1; CREATE VIEW a1 (t_CRASHME) AS SELECT f1 FROM t_crashme GROUP BY f1;
CREATE VIEW a2 AS SELECT t_CRASHME FROM a1; CREATE VIEW a2 AS SELECT t_CRASHME FROM a1;
count(*) count(*)
100 101
drop view a2, a1; drop view a2, a1;
drop table t_crashme; drop table t_crashme;
select table_schema,table_name, column_name from select table_schema,table_name, column_name from
...@@ -701,6 +708,8 @@ information_schema COLUMNS COLUMN_TYPE ...@@ -701,6 +708,8 @@ information_schema COLUMNS COLUMN_TYPE
information_schema ROUTINES ROUTINE_DEFINITION information_schema ROUTINES ROUTINE_DEFINITION
information_schema ROUTINES SQL_MODE information_schema ROUTINES SQL_MODE
information_schema VIEWS VIEW_DEFINITION information_schema VIEWS VIEW_DEFINITION
information_schema TRIGGERS ACTION_CONDITION
information_schema TRIGGERS ACTION_STATEMENT
select table_name, column_name, data_type from information_schema.columns select table_name, column_name, data_type from information_schema.columns
where data_type = 'datetime'; where data_type = 'datetime';
table_name column_name data_type table_name column_name data_type
...@@ -709,6 +718,7 @@ TABLES UPDATE_TIME datetime ...@@ -709,6 +718,7 @@ TABLES UPDATE_TIME datetime
TABLES CHECK_TIME datetime TABLES CHECK_TIME datetime
ROUTINES CREATED datetime ROUTINES CREATED datetime
ROUTINES LAST_ALTERED datetime ROUTINES LAST_ALTERED datetime
TRIGGERS CREATED datetime
SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES A SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES A
WHERE NOT EXISTS WHERE NOT EXISTS
(SELECT * FROM INFORMATION_SCHEMA.COLUMNS B (SELECT * FROM INFORMATION_SCHEMA.COLUMNS B
...@@ -755,8 +765,71 @@ delete from mysql.db where user='mysqltest_4'; ...@@ -755,8 +765,71 @@ delete from mysql.db where user='mysqltest_4';
flush privileges; flush privileges;
SELECT table_schema, count(*) FROM information_schema.TABLES GROUP BY TABLE_SCHEMA; SELECT table_schema, count(*) FROM information_schema.TABLES GROUP BY TABLE_SCHEMA;
table_schema count(*) table_schema count(*)
information_schema 15 information_schema 16
mysql 17 mysql 17
create table t1 (i int, j int);
create trigger trg1 before insert on t1 for each row
begin
if new.j > 10 then
set new.j := 10;
end if;
end|
create trigger trg2 before update on t1 for each row
begin
if old.i % 2 = 0 then
set new.j := -1;
end if;
end|
create trigger trg3 after update on t1 for each row
begin
if new.j = -1 then
set @fired:= "Yes";
end if;
end|
show triggers;
Trigger Event Table Statement Timing Created
trg1 INSERT t1
begin
if new.j > 10 then
set new.j := 10;
end if;
end BEFORE NULL
trg2 UPDATE t1
begin
if old.i % 2 = 0 then
set new.j := -1;
end if;
end BEFORE NULL
trg3 UPDATE t1
begin
if new.j = -1 then
set @fired:= "Yes";
end if;
end AFTER NULL
select * from information_schema.triggers;
TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATALOG EVENT_OBJECT_SCHEMA EVENT_OBJECT_TABLE ACTION_ORDER ACTION_CONDITION ACTION_STATEMENT ACTION_ORIENTATION ACTION_TIMING ACTION_REFERENCE_OLD_TABLE ACTION_REFERENCE_NEW_TABLE ACTION_REFERENCE_OLD_ROW ACTION_REFERENCE_NEW_ROW CREATED
NULL test trg1 INSERT NULL test t1 0 NULL
begin
if new.j > 10 then
set new.j := 10;
end if;
end ROW BEFORE NULL NULL OLD NEW NULL
NULL test trg2 UPDATE NULL test t1 0 NULL
begin
if old.i % 2 = 0 then
set new.j := -1;
end if;
end ROW BEFORE NULL NULL OLD NEW NULL
NULL test trg3 UPDATE NULL test t1 0 NULL
begin
if new.j = -1 then
set @fired:= "Yes";
end if;
end ROW AFTER NULL NULL OLD NEW NULL
drop trigger trg1;
drop trigger trg2;
drop trigger trg3;
drop table t1;
create database mysqltest; create database mysqltest;
create table mysqltest.t1 (f1 int, f2 int); create table mysqltest.t1 (f1 int, f2 int);
create table mysqltest.t2 (f1 int); create table mysqltest.t2 (f1 int);
......
...@@ -16,11 +16,13 @@ TABLE_PRIVILEGES ...@@ -16,11 +16,13 @@ TABLE_PRIVILEGES
COLUMN_PRIVILEGES COLUMN_PRIVILEGES
TABLE_CONSTRAINTS TABLE_CONSTRAINTS
KEY_COLUMN_USAGE KEY_COLUMN_USAGE
TRIGGERS
show tables from INFORMATION_SCHEMA like 'T%'; show tables from INFORMATION_SCHEMA like 'T%';
Tables_in_information_schema (T%) Tables_in_information_schema (T%)
TABLES TABLES
TABLE_PRIVILEGES TABLE_PRIVILEGES
TABLE_CONSTRAINTS TABLE_CONSTRAINTS
TRIGGERS
create database `inf%`; create database `inf%`;
use `inf%`; use `inf%`;
show tables; show tables;
......
...@@ -237,7 +237,7 @@ select * from t1; ...@@ -237,7 +237,7 @@ select * from t1;
a a
10 10
delete from t1; delete from t1;
drop trigger t1.trg; drop trigger trg;
insert into t1 values (1); insert into t1 values (1);
select * from t1; select * from t1;
a a
...@@ -248,7 +248,7 @@ master-bin.000002 # Query 1 # use `mysqltest1`; delete from t1 ...@@ -248,7 +248,7 @@ master-bin.000002 # Query 1 # use `mysqltest1`; delete from t1
master-bin.000002 # Query 1 # use `mysqltest1`; create trigger trg before insert on t1 for each row set new.a= 10 master-bin.000002 # Query 1 # use `mysqltest1`; create trigger trg before insert on t1 for each row set new.a= 10
master-bin.000002 # Query 1 # use `mysqltest1`; insert into t1 values (1) master-bin.000002 # Query 1 # use `mysqltest1`; insert into t1 values (1)
master-bin.000002 # Query 1 # use `mysqltest1`; delete from t1 master-bin.000002 # Query 1 # use `mysqltest1`; delete from t1
master-bin.000002 # Query 1 # use `mysqltest1`; drop trigger t1.trg master-bin.000002 # Query 1 # use `mysqltest1`; drop trigger trg
master-bin.000002 # Query 1 # use `mysqltest1`; insert into t1 values (1) master-bin.000002 # Query 1 # use `mysqltest1`; insert into t1 values (1)
select * from t1; select * from t1;
a a
......
...@@ -12,13 +12,13 @@ insert into t1 values (1); ...@@ -12,13 +12,13 @@ insert into t1 values (1);
select @a; select @a;
@a @a
1 1
drop trigger t1.trg; drop trigger trg;
create trigger trg before insert on t1 for each row set @a:=new.i; create trigger trg before insert on t1 for each row set @a:=new.i;
insert into t1 values (123); insert into t1 values (123);
select @a; select @a;
@a @a
123 123
drop trigger t1.trg; drop trigger trg;
drop table t1; drop table t1;
create table t1 (i int not null, j int); create table t1 (i int not null, j int);
create trigger trg before insert on t1 for each row create trigger trg before insert on t1 for each row
...@@ -33,7 +33,7 @@ select * from t1| ...@@ -33,7 +33,7 @@ select * from t1|
i j i j
1 10 1 10
2 3 2 3
drop trigger t1.trg| drop trigger trg|
drop table t1| drop table t1|
create table t1 (i int not null primary key); create table t1 (i int not null primary key);
create trigger trg after insert on t1 for each row create trigger trg after insert on t1 for each row
...@@ -43,7 +43,7 @@ insert into t1 values (2),(3),(4),(5); ...@@ -43,7 +43,7 @@ insert into t1 values (2),(3),(4),(5);
select @a; select @a;
@a @a
2:3:4:5 2:3:4:5
drop trigger t1.trg; drop trigger trg;
drop table t1; drop table t1;
create table t1 (aid int not null primary key, balance int not null default 0); create table t1 (aid int not null primary key, balance int not null default 0);
insert into t1 values (1, 1000), (2,3000); insert into t1 values (1, 1000), (2,3000);
...@@ -65,7 +65,7 @@ Too big change for aid = 2 ...@@ -65,7 +65,7 @@ Too big change for aid = 2
aid balance aid balance
1 1500 1 1500
2 3000 2 3000
drop trigger t1.trg| drop trigger trg|
drop table t1| drop table t1|
create table t1 (i int); create table t1 (i int);
insert into t1 values (1),(2),(3),(4); insert into t1 values (1),(2),(3),(4);
...@@ -76,7 +76,7 @@ update t1 set i=3; ...@@ -76,7 +76,7 @@ update t1 set i=3;
select @total_change; select @total_change;
@total_change @total_change
2 2
drop trigger t1.trg; drop trigger trg;
drop table t1; drop table t1;
create table t1 (i int); create table t1 (i int);
insert into t1 values (1),(2),(3),(4); insert into t1 values (1),(2),(3),(4);
...@@ -87,7 +87,7 @@ delete from t1 where i <= 3; ...@@ -87,7 +87,7 @@ delete from t1 where i <= 3;
select @del_sum; select @del_sum;
@del_sum @del_sum
6 6
drop trigger t1.trg; drop trigger trg;
drop table t1; drop table t1;
create table t1 (i int); create table t1 (i int);
insert into t1 values (1),(2),(3),(4); insert into t1 values (1),(2),(3),(4);
...@@ -97,7 +97,7 @@ delete from t1 where i <> 0; ...@@ -97,7 +97,7 @@ delete from t1 where i <> 0;
select @del; select @del;
@del @del
1 1
drop trigger t1.trg; drop trigger trg;
drop table t1; drop table t1;
create table t1 (i int, j int); create table t1 (i int, j int);
create trigger trg1 before insert on t1 for each row create trigger trg1 before insert on t1 for each row
...@@ -137,9 +137,9 @@ i j ...@@ -137,9 +137,9 @@ i j
1 20 1 20
2 -1 2 -1
3 20 3 20
drop trigger t1.trg1; drop trigger trg1;
drop trigger t1.trg2; drop trigger trg2;
drop trigger t1.trg3; drop trigger trg3;
drop table t1; drop table t1;
create table t1 (id int not null primary key, data int); create table t1 (id int not null primary key, data int);
create trigger t1_bi before insert on t1 for each row create trigger t1_bi before insert on t1 for each row
...@@ -197,7 +197,7 @@ select * from t2; ...@@ -197,7 +197,7 @@ select * from t2;
event event
INSERT INTO t1 id=1 data='one' INSERT INTO t1 id=1 data='one'
INSERT INTO t1 id=2 data='two' INSERT INTO t1 id=2 data='two'
drop trigger t1.t1_ai; drop trigger t1_ai;
create trigger t1_bi before insert on t1 for each row create trigger t1_bi before insert on t1 for each row
begin begin
if exists (select id from t3 where id=new.fk) then if exists (select id from t3 where id=new.fk) then
...@@ -271,6 +271,7 @@ id copy ...@@ -271,6 +271,7 @@ id copy
3 NULL 3 NULL
drop table t1, t2; drop table t1, t2;
create table t1 (i int); create table t1 (i int);
create table t3 (i int);
create trigger trg before insert on t1 for each row set @a:= old.i; create trigger trg before insert on t1 for each row set @a:= old.i;
ERROR HY000: There is no OLD row in on INSERT trigger ERROR HY000: There is no OLD row in on INSERT trigger
create trigger trg before delete on t1 for each row set @a:= new.i; create trigger trg before delete on t1 for each row set @a:= new.i;
...@@ -292,14 +293,19 @@ create trigger trg after insert on t1 for each row set @a:=1; ...@@ -292,14 +293,19 @@ create trigger trg after insert on t1 for each row set @a:=1;
ERROR HY000: Trigger already exists ERROR HY000: Trigger already exists
create trigger trg2 before insert on t1 for each row set @a:=1; create trigger trg2 before insert on t1 for each row set @a:=1;
ERROR HY000: Trigger already exists ERROR HY000: Trigger already exists
drop trigger t1.trg; create trigger trg before insert on t3 for each row set @a:=1;
drop trigger t1.trg; ERROR HY000: Trigger already exists
create trigger trg2 before insert on t3 for each row set @a:=1;
drop trigger trg2;
drop trigger trg;
drop trigger trg;
ERROR HY000: Trigger does not exist ERROR HY000: Trigger does not exist
create view v1 as select * from t1; create view v1 as select * from t1;
create trigger trg before insert on v1 for each row set @a:=1; create trigger trg before insert on v1 for each row set @a:=1;
ERROR HY000: 'test.v1' is not BASE TABLE ERROR HY000: 'test.v1' is not BASE TABLE
drop view v1; drop view v1;
drop table t1; drop table t1;
drop table t3;
create temporary table t1 (i int); create temporary table t1 (i int);
create trigger trg before insert on t1 for each row set @a:=1; create trigger trg before insert on t1 for each row set @a:=1;
ERROR HY000: Trigger's 't1' is view or temporary table ERROR HY000: Trigger's 't1' is view or temporary table
...@@ -307,7 +313,7 @@ drop table t1; ...@@ -307,7 +313,7 @@ drop table t1;
create table t1 (x1col char); create table t1 (x1col char);
create trigger tx1 before insert on t1 for each row set new.x1col = 'x'; create trigger tx1 before insert on t1 for each row set new.x1col = 'x';
insert into t1 values ('y'); insert into t1 values ('y');
drop trigger t1.tx1; drop trigger tx1;
drop table t1; drop table t1;
create table t1 (i int) engine=myisam; create table t1 (i int) engine=myisam;
insert into t1 values (1), (2); insert into t1 values (1), (2);
...@@ -318,8 +324,8 @@ delete from t1; ...@@ -318,8 +324,8 @@ delete from t1;
select @del_before, @del_after; select @del_before, @del_after;
@del_before @del_after @del_before @del_after
3 3 3 3
drop trigger t1.trg1; drop trigger trg1;
drop trigger t1.trg2; drop trigger trg2;
drop table t1; drop table t1;
create table t1 (a int); create table t1 (a int);
create trigger trg1 before insert on t1 for each row set new.a= 10; create trigger trg1 before insert on t1 for each row set new.a= 10;
...@@ -336,6 +342,15 @@ create table t1 (i int); ...@@ -336,6 +342,15 @@ create table t1 (i int);
create trigger trg1 before insert on t1 for each row set @a:= 1; create trigger trg1 before insert on t1 for each row set @a:= 1;
drop database mysqltest; drop database mysqltest;
use test; use test;
create database mysqltest;
create table mysqltest.t1 (i int);
create trigger trg1 before insert on mysqltest.t1 for each row set @a:= 1;
ERROR HY000: Trigger in wrong schema
use mysqltest;
create trigger test.trg1 before insert on t1 for each row set @a:= 1;
ERROR HY000: Trigger in wrong schema
drop database mysqltest;
use test;
create table t1 (i int, j int default 10, k int not null, key (k)); create table t1 (i int, j int default 10, k int not null, key (k));
create table t2 (i int); create table t2 (i int);
insert into t1 (i, k) values (1, 1); insert into t1 (i, k) values (1, 1);
...@@ -549,7 +564,7 @@ i k ...@@ -549,7 +564,7 @@ i k
1 1 1 1
2 2 2 2
alter table t1 add primary key (i); alter table t1 add primary key (i);
drop trigger t1.bi; drop trigger bi;
insert into t1 values (2, 4) on duplicate key update k= k + 10; insert into t1 values (2, 4) on duplicate key update k= k + 10;
ERROR 42S22: Unknown column 'bt' in 'NEW' ERROR 42S22: Unknown column 'bt' in 'NEW'
select * from t1; select * from t1;
...@@ -578,5 +593,5 @@ create trigger t1_bu before update on t1 for each row set new.col1= bug5893(); ...@@ -578,5 +593,5 @@ create trigger t1_bu before update on t1 for each row set new.col1= bug5893();
drop function bug5893; drop function bug5893;
update t1 set col2 = 4; update t1 set col2 = 4;
ERROR 42000: FUNCTION test.bug5893 does not exist ERROR 42000: FUNCTION test.bug5893 does not exist
drop trigger t1.t1_bu; drop trigger t1_bu;
drop table t1; drop table t1;
...@@ -1245,7 +1245,7 @@ select * from v1; ...@@ -1245,7 +1245,7 @@ select * from v1;
s1 s1
select * from t1; select * from t1;
s1 s1
drop trigger t1.t1_bi; drop trigger t1_bi;
drop view v1; drop view v1;
drop table t1; drop table t1;
create table t1 (s1 tinyint); create table t1 (s1 tinyint);
......
...@@ -505,6 +505,41 @@ flush privileges; ...@@ -505,6 +505,41 @@ flush privileges;
# #
SELECT table_schema, count(*) FROM information_schema.TABLES GROUP BY TABLE_SCHEMA; SELECT table_schema, count(*) FROM information_schema.TABLES GROUP BY TABLE_SCHEMA;
#
# TRIGGERS table test
#
create table t1 (i int, j int);
delimiter |;
create trigger trg1 before insert on t1 for each row
begin
if new.j > 10 then
set new.j := 10;
end if;
end|
create trigger trg2 before update on t1 for each row
begin
if old.i % 2 = 0 then
set new.j := -1;
end if;
end|
create trigger trg3 after update on t1 for each row
begin
if new.j = -1 then
set @fired:= "Yes";
end if;
end|
delimiter ;|
show triggers;
select * from information_schema.triggers;
drop trigger trg1;
drop trigger trg2;
drop trigger trg3;
drop table t1;
# #
# Bug #10964 Information Schema:Authorization check on privilege tables is improper # Bug #10964 Information Schema:Authorization check on privilege tables is improper
# #
......
...@@ -249,7 +249,7 @@ select * from t1; ...@@ -249,7 +249,7 @@ select * from t1;
connection master; connection master;
delete from t1; delete from t1;
drop trigger t1.trg; drop trigger trg;
insert into t1 values (1); insert into t1 values (1);
select * from t1; select * from t1;
--replace_column 2 # 5 # --replace_column 2 # 5 #
......
...@@ -17,13 +17,13 @@ set @a:=0; ...@@ -17,13 +17,13 @@ set @a:=0;
select @a; select @a;
insert into t1 values (1); insert into t1 values (1);
select @a; select @a;
drop trigger t1.trg; drop trigger trg;
# let us test simple trigger reading some values # let us test simple trigger reading some values
create trigger trg before insert on t1 for each row set @a:=new.i; create trigger trg before insert on t1 for each row set @a:=new.i;
insert into t1 values (123); insert into t1 values (123);
select @a; select @a;
drop trigger t1.trg; drop trigger trg;
drop table t1; drop table t1;
...@@ -40,7 +40,7 @@ end| ...@@ -40,7 +40,7 @@ end|
insert into t1 (i) values (1)| insert into t1 (i) values (1)|
insert into t1 (i,j) values (2, 3)| insert into t1 (i,j) values (2, 3)|
select * from t1| select * from t1|
drop trigger t1.trg| drop trigger trg|
drop table t1| drop table t1|
delimiter ;| delimiter ;|
...@@ -52,7 +52,7 @@ create trigger trg after insert on t1 for each row ...@@ -52,7 +52,7 @@ create trigger trg after insert on t1 for each row
set @a:=""; set @a:="";
insert into t1 values (2),(3),(4),(5); insert into t1 values (2),(3),(4),(5);
select @a; select @a;
drop trigger t1.trg; drop trigger trg;
drop table t1; drop table t1;
# PS doesn't work with multi-row statements # PS doesn't work with multi-row statements
...@@ -75,7 +75,7 @@ set @update_failed:=""| ...@@ -75,7 +75,7 @@ set @update_failed:=""|
update t1 set balance=1500| update t1 set balance=1500|
select @update_failed; select @update_failed;
select * from t1| select * from t1|
drop trigger t1.trg| drop trigger trg|
drop table t1| drop table t1|
delimiter ;| delimiter ;|
--enable_ps_protocol --enable_ps_protocol
...@@ -88,7 +88,7 @@ create trigger trg after update on t1 for each row ...@@ -88,7 +88,7 @@ create trigger trg after update on t1 for each row
set @total_change:=0; set @total_change:=0;
update t1 set i=3; update t1 set i=3;
select @total_change; select @total_change;
drop trigger t1.trg; drop trigger trg;
drop table t1; drop table t1;
# Before delete trigger # Before delete trigger
...@@ -100,7 +100,7 @@ create trigger trg before delete on t1 for each row ...@@ -100,7 +100,7 @@ create trigger trg before delete on t1 for each row
set @del_sum:= 0; set @del_sum:= 0;
delete from t1 where i <= 3; delete from t1 where i <= 3;
select @del_sum; select @del_sum;
drop trigger t1.trg; drop trigger trg;
drop table t1; drop table t1;
# After delete trigger. # After delete trigger.
...@@ -111,7 +111,7 @@ create trigger trg after delete on t1 for each row set @del:= 1; ...@@ -111,7 +111,7 @@ create trigger trg after delete on t1 for each row set @del:= 1;
set @del:= 0; set @del:= 0;
delete from t1 where i <> 0; delete from t1 where i <> 0;
select @del; select @del;
drop trigger t1.trg; drop trigger trg;
drop table t1; drop table t1;
# Several triggers on one table # Several triggers on one table
...@@ -145,9 +145,9 @@ update t1 set j= 20; ...@@ -145,9 +145,9 @@ update t1 set j= 20;
select @fired; select @fired;
select * from t1; select * from t1;
drop trigger t1.trg1; drop trigger trg1;
drop trigger t1.trg2; drop trigger trg2;
drop trigger t1.trg3; drop trigger trg3;
drop table t1; drop table t1;
...@@ -212,7 +212,7 @@ create trigger t1_ai after insert on t1 for each row ...@@ -212,7 +212,7 @@ create trigger t1_ai after insert on t1 for each row
insert into t1 (id, data) values (1, "one"), (2, "two"); insert into t1 (id, data) values (1, "one"), (2, "two");
select * from t1; select * from t1;
select * from t2; select * from t2;
drop trigger t1.t1_ai; drop trigger t1_ai;
# Trigger which uses couple of tables (and partially emulates FK constraint) # Trigger which uses couple of tables (and partially emulates FK constraint)
delimiter |; delimiter |;
create trigger t1_bi before insert on t1 for each row create trigger t1_bi before insert on t1 for each row
...@@ -282,6 +282,7 @@ drop table t1, t2; ...@@ -282,6 +282,7 @@ drop table t1, t2;
# Test of wrong column specifiers in triggers # Test of wrong column specifiers in triggers
# #
create table t1 (i int); create table t1 (i int);
create table t3 (i int);
--error 1363 --error 1363
create trigger trg before insert on t1 for each row set @a:= old.i; create trigger trg before insert on t1 for each row set @a:= old.i;
...@@ -301,7 +302,7 @@ create trigger trg before update on t1 for each row set @a:=old.j; ...@@ -301,7 +302,7 @@ create trigger trg before update on t1 for each row set @a:=old.j;
# #
# Let us test various trigger creation errors # Let us test various trigger creation errors
# # Also quickly test table namespace (bug#5892/6182)
# #
--error 1146 --error 1146
create trigger trg before insert on t2 for each row set @a:=1; create trigger trg before insert on t2 for each row set @a:=1;
...@@ -311,10 +312,14 @@ create trigger trg before insert on t1 for each row set @a:=1; ...@@ -311,10 +312,14 @@ create trigger trg before insert on t1 for each row set @a:=1;
create trigger trg after insert on t1 for each row set @a:=1; create trigger trg after insert on t1 for each row set @a:=1;
--error 1359 --error 1359
create trigger trg2 before insert on t1 for each row set @a:=1; create trigger trg2 before insert on t1 for each row set @a:=1;
drop trigger t1.trg; --error 1359
create trigger trg before insert on t3 for each row set @a:=1;
create trigger trg2 before insert on t3 for each row set @a:=1;
drop trigger trg2;
drop trigger trg;
--error 1360 --error 1360
drop trigger t1.trg; drop trigger trg;
create view v1 as select * from t1; create view v1 as select * from t1;
--error 1347 --error 1347
...@@ -322,6 +327,7 @@ create trigger trg before insert on v1 for each row set @a:=1; ...@@ -322,6 +327,7 @@ create trigger trg before insert on v1 for each row set @a:=1;
drop view v1; drop view v1;
drop table t1; drop table t1;
drop table t3;
create temporary table t1 (i int); create temporary table t1 (i int);
--error 1361 --error 1361
...@@ -339,7 +345,7 @@ drop table t1; ...@@ -339,7 +345,7 @@ drop table t1;
create table t1 (x1col char); create table t1 (x1col char);
create trigger tx1 before insert on t1 for each row set new.x1col = 'x'; create trigger tx1 before insert on t1 for each row set new.x1col = 'x';
insert into t1 values ('y'); insert into t1 values ('y');
drop trigger t1.tx1; drop trigger tx1;
drop table t1; drop table t1;
# #
...@@ -355,8 +361,8 @@ create trigger trg2 after delete on t1 for each row set @del_after:= @del_after ...@@ -355,8 +361,8 @@ create trigger trg2 after delete on t1 for each row set @del_after:= @del_after
set @del_before:=0, @del_after:= 0; set @del_before:=0, @del_after:= 0;
delete from t1; delete from t1;
select @del_before, @del_after; select @del_before, @del_after;
drop trigger t1.trg1; drop trigger trg1;
drop trigger t1.trg2; drop trigger trg2;
drop table t1; drop table t1;
# Test for bug #5859 "DROP TABLE does not drop triggers". Trigger should not # Test for bug #5859 "DROP TABLE does not drop triggers". Trigger should not
...@@ -378,6 +384,19 @@ create trigger trg1 before insert on t1 for each row set @a:= 1; ...@@ -378,6 +384,19 @@ create trigger trg1 before insert on t1 for each row set @a:= 1;
drop database mysqltest; drop database mysqltest;
use test; use test;
# Test for bug #8791
# "Triggers: Allowed to create triggers on a subject table in a different DB".
create database mysqltest;
create table mysqltest.t1 (i int);
--error 1429
create trigger trg1 before insert on mysqltest.t1 for each row set @a:= 1;
use mysqltest;
--error 1429
create trigger test.trg1 before insert on t1 for each row set @a:= 1;
drop database mysqltest;
use test;
# Test for bug #5860 "Multi-table UPDATE does not activate update triggers" # Test for bug #5860 "Multi-table UPDATE does not activate update triggers"
# We will also test how delete triggers wor for multi-table DELETE. # We will also test how delete triggers wor for multi-table DELETE.
create table t1 (i int, j int default 10, k int not null, key (k)); create table t1 (i int, j int default 10, k int not null, key (k));
...@@ -559,7 +578,7 @@ select * from t1; ...@@ -559,7 +578,7 @@ select * from t1;
# To test properly code-paths different from those that are used # To test properly code-paths different from those that are used
# in ordinary INSERT we need to drop "before insert" trigger. # in ordinary INSERT we need to drop "before insert" trigger.
alter table t1 add primary key (i); alter table t1 add primary key (i);
drop trigger t1.bi; drop trigger bi;
--error 1054 --error 1054
insert into t1 values (2, 4) on duplicate key update k= k + 10; insert into t1 values (2, 4) on duplicate key update k= k + 10;
select * from t1; select * from t1;
...@@ -589,5 +608,5 @@ drop function bug5893; ...@@ -589,5 +608,5 @@ drop function bug5893;
--error 1305 --error 1305
update t1 set col2 = 4; update t1 set col2 = 4;
# This should not crash server too. # This should not crash server too.
drop trigger t1.t1_bu; drop trigger t1_bu;
drop table t1; drop table t1;
...@@ -1182,7 +1182,7 @@ create view v1 as select * from t1 where s1 <> 127 with check option; ...@@ -1182,7 +1182,7 @@ create view v1 as select * from t1 where s1 <> 127 with check option;
insert into v1 values (0); insert into v1 values (0);
select * from v1; select * from v1;
select * from t1; select * from t1;
drop trigger t1.t1_bi; drop trigger t1_bi;
drop view v1; drop view v1;
drop table t1; drop table t1;
......
...@@ -2434,6 +2434,7 @@ TYPELIB *ha_known_exts(void) ...@@ -2434,6 +2434,7 @@ TYPELIB *ha_known_exts(void)
known_extensions_id= mysys_usage_id; known_extensions_id= mysys_usage_id;
found_exts.push_back((char*) triggers_file_ext); found_exts.push_back((char*) triggers_file_ext);
found_exts.push_back((char*) trigname_file_ext);
for (types= sys_table_types; types->type; types++) for (types= sys_table_types; types->type; types++)
{ {
if (*types->value == SHOW_OPTION_YES) if (*types->value == SHOW_OPTION_YES)
......
...@@ -1781,7 +1781,7 @@ class Item_insert_value : public Item_field ...@@ -1781,7 +1781,7 @@ class Item_insert_value : public Item_field
*/ */
enum trg_action_time_type enum trg_action_time_type
{ {
TRG_ACTION_BEFORE= 0, TRG_ACTION_AFTER= 1 TRG_ACTION_BEFORE= 0, TRG_ACTION_AFTER= 1, TRG_ACTION_MAX
}; };
/* /*
...@@ -1789,7 +1789,7 @@ enum trg_action_time_type ...@@ -1789,7 +1789,7 @@ enum trg_action_time_type
*/ */
enum trg_event_type enum trg_event_type
{ {
TRG_EVENT_INSERT= 0 , TRG_EVENT_UPDATE= 1, TRG_EVENT_DELETE= 2 TRG_EVENT_INSERT= 0 , TRG_EVENT_UPDATE= 1, TRG_EVENT_DELETE= 2, TRG_EVENT_MAX
}; };
class Table_triggers_list; class Table_triggers_list;
......
...@@ -497,6 +497,7 @@ static SYMBOL symbols[] = { ...@@ -497,6 +497,7 @@ static SYMBOL symbols[] = {
{ "TRAILING", SYM(TRAILING)}, { "TRAILING", SYM(TRAILING)},
{ "TRANSACTION", SYM(TRANSACTION_SYM)}, { "TRANSACTION", SYM(TRANSACTION_SYM)},
{ "TRIGGER", SYM(TRIGGER_SYM)}, { "TRIGGER", SYM(TRIGGER_SYM)},
{ "TRIGGERS", SYM(TRIGGERS_SYM)},
{ "TRUE", SYM(TRUE_SYM)}, { "TRUE", SYM(TRUE_SYM)},
{ "TRUNCATE", SYM(TRUNCATE_SYM)}, { "TRUNCATE", SYM(TRUNCATE_SYM)},
{ "TYPE", SYM(TYPE_SYM)}, { "TYPE", SYM(TYPE_SYM)},
......
...@@ -1082,6 +1082,7 @@ extern const char **errmesg; /* Error messages */ ...@@ -1082,6 +1082,7 @@ extern const char **errmesg; /* Error messages */
extern const char *myisam_recover_options_str; extern const char *myisam_recover_options_str;
extern const char *in_left_expr_name, *in_additional_cond; extern const char *in_left_expr_name, *in_additional_cond;
extern const char * const triggers_file_ext; extern const char * const triggers_file_ext;
extern const char * const trigname_file_ext;
extern Eq_creator eq_creator; extern Eq_creator eq_creator;
extern Ne_creator ne_creator; extern Ne_creator ne_creator;
extern Gt_creator gt_creator; extern Gt_creator gt_creator;
......
...@@ -5722,6 +5722,7 @@ struct show_var_st status_vars[]= { ...@@ -5722,6 +5722,7 @@ struct show_var_st status_vars[]= {
{"Com_show_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_STATUS]), SHOW_LONG_STATUS}, {"Com_show_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_STATUS]), SHOW_LONG_STATUS},
{"Com_show_storage_engines", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_STORAGE_ENGINES]), SHOW_LONG_STATUS}, {"Com_show_storage_engines", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_STORAGE_ENGINES]), SHOW_LONG_STATUS},
{"Com_show_tables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TABLES]), SHOW_LONG_STATUS}, {"Com_show_tables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TABLES]), SHOW_LONG_STATUS},
{"Com_show_triggers", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TRIGGERS]), SHOW_LONG_STATUS},
{"Com_show_variables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_VARIABLES]), SHOW_LONG_STATUS}, {"Com_show_variables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_VARIABLES]), SHOW_LONG_STATUS},
{"Com_show_warnings", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_WARNS]), SHOW_LONG_STATUS}, {"Com_show_warnings", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_WARNS]), SHOW_LONG_STATUS},
{"Com_slave_start", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SLAVE_START]), SHOW_LONG_STATUS}, {"Com_slave_start", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SLAVE_START]), SHOW_LONG_STATUS},
......
...@@ -5370,3 +5370,5 @@ ER_SCALE_BIGGER_THAN_PRECISION 42000 S1009 ...@@ -5370,3 +5370,5 @@ ER_SCALE_BIGGER_THAN_PRECISION 42000 S1009
eng "Scale may not be larger than the precision (column '%-.64s')." eng "Scale may not be larger than the precision (column '%-.64s')."
ER_WRONG_LOCK_OF_SYSTEM_TABLE ER_WRONG_LOCK_OF_SYSTEM_TABLE
eng "You can't combine write-locking of system '%-.64s.%-.64s' table with other tables" eng "You can't combine write-locking of system '%-.64s.%-.64s' table with other tables"
ER_TRG_IN_WRONG_SCHEMA
eng "Trigger in wrong schema"
...@@ -1442,8 +1442,8 @@ sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex, ...@@ -1442,8 +1442,8 @@ sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
{ {
Sroutine_hash_entry **last_cached_routine_ptr= Sroutine_hash_entry **last_cached_routine_ptr=
(Sroutine_hash_entry **)lex->sroutines_list.next; (Sroutine_hash_entry **)lex->sroutines_list.next;
for (int i= 0; i < 3; i++) for (int i= 0; i < (int)TRG_EVENT_MAX; i++)
for (int j= 0; j < 2; j++) for (int j= 0; j < (int)TRG_ACTION_MAX; j++)
if (triggers->bodies[i][j]) if (triggers->bodies[i][j])
{ {
(void)triggers->bodies[i][j]->add_used_tables_to_table_list(thd, (void)triggers->bodies[i][j]->add_used_tables_to_table_list(thd,
......
...@@ -1740,7 +1740,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db, ...@@ -1740,7 +1740,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
!my_strcasecmp(system_charset_info, name, "proc")) !my_strcasecmp(system_charset_info, name, "proc"))
entry->s->system_table= 1; entry->s->system_table= 1;
if (Table_triggers_list::check_n_load(thd, db, name, entry)) if (Table_triggers_list::check_n_load(thd, db, name, entry, 0))
goto err; goto err;
/* /*
......
...@@ -57,6 +57,7 @@ enum enum_sql_command { ...@@ -57,6 +57,7 @@ enum enum_sql_command {
SQLCOM_SHOW_PROCESSLIST, SQLCOM_SHOW_MASTER_STAT, SQLCOM_SHOW_SLAVE_STAT, SQLCOM_SHOW_PROCESSLIST, SQLCOM_SHOW_MASTER_STAT, SQLCOM_SHOW_SLAVE_STAT,
SQLCOM_SHOW_GRANTS, SQLCOM_SHOW_CREATE, SQLCOM_SHOW_CHARSETS, SQLCOM_SHOW_GRANTS, SQLCOM_SHOW_CREATE, SQLCOM_SHOW_CHARSETS,
SQLCOM_SHOW_COLLATIONS, SQLCOM_SHOW_CREATE_DB, SQLCOM_SHOW_TABLE_STATUS, SQLCOM_SHOW_COLLATIONS, SQLCOM_SHOW_CREATE_DB, SQLCOM_SHOW_TABLE_STATUS,
SQLCOM_SHOW_TRIGGERS,
SQLCOM_LOAD,SQLCOM_SET_OPTION,SQLCOM_LOCK_TABLES,SQLCOM_UNLOCK_TABLES, SQLCOM_LOAD,SQLCOM_SET_OPTION,SQLCOM_LOCK_TABLES,SQLCOM_UNLOCK_TABLES,
SQLCOM_GRANT, SQLCOM_GRANT,
......
...@@ -2104,6 +2104,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, ...@@ -2104,6 +2104,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
case SCH_TABLE_NAMES: case SCH_TABLE_NAMES:
case SCH_TABLES: case SCH_TABLES:
case SCH_VIEWS: case SCH_VIEWS:
case SCH_TRIGGERS:
#ifdef DONT_ALLOW_SHOW_COMMANDS #ifdef DONT_ALLOW_SHOW_COMMANDS
my_message(ER_NOT_ALLOWED_COMMAND, my_message(ER_NOT_ALLOWED_COMMAND,
ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */ ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "sql_select.h" // For select_describe #include "sql_select.h" // For select_describe
#include "repl_failsafe.h" #include "repl_failsafe.h"
#include "sp_head.h" #include "sp_head.h"
#include "sql_trigger.h"
#include <my_dir.h> #include <my_dir.h>
#ifdef HAVE_BERKELEY_DB #ifdef HAVE_BERKELEY_DB
...@@ -1696,6 +1697,7 @@ void get_index_field_values(LEX *lex, INDEX_FIELD_VALUES *index_field_values) ...@@ -1696,6 +1697,7 @@ void get_index_field_values(LEX *lex, INDEX_FIELD_VALUES *index_field_values)
break; break;
case SQLCOM_SHOW_TABLES: case SQLCOM_SHOW_TABLES:
case SQLCOM_SHOW_TABLE_STATUS: case SQLCOM_SHOW_TABLE_STATUS:
case SQLCOM_SHOW_TRIGGERS:
index_field_values->db_value= lex->current_select->db; index_field_values->db_value= lex->current_select->db;
index_field_values->table_value= wild; index_field_values->table_value= wild;
break; break;
...@@ -2963,6 +2965,73 @@ static int get_schema_constraints_record(THD *thd, struct st_table_list *tables, ...@@ -2963,6 +2965,73 @@ static int get_schema_constraints_record(THD *thd, struct st_table_list *tables,
} }
static bool store_trigger(THD *thd, TABLE *table, const char *db,
const char *tname, LEX_STRING *trigger_name,
enum trg_event_type event,
enum trg_action_time_type timing,
LEX_STRING *trigger_stmt)
{
CHARSET_INFO *cs= system_charset_info;
restore_record(table, s->default_values);
table->field[1]->store(db, strlen(db), cs);
table->field[2]->store(trigger_name->str, trigger_name->length, cs);
table->field[3]->store(trg_event_type_names[event].str,
trg_event_type_names[event].length, cs);
table->field[5]->store(db, strlen(db), cs);
table->field[6]->store(tname, strlen(tname), cs);
table->field[9]->store(trigger_stmt->str, trigger_stmt->length, cs);
table->field[10]->store("ROW", 3, cs);
table->field[11]->store(trg_action_time_type_names[timing].str,
trg_action_time_type_names[timing].length, cs);
table->field[14]->store("OLD", 3, cs);
table->field[15]->store("NEW", 3, cs);
return schema_table_store_record(thd, table);
}
static int get_schema_triggers_record(THD *thd, struct st_table_list *tables,
TABLE *table, bool res,
const char *base_name,
const char *file_name)
{
DBUG_ENTER("get_schema_triggers_record");
/*
res can be non zero value when processed table is a view or
error happened during opening of processed table.
*/
if (res)
{
if (!tables->view)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
thd->net.last_errno, thd->net.last_error);
thd->clear_error();
DBUG_RETURN(0);
}
if (!tables->view && tables->table->triggers)
{
Table_triggers_list *triggers= tables->table->triggers;
int event, timing;
for (event= 0; event < (int)TRG_EVENT_MAX; event++)
{
for (timing= 0; timing < (int)TRG_ACTION_MAX; timing++)
{
LEX_STRING trigger_name;
LEX_STRING trigger_stmt;
if (triggers->get_trigger_info(thd, (enum trg_event_type) event,
(enum trg_action_time_type)timing,
&trigger_name, &trigger_stmt))
continue;
if (store_trigger(thd, table, base_name, file_name, &trigger_name,
(enum trg_event_type) event,
(enum trg_action_time_type) timing, &trigger_stmt))
DBUG_RETURN(1);
}
}
}
DBUG_RETURN(0);
}
void store_key_column_usage(TABLE *table, const char*db, const char *tname, void store_key_column_usage(TABLE *table, const char*db, const char *tname,
const char *key_name, uint key_len, const char *key_name, uint key_len,
const char *con_type, uint con_len, longlong idx) const char *con_type, uint con_len, longlong idx)
...@@ -3847,6 +3916,29 @@ ST_FIELD_INFO open_tables_fields_info[]= ...@@ -3847,6 +3916,29 @@ ST_FIELD_INFO open_tables_fields_info[]=
}; };
ST_FIELD_INFO triggers_fields_info[]=
{
{"TRIGGER_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
{"TRIGGER_SCHEMA",NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
{"TRIGGER_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Trigger"},
{"EVENT_MANIPULATION", 6, MYSQL_TYPE_STRING, 0, 0, "Event"},
{"EVENT_OBJECT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
{"EVENT_OBJECT_SCHEMA",NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
{"EVENT_OBJECT_TABLE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table"},
{"ACTION_ORDER", 4, MYSQL_TYPE_LONG, 0, 0, 0},
{"ACTION_CONDITION", 65535, MYSQL_TYPE_STRING, 0, 1, 0},
{"ACTION_STATEMENT", 65535, MYSQL_TYPE_STRING, 0, 0, "Statement"},
{"ACTION_ORIENTATION", 9, MYSQL_TYPE_STRING, 0, 0, 0},
{"ACTION_TIMING", 6, MYSQL_TYPE_STRING, 0, 0, "Timing"},
{"ACTION_REFERENCE_OLD_TABLE", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
{"ACTION_REFERENCE_NEW_TABLE", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
{"ACTION_REFERENCE_OLD_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0},
{"ACTION_REFERENCE_NEW_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0},
{"CREATED", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Created"},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
};
ST_FIELD_INFO variables_fields_info[]= ST_FIELD_INFO variables_fields_info[]=
{ {
{"Variable_name", 80, MYSQL_TYPE_STRING, 0, 0, "Variable_name"}, {"Variable_name", 80, MYSQL_TYPE_STRING, 0, 0, "Variable_name"},
...@@ -3897,6 +3989,8 @@ ST_SCHEMA_TABLE schema_tables[]= ...@@ -3897,6 +3989,8 @@ ST_SCHEMA_TABLE schema_tables[]=
fill_open_tables, make_old_format, 0, -1, -1, 1}, fill_open_tables, make_old_format, 0, -1, -1, 1},
{"STATUS", variables_fields_info, create_schema_table, fill_status, {"STATUS", variables_fields_info, create_schema_table, fill_status,
make_old_format, 0, -1, -1, 1}, make_old_format, 0, -1, -1, 1},
{"TRIGGERS", triggers_fields_info, create_schema_table,
get_all_tables, make_old_format, get_schema_triggers_record, 5, 6, 0},
{"VARIABLES", variables_fields_info, create_schema_table, fill_variables, {"VARIABLES", variables_fields_info, create_schema_table, fill_variables,
make_old_format, 0, -1, -1, 1}, make_old_format, 0, -1, -1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0} {0, 0, 0, 0, 0, 0, 0, 0, 0}
......
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
#include <hash.h> #include <hash.h>
#include <myisam.h> #include <myisam.h>
#include <my_dir.h> #include <my_dir.h>
#include "sp_head.h"
#include "sql_trigger.h"
#ifdef __WIN__ #ifdef __WIN__
#include <io.h> #include <io.h>
...@@ -290,16 +292,8 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -290,16 +292,8 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
if (!(new_error=my_delete(path,MYF(MY_WME)))) if (!(new_error=my_delete(path,MYF(MY_WME))))
{ {
some_tables_deleted=1; some_tables_deleted=1;
/* new_error= Table_triggers_list::drop_all_triggers(thd, db,
Destroy triggers for this table if there are any. table->table_name);
We won't need this as soon as we will have new .FRM format,
in which we will store trigger definitions in the same .FRM
files as table descriptions.
*/
strmov(end, triggers_file_ext);
if (!access(path, F_OK))
new_error= my_delete(path, MYF(MY_WME));
} }
error|= new_error; error|= new_error;
} }
......
...@@ -38,6 +38,45 @@ static File_option triggers_file_parameters[]= ...@@ -38,6 +38,45 @@ static File_option triggers_file_parameters[]=
}; };
/*
Structure representing contents of .TRN file which are used to support
database wide trigger namespace.
*/
struct st_trigname
{
LEX_STRING trigger_table;
};
static const LEX_STRING trigname_file_type= {(char *)"TRIGGERNAME", 11};
const char * const trigname_file_ext= ".TRN";
static File_option trigname_file_parameters[]=
{
{{(char*)"trigger_table", 15}, offsetof(struct st_trigname, trigger_table),
FILE_OPTIONS_ESTRING},
{{0, 0}, 0, FILE_OPTIONS_STRING}
};
const LEX_STRING trg_action_time_type_names[]=
{
{ (char *) STRING_WITH_LEN("BEFORE") },
{ (char *) STRING_WITH_LEN("AFTER") }
};
const LEX_STRING trg_event_type_names[]=
{
{ (char *) STRING_WITH_LEN("INSERT") },
{ (char *) STRING_WITH_LEN("UPDATE") },
{ (char *) STRING_WITH_LEN("DELETE") }
};
static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig);
/* /*
Create or drop trigger for table. Create or drop trigger for table.
...@@ -69,6 +108,10 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) ...@@ -69,6 +108,10 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
But do we want this ? But do we want this ?
*/ */
if (!create &&
!(tables= add_table_for_trigger(thd, thd->lex->spname)))
DBUG_RETURN(TRUE);
/* We should have only one table in table list. */ /* We should have only one table in table list. */
DBUG_ASSERT(tables->next_global == 0); DBUG_ASSERT(tables->next_global == 0);
...@@ -174,28 +217,28 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables) ...@@ -174,28 +217,28 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables)
{ {
LEX *lex= thd->lex; LEX *lex= thd->lex;
TABLE *table= tables->table; TABLE *table= tables->table;
char dir_buff[FN_REFLEN], file_buff[FN_REFLEN]; char dir_buff[FN_REFLEN], file_buff[FN_REFLEN], trigname_buff[FN_REFLEN],
LEX_STRING dir, file; trigname_path[FN_REFLEN];
LEX_STRING dir, file, trigname_file;
LEX_STRING *trg_def, *name; LEX_STRING *trg_def, *name;
Item_trigger_field *trg_field; Item_trigger_field *trg_field;
List_iterator_fast<LEX_STRING> it(names_list); struct st_trigname trigname;
/* We don't allow creation of several triggers of the same type yet */
if (bodies[lex->trg_chistics.event][lex->trg_chistics.action_time]) /* Trigger must be in the same schema as target table. */
if (my_strcasecmp(system_charset_info, table->s->db,
lex->spname->m_db.str ? lex->spname->m_db.str :
thd->db))
{ {
my_message(ER_TRG_ALREADY_EXISTS, ER(ER_TRG_ALREADY_EXISTS), MYF(0)); my_error(ER_TRG_IN_WRONG_SCHEMA, MYF(0));
return 1; return 1;
} }
/* Let us check if trigger with the same name exists */ /* We don't allow creation of several triggers of the same type yet */
while ((name= it++)) if (bodies[lex->trg_chistics.event][lex->trg_chistics.action_time])
{ {
if (my_strcasecmp(system_charset_info, lex->ident.str, my_message(ER_TRG_ALREADY_EXISTS, ER(ER_TRG_ALREADY_EXISTS), MYF(0));
name->str) == 0) return 1;
{
my_message(ER_TRG_ALREADY_EXISTS, ER(ER_TRG_ALREADY_EXISTS), MYF(0));
return 1;
}
} }
/* /*
...@@ -234,6 +277,25 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables) ...@@ -234,6 +277,25 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables)
file.length= strxnmov(file_buff, FN_REFLEN, tables->table_name, file.length= strxnmov(file_buff, FN_REFLEN, tables->table_name,
triggers_file_ext, NullS) - file_buff; triggers_file_ext, NullS) - file_buff;
file.str= file_buff; file.str= file_buff;
trigname_file.length= strxnmov(trigname_buff, FN_REFLEN,
lex->spname->m_name.str,
trigname_file_ext, NullS) - trigname_buff;
trigname_file.str= trigname_buff;
strxnmov(trigname_path, FN_REFLEN, dir_buff, trigname_buff, NullS);
/* Use the filesystem to enforce trigger namespace constraints. */
if (!access(trigname_path, F_OK))
{
my_error(ER_TRG_ALREADY_EXISTS, MYF(0));
return 1;
}
trigname.trigger_table.str= tables->table_name;
trigname.trigger_table.length= tables->table_name_length;
if (sql_create_definition_file(&dir, &trigname_file, &trigname_file_type,
(gptr)&trigname, trigname_file_parameters, 0))
return 1;
/* /*
Soon we will invalidate table object and thus Table_triggers_list object Soon we will invalidate table object and thus Table_triggers_list object
...@@ -246,13 +308,66 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables) ...@@ -246,13 +308,66 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables)
if (!(trg_def= (LEX_STRING *)alloc_root(&table->mem_root, if (!(trg_def= (LEX_STRING *)alloc_root(&table->mem_root,
sizeof(LEX_STRING))) || sizeof(LEX_STRING))) ||
definitions_list.push_back(trg_def, &table->mem_root)) definitions_list.push_back(trg_def, &table->mem_root))
return 1; goto err_with_cleanup;
trg_def->str= thd->query; trg_def->str= thd->query;
trg_def->length= thd->query_length; trg_def->length= thd->query_length;
return sql_create_definition_file(&dir, &file, &triggers_file_type, if (!sql_create_definition_file(&dir, &file, &triggers_file_type,
(gptr)this, triggers_file_parameters, 3); (gptr)this, triggers_file_parameters, 3))
return 0;
err_with_cleanup:
my_delete(trigname_path, MYF(MY_WME));
return 1;
}
/*
Deletes the .TRG file for a table
SYNOPSIS
rm_trigger_file()
path - char buffer of size FN_REFLEN to be used
for constructing path to .TRG file.
db - table's database name
table_name - table's name
RETURN VALUE
False - success
True - error
*/
static bool rm_trigger_file(char *path, char *db, char *table_name)
{
strxnmov(path, FN_REFLEN, mysql_data_home, "/", db, "/", table_name,
triggers_file_ext, NullS);
unpack_filename(path, path);
return my_delete(path, MYF(MY_WME));
}
/*
Deletes the .TRN file for a trigger
SYNOPSIS
rm_trigname_file()
path - char buffer of size FN_REFLEN to be used
for constructing path to .TRN file.
db - trigger's database name
table_name - trigger's name
RETURN VALUE
False - success
True - error
*/
static bool rm_trigname_file(char *path, char *db, char *trigger_name)
{
strxnmov(path, FN_REFLEN, mysql_data_home, "/", db, "/", trigger_name,
trigname_file_ext, NullS);
unpack_filename(path, path);
return my_delete(path, MYF(MY_WME));
} }
...@@ -275,12 +390,13 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables) ...@@ -275,12 +390,13 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables)
LEX_STRING *name; LEX_STRING *name;
List_iterator_fast<LEX_STRING> it_name(names_list); List_iterator_fast<LEX_STRING> it_name(names_list);
List_iterator<LEX_STRING> it_def(definitions_list); List_iterator<LEX_STRING> it_def(definitions_list);
char path[FN_REFLEN];
while ((name= it_name++)) while ((name= it_name++))
{ {
it_def++; it_def++;
if (my_strcasecmp(system_charset_info, lex->ident.str, if (my_strcasecmp(system_charset_info, lex->spname->m_name.str,
name->str) == 0) name->str) == 0)
{ {
/* /*
...@@ -291,18 +407,14 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables) ...@@ -291,18 +407,14 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables)
if (definitions_list.is_empty()) if (definitions_list.is_empty())
{ {
char path[FN_REFLEN];
/* /*
TODO: Probably instead of removing .TRG file we should move TODO: Probably instead of removing .TRG file we should move
to archive directory but this should be done as part of to archive directory but this should be done as part of
parse_file.cc functionality (because we will need it parse_file.cc functionality (because we will need it
elsewhere). elsewhere).
*/ */
strxnmov(path, FN_REFLEN, mysql_data_home, "/", tables->db, "/", if (rm_trigger_file(path, tables->db, tables->table_name))
tables->table_name, triggers_file_ext, NullS); return 1;
unpack_filename(path, path);
return my_delete(path, MYF(MY_WME));
} }
else else
{ {
...@@ -317,10 +429,15 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables) ...@@ -317,10 +429,15 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables)
triggers_file_ext, NullS) - file_buff; triggers_file_ext, NullS) - file_buff;
file.str= file_buff; file.str= file_buff;
return sql_create_definition_file(&dir, &file, &triggers_file_type, if (sql_create_definition_file(&dir, &file, &triggers_file_type,
(gptr)this, (gptr)this, triggers_file_parameters,
triggers_file_parameters, 3); 3))
return 1;
} }
if (rm_trigname_file(path, tables->db, lex->spname->m_name.str))
return 1;
return 0;
} }
} }
...@@ -331,8 +448,8 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables) ...@@ -331,8 +448,8 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables)
Table_triggers_list::~Table_triggers_list() Table_triggers_list::~Table_triggers_list()
{ {
for (int i= 0; i < 3; i++) for (int i= 0; i < (int)TRG_EVENT_MAX; i++)
for (int j= 0; j < 2; j++) for (int j= 0; j < (int)TRG_ACTION_MAX; j++)
delete bodies[i][j]; delete bodies[i][j];
if (record1_field) if (record1_field)
...@@ -389,13 +506,16 @@ bool Table_triggers_list::prepare_record1_accessors(TABLE *table) ...@@ -389,13 +506,16 @@ bool Table_triggers_list::prepare_record1_accessors(TABLE *table)
db - table's database name db - table's database name
table_name - table's name table_name - table's name
table - pointer to table object table - pointer to table object
names_only - stop after loading trigger names
RETURN VALUE RETURN VALUE
False - success False - success
True - error True - error
*/ */
bool Table_triggers_list::check_n_load(THD *thd, const char *db, bool Table_triggers_list::check_n_load(THD *thd, const char *db,
const char *table_name, TABLE *table) const char *table_name, TABLE *table,
bool names_only)
{ {
char path_buff[FN_REFLEN]; char path_buff[FN_REFLEN];
LEX_STRING path; LEX_STRING path;
...@@ -451,7 +571,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, ...@@ -451,7 +571,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
TODO: This could be avoided if there is no triggers TODO: This could be avoided if there is no triggers
for UPDATE and DELETE. for UPDATE and DELETE.
*/ */
if (triggers->prepare_record1_accessors(table)) if (!names_only && triggers->prepare_record1_accessors(table))
DBUG_RETURN(1); DBUG_RETURN(1);
List_iterator_fast<LEX_STRING> it(triggers->definitions_list); List_iterator_fast<LEX_STRING> it(triggers->definitions_list);
...@@ -471,32 +591,20 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, ...@@ -471,32 +591,20 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
Free lex associated resources Free lex associated resources
QQ: Do we really need all this stuff here ? QQ: Do we really need all this stuff here ?
*/ */
if (lex.sphead) delete lex.sphead;
{
delete lex.sphead;
lex.sphead= 0;
}
goto err_with_lex_cleanup; goto err_with_lex_cleanup;
} }
triggers->bodies[lex.trg_chistics.event] triggers->bodies[lex.trg_chistics.event]
[lex.trg_chistics.action_time]= lex.sphead; [lex.trg_chistics.action_time]= lex.sphead;
lex.sphead= 0; if (triggers->names_list.push_back(&lex.sphead->m_name, &table->mem_root))
goto err_with_lex_cleanup;
if (!(trg_name_buff= alloc_root(&table->mem_root,
sizeof(LEX_STRING) +
lex.ident.length + 1)))
goto err_with_lex_cleanup;
trg_name_str= (LEX_STRING *)trg_name_buff;
trg_name_buff+= sizeof(LEX_STRING);
memcpy(trg_name_buff, lex.ident.str,
lex.ident.length + 1);
trg_name_str->str= trg_name_buff;
trg_name_str->length= lex.ident.length;
if (triggers->names_list.push_back(trg_name_str, &table->mem_root)) if (names_only)
goto err_with_lex_cleanup; {
lex_end(&lex);
continue;
}
/* /*
Let us bind Item_trigger_field objects representing access to fields Let us bind Item_trigger_field objects representing access to fields
...@@ -537,3 +645,160 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, ...@@ -537,3 +645,160 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
DBUG_RETURN(1); DBUG_RETURN(1);
} }
/*
Obtains and returns trigger metadata
SYNOPSIS
get_trigger_info()
thd - current thread context
event - trigger event type
time_type - trigger action time
name - returns name of trigger
stmt - returns statement of trigger
RETURN VALUE
False - success
True - error
*/
bool Table_triggers_list::get_trigger_info(THD *thd, trg_event_type event,
trg_action_time_type time_type,
LEX_STRING *trigger_name,
LEX_STRING *trigger_stmt)
{
sp_head *body;
DBUG_ENTER("get_trigger_info");
if ((body= bodies[event][time_type]))
{
*trigger_name= body->m_name;
*trigger_stmt= body->m_body;
DBUG_RETURN(0);
}
DBUG_RETURN(1);
}
/*
Find trigger's table from trigger identifier and add it to
the statement table list.
SYNOPSIS
mysql_table_for_trigger()
thd - current thread context
trig - identifier for trigger
RETURN VALUE
0 - error
# - pointer to TABLE_LIST object for the table
*/
static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig)
{
const char *db= !trig->m_db.str ? thd->db : trig->m_db.str;
LEX *lex= thd->lex;
char path_buff[FN_REFLEN];
LEX_STRING path;
File_parser *parser;
struct st_trigname trigname;
DBUG_ENTER("add_table_for_trigger");
strxnmov(path_buff, FN_REFLEN, mysql_data_home, "/", db, "/",
trig->m_name.str, trigname_file_ext, NullS);
path.length= unpack_filename(path_buff, path_buff);
path.str= path_buff;
if (access(path_buff, F_OK))
{
my_error(ER_TRG_DOES_NOT_EXIST, MYF(0));
DBUG_RETURN(0);
}
if (!(parser= sql_parse_prepare(&path, thd->mem_root, 1)))
DBUG_RETURN(0);
if (strncmp(trigname_file_type.str, parser->type()->str,
parser->type()->length))
{
my_error(ER_WRONG_OBJECT, MYF(0), trig->m_name.str, trigname_file_ext,
"TRIGGERNAME");
DBUG_RETURN(0);
}
if (parser->parse((gptr)&trigname, thd->mem_root,
trigname_file_parameters, 1))
DBUG_RETURN(0);
/* We need to reset statement table list to be PS/SP friendly. */
lex->query_tables= 0;
lex->query_tables_last= &lex->query_tables;
DBUG_RETURN(sp_add_to_query_tables(thd, lex, db,
trigname.trigger_table.str, TL_WRITE));
}
/*
Drop all triggers for table.
SYNOPSIS
drop_all_triggers()
thd - current thread context
db - schema for table
name - name for table
NOTE
The calling thread should hold the LOCK_open mutex;
RETURN VALUE
False - success
True - error
*/
bool Table_triggers_list::drop_all_triggers(THD *thd, char *db, char *name)
{
TABLE table;
char path[FN_REFLEN];
bool result= 0;
DBUG_ENTER("drop_all_triggers");
bzero(&table, sizeof(table));
init_alloc_root(&table.mem_root, 8192, 0);
safe_mutex_assert_owner(&LOCK_open);
if (Table_triggers_list::check_n_load(thd, db, name, &table, 1))
{
result= 1;
goto end;
}
if (table.triggers)
{
LEX_STRING *trigger;
List_iterator_fast<LEX_STRING> it_name(table.triggers->names_list);
while ((trigger= it_name++))
{
if (rm_trigname_file(path, db, trigger->str))
{
/*
Instead of immediately bailing out with error if we were unable
to remove .TRN file we will try to drop other files.
*/
result= 1;
continue;
}
}
if (rm_trigger_file(path, db, name))
{
result= 1;
goto end;
}
}
end:
if (table.triggers)
delete table.triggers;
free_root(&table.mem_root, MYF(0));
DBUG_RETURN(result);
}
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
class Table_triggers_list: public Sql_alloc class Table_triggers_list: public Sql_alloc
{ {
/* Triggers as SPs grouped by event, action_time */ /* Triggers as SPs grouped by event, action_time */
sp_head *bodies[3][2]; sp_head *bodies[TRG_EVENT_MAX][TRG_ACTION_MAX];
/* /*
Copy of TABLE::Field array with field pointers set to TABLE::record[1] Copy of TABLE::Field array with field pointers set to TABLE::record[1]
buffer instead of TABLE::record[0] (used for OLD values in on UPDATE buffer instead of TABLE::record[0] (used for OLD values in on UPDATE
...@@ -121,9 +121,13 @@ class Table_triggers_list: public Sql_alloc ...@@ -121,9 +121,13 @@ class Table_triggers_list: public Sql_alloc
return res; return res;
} }
bool get_trigger_info(THD *thd, trg_event_type event,
trg_action_time_type time_type,
LEX_STRING *trigger_name, LEX_STRING *trigger_stmt);
static bool check_n_load(THD *thd, const char *db, const char *table_name, static bool check_n_load(THD *thd, const char *db, const char *table_name,
TABLE *table); TABLE *table, bool names_only);
static bool drop_all_triggers(THD *thd, char *db, char *table_name);
bool has_delete_triggers() bool has_delete_triggers()
{ {
...@@ -143,3 +147,6 @@ class Table_triggers_list: public Sql_alloc ...@@ -143,3 +147,6 @@ class Table_triggers_list: public Sql_alloc
private: private:
bool prepare_record1_accessors(TABLE *table); bool prepare_record1_accessors(TABLE *table);
}; };
extern const LEX_STRING trg_action_time_type_names[];
extern const LEX_STRING trg_event_type_names[];
...@@ -599,6 +599,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); ...@@ -599,6 +599,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token TRAILING %token TRAILING
%token TRANSACTION_SYM %token TRANSACTION_SYM
%token TRIGGER_SYM %token TRIGGER_SYM
%token TRIGGERS_SYM
%token TRIM %token TRIM
%token TRUE_SYM %token TRUE_SYM
%token TRUNCATE_SYM %token TRUNCATE_SYM
...@@ -1266,7 +1267,7 @@ create: ...@@ -1266,7 +1267,7 @@ create:
} }
opt_view_list AS select_init check_option opt_view_list AS select_init check_option
{} {}
| CREATE TRIGGER_SYM ident trg_action_time trg_event | CREATE TRIGGER_SYM sp_name trg_action_time trg_event
ON table_ident FOR_SYM EACH_SYM ROW_SYM ON table_ident FOR_SYM EACH_SYM ROW_SYM
{ {
LEX *lex= Lex; LEX *lex= Lex;
...@@ -1285,6 +1286,7 @@ create: ...@@ -1285,6 +1286,7 @@ create:
sp->m_type= TYPE_ENUM_TRIGGER; sp->m_type= TYPE_ENUM_TRIGGER;
lex->sphead= sp; lex->sphead= sp;
lex->spname= $3;
/* /*
We have to turn of CLIENT_MULTI_QUERIES while parsing a We have to turn of CLIENT_MULTI_QUERIES while parsing a
stored procedure, otherwise yylex will chop it into pieces stored procedure, otherwise yylex will chop it into pieces
...@@ -1295,7 +1297,7 @@ create: ...@@ -1295,7 +1297,7 @@ create:
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics)); bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
lex->sphead->m_chistics= &lex->sp_chistics; lex->sphead->m_chistics= &lex->sp_chistics;
lex->sphead->m_body_begin= lex->tok_start; lex->sphead->m_body_begin= lex->ptr;
} }
sp_proc_stmt sp_proc_stmt
{ {
...@@ -1303,14 +1305,12 @@ create: ...@@ -1303,14 +1305,12 @@ create:
sp_head *sp= lex->sphead; sp_head *sp= lex->sphead;
lex->sql_command= SQLCOM_CREATE_TRIGGER; lex->sql_command= SQLCOM_CREATE_TRIGGER;
sp->init_strings(YYTHD, lex, NULL); sp->init_strings(YYTHD, lex, $3);
/* Restore flag if it was cleared above */ /* Restore flag if it was cleared above */
if (sp->m_old_cmq) if (sp->m_old_cmq)
YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES; YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES;
sp->restore_thd_mem_root(YYTHD); sp->restore_thd_mem_root(YYTHD);
lex->ident= $3;
/* /*
We have to do it after parsing trigger body, because some of We have to do it after parsing trigger body, because some of
sp_proc_stmt alternatives are not saving/restoring LEX, so sp_proc_stmt alternatives are not saving/restoring LEX, so
...@@ -5919,19 +5919,11 @@ drop: ...@@ -5919,19 +5919,11 @@ drop:
lex->sql_command= SQLCOM_DROP_VIEW; lex->sql_command= SQLCOM_DROP_VIEW;
lex->drop_if_exists= $3; lex->drop_if_exists= $3;
} }
| DROP TRIGGER_SYM ident '.' ident | DROP TRIGGER_SYM sp_name
{ {
LEX *lex= Lex; LEX *lex= Lex;
lex->sql_command= SQLCOM_DROP_TRIGGER; lex->sql_command= SQLCOM_DROP_TRIGGER;
/* QQ: Could we loosen lock type in certain cases ? */ lex->spname= $3;
if (!lex->select_lex.add_table_to_list(YYTHD,
new Table_ident($3),
(LEX_STRING*) 0,
TL_OPTION_UPDATING,
TL_WRITE))
YYABORT;
lex->ident= $5;
} }
; ;
...@@ -6296,6 +6288,15 @@ show_param: ...@@ -6296,6 +6288,15 @@ show_param:
if (prepare_schema_table(YYTHD, lex, 0, SCH_TABLE_NAMES)) if (prepare_schema_table(YYTHD, lex, 0, SCH_TABLE_NAMES))
YYABORT; YYABORT;
} }
| opt_full TRIGGERS_SYM opt_db wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SELECT;
lex->orig_sql_command= SQLCOM_SHOW_TRIGGERS;
lex->select_lex.db= $3;
if (prepare_schema_table(YYTHD, lex, 0, SCH_TRIGGERS))
YYABORT;
}
| TABLE_SYM STATUS_SYM opt_db wild_and_where | TABLE_SYM STATUS_SYM opt_db wild_and_where
{ {
LEX *lex= Lex; LEX *lex= Lex;
...@@ -7590,6 +7591,7 @@ keyword_sp: ...@@ -7590,6 +7591,7 @@ keyword_sp:
| TEMPTABLE_SYM {} | TEMPTABLE_SYM {}
| TEXT_SYM {} | TEXT_SYM {}
| TRANSACTION_SYM {} | TRANSACTION_SYM {}
| TRIGGERS_SYM {}
| TIMESTAMP {} | TIMESTAMP {}
| TIMESTAMP_ADD {} | TIMESTAMP_ADD {}
| TIMESTAMP_DIFF {} | TIMESTAMP_DIFF {}
......
...@@ -282,7 +282,7 @@ enum enum_schema_tables ...@@ -282,7 +282,7 @@ enum enum_schema_tables
SCH_COLLATION_CHARACTER_SET_APPLICABILITY, SCH_PROCEDURES, SCH_STATISTICS, SCH_COLLATION_CHARACTER_SET_APPLICABILITY, SCH_PROCEDURES, SCH_STATISTICS,
SCH_VIEWS, SCH_USER_PRIVILEGES, SCH_SCHEMA_PRIVILEGES, SCH_TABLE_PRIVILEGES, SCH_VIEWS, SCH_USER_PRIVILEGES, SCH_SCHEMA_PRIVILEGES, SCH_TABLE_PRIVILEGES,
SCH_COLUMN_PRIVILEGES, SCH_TABLE_CONSTRAINTS, SCH_KEY_COLUMN_USAGE, SCH_COLUMN_PRIVILEGES, SCH_TABLE_CONSTRAINTS, SCH_KEY_COLUMN_USAGE,
SCH_TABLE_NAMES, SCH_OPEN_TABLES, SCH_STATUS, SCH_VARIABLES SCH_TABLE_NAMES, SCH_OPEN_TABLES, SCH_STATUS, SCH_TRIGGERS, SCH_VARIABLES
}; };
......
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