После некоторых обсуждений с другими пользователями / разработчиками PostgreSQL в общем списке рассылки было определено, что эта конкретная проблема вызвана видимостью мутаций в одном выражении. Вы можете просмотреть всю дискуссию здесь .Отдельное спасибо Дину Рашиду за объяснение проблемы и решение проблемы.Здесь я кратко изложил его ответ в интересах сообщества Stack Overflow.
Таким образом, строка, вставленная триггером, не видна в последующем предложении EXISTS
в политике безопасности на уровне строк SELECT
из-за того, что весь оператор выполняется в одном снимке PostgreSQL.
Один из способов обойти эту проблему - убедиться, что предложение EXISTS
запущено с новым снимком.Для этого в предложении EXISTS
может использоваться функция PostgreSQL, помеченная VOLATILE
.Этот атрибут функции даст возможность функции наблюдать изменения, внесенные в одном и том же утверждении.Для получения дополнительной информации см. документацию .Соответствующий параграф извлечен здесь для справки:
Для функций, написанных на SQL или на любом из стандартных процедурных языков, существует еще одно важное свойство, определяемое категорией волатильности, а именно видимость любых данных.изменения, которые были сделаны командой SQL, которая вызывает функцию.Функция VOLATILE будет видеть такие изменения, функция STABLE или IMMUTABLE - нет.Это поведение реализуется с использованием поведения снимков MVCC (см. Главу 13): функции STABLE и IMMUTABLE используют снимок, созданный в начале вызывающего запроса, тогда как функции VOLATILE получают новый снимок в начале каждого выполняемого ими запроса.
Итак, одним из решений этой проблемы является реализация политики выбора RLS в виде функции VOLATILE
.Пример изменения политики:
CREATE OR REPLACE FUNCTION rlsCheck(_id text) RETURNS TABLE (id text) AS $$
select * from b where b.id = _id
$$ LANGUAGE sql VOLATILE;
CREATE POLICY reproPolicySelect ON a FOR SELECT
USING (
EXISTS(select * from rlsCheck(a.id))
);
. В этом решении каждая строка, спроецированная из таблицы a
, потребует, чтобы функция rlsCheck
возвращала хотя бы одну строку.Эта функция будет запущена с новым снимком для каждой проецируемой строки.Новый снимок, сгенерированный каждым вызовом rlsCheck
, позволит ему увидеть изменение таблицы b триггером INSERT
в исходном примере.
Если вы сделаете вышеуказанную модификацию и запустите тест, выувидит следующее поведение:
test=> select * from a;
id
----
(0 rows)
test=> select * from b;
id
----
(0 rows)
test=> insert into a values ('hi') returning id;
NOTICE: inside trigger handler
id
----
hi
(1 row)
INSERT 0 1
Это поведение соответствует моим ожиданиям, поэтому я принимаю это как ответ на проблему.К сожалению, функция приводит к неприемлемому ограничению оптимизации во время выполнения запроса, поэтому я не буду использовать это в моей реализации RBAC.Я не верю, что возможно иметь оптимизируемое решение моей проблемы, поскольку выражение EXISTS
в политике SELECT
не может быть встроенным и VOLATILE одновременно.