如何限制存储过程中的任何 DML 操作
Posted
技术标签:
【中文标题】如何限制存储过程中的任何 DML 操作【英文标题】:How to restrict any DML operation in a stored procedure 【发布时间】:2021-03-21 15:08:51 【问题描述】:我正在尝试将特定月份的一些记录插入到表中。如何在存储过程中的其他月份限制该表上的任何 DML 操作(没有任何触发器或约束)。请帮助我,在此先感谢。
【问题讨论】:
请edit 与minimal reproducible example 联系您的问题,包括:您正在使用的程序示例;您的最终用户将如何调用该过程的示例;您的表格的详细信息。 【参考方案1】:将“特定月份”作为参数传递并在整个过程的代码中使用它,很可能在WHERE
子句或IF
s、CASE
s 等中使用。
【讨论】:
我们可以通过它,但我们如何限制最终用户何时将插入或更新到表中的任何其他月份。 创建由您维护的附加表,其中仅包含允许的月份。从过程中引用该表。【参考方案2】:创建 2 个用户:
第一个(我们可以称之为DATA_OWNER
)将拥有包含数据的表以及在这些表上执行 DML 的存储过程/包;和
第二个(我们可以称之为END_USER
)将是您的最终用户连接的数据库用户。
然后您可以创建表:
CREATE TABLE data_owner.table_name (
id NUMBER
GENERATED ALWAYS AS IDENTITY
PRIMARY KEY,
datetime DATE
NOT NULL,
value NUMBER
);
CREATE TABLE data_owner.table_name_insert_bounds (
start_datetime DATE,
end_datetime DATE,
CONSTRAINT table_name_insert_bounds__pk PRIMARY KEY ( start_datetime, end_datetime ),
CONSTRAINT table_name_insert_bounds__chk CHECK ( start_datetime <= end_datetime )
);
还有一个包含您的存储过程的包:
CREATE PACKAGE data_owner.table_name_management_pkg IS
PROCEDURE add_value(
i_datetime IN TABLE_NAME.DATETIME%TYPE,
i_value IN TABLE_NAME.VALUE%TYPE
);
END;
/
CREATE PACKAGE BODY data_owner.table_name_management_pkg IS
PROCEDURE add_value(
i_datetime IN TABLE_NAME.DATETIME%TYPE,
i_value IN TABLE_NAME.VALUE%TYPE
)
IS
valid_datetime NUMBER;
BEGIN
SELECT CASE
WHEN EXISTS(
SELECT 1
FROM table_name_insert_bounds
WHERE i_datetime BETWEEN start_datetime AND end_datetime
)
THEN 1
ELSE 0
END
INTO valid_datetime
FROM DUAL;
IF valid_datetime = 0 THEN
RAISE_APPLICATION_ERROR(
-20000,
'Date-time is outside of current insertion range.'
);
END IF;
INSERT INTO table_name ( datetime, value )
VALUES ( i_datetime, i_value );
END;
END;
/
然后将权限授予最终用户:
GRANT SELECT ON data_owner.table_name TO end_user;
GRANT EXECUTE ON data_owner.table_name_management_pkg TO end_user;
那么最终用户只能通过包中的存储过程执行DML操作(他们无权绕过过程直接对表执行DML)但也可以SELECT
所有数据和数据所有者可以设置最终用户能够插入的日期范围(并且最终用户无法修改这些范围)。
例如:
如果数据所有者设置了这些界限:
INSERT INTO table_name_insert_bounds ( start_datetime, end_datetime )
VALUES ( DATE '2020-01-01', DATE '2020-02-01' );
那么最终用户就可以运行了:
BEGIN
data_owner.table_name_management_pkg.ADD_VALUE( DATE '2020-01-10', 42 );
END;
/
将插入一行,但如果他们尝试:
BEGIN
data_owner.table_name_management_pkg.ADD_VALUE( DATE '2020-02-02', 13 );
END;
/
然后会得到异常:
ORA-20000: Date-time is outside of current insertion range.
db小提琴here
【讨论】:
以上是关于如何限制存储过程中的任何 DML 操作的主要内容,如果未能解决你的问题,请参考以下文章