CREATE POLICY — создать новую политику защиты на уровне строк для таблицы
CREATE POLICYимяONимя_таблицы[ FOR { ALL | SELECT | INSERT | UPDATE | DELETE } ] [ TO {имя_роли| PUBLIC | CURRENT_USER | SESSION_USER } [, ...] ] [ USING (выражение_USING) ] [ WITH CHECK (выражение_CHECK) ]
Команда CREATE POLICY определяет для таблицы новую политику защиты на уровне строк. Заметьте, что для таблицы должна быть включена защита на уровне строк (using ALTER TABLE ... ENABLE ROW LEVEL SECURITY), чтобы созданные политики действовали.
Политика даёт разрешение на выборку, добавление, изменение или удаление строк, удовлетворяющих соответствующему выражению политики. Существующие строки таблицы проверяются по выражению, указанному в USING, тогда как строки, которые могут быть созданы командами INSERT или UPDATE проверяются по выражению, указанному в WITH CHECK. Когда выражение USING истинно для заданной строки, эта строка видна пользователю, а если ложно или выдаёт NULL, строка не видна. Когда выражение WITH CHECK истинно для заданной строки, эта строка добавляется или изменяется, а если ложно или выдаёт NULL, происходит ошибка.
Для операторов INSERT и UPDATE выражения WITH CHECK применяются после срабатывания триггеров BEFORE, но до того, как будут собственно модифицированы данные. Таким образом, триггер BEFORE ROW может изменить данные, подлежащие добавлению, и повлиять на результат условия политики защиты. Выражения WITH CHECK обрабатываются до каких-либо других ограничений.
Имена политик задаются на уровне таблицы. Таким образом, одно имя политики можно использовать в нескольких разных таблицах и в каждой дать отдельное, подходящее этой таблице определение политики.
Политики можно применять к определённым командам или избранным ролям. По умолчанию создаваемые политики применяются ко всем командам и ролям, если нет других указаний. Если к заданному оператору применяются несколько политик, они будут объединены логическим сложением (хотя политики ON CONFLICT DO UPDATE и INSERT таким образом не складываются, а применяются как отмечено на каждой стадии выполнения ON CONFLICT).
Для команд, допускающих наличие политик USING и WITH CHECK (ALL и UPDATE), в отсутствие политики WITH CHECK политика USING будет определять и видимость строк (обычное предназначение USING), и разрешение на добавление строк (предназначение WITH CHECK).
Если для таблицы включена защита на уровне строк, но применимые политики отсутствуют, предполагается политика «запрета по умолчанию», так что никакие строки нельзя будет увидеть или изменить.
имяИмя создаваемой политики. Оно должно отличаться от имён других политик для этой таблицы.
имя_таблицыИмя (возможно, дополненное схемой) существующей таблицы (или представления), к которой применяется эта политика.
командаКоманда, к которой применяется политика. Допустимые варианты: ALL, SELECT, INSERT, UPDATE и DELETE. ALL (все) подразумевается по умолчанию. Особенности их применения описаны ниже.
имя_ролиРоль (роли), к которой применяется политика. По умолчанию подразумевается PUBLIC, то есть политика применяется ко всем ролям.
выражение_USINGПроизвольное условное выражение SQL (возвращающее boolean). Это условное выражение не может содержать агрегатные или оконные функции. Когда включена защита на уровне строк, оно добавляется в запросы, обращающиеся к данной таблице, и в их результатах оказываются видимыми только те строки, для которых оно выдаёт true. Все строки, для которых это выражение возвращает false или NULL, не будут видны пользователю (в запросе SELECT), и не будут доступны для модификации (запросами UPDATE или DELETE). Такая строка просто пропускается, ошибка при этом не выдаётся.
выражение_CHECKПроизвольное условное выражение SQL (возвращающее boolean). Это условное выражение не может содержать агрегатные или оконные функции. Когда включена защита на уровне строк, оно применяется в запросах INSERT и UPDATE к этой таблице, так что в них принимаются только те строки, для которых оно выдаёт true. Если это выражение выдаёт false или NULL для любой из добавляемых записей или записей, получаемых при изменении, выдаётся ошибка. Заметьте, что ограничение_проверки вычисляется для предлагаемого нового содержимого строки, а не для существующих данных.
ALLУказание ALL для политики означает, что она применяется ко всем командам, вне зависимости от типа. Если существует политика ALL и другие более детализированные политики, тогда и политика ALL, и более детализированная политика (или политики) объединяются логическим сложением, как обычно при наложении политик. Кроме того, политики ALL с выражением USING будут применяться и к стороне выборки, и к стороне изменения данных в запросе, если определено только выражение USING.
Например, когда выполняется UPDATE, политика ALL будет фильтровать и строки, которые сможет прочитать UPDATE для изменения (применяя выражение USING), и окончательные изменённые строки, проверяя, можно ли записать их в таблицу (применяя выражение WITH CHECK, если оно определено, или USING в противном случае). Если команда INSERT или UPDATE пытается добавить в таблицу строки, не удовлетворяющие выражению WITH CHECK политики ALL, вся команда будет прервана.
SELECTУказание SELECT для политики означает, что она применяется к запросам SELECT и тогда, когда при обращении к отношению, для которого определена политика, задействуется право SELECT. В результате запрос SELECT выдаст только те записи из отношения, которые удовлетворят политике SELECT, и запрос, использующий право SELECT, например, запрос UPDATE, увидит только записи, разрешённые политикой SELECT. Для политики SELECT не может задаваться выражение WITH CHECK, так как оно действует только когда записи читаются из отношения.
INSERTУказание INSERT для политики означает, что она применяется к командам INSERT. Если вставляемые строки не проходят проверку политики, выдаётся ошибка нарушения политики и вся команда INSERT прерывается. Для политики INSERT не может задаваться выражение USING, так как она действует только когда в отношение добавляются записи.
Заметьте, что INSERT с указанием ON CONFLICT DO UPDATE проверяет выражения WITH CHECK политик INSERT только для строк, добавляемых в отношение по пути INSERT.
UPDATEУказание UPDATE для политики означает, что она применяется к командам UPDATE (или дополнительным предложениям ON CONFLICT DO UPDATE команд INSERT). Так как действие UPDATE подразумевает извлечение существующей записи и последующее изменение в ней полей (возможно, не всех), политики UPDATE принимают и выражение USING, и выражение WITH CHECK. Выражение USING определяет, какие строки будет обрабатывать команда UPDATE, тогда как выражение WITH CHECK определяет, какие изменённые строки можно снова записать в отношение.
Когда выполняется команда UPDATE с предложением WHERE или RETURNING, для обращения к целевому отношению также требуются права SELECT, так что соответствующие политики SELECT и ALL будут объединены (логическим сложением всех найденных связанных политик SELECT), а затем совмещены (логическим умножением) с предложением USING политики UPDATE. Таким образом, чтобы пользователь мог изменять определённые строки (выполняя UPDATE), ему должен быть разрешён доступ к ним политикой SELECT или ALL и эти строки должны удовлетворять выражению USING политики UPDATE.
Если в какой-либо строке изменённые значения не будут удовлетворять выражению WITH CHECK, произойдёт ошибка и вся команда будет прервана. Если указывается только предложение USING, его выражение будет применяться и в качестве USING, и в качестве выражения WITH CHECK.
Заметьте однако, что INSERT с ON CONFLICT DO UPDATE требует, чтобы выражение USING политики UPDATE всегда действовало как выражение WITH CHECK. Эта политика UPDATE должна всегда выполняться, когда выбирается путь UPDATE. Любая существующая строка, из-за которой выбирается путь UPDATE, должна удовлетворять проверкам (политик UPDATE или ALL) USING (объединённым логическим сложением), которые всегда действуют как WITH CHECK в данном контексте. (Путь UPDATE никогда не игнорируется, так что в случае невыполнения условия выдаётся ошибка.) Наконец, окончательная строка, добавляемая в отношение, должна проходить все проверки WITH CHECK, которые должны быть пройдены и при обычном UPDATE.
DELETEУказание DELETE для политики означает, что она применяется к командам DELETE. Команда DELETE будет видеть только те строки, которые позволит эта политика. При этом строки могут быть видны через SELECT, но удалить их будет нельзя, если они не удовлетворяют выражению USING политики DELETE.
Когда выполняется команда DELETE с предложением WHERE или RETURNING, для обращения к целевому отношению также требуются права SELECT, так что соответствующие политики SELECT и ALL будут объединены (логическим сложением всех найденных связанных политик SELECT), а затем совмещены (логическим умножением) с предложением USING политики DELETE. Таким образом, чтобы пользователь мог удалить определённые строки (выполняя DELETE), ему должен быть разрешён доступ к ним политикой SELECT или ALL и эти строки должны удовлетворять выражению USING политики DELETE.
Для политики DELETE не может задаваться выражение WITH CHECK, так как она применяется только тогда, когда записи удаляются из отношения, а в этом случае новые строки, подлежащие проверке, отсутствуют.
Чтобы создать или изменить политики для таблицы, нужно быть её владельцем.
Хотя политики применяются к явно выполняемым запросам к таблицам БД, они не применяются, когда система выполняет внутренние проверки ссылочной целостности или проверяет ограничения. Это означает, что существуют косвенные пути проверить существование заданного значения. Например, можно попытаться вставить повторяющееся значение в столбец, образующий первичный ключ или имеющую ограничение уникальности. Если при этом произойдёт ошибка, пользователь может заключить, что это значение уже существует. (В данном случае предполагается, что политика разрешает пользователю вставлять записи, которые он может не видеть.) Подобный приём также возможен, если пользователь может вставлять записи в таблицу, которая ссылается на другую, иным образом не видимую. Существование значения можно определить, вставив его в подчинённую таблицу, при этом успешный результат операции будет признаком того, что это значение есть в главной таблице. Эти изъяны можно устранить, либо тщательно разработав политики, которые вовсе не позволят пользователям выполнять операции добавления, изменения и удаления, по результатам которых можно узнать о значениях в таблицах, не видимых иным образом, либо используя генерируемые значения (например, суррогатные ключи).
Вообще система будет применять фильтры, устанавливаемые политиками безопасности, до условий в запросах пользователя, чтобы предотвратить нежелательную утечку защищаемых данных через пользовательские функции, которые могут быть недоверенными. Однако функции и операторы, помеченные системой (или системным администратором) как LEAKPROOF (герметичные) могут вычисляться до условий политики, так как они считаются доверенными.
Так как выражения политики добавляются непосредственно в запрос пользователя, они выполняются с правами пользователя, запускающего исходный запрос. Таким образом, пользователи, на которых распространяется заданная политика, должны иметь права для обращения ко всем таблицам и функциям, задействованным в выражении, иначе им просто будет отказано в доступе при попытке обращения к целевой таблице (если для неё включена защита на уровне строк). Однако это не влияет на работу представлений — как и с обычными запросами и представлениями, проверки разрешений и политики для нижележащих таблиц представления будут выполняться с правами владельца представления, и при этом будут действовать политики, распространяющиеся на этого владельца.
Дополнительное описание и практические примеры можно найти в Разделе 5.7.
CREATE POLICY является расширением Postgres Pro Enterprise.