创建 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