【问题标题】:Column-level privileges vs. legacy application列级权限与旧版应用程序
【发布时间】:2010-01-26 15:18:50
【问题描述】:

我收到了一个实现列级权限的请求,例如:

GRANT UPDATE("column1") ON "TABLE" TO ROLE; 

但我发现客户端应用程序(在 Delphi+ODAC 中)总是发出 SQL 更新,例如:

update TABLE set column1=:column1,column2=:column2,column3=:column3,...etc
where id_c=:id_c;

是什么导致 Oracle 总是抛出 ORA-01031:权限不足,即使仅更改了 column1。显而易见的解决方案是更改客户端应用程序,使其仅使用更改的列发出 SQL 更新,但这看起来需要大量编码。

有没有更优雅的解决方案?

编辑:我忘了提到在我的 Delphi 源代码中有大量硬编码的插入/更新查询。在这种情况下,ODAC 无能为力。

【问题讨论】:

    标签: oracle delphi privileges sql-grant


    【解决方案1】:

    您可以在该视图上创建一个视图和一个INSTEAD OF UPDATE 触发器:

    CREATE VIEW myview ON mytable
    AS
    SELECT  *
    FROM    table
    
    CREATE TRIGGER trg_myview_iu
    INSTEAD OF UPDATE
    ON myview
    FOR EACH ROW
    BEGIN
            UPDATE  mytable
            SET     column1 = :NEW.column1
            WHERE   id_c = :NEW.id_c;
    END;
    

    如果您只想在其值未更改的情况下处理一列,那么您将不得不编写多个UPDATE 语句:

    CREATE TRIGGER trg_myview_iu
    INSTEAD OF UPDATE
    ON myview
    FOR EACH ROW
    BEGIN
            IF :NEW.column1 <> :OLD.column1 THEN -- add `NULL` processing options if necessary
                    UPDATE  mytable
                    SET     column1 = :NEW.column1
                    WHERE   id_c = :NEW.id_c;
            END IF;
            IF :NEW.column2 <> :OLD.column2 THEN
                    UPDATE  mytable
                    SET     column2 = :NEW.column2
                    WHERE   id_c = :NEW.id_c;
            END IF;
            …
    END;
    

    不过,这远非高效。

    Oracle 中,即使列的实际值没有改变,UPDATE 也会执行。这意味着该行被锁定,触发触发等。

    【讨论】:

    • 谢谢!但这不是很好维护。例如,如果客户后来决定他想要一个包含 column2 的新角色怎么办?然后另一个?每次都要更新代码吗?
    • @Juraj,你错过了 Quassnoi 的观点。他的视图从表中选择 *(所有列)。触发器仅更新实际更改的列(尽管一次只有一列,效率非常低,但解决问题的唯一实用方法)。只需要在底层表的结构发生变化时更新代码,而不是仅仅改变一些角色授予。
    • 当然,如果用户 A 没有列的更新权限,但无论如何尝试更改它,他们仍然会得到 ORA-01031 - 这是一件好事。
    • 另一种方法是使用动态 SQL 构造 UPDATE 语句 - 这将具有只需要单个 UPDATE 语句的优点,但可能会增加共享池的使用量,具体取决于有多少不同的组合列已更新。
    • 现在我明白了。仅使用更改的列构造代理 SQL 语句并将其传递给 EXECUTE IMMEDIATE 似乎是可行的。服务器有足够的未使用的 SGA 内存和 CPU 电源,所以这应该不是问题。
    【解决方案2】:

    我不了解 ODAC 组件或库,但您不能不设置一些属性,例如:update only:changed fieldsall fields 吗?

    即使没有更改,也要包含所有列似乎是浪费时间。我应该认为大多数客户端库都提供了这个选项。

    当然,如果你设置了sn TQuery-alike组件的一些SQL属性,你应该自己创建sql语句(也只基于改变的列)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-20
      • 2013-02-07
      • 2018-08-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多