这是场景(简化示例):
我有一个名为ABC的Oracle用户/架构。 ABC拥有一张叫做TRN的桌子。客户端代码以ABC格式连接到数据库,并从ABC.TRN中选择。
到目前为止一切顺利。但是,我不希望客户端代码指定Oracle模式名称。现在我想我已经删除了引用模式的客户端代码中的所有引用,但我想测试它以确保。
所以我想创建一个名为DEF的新用户/模式,客户端将使用它来连接数据库。当客户端应用程序从ABC.TRN中选择时,它必须给出错误。但是,如果客户端应用程序从TRN(无模式名称)中选择,则它必须返回数据。
有没有办法做到这一点?请注意,DEF必须与ABC在同一个数据库中,只有一个表TRN表(由ABC拥有),我不能使用数据库链接。
我尝试创建一个新的XYZ用户,其同义词指向ABC.TRN,并在ABC.TRN上赋予它选择权限。然后我创建了DEF用户,其同义词指向XYZ.TRN,并且给予DEF对XYZ.TRN的选择权限。这很有效但是Oracle很聪明地知道如果DEF有权从XYZ.TRN中选择,那么它也有权从ABC.TRN中进行选择,从而违背了本练习的目的,因为我希望这个案例给出错误。 / p>
告诉你......
答案 0 :(得分:7)
没有简单的方法可以做到这一点。
一种方法是政治性的:机构代码审查,也许是对代码库的自动搜索,当人们这样做时,只需拍打手腕。
架构方法类似于您的三种架构结构,但有一个微妙的转折:中间的架构使用视图。因此,模式ABC拥有表并授予它们对模式XYZ的权限。 Schema XYZ针对这些表(SELECT *,没有WHERE子句)构建简单视图,并将视图权限授予模式DEF。 Schema DEF只能从XYZ对象中选择。
当然,所有这些努力仍然不会阻止开发者编码SELECT * FROM xyz.whatever
。在这种情况下,我会向您推荐我的第一个建议8 - )
实际上有一种,非常邪恶的方式来做到这一点。在面向架构的应用程序(DEF)中使用同义词,然后更改数据拥有架构(ABC)的名称。
当然,如果您的安装脚本完全是参数化的,并且没有自己的硬编码模式名称,那么您应该只尝试这种策略。
答案 1 :(得分:5)
你真的需要抛出错误吗?或者您只是需要验证应用程序是否使用完全限定名称(即ABC.TRN
)?
假设您只是想验证应用程序没有使用完全限定名称,并且抛出错误仅仅是您想要通知您的机制,您可以通过查询V$SQL
来验证代码。在应用程序运行时。 V$SQL
列出了Oracle中共享池中的所有SQL语句。如果在应用程序运行时定期查询该表,您将看到它发出的所有SQL语句。然后,您可以记录任何使用完全限定名称的语句。
例如
CREATE OR PROCEDURE look_for_abc_trn
AS
BEGIN
FOR x IN (SELECT *
FROM v$sql
WHERE upper(sql_fulltext) LIKE '%ABC.TRN%')
LOOP
INSERT INTO log_of_bad_sql( sql_fulltext, <<other columns>> )
VALUES( x.sql_fulltext, <<other columns>> );
END LOOP;
END;
如果在应用程序运行时每隔几分钟运行一次该过程,您将看到任何使用完全限定名称的SQL并在LOG_OF_BAD_SQL
表中记录该语句。对于编写良好的系统来说,每隔几分钟就可能有点过分了,您只需要确保它的运行频率高于语句在共享池中的老化程度。如果您的应用程序没有正确使用绑定变量,则可能需要每隔几分钟才能避免遗漏任何内容。
答案 2 :(得分:1)
ALTER SESSION怎么样?
ALTER SESSION SET CURRENT_SCHEMA = schema
这将允许您以用户身份登录,向模式X拥有的表授予选择权限,并执行将会话更改为模式X的SP。前端代码不会知道这发生了。
但是,如果您的前端代码指定了架构X:
select * from X.tableName
我认为这不会引起错误。
也许您可以解释为什么客户端代码在使用正确的当前架构名称时收到错误很重要?
是否可以创建新架构,转移旧架构对象的所有者,然后删除旧架构,然后使用上述方法?
P.S。请参阅AFTER LOGON触发器:http://psoug.org/reference/system_trigger.html
P.P.S。既然你已经详细说明了你的要求:
...表可以是使用数据库链接的同义词,或者表可能由多个模式托管, 每个用于不同的版本。它应留给数据库来解析实际位置 客户端应用程序引用的对象。
如果对象的位置不在CURRENT_SCHEMA中,而是在某些其他模式中,例如,这两个模式碰巧都有名为CUSTOMER的表,则数据库引擎将不知道客户端应用程序发送给它的语句如果表名不是那么合格,则应该引用其他模式。这意味着引擎没有一定程度的元知识,尽管它为开发人员提供了以存储过程和触发器的形式创建这种智能的工具,以及对对象的授予/撤销控制。
将此智能放在后端的最佳成功机会是撤销对表和视图的所有直接权限,并要求客户端应用程序通过存储过程访问对象,因为数据库引擎本身并不了解事物像应用程序发布级别。我认为没有纯粹的DECLARATIVE方式来实现它。它必须在很大程度上是程序性的。您自己的后端逻辑必须承担在不同模式中在同名对象之间进行仲裁的责任。也就是说,功能类似于登录触发器和ALTER SCHEMA应该对您有所帮助。
答案 3 :(得分:0)
你不能这样做。同义词只是指向其他模式对象的指针。您授予对实际对象的访问权限,而不是同义词。来自Oracle文档:
http://download.oracle.com/docs/cd/B28359_01/server.111/b28310/views003.htm
同义词本身不可保证。当您在同义词上授予对象权限时,您实际上是在对基础对象授予权限,并且同义词仅作为GRANT语句中对象的别名。