バージョンごとのドキュメント一覧

5.8. 行セキュリティポリシー #

<title>Row Security Policies</title>

In addition to the SQL-standard <link linkend="ddl-priv">privilege system</link> available through <xref linkend="sql-grant"/>, tables can have <firstterm>row security policies</firstterm> that restrict, on a per-user basis, which rows can be returned by normal queries or inserted, updated, or deleted by data modification commands. This feature is also known as <firstterm>Row-Level Security</firstterm>. By default, tables do not have any policies, so that if a user has access privileges to a table according to the SQL privilege system, all rows within it are equally available for querying or updating. GRANTによって利用できるSQL標準の権限システムに加えて、通常の問い合わせでどの行が戻され、データ更新のコマンドでどの行を挿入、更新、削除できるかをユーザ単位で制限する行セキュリティポリシーをテーブルに定義できます。 この機能は行単位セキュリティとしても知られています。 デフォルトではテーブルには何もポリシーはなく、SQLの権限システムによってテーブルのアクセス権限があるユーザは、テーブル内のすべての行について同じように、問い合わせや更新をできます。

When row security is enabled on a table (with <link linkend="sql-altertable">ALTER TABLE ... ENABLE ROW LEVEL SECURITY</link>), all normal access to the table for selecting rows or modifying rows must be allowed by a row security policy. (However, the table's owner is typically not subject to row security policies.) If no policy exists for the table, a default-deny policy is used, meaning that no rows are visible or can be modified. Operations that apply to the whole table, such as <command>TRUNCATE</command> and <literal>REFERENCES</literal>, are not subject to row security. テーブルの行セキュリティが有効の場合(ALTER TABLE ... ENABLE ROW LEVEL SECURITYを使います)、行の検索や行の更新のための通常のテーブルアクセスはすべて、行セキュリティポリシーによって許可される必要があります。 (ただし、テーブルの所有者は典型的には行セキュリティポリシーの対象とはなりません。) テーブルにポリシーが存在しない場合は、デフォルト拒否のポリシーが使われて、どの行も見ることも更新することもできなくなります。 TRUNCATEREFERENCESなど、テーブル全体に対する操作は行セキュリティの対象とはなりません。

Row security policies can be specific to commands, or to roles, or to both. A policy can be specified to apply to <literal>ALL</literal> commands, or to <literal>SELECT</literal>, <literal>INSERT</literal>, <literal>UPDATE</literal>, or <literal>DELETE</literal>. Multiple roles can be assigned to a given policy, and normal role membership and inheritance rules apply. 行セキュリティポリシーは特定のコマンド、特定のロール、あるいはその両方に対して定義できます。 ポリシーはALLつまりすべてのコマンドに対して適用、あるいはSELECTINSERTUPDATEDELETEに適用することを指定できます。 1つのポリシーを複数のロールに割り当てることができ、通常のロールのメンバ資格と継承の規則が当てはまります。

To specify which rows are visible or modifiable according to a policy, an expression is required that returns a Boolean result. This expression will be evaluated for each row prior to any conditions or functions coming from the user's query. (The only exceptions to this rule are <literal>leakproof</literal> functions, which are guaranteed to not leak information; the optimizer may choose to apply such functions ahead of the row-security check.) Rows for which the expression does not return <literal>true</literal> will not be processed. Separate expressions may be specified to provide independent control over the rows which are visible and the rows which are allowed to be modified. Policy expressions are run as part of the query and with the privileges of the user running the query, although security-definer functions can be used to access data not available to the calling user. ポリシーでどの行が可視である、あるいは更新可能であるかを指定するために、論理値を返す式が必要です。 ユーザの問い合わせにあるどの条件や関数よりも前に、この式が各行について評価されます。 (この規則の例外は、情報リークがないことが保証されるleakproof関数だけです。 行セキュリティの確認の前にこのような関数を適用することをオプティマイザが選択することがあります。) 式がtrueを返さない行は処理対象になりません。 可視である行と変更可能な行について独立した制御ができるように、別々の式を指定することも可能です。 ポリシーの式は問い合わせの一部分として、問い合わせをしているユーザの権限で実行されます。 ただし、呼び出しユーザが利用できないデータにアクセスするために、セキュリティ定義関数を使うことができます。

Superusers and roles with the <literal>BYPASSRLS</literal> attribute always bypass the row security system when accessing a table. Table owners normally bypass row security as well, though a table owner can choose to be subject to row security with <link linkend="sql-altertable">ALTER TABLE ... FORCE ROW LEVEL SECURITY</link>. スーパーユーザ、およびBYPASSRLS属性のあるロールは、テーブルへのアクセス時に、常に行セキュリティシステムを無視します。 テーブルの所有者も通常は行セキュリティを無視しますが、ALTER TABLE ... FORCE ROW LEVEL SECURITYにより、テーブルの所有者も行セキュリティの対象となることができます。

Enabling and disabling row security, as well as adding policies to a table, is always the privilege of the table owner only. 行セキュリティの有効化、無効化、およびポリシーのテーブルへの追加は、常に、テーブルの所有者のみの権限です。

Policies are created using the <xref linkend="sql-createpolicy"/> command, altered using the <xref linkend="sql-alterpolicy"/> command, and dropped using the <xref linkend="sql-droppolicy"/> command. To enable and disable row security for a given table, use the <xref linkend="sql-altertable"/> command. ポリシーはCREATE POLICYコマンドで作成され、ALTER POLICYコマンドで変更され、DROP POLICYコマンドで削除されます。 テーブルの行セキュリティを有効に、あるいは無効にするにはALTER TABLEコマンドを使います。

Each policy has a name and multiple policies can be defined for a table. As policies are table-specific, each policy for a table must have a unique name. Different tables may have policies with the same name. 各ポリシーには名前があり、1つのテーブルに複数のポリシーを定義できます。 ポリシーはテーブルごとに定義されるので、1つのテーブルの各ポリシーは異なる名前でなければなりません。 異なるテーブルであれば、同じ名前のポリシーが存在しても構いません。

When multiple policies apply to a given query, they are combined using either <literal>OR</literal> (for permissive policies, which are the default) or using <literal>AND</literal> (for restrictive policies). This is similar to the rule that a given role has the privileges of all roles that they are a member of. Permissive vs. restrictive policies are discussed further below. ある問い合わせに複数のポリシーが適用される場合、(デフォルトの許容(permissive)ポリシーについては)ORまたは(制限(restrictive)ポリシーについては) ANDを使って結合されます。 これは、あるロールが、それが属するすべてのロールの権限を合わせ持つのと類似しています。 許容ポリシーと制限ポリシーについては以下でさらに説明します。

As a simple example, here is how to create a policy on the <literal>account</literal> relation to allow only members of the <literal>managers</literal> role to access rows, and only rows of their accounts: 簡単な例として、managersロールのメンバーだけが行にアクセスでき、かつ自分のアカウントの行のみアクセスできるポリシーをaccountリレーション上に作成する方法を以下に示します。

CREATE TABLE accounts (manager text, company text, contact_email text);

ALTER TABLE accounts ENABLE ROW LEVEL SECURITY;

CREATE POLICY account_managers ON accounts TO managers
    USING (manager = current_user);

The policy above implicitly provides a <literal>WITH CHECK</literal> clause identical to its <literal>USING</literal> clause, so that the constraint applies both to rows selected by a command (so a manager cannot <command>SELECT</command>, <command>UPDATE</command>, or <command>DELETE</command> existing rows belonging to a different manager) and to rows modified by a command (so rows belonging to a different manager cannot be created via <command>INSERT</command> or <command>UPDATE</command>). 上記のポリシーは、上記のUSING句と同じWITH CHECK句を暗黙的に提供するので、制約は、コマンドが選択した行にも適用されますし(ですから、マネージャは、違うマネージャに属する既存の行に対してSELECTUPDATEDELETEを発行することはできません)、コマンドが変更した行にも適用されます(ですから、違うマネージャに属する行を、INSERTあるいはUPDATEで作ることはできません)。

If no role is specified, or the special user name <literal>PUBLIC</literal> is used, then the policy applies to all users on the system. To allow all users to access only their own row in a <literal>users</literal> table, a simple policy can be used: ロールが指定されなかった場合、あるいは特別なユーザ名PUBLICが指定された場合、ポリシーはシステム上の全ユーザに適用されます。 すべてのユーザがusersテーブルの自分自身の行にだけアクセスできるようにするためには、次の簡単なポリシーが使用できます。

CREATE POLICY user_policy ON users
    USING (user_name = current_user);

This works similarly to the previous example. これは前の例と同じように動きます。

To use a different policy for rows that are being added to the table compared to those rows that are visible, multiple policies can be combined. This pair of policies would allow all users to view all rows in the <literal>users</literal> table, but only modify their own: テーブルに追加される行に対し、可視である行とは異なるポリシーを使用する場合は、複数のポリシーを組み合わせることができます。 組み合わせたポリシーにより、すべてのユーザがusersテーブルのすべての行を見ることができますが、自分自身の行だけしか更新できません。

CREATE POLICY user_sel_policy ON users
    FOR SELECT
    USING (true);
CREATE POLICY user_mod_policy ON users
    USING (user_name = current_user);

In a <command>SELECT</command> command, these two policies are combined using <literal>OR</literal>, with the net effect being that all rows can be selected. In other command types, only the second policy applies, so that the effects are the same as before. SELECTコマンドでは、ORを使って2つのポリシーが組み合わされ、すべての行を検索できる効果をもたらします。 他のコマンドに対しては、二番目のポリシーだけが適用され、以前と効果は同じです。

Row security can also be disabled with the <command>ALTER TABLE</command> command. Disabling row security does not remove any policies that are defined on the table; they are simply ignored. Then all rows in the table are visible and modifiable, subject to the standard SQL privileges system. 行セキュリティはALTER TABLEで無効にすることもできます。 行セキュリティを無効にしても、テーブルに定義されているポリシーは削除されず、単に無視されるだけになります。 このときはSQL標準の権限システムに従って、すべての行が可視で更新可能になります。

Below is a larger example of how this feature can be used in production environments. The table <literal>passwd</literal> emulates a Unix password file: 以下のより大きな例で、この機能が実運用の環境でいかにして使えるかを示します。 passwdテーブルはUnixのパスワードファイルと同等のものです。


&#45;- Simple passwd-file based example

-- passwdファイルに基づく簡単な例
CREATE TABLE passwd (
  user_name             text UNIQUE NOT NULL,
  pwhash                text,
  uid                   int  PRIMARY KEY,
  gid                   int  NOT NULL,
  real_name             text NOT NULL,
  home_phone            text,
  extra_info            text,
  home_dir              text NOT NULL,
  shell                 text NOT NULL
);


CREATE ROLE admin;  &#45;- Administrator
CREATE ROLE bob;    &#45;- Normal user
CREATE ROLE alice;  &#45;- Normal user

CREATE ROLE admin;  -- 管理者
CREATE ROLE bob;    -- 一般ユーザ
CREATE ROLE alice;  -- 一般ユーザ


&#45;- Populate the table

-- テーブルに値を入れる
INSERT INTO passwd VALUES
  ('admin','xxx',0,0,'Admin','111-222-3333',null,'/root','/bin/dash');
INSERT INTO passwd VALUES
  ('bob','xxx',1,1,'Bob','123-456-7890',null,'/home/bob','/bin/zsh');
INSERT INTO passwd VALUES
  ('alice','xxx',2,1,'Alice','098-765-4321',null,'/home/alice','/bin/zsh');


&#45;- Be sure to enable row-level security on the table

-- テーブルの行単位セキュリティを有効にする
ALTER TABLE passwd ENABLE ROW LEVEL SECURITY;


&#45;- Create policies
&#45;- Administrator can see all rows and add any rows

-- ポリシーを作成する
-- 管理者はすべての行を見ることができ、どんな行でも追加できる
CREATE POLICY admin_all ON passwd TO admin USING (true) WITH CHECK (true);

&#45;- Normal users can view all rows

-- 一般ユーザはすべての行を見ることができる
CREATE POLICY all_view ON passwd FOR SELECT USING (true);

&#45;- Normal users can update their own records, but
&#45;- limit which shells a normal user is allowed to set

-- 一般ユーザは自身のレコードを更新できるが、
-- 変更できるのは使用するシェルだけに制限する
CREATE POLICY user_mod ON passwd FOR UPDATE
  USING (current_user = user_name)
  WITH CHECK (
    current_user = user_name AND
    shell IN ('/bin/bash','/bin/sh','/bin/dash','/bin/zsh','/bin/tcsh')
  );


&#45;- Allow admin all normal rights

-- adminにはすべての通常の権限を付与する
GRANT SELECT, INSERT, UPDATE, DELETE ON passwd TO admin;

&#45;- Users only get select access on public columns

-- 一般ユーザは公開列にSELECTでアクセスできるだけとする
GRANT SELECT
  (user_name, uid, gid, real_name, home_phone, extra_info, home_dir, shell)
  ON passwd TO public;

&#45;- Allow users to update certain columns

-- 特定の列についてはユーザによる更新を許可する
GRANT UPDATE
  (pwhash, real_name, home_phone, extra_info, shell)
  ON passwd TO public;

As with any security settings, it's important to test and ensure that the system is behaving as expected. Using the example above, this demonstrates that the permission system is working properly. どんなセキュリティ設定でも同じですが、システムが期待通りに動作していることをテストして確認することが重要です。 上の例を利用して、以下ではパーミッションのシステムが適切に動作していることを示します。


&#45;- admin can view all rows and fields

-- adminはすべての行と列を見ることができる
postgres=> set role admin;
SET
postgres=> table passwd;
 user_name | pwhash | uid | gid | real_name |  home_phone  | extra_info | home_dir    |   shell
-----------+--------+-----+-----+-----------+--------------+------------+-------------+-----------
 admin     | xxx    |   0 |   0 | Admin     | 111-222-3333 |            | /root       | /bin/dash
 bob       | xxx    |   1 |   1 | Bob       | 123-456-7890 |            | /home/bob   | /bin/zsh
 alice     | xxx    |   2 |   1 | Alice     | 098-765-4321 |            | /home/alice | /bin/zsh
(3 rows)


&#45;- Test what Alice is able to do

-- Aliceに何ができるか試してみる
postgres=> set role alice;
SET
postgres=> table passwd;
ERROR:  permission denied for table passwd
postgres=> select user_name,real_name,home_phone,extra_info,home_dir,shell from passwd;
 user_name | real_name |  home_phone  | extra_info | home_dir    |   shell
-----------+-----------+--------------+------------+-------------+-----------
 admin     | Admin     | 111-222-3333 |            | /root       | /bin/dash
 bob       | Bob       | 123-456-7890 |            | /home/bob   | /bin/zsh
 alice     | Alice     | 098-765-4321 |            | /home/alice | /bin/zsh
(3 rows)

postgres=> update passwd set user_name = 'joe';
ERROR:  permission denied for table passwd

&#45;- Alice is allowed to change her own real_name, but no others

-- Aliceは自分のreal_nameを変更できるが、他は変更できない
postgres=> update passwd set real_name = 'Alice Doe';
UPDATE 1
postgres=> update passwd set real_name = 'John Doe' where user_name = 'admin';
UPDATE 0
postgres=> update passwd set shell = '/bin/xx';
ERROR:  new row violates WITH CHECK OPTION for "passwd"
postgres=> delete from passwd;
ERROR:  permission denied for table passwd
postgres=> insert into passwd (user_name) values ('xxx');
ERROR:  permission denied for table passwd

&#45;- Alice can change her own password; RLS silently prevents updating other rows

-- Aliceは自分のパスワードを変更できる。
-- RLSにより他の行は更新されないが、何も報告されない。
postgres=> update passwd set pwhash = 'abc';
UPDATE 1

All of the policies constructed thus far have been permissive policies, meaning that when multiple policies are applied they are combined using the <quote>OR</quote> Boolean operator. While permissive policies can be constructed to only allow access to rows in the intended cases, it can be simpler to combine permissive policies with restrictive policies (which the records must pass and which are combined using the <quote>AND</quote> Boolean operator). Building on the example above, we add a restrictive policy to require the administrator to be connected over a local Unix socket to access the records of the <literal>passwd</literal> table: ここまでで作成したポリシーはすべて許容ポリシーで、つまり複数のポリシーが適用される場合、それらは論理演算子ORを使って結合されるものでした。 意図した場合にのみ行へのアクセスが許されるよう許容ポリシーを構築することは可能ですが、許容ポリシーを制限ポリシーと組み合わせることで、より単純にすることが可能です(制限ポリシーはレコードが満たさなければならないポリシーで、論理演算子ANDを使って結合されます)。 上記の例に重ねて、管理者がローカルのUnixソケットを通して接続してpasswdテーブルのレコードにアクセスすることを要求する制限ポリシーを追加してみます。

CREATE POLICY admin_local_only ON passwd AS RESTRICTIVE TO admin
    USING (pg_catalog.inet_client_addr() IS NULL);

We can then see that an administrator connecting over a network will not see any records, due to the restrictive policy: こうすると以下のように、制限ポリシーにより、ネットワーク経由で接続している管理者にはレコードが見えないことがわかります。

=> SELECT current_user;
 current_user
--------------
 admin
(1 row)

=> select inet_client_addr();
 inet_client_addr
------------------
 127.0.0.1
(1 row)

=> TABLE passwd;
 user_name | pwhash | uid | gid | real_name | home_phone | extra_info | home_dir | shell
-----------+--------+-----+-----+-----------+------------+------------+----------+-------
(0 rows)

=> UPDATE passwd set pwhash = NULL;
UPDATE 0

Referential integrity checks, such as unique or primary key constraints and foreign key references, always bypass row security to ensure that data integrity is maintained. Care must be taken when developing schemas and row level policies to avoid <quote>covert channel</quote> leaks of information through such referential integrity checks. 一意性制約、主キー制約、外部キー制約などの参照整合性確認は、データの整合性を維持するため、常に行セキュリティを無視します。 スキーマと行単位セキュリティの開発において、このような参照整合性確認によりカバートチャネル(covert channel)の情報漏洩が起こらないようにするため、注意が必要です。

In some contexts it is important to be sure that row security is not being applied. For example, when taking a backup, it could be disastrous if row security silently caused some rows to be omitted from the backup. In such a situation, you can set the <xref linkend="guc-row-security"/> configuration parameter to <literal>off</literal>. This does not in itself bypass row security; what it does is throw an error if any query's results would get filtered by a policy. The reason for the error can then be investigated and fixed. 状況によっては、行セキュリティが適用されないことを確実にするのが重要になります。 例えばバックアップを取るとき、行セキュリティのために、何のエラーや警告もなしに一部の行がバックアップされないとすると、破滅的です。 このような状況では、設定パラメータrow_securityoffにすることができます。 これ自体は行セキュリティを無視するわけではなく、問い合わせの結果がポリシーによって影響を受ける場合にエラーを発生させます。 その後でエラーの原因を調査して解決することができます。

In the examples above, the policy expressions consider only the current values in the row to be accessed or updated. This is the simplest and best-performing case; when possible, it's best to design row security applications to work this way. If it is necessary to consult other rows or other tables to make a policy decision, that can be accomplished using sub-<command>SELECT</command>s, or functions that contain <command>SELECT</command>s, in the policy expressions. Be aware however that such accesses can create race conditions that could allow information leakage if care is not taken. As an example, consider the following table design: 上の例では、ポリシーの式はアクセス対象または更新対象の行の現在の値のみを考慮していました。 これは最も単純で、しかも効率の良い場合です。 可能であれば、行セキュリティの適用はこのように動作するよう設計するのが最善です。 ポリシーの決定をするために他の行あるいは他のテーブルを参照する必要がある場合は、ポリシーの式で副SELECTを使う、あるいはSELECTを含む関数を使うことができます。 ただし、そのようなアクセスは注意深く設計しなければ、情報漏洩を起こすような競合条件を作り出す場合があることに注意してください。 例えば、以下のテーブル設計を考えます。


&#45;- definition of privilege groups

-- 権限グループの定義
CREATE TABLE groups (group_id int PRIMARY KEY,
                     group_name text NOT NULL);

INSERT INTO groups VALUES
  (1, 'low'),
  (2, 'medium'),
  (5, 'high');


GRANT ALL ON groups TO alice;  &#45;- alice is the administrator

GRANT ALL ON groups TO alice;  -- aliceが管理者
GRANT SELECT ON groups TO public;


&#45;- definition of users' privilege levels

-- ユーザの権限レベルの定義
CREATE TABLE users (user_name text PRIMARY KEY,
                    group_id int NOT NULL REFERENCES groups);

INSERT INTO users VALUES
  ('alice', 5),
  ('bob', 2),
  ('mallory', 2);

GRANT ALL ON users TO alice;
GRANT SELECT ON users TO public;


&#45;- table holding the information to be protected

-- 保護される情報を保持するテーブル
CREATE TABLE information (info text,
                          group_id int NOT NULL REFERENCES groups);

INSERT INTO information VALUES
  ('barely secret', 1),
  ('slightly secret', 2),
  ('very secret', 5);

ALTER TABLE information ENABLE ROW LEVEL SECURITY;


&#45;- a row should be visible to/updatable by users whose security group_id is
&#45;- greater than or equal to the row's group_id

-- セキュリティのgroup_idが行のgroup_idより大きいか等しいユーザは
-- その行を見ること、更新することが可能
CREATE POLICY fp_s ON information FOR SELECT
  USING (group_id <= (SELECT group_id FROM users WHERE user_name = current_user));
CREATE POLICY fp_u ON information FOR UPDATE
  USING (group_id <= (SELECT group_id FROM users WHERE user_name = current_user));


&#45;- we rely only on RLS to protect the information table

-- informationテーブルを保護するのにRLSのみに依存する
GRANT ALL ON information TO public;

Now suppose that <literal>alice</literal> wishes to change the <quote>slightly secret</quote> information, but decides that <literal>mallory</literal> should not be trusted with the new content of that row, so she does: ここでaliceslightly secretの情報を更新したいが、この行の新しい内容に関してmalloryは信頼すべきでないと判断しました。 そこで、彼女は次のようにします。

BEGIN;
UPDATE users SET group_id = 1 WHERE user_name = 'mallory';
UPDATE information SET info = 'secret from mallory' WHERE group_id = 2;
COMMIT;

That looks safe; there is no window wherein <literal>mallory</literal> should be able to see the <quote>secret from mallory</quote> string. However, there is a race condition here. If <literal>mallory</literal> is concurrently doing, say, これは安全なように見えます。 mallorysecret from malloryの文字列を見ることができる隙はありません。 しかし、ここには競合条件があります。 例えば、malloryが同時に以下を実行していたとしましょう。

SELECT * FROM information WHERE group_id = 2 FOR UPDATE;

and her transaction is in <literal>READ COMMITTED</literal> mode, it is possible for her to see <quote>secret from mallory</quote>. That happens if her transaction reaches the <structname>information</structname> row just after <literal>alice</literal>'s does. It blocks waiting for <literal>alice</literal>'s transaction to commit, then fetches the updated row contents thanks to the <literal>FOR UPDATE</literal> clause. However, it does <emphasis>not</emphasis> fetch an updated row for the implicit <command>SELECT</command> from <structname>users</structname>, because that sub-<command>SELECT</command> did not have <literal>FOR UPDATE</literal>; instead the <structname>users</structname> row is read with the snapshot taken at the start of the query. Therefore, the policy expression tests the old value of <literal>mallory</literal>'s privilege level and allows her to see the updated row. ここで彼女のトランザクションがREAD COMMITTEDモードなら、彼女はsecret from malloryを見ることが可能です。 それは彼女のトランザクションが、aliceのトランザクションの直後にinformationの行にアクセスした場合に発生します。 それはaliceのトランザクションがコミットされるのを待ってブロックされ、次にFOR UPDATE句があるため、更新後の行の内容をフェッチします。 しかし、usersからの暗示的なSELECTでは更新後の行をフェッチしません。 なぜなら、その副SELECTにはFOR UPDATEがないため、usersの行は問い合わせの開始時に取得したスナップショットから読まれるからです。 そのため、ポリシーの式はmalloryの権限レベルの古い値について検査し、更新後の行を見ることを許してしまいます。

There are several ways around this problem. One simple answer is to use <literal>SELECT ... FOR SHARE</literal> in sub-<command>SELECT</command>s in row security policies. However, that requires granting <literal>UPDATE</literal> privilege on the referenced table (here <structname>users</structname>) to the affected users, which might be undesirable. (But another row security policy could be applied to prevent them from actually exercising that privilege; or the sub-<command>SELECT</command> could be embedded into a security definer function.) Also, heavy concurrent use of row share locks on the referenced table could pose a performance problem, especially if updates of it are frequent. Another solution, practical if updates of the referenced table are infrequent, is to take an <literal>ACCESS EXCLUSIVE</literal> lock on the referenced table when updating it, so that no concurrent transactions could be examining old row values. Or one could just wait for all concurrent transactions to end after committing an update of the referenced table and before making changes that rely on the new security situation. この問題を回避する方法はいくつかあります。 一つの簡単な答えは行セキュリティポリシーの副SELECTSELECT ... FOR SHAREを使うことです。 しかし、これは影響を受けるユーザに対し、参照先テーブル(この場合はusers)のUPDATE権限を付与する必要があり、望ましくないかもしれません。 (しかし、もう一つの行セキュリティポリシーを適用して、彼らが実際にその権限を行使することを防ぐことはできます。 また、副SELECTをセキュリティ定義関数内に埋め込むことも可能です。) また、参照先テーブルに行共有ロックが同時に大量に発生するとパフォーマンス問題が起きるかもしれません。 特にそのテーブルの更新が多いときは問題になるでしょう。 別の解決策で、参照先テーブルの更新が少ない場合に現実的なのは、参照先テーブルの更新時にACCESS EXCLUSIVEロックを取得するものです。 そうすれば、同時実行のトランザクションが行の古い値を調べることはできません。 あるいは、参照先のテーブルの更新をコミットした後、単にすべての同時実行トランザクションが終わるのを待ってから、新しいセキュリティ状況に依存する変更をする、ということもできます。

For additional details see <xref linkend="sql-createpolicy"/> and <xref linkend="sql-altertable"/>. さらなる詳細はCREATE POLICYALTER TABLEを参照してください。