CREATE POLICY name ON table_name [ FOR { ALL | SELECT | INSERT | UPDATE | DELETE } ] [ TO { role_name | PUBLIC | CURRENT_USER | SESSION_USER } [, ...] ] [ USING ( using_expression ) ] [ WITH CHECK ( check_expression ) ]
CREATE POLICY命令为表定义新的行级安全策略。 注意,必须在表上启用行级安全性(使用 ALTER TABLE ... ENABLE ROW LEVEL SECURITY) 才能应用已创建的策略。
策略授予选择,插入,更新或删除与相关策略表达式匹配的行的权限。 将根据USING中指定的表达式检查现有表行, 而根据WITH CHECK指定的表达式检查将通过 INSERT或UPDATE创建的新行。 当USING表达式对给定行返回true时,该行对用户可见, 而如果返回false或null,则该行不可见。当一个WITH CHECK 表达式对一个行返回true,那么插入或更新该行,而如果返回false或null,那么会发生错误。
对于INSERT和UPDATE语句, WITH CHECK表达式是在触发BEFORE触发器后, 在实际进行任何数据修改之前强制执行的。因此,BEFORE ROW 触发器可以修改要插入的数据,影响安全策略检查的结果。WITH CHECK 表达式在任何其他约束之前强制执行。
策略名称是每表的。因此,一个策略名称可用于许多不同的表, 并具有适合于该表的每个表的定义。
策略可以应用于特定命令或特定角色。新创建策略的缺省是应用到所有命令和角色, 除非另有指定。如果多个策略应用到一个给定的语句,则它们将使用OR组合 (尽管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, 它将策略应用于所有角色。
任意SQL条件表达式(返回boolean). 该条件表达式不能包含任何聚合或窗口函数。如果启用了行级安全, 那么该表达式将添加到引用该表的查询中。表达式返回真的行是可见的。 表达式返回假或空的任何行将不会对用户可见(在一个SELECT中)。 并且不能用于修改(在UPDATE或DELETE中)。 这样的行被静默地抑制;没有报告错误。
任何SQL条件表达式(返回boolean)。 条件表达式不能包含任何聚合或窗口函数。如果启用了行级安全性, 则此表达式将用于对表的INSERT和UPDATE查询。 只允许表达式计算结果为true的行。如果对于插入的任何记录或从更新导致的任何记录, 表达式的计算结果为false或null时将抛出错误。注意, check_expression 是针对所提出的行的新内容而不是原始内容来评估的。
对策略使用ALL意味着它将应用于所有命令, 而不管命令的类型。如果存在ALL 策略并且存在更具体的策略,则将使用OR来组合ALL 策略和更具体的策略(或多个策略),如同对于重叠策略一样。 此外,ALL策略将应用于查询的选择端和修改端, 如果只定义了一个USING表达式, 则对这两种情况使用USING表达式。
作为示例,如果发出UPDATE,则ALL 策略将适用于UPDATE能够选择为要更新的行 (应用USING表达式),以及适用于导致更新的行, 以检查它们是否被允许添加到该表(如果已定义,则应用 WITH CHECK表达式,否则应用USING 表达式)。如果INSERT或UPDATE 命令尝试向没有通过ALL策略的 WITH CHECK表达式的表中添加行,则整个命令将被中止。
对策略使用SELECT意味着它将应用于 SELECT查询,并且在为其定义策略的关系上需要 SELECT权限。结果是,只有来自通过 SELECT策略的关系的那些记录将在SELECT 查询期间返回,并且需要SELECT权限的查询 (例如UPDATE)也将仅看到SELECT 策略允许的那些记录。SELECT策略不能有 WITH CHECK表达式,因为它只适用于从关系中检索记录的情况。
对策略使用INSERT意味着它将应用于 INSERT命令。如果插入的行未通过此策略, 则会导致出现策略违规错误,并且整个INSERT命令将被中止。 INSERT策略不能具有USING表达式, 因为它仅适用于将记录添加到关系的情况。
注意,使用ON CONFLICT DO UPDATE的INSERT 仅对由INSERT路径附加到关系的行检查 INSERT策略的WITH CHECK表达式。
对策略使用UPDATE意味着它将应用于 UPDATE命令(或INSERT命令的辅助 ON CONFLICT DO UPDATE子句)。 由于UPDATE涉及拉取现有记录,然后对记录的某些部分 (但可能不是全部)进行更改,UPDATE 策略接受USING表达式和WITH CHECK 表达式。USING表达式确定UPDATE 命令将对哪些记录进行操作,而WITH CHECK 表达式定义允许哪些修改的行存储回关系。
当UPDATE命令与WHERE 子句或RETURNING子句一起使用时, 在被更新的关系上也需要SELECT权限, 并且合适的SELECT和ALL 策略将使用AND与UPDATE策略的 USING子句组合(对于发现的任何重叠的 SELECT相关策略,使用OR)。因此, 为了使用户能够UPDATE特定行, 用户必须通过SELECT或ALL 策略访问该行,并且该行必须通过UPDATE 策略的USING表达式。
任何更新的值不通过WITH CHECK表达式的行都会导致错误, 整个命令将被中止。如果只指定了USING子句, 则该子句将用于USING和WITH CHECK 两种情况。
但是,请注意,使用ON CONFLICT DO UPDATE的 INSERT要求将UPDATE策略 USING表达式始终强制为WITH CHECK 表达式。此UPDATE策略必须在采取UPDATE 路径时始终通过。需要采用UPDATE路径的任何现有行必须通过( UPDATE或ALL)USING 资格(使用OR组合),这些资格在此上下文中始终作为WITH CHECK 选项实施。(UPDATE路径永远不会 默默避免; 否则将抛出一个错误。)最后,附加到关系的最后一行必须通过传统 UPDATE需要传递的任何WITH CHECK选项。
对策略使用DELETE意味着它将应用于DELETE命令。 只有通过此策略的行才能由DELETE命令查看。 如果没有通过DELETE策略的USING表达式, 则通过SELECT可以看到不可删除的行。
当DELETE命令与WHERE 子句或RETURNING子句一起使用时, 在被更新的关系上也需要SELECT权限, 并且合适的SELECT和ALL 策略将使用AND与DELETE策略的 USING子句组合(对于发现的任何重叠的 SELECT相关策略,使用OR)。因此, 为了使用户能够DELETE特定的行, 用户必须通过SELECT或ALL 策略访问该行,并且该行必须通过DELETE策略的 USING表达式。
DELETE策略不能有WITH CHECK 表达式,因为它仅适用于从关系中删除记录的情况,因此没有要检查的新行。
您必须是表的所有者才能为其创建或更改策略。
虽然策略将应用于针对数据库中的表的显式查询, 但是当系统执行内部参照完整性检查或验证约束时,不应用策略。 这意味着存在确定给定值存在的间接方式。 一个示例是尝试将重复值插入到作为主键或具有唯一约束的列中。如果插入失败, 则用户可以推断该值已经存在。(此示例假设用户被策略允许插入他们看不到的记录。) 另一个示例是允许用户插入到引用另一个否则隐藏表的表中。 可以由用户将值插入引用表中来确定存在,其中成功将指示该值存在于引用的表中。 这些问题可以通过仔细制定策略来解决,以防止用户能够插入, 删除或更新所有可能指示他们无法看到的值的记录,或通过使用生成的值 (例如,代理键)而不是具有外部意义的键。
通常,系统将使用出现在用户查询中的资格之前的安全策略强制实施过滤条件, 以便防止受保护数据无意中暴露给可能不可信的用户定义的功能。 然而,由系统(或系统管理员)标记为LEAKPROOF 的函数和运算符可以在策略表达式之前被评估,因为它们被假定为可信赖的。
由于策略表达式直接添加到用户的查询中, 因此它们将与运行整体查询的用户的权限一起运行。因此, 使用给定策略的用户必须能够访问表达式中引用的任何表或函数, 否则当尝试查询已启用行级安全性的表时,它们将仅接收到权限被拒绝错误。 但是,这不会改变视图的工作方式。与常规查询和视图一样, 视图引用的表的权限检查和策略将使用视图所有者的权限和适用于视图所有者的任何策略。
其他讨论和实际示例可以在第 5.7 节中找到。