[英]How to set trigger on column drop in oracle PL/SQL?
I tried to do this:我试图这样做:
CREATE OR REPLACE TRIGGER DLL_No_Column_Del
BEFORE DROP ON SCHEMA
BEGIN
IF ORA_DICT_OBJ_TYPE = 'COLUMN'
THEN
INSERT INTO column_del_attempt VALUES
(
user,
SYSDATE,
ora_dict_obj_name
);
RAISE_APPLICATION_ERROR(-20100, 'No column deletion allowed on table ' || ORA_DICT_OBJ_NAME);
END IF;
END;
Then drop column like that:然后像这样删除列:
ALTER TABLE emp_copy
DROP COLUMN employee_id;
But it doesn't work但它不起作用
Create an autonomous procedure to log the event:创建一个自治过程来记录事件:
CREATE PROCEDURE log_system_event(
p_user_name IN COLUMN_DEL_ATTEMPT.USER_NAME%TYPE,
p_object_name IN COLUMN_DEL_ATTEMPT.OBJECT_NAME%TYPE,
p_object_type IN COLUMN_DEL_ATTEMPT.OBJECT_TYPE%TYPE
)
AS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO column_del_attempt (
user_name,
datetime,
object_name,
object_type
) VALUES (
p_user_name,
SYSDATE,
p_object_name,
p_object_type
);
COMMIT;
END log_system_event;
/
Then you can call it from the trigger (on the ALTER
event, rather than the DROP
event):然后您可以从触发器调用它(在
ALTER
事件上,而不是在DROP
事件上):
CREATE TRIGGER DLL_No_Column_Del
BEFORE ALTER ON SCHEMA
BEGIN
IF ora_dict_obj_name = 'EMP_COPY' AND ORA_DICT_OBJ_TYPE = 'TABLE' THEN
log_system_event( login_user, ora_dict_obj_name, ORA_DICT_OBJ_TYPE );
RAISE_APPLICATION_ERROR(-20100, 'No column deletion allowed on table ' || ORA_DICT_OBJ_NAME);
END IF;
END;
/
Then, if you do:然后,如果你这样做:
ALTER TABLE emp_copy DROP COLUMN employee_id;
It will raise the exception:它将引发异常:
ORA-04088: error during execution of trigger 'FIDDLE_SPRKWOBAQONFKBBYMKLX.DLL_NO_COLUMN_DEL' ORA-00604: error occurred at recursive SQL level 1 ORA-20100: No column deletion allowed on table EMP_COPY ORA-06512: at line 5
Then:然后:
SELECT * FROM column_del_attempt;
Outputs:输出:
USER_NAME |用户名 | DATETIME |
日期时间 | OBJECT_NAME |
对象名 | OBJECT_TYPE:-------------------------- |:-------- |:---------- |:---------- FIDDLE_SPRKWOBAQONFKBBYMKLX |
OBJECT_TYPE:-------------- |:-------- |:---------- |:--------- FIDDLE_SPRKWOBAQONFKBBYMKLX | 18-DEC-20 |
20 年 12 月 18 日 | EMP_COPY |
EMP_COPY | TABLE
桌子
To get the text of the ALTER
DDL statement, according to AskTom , you can use the V$OPEN_CURSOR
dynamic performance view to get the text of the DDL statement and then you can filter on that:要获取
ALTER
DDL 语句的文本, 根据 AskTom ,您可以使用V$OPEN_CURSOR
动态性能视图来获取 DDL 语句的文本,然后您可以对其进行过滤:
CREATE PROCEDURE log_system_event(
p_user_name IN COLUMN_DEL_ATTEMPT.USER_NAME%TYPE,
p_object_name IN COLUMN_DEL_ATTEMPT.OBJECT_NAME%TYPE,
p_object_type IN COLUMN_DEL_ATTEMPT.OBJECT_TYPE%TYPE,
p_text IN COLUMN_DEL_ATTEMPT.TEXT%TYPE
)
AS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO column_del_attempt (
user_name,
datetime,
object_name,
object_type,
text
) VALUES (
p_user_name,
SYSDATE,
p_object_name,
p_object_type,
p_text
);
COMMIT;
END log_system_event;
/
Then:然后:
CREATE TRIGGER DLL_No_Column_Del
BEFORE ALTER ON SCHEMA
DECLARE
v_text VARCHAR2(4000);
BEGIN
SELECT SQL_TEXT
INTO v_text
FROM V$OPEN_CURSOR;
IF REGEXP_LIKE( v_text, '^ALTER\s+TABLE\s+("?)EMP_COPY\1\s+DROP\s+', 'i') THEN
log_system_event( login_user, ora_dict_obj_name, ORA_DICT_OBJ_TYPE, v_text );
RAISE_APPLICATION_ERROR(-20100, 'No column deletion allowed on table ' || ORA_DICT_OBJ_NAME);
END IF;
END;
/
(However, none of db<>fiddle , SQLFiddle nor Oracle's LiveSQL has granted permissions to use the V$OPEN_CURSOR
dynamic performance view so I cannot test this.) (但是, db<>fiddle 、 SQLFiddle 和 Oracle 的 LiveSQL 都没有授予使用
V$OPEN_CURSOR
动态性能视图的权限,因此我无法对此进行测试。)
Final solution:最终解决方案:
CREATE TABLE column_del_attempt (
user_name VARCHAR2(30),
datetime DATE,
object_name VARCHAR2(30),
object_type VARCHAR2(30)
)
/
CREATE OR REPLACE PROCEDURE log_system_event(
p_user_name IN COLUMN_DEL_ATTEMPT.USER_NAME%TYPE,
p_object_name IN COLUMN_DEL_ATTEMPT.OBJECT_NAME%TYPE,
p_object_type IN COLUMN_DEL_ATTEMPT.OBJECT_TYPE%TYPE
)
AS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO column_del_attempt (
user_name,
datetime,
object_name,
object_type
) VALUES (
p_user_name,
SYSDATE,
p_object_name,
p_object_type
);
COMMIT;
END log_system_event;
/
CREATE OR REPLACE TRIGGER DLL_No_Column_Del
BEFORE ALTER ON SCHEMA
DECLARE
n NUMBER;
sql_text_list ora_name_list_t;
drop_exist BOOLEAN := FALSE;
BEGIN
n := ora_sql_txt(sql_text_list);
FOR i in 1..n LOOP
IF sql_text_list(i) LIKE '%DROP%' THEN
drop_exist := TRUE;
END IF;
END LOOP;
IF drop_exist THEN
log_system_event( login_user, ora_dict_obj_name, ORA_DICT_OBJ_TYPE );
RAISE_APPLICATION_ERROR(-20100, 'No column deletion allowed on table ' || ORA_DICT_OBJ_NAME);
END IF;
END;
/
-- for tests:
/*
ALTER TABLE emp_copy ADD birth_date DATE NOT NULL;
ALTER TABLE emp_copy DROP COLUMN birth_date;
SELECT * FROM column_del_attempt;
*/
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.