【问题标题】:Postgres - Create trigger that can exist in multiple schemasPostgres - 创建可以存在于多个模式中的触发器
【发布时间】:2020-08-02 22:30:34
【问题描述】:

我有一个我写的 postgres 触发器。它100%有效,我已经对其进行了彻底的测试。但是,当我的应用程序写入该数据库表时,它会失败。我把代码放在下面,然后我会解释失败的原因。

CREATE OR REPLACE FUNCTION validate_client_user_role()
    RETURNS trigger AS
    $BODY$

    DECLARE role_has_client INT;
    DECLARE user_has_client INT;

    BEGIN
        IF NEW.client_id IS NULL THEN
            RAISE EXCEPTION 'client_id cannot be null';
        END IF;

        IF NEW.user_id IS NULL THEN
            RAISE EXCEPTION 'user_id cannot be null';
        END IF;

        IF NEW.role_id IS NULL THEN
            RAISE EXCEPTION 'role_id cannot be null';
        END IF;

        SELECT COUNT(*)
        INTO role_has_client
        FROM roles
        WHERE id = NEW.role_id
        AND client_id = NEW.client_id;

        SELECT COUNT(*)
        INTO user_has_client
        FROM client_users
        WHERE user_id = NEW.user_id
        AND client_id = NEW.client_id;

        IF role_has_client = 0 THEN
            RAISE EXCEPTION 'Role is not allowed by client';
        END IF;

        IF user_has_client = 0 THEN
            RAISE EXCEPTION 'User is not allowed by client';
        END IF;

        RETURN NEW;
    END
    $BODY$ LANGUAGE plpgsql;

CREATE TRIGGER client_user_role_validation
    BEFORE INSERT OR UPDATE
    ON client_user_roles
    FOR EACH ROW
    EXECUTE PROCEDURE validate_client_user_role();

所以,我的应用程序数据库有多个模式,一个用于 dev、qa、prod 等。当我第一次编写这个 DDL 语句时,我首先运行它:

set search_path to dev;

然后将其正确添加到“dev”架构中。只要我在我的数据库查询控制台中,我就可以验证这个触发器是否正常工作。

但是,当我的应用程序尝试写入表时,触发器失败,说它尝试从不存在选择的关系(角色、client_users)。我可以通过修改函数代码以显式引用每个表的“dev”模式来解决这个问题。不过,我不想这样做。我更喜欢可以作为 dev/qa/prod 的 DDL 语句执行的代码,而无需替换所有架构引用或保留它的多个副本。

我希望有人能解释一下是否有办法做到这一点。显然,触发器不是从我执行它时分配给它的架构继承的。但是,如果有一些我不知道的 postgres 技巧来完成这项工作,我将不胜感激。谢谢。

【问题讨论】:

    标签: postgresql


    【解决方案1】:

    您可以使用TG_TABLE_SCHEMA 变量和set_config()IS_LOCAL = true 来完成此操作:

    CREATE OR REPLACE FUNCTION validate_client_user_role()
        RETURNS trigger AS
        $BODY$
    
        DECLARE role_has_client INT;
        DECLARE user_has_client INT;
    
        BEGIN
            IF NEW.client_id IS NULL THEN
                RAISE EXCEPTION 'client_id cannot be null';
            END IF;
    
            IF NEW.user_id IS NULL THEN
                RAISE EXCEPTION 'user_id cannot be null';
            END IF;
    
            IF NEW.role_id IS NULL THEN
                RAISE EXCEPTION 'role_id cannot be null';
            END IF;
    
            PERFORM set_config('search_path', TG_TABLE_SCHEMA, true);  -- <-- This line
    
            SELECT COUNT(*)
            INTO role_has_client
            FROM roles
            WHERE id = NEW.role_id
            AND client_id = NEW.client_id;
    
            SELECT COUNT(*)
            INTO user_has_client
            FROM client_users
            WHERE user_id = NEW.user_id
            AND client_id = NEW.client_id;
    
            IF role_has_client = 0 THEN
                RAISE EXCEPTION 'Role is not allowed by client';
            END IF;
    
            IF user_has_client = 0 THEN
                RAISE EXCEPTION 'User is not allowed by client';
            END IF;
    
            RETURN NEW;
        END
        $BODY$ LANGUAGE plpgsql;
    

    【讨论】:

    • 谢谢,就是这样。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-03
    • 2021-08-18
    • 1970-01-01
    • 2016-06-25
    • 1970-01-01
    • 2019-05-14
    相关资源
    最近更新 更多