web-dev-qa-db-ja.com

Postgres9.2-条件付き制約チェックを追加

PostgreSQL 9.2を使用しており、列に条件付き制約を追加する必要があります。基本的に、他の2つの列に特定の値がある場合、その列がfalseであることを確認したいと思います。

gid          | int_unsigned           | not null default 0
realm        | character varying(255) | not null default ''::character varying
grant_update | smallint_unsigned      | not null default (0)::smallint
grant_delete | smallint_unsigned      | not null default (0)::smallint

例:

alter table node_access add constraint block_anonymous_page_edit
check (grant_update = 0 WHERE (gid = 1 AND realm = 'nodeaccess_rid'));

これが行うことになっていることは、gidが1でrealm = nodeaccess_ridの場合にgrant_updateが0に等しいことを確認することです。ただし、私が望むことを行うのではなく、実際にはすべての列にこれらの値を模倣させようとしていると思います。本質的には、grant_updateが常に0、gidが常に1、レルムが常にnodeaccess_ridであることを確認しようとしています。私が得るエラーは次のとおりです。

ERROR:  check constraint "block_anonymous_page_edit" is violated by some row

[〜#〜]編集[〜#〜]

これは、更新時にトリガーされる関数である必要があると思います。

[〜#〜]編集[〜#〜]

上記の質問に行を追加した結果、承認されたソリューションを以下のコメントで更新しました。

13
thepriebe

ロジックに頭を悩ませたら、それはかなり単純です CHECK制約

CREATE TABLE tbl (
   gid          int      NOT NULL DEFAULT 0
  ,realm        text     NOT NULL DEFAULT ''
  ,grant_update smallint NOT NULL DEFAULT 0
  ,CHECK (gid <> 1
          OR realm <> 'nodeaccess_rid'
          OR grant_update = 0)
);

テスト:

INSERT INTO tbl(gid, realm, grant_update)
VALUES (1, 'nodeaccess_rid', 0);          -- works

INSERT INTO tbl(gid, realm, grant_update)
VALUES (1, 'nodeaccess_rid', 1);           -- check violation!

INSERT INTO tbl(gid, realm, grant_update)
VALUES (1, 'some_string',    1);           -- works

INSERT INTO tbl(gid, realm, grant_update)
VALUES (2, 'nodeaccess_rid', 1);           -- works
19

これをトリガーとして書きます。これにより、エラーを発生させる(場合によっては、最適にテストできるカスタムコードを使用する)か、問題を処理して、gid = 1およびrealm = 'nodeaccess_rid'の場合にgrant_update = 0を設定する柔軟性が得られます。

2
David S

結局、トリガー機能を使いました。これにより、ロールがチェックされ、ブール値のフィールドgrant_updateとgrant_deleteを使用して不要な機能がオフに設定されます。以下の関数は、grant_view値を上書きするのではなく、保持します。

CREATE OR REPLACE function block_anonymous_page_edit()
RETURNS trigger AS $function$
BEGIN
  IF NEW.gid = 1 AND NEW.realm != 'nodeaccess_author' AND (NEW.grant_update = 1 OR NEW.grant_delete = 1) THEN
    RAISE WARNING 'Anonymous users are not allowed to edit pages.';
    NEW.grant_update := 0;
    NEW.grant_delete := 0;
  END IF;
  RETURN NEW;
END;
$function$ LANGUAGE plpgsql;

CREATE TRIGGER tgr_block_anonymous_page_edit BEFORE INSERT OR UPDATE ON node_access FOR EACH ROW EXECUTE PROCEDURE block_anonymous_page_edit();
0
thepriebe