Триггер: разрешить обновления "нет столбца, кроме foo" - PullRequest
1 голос
/ 26 февраля 2020

Допустим, у нас есть таблица типа:

                         Table "someschema.todo"
    Column    |    Type      | Nullable |             Default
--------------+--------------+----------+----------------------------------
 id           | integer      | not null | nextval('todo_id_seq'::regclass)
 contract_id  | integer      | not null |
 title        | text         |          |
 description  | text         |          |
 status       | todo_status  |          | 'INCOMPLETE'::todo_status
Foreign-key constraints:
    "todo_contract_id_fkey" FOREIGN KEY (contract_id) REFERENCES contract(id)

Защита на уровне строк включена, и мы будем предполагать, что правила были установлены соответствующим образом с одним исключением: пользовательский тип, который обычно не будет Чтобы иметь возможность UPDATE строк в этой таблице, требуется иметь возможность преобразовывать столбец status из одного значения enum в другое. Скажем, от INCOMPLETE до PENDING. Этот тип пользователя также должен иметь возможность UPDATE таблицы в другое время (в зависимости от условий, связанных с contract_id fkey), поэтому мы не можем просто использовать грант общего столбца.

Возможно, это может сделать столбец кандидатом для включения в новую таблицу todo_status, но давайте пока что исключим это. Теперь мы могли бы написать триггер для проверки каждого столбца по имени, чтобы увидеть, был ли он изменен, и разрешить только те запросы, которые изменяют status и ничего больше ... но это кажется fr agile (что, если мы позже добавим еще один столбец ?) и болезненно.

Есть ли в триггере способ разрешить модификацию "нет столбца , кроме status"? Другими словами, «запретить доступ, если изменен только столбец status».

Дополнительный: есть ли способ выполнить sh, используя check_expression или using_expression в пределах CREATE POLICY, что Я не учел? Я предполагал, что, поскольку у нас нет значений NEW в using_expression или OLD в check_expression, я не могу использовать RLS для достижения того, что нам нужно.

1 Ответ

2 голосов
/ 26 февраля 2020

Триггер был бы относительно устойчивым

CREATE OR REPLACE FUNCTION validate_update()
RETURNS trigger AS
$BODY$
DECLARE
    v_key TEXT;
    v_value TEXT;
    valid_update boolean := true;
BEGIN
    FOR v_key, v_value IN select key, value from each(hstore(NEW))  each LOOP
        if (coalesce(v_value,'') != coalesce((hstore(OLD) -> v_key),'')) then
            if (v_key != 'status')  then
                valid_update := false;
            end if;
        end if;
    END LOOP;
    if (valid_update) then
        raise info 'good update';
        return NEW;
    else
        raise info 'bad update';
        return null;
    end if;
 END;
$BODY$
LANGUAGE plpgsql;

create trigger validate_update before update on someschema.todo 
for each row execute procedure validate_update();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...