Postgres - Создать триггер, который может существовать в нескольких схемах - PullRequest
0 голосов
/ 02 августа 2020

У меня есть написанный мной триггер 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, et c. Когда я впервые пишу этот оператор DDL, я сначала запускаю его:

set search_path to dev;

Затем он правильно добавляет его в схему «dev». Пока я нахожусь в своей консоли запросов к БД, я могу проверить, что этот триггер работает безупречно.

Однако, когда мое приложение пытается выполнить запись в таблицы, триггер не работает, указывая отношения (роли, client_users ), из которых он пытается выбрать, не существует. Я могу исправить это, изменив код функции, чтобы явно ссылаться на схему «dev» для каждой таблицы. Но я не хочу этого делать. Я бы предпочел код, который я могу выполнить как оператор DDL для dev / qa / prod без необходимости заменять все ссылки на схемы или хранить их несколько копий.

Я надеюсь, что кто-нибудь сможет объяснить, есть ли какие-то способ сделать это. Очевидно, что триггер не наследуется от схемы, которой он назначен, когда я его выполняю. Однако, если есть какой-то трюк postgres, о котором я не знаю, чтобы заставить эту работу работать, я был бы признателен за руководство. Спасибо.

1 Ответ

2 голосов
/ 02 августа 2020

Вы можете использовать переменную TG_TABLE_SCHEMA и set_config() с IS_LOCAL = true, чтобы выполнить sh это:

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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...