【问题标题】:postgresql: how modify pg_catalog with a function?postgresql:如何使用函数修改 pg_catalog?
【发布时间】:2014-02-17 16:42:07
【问题描述】:

您好,我想创建一个在 pg_catalog 中创建表的函数,例如:

CREATE OR REPLACE FUNCTION foo() RETURNS void AS $$
DECLARE

BEGIN
EXECUTE 'CREATE TABLE pg_catalog.tab(a integer)';   
        RETURN;

END;
$$ LANGUAGE plpgsql;

错误:创建“pg_catalog.tab”的权限被拒绝
详细信息:当前不允许修改系统目录。

我编辑我的问题以添加更多细节:

真正的我想创建一个在删除表时启动的函数。我认为唯一的方法是在表 pg_catalog.tables 上创建触发器:

CREATE OR REPLACE FUNCTION a() RETURNS void AS $$
DECLARE
BEGIN

  EXECUTE 'CREATE TRIGGER "tt_drop" BEFORE DELETE ON pg_catalog.pg_tables EXECUTE PROCEDURE public.b()';
  RETURN;

END;
$$ LANGUAGE plpgsql;

在函数 b 中,我想在删除表之前对其进行一些操作...

【问题讨论】:

    标签: postgresql plpgsql


    【解决方案1】:

    出于实际和主要安全原因,这是禁止的 - pg_catalog 始终位于搜索路径的首位,没有人可以仅仅因为 PostgreSQL 团队期望 pg_catalog 中的函数不会被自定义函数覆盖而更改它。

    存在一些非常丑陋的技巧,但我不建议使用它。

    不那么丑陋,但仍然非常丑陋的是将 Postgres 切换到单一模式 - 任何安全机制都已关闭 - 但存在数据库损坏的高风险。所以只有完全了解 Postgres 内部结构的人才应该使用它。

    回复更新的问题:

    您不能在系统表上创建触发器。但是有event triggers,它可能就是你想要的(PostgreSQL 9.3 支持)。

    CREATE FUNCTION test_event_trigger_for_drops()
            RETURNS event_trigger LANGUAGE plpgsql AS $$
    DECLARE
        obj record;
    BEGIN
        FOR obj IN SELECT * FROM pg_event_trigger_dropped_objects()
        LOOP
            RAISE NOTICE '% dropped object: % %.% %',
                         tg_tag,
                         obj.object_type,
                         obj.schema_name,
                         obj.object_name,
                         obj.object_identity;
        END LOOP;
    END
    $$;
    
    CREATE EVENT TRIGGER test_event_trigger_for_drops
       ON sql_drop
       EXECUTE PROCEDURE test_event_trigger_for_drops();
    
    postgres=# DROP TABLE obce CASCADE;
    NOTICE:  drop cascades to materialized view obce_stredocesky_kraj
    NOTICE:  DROP TABLE dropped object: table public.obce public.obce
    NOTICE:  DROP TABLE dropped object: index public.obce_okres_id_idx public.obce_okres_id_idx
    NOTICE:  DROP TABLE dropped object: table constraint public.<NULL> obce_okres_id_fk on public.obce
    NOTICE:  DROP TABLE dropped object: trigger <NULL>.<NULL>  "RI_ConstraintTrigger_a_46471" on public.okresy
    NOTICE:  DROP TABLE dropped object: trigger <NULL>.<NULL> "RI_ConstraintTrigger_a_46472" on public.okresy
    NOTICE:  DROP TABLE dropped object: trigger <NULL>.<NULL> "RI_ConstraintTrigger_c_46473" on public.obce
    NOTICE:  DROP TABLE dropped object: trigger <NULL>.<NULL> "RI_ConstraintTrigger_c_46474" on public.obce
    NOTICE:  DROP TABLE dropped object: sequence public.obce_id_seq public.obce_id_seq
    NOTICE:  DROP TABLE dropped object: type public.obce_id_seq public.obce_id_seq
    NOTICE:  DROP TABLE dropped object: default value <NULL>.<NULL> for public.obce.id
    NOTICE:  DROP TABLE dropped object: table constraint public.<NULL> _obce_pkey on public.obce
    NOTICE:  DROP TABLE dropped object: index public._obce_pkey public._obce_pkey
    NOTICE:  DROP TABLE dropped object: materialized view public.obce_stredocesky_kraj public.obce_stredocesky_kraj
    NOTICE:  DROP TABLE dropped object: index public.obce_stredocesky_kraj_nazev_idx public.obce_stredocesky_kraj_nazev_idx
    NOTICE:  DROP TABLE dropped object: type public.obce_stredocesky_kraj public.obce_stredocesky_kraj
    NOTICE:  DROP TABLE dropped object: type public._obce_stredocesky_kraj public.obce_stredocesky_kraj[]
    NOTICE:  DROP TABLE dropped object: rule <NULL>.<NULL> "_RETURN" on public.obce_stredocesky_kraj
    NOTICE:  DROP TABLE dropped object: type public.obce public.obce
    NOTICE:  DROP TABLE dropped object: type public._obce public.obce[]
    DROP TABLE   
    

    【讨论】:

    • 非常有趣,但我需要删除表的名称,现在不支持 TG_OBJECTNAME!将来我将修改我的函数使用事件触发器。现在我发现 allow_system_table_mods = on 添加到 postgres.conf 但你怎么告诉我这不是正确的模式:-( 如果我只在创建触发器时激活它并在之后禁用它,触发器的工作方式相同?
    • @user3297525: 删除的表名已知 - 请参阅更新的回复
    • 好的,但是被删除的表不能移动到另一个模式(alter table t set schema s),因为表 t 现在对于 postgres 不存在。如何在放置动作之前触发触发器?
    • 可能你做不到。这太难了harakiri。如果你需要对数据库结构做一些更复杂的操作,那么应用层比触发器更好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-31
    • 1970-01-01
    • 1970-01-01
    • 2014-05-01
    • 1970-01-01
    • 2014-09-29
    • 1970-01-01
    相关资源
    最近更新 更多