简体   繁体   中英

DEFERRABLE INITIALLY DEFERRED on index contraint in postgresql

I can add DEFERRABLE INITIALLY DEFERRED using the following query:

ALTER TABLE user DROP CONSTRAINT unq_user_address, add CONSTRAINT unq_user_address UNIQUE(user_address) deferrable INITIALLY DEFERRED;

Now I have another column and I want to add DEFERRABLE INITIALLY DEFERRED. The constraint is on index so I am getting error when I do so.

Here is the index constraint:

CREATE UNIQUE INDEX unq_account
  ON user 
  USING btree 
  (lower(account::text) COLLATE pg_catalog."default");

I modified it to say,

CREATE UNIQUE INDEX unq_account
      ON user 
      USING btree 
      (lower(account::text) COLLATE pg_catalog."default") deferrable INITIALLY DEFERRED;

Also tried,

CREATE UNIQUE INDEX unq_account
      ON user 
      USING btree 
      (lower(account::text) COLLATE pg_catalog."default") UNIQUE_CHECK_PARTIAL;

So don't know how to apply the same on index.

I see the following official doc: https://www.postgresql.org/docs/9.6/static/index-unique-checks.html

UNIQUE_CHECK_PARTIAL indicates that the unique constraint is deferrable. PostgreSQL will use this mode to insert each row's index entry. The access method must allow duplicate entries into the index, and report any potential duplicates by returning FALSE from aminsert. For each row for which FALSE is returned, a deferred recheck will be scheduled.

And here:

UNIQUE_CHECK_EXISTING indicates that this is a deferred recheck of a row that was reported as a potential uniqueness violation. Although this is implemented by calling aminsert, the access method must not insert a new index entry in this case. The index entry is already present. Rather, the access method must check to see if there is another live index entry. If so, and if the target row is also still live, report error.

Is it something I need to use and if yes then how?

You cannot define an index as deferrable. Deferrable is an attribute of constraints, not indexes.

CREATE TABLE test_table
(
    test_col integer not null
);

ALTER TABLE test_table
ADD constraint test_col_unique unique (test_col) deferrable initially deferred;

However, you cannot use arbitrary expressions for unique constraints, only direct column references:

ALTER TABLE test_table
ADD CONSTRAINT test_col_abs_unique UNIQUE (abs(test_col));

will report

ERROR:  syntax error at or near "("

because the parser only handles simple column references.

So you can't make this check deferrable.

You can't use neither of UNIQUE_CHECK_PARTIAL , UNIQUE_CHECK_EXISTING in CREATE INDEX ... SQL query. As it said on the Access Method Interface documentation page you quote,

...the aminsert function is passed a checkUnique parameter having one of the following values: UNIQUE_CHECK_NO..., UNIQUE_CHECK_YES..., UNIQUE_CHECK_PARTIAL..., UNIQUE_CHECK_EXISTING

So those are values for checkUnique parameter to be passed to aminsert function (which I assume is a part of Access Method Interface API or internals)

The rest is answered by Craig.

You can alter table "user" add CONSTRAINT unq_user_address UNIQUE(account) deferrable INITIALLY DEFERRED; losing the lower(account) condition:

as a workaround you can do this ugly thing - add column and trigger:

b=# create table "user" (account text, account_uq text);
CREATE TABLE
b=# create function tf() returns trigger as $$ begin NEW.account_uq = lower(NEW.account); return NEW; end;$$ language plpgsql;
ERROR:  function "tf" already exists with same argument types
b=# CREATE TRIGGER tg BEFORE UPDATE OR INSERT ON "user" FOR EACH ROW EXECUTE PROCEDURE tf();
CREATE TRIGGER
b=# alter table "user" add CONSTRAINT another_uq UNIQUE(account_uq) deferrable INITIALLY DEFERRED;
ALTER TABLE
b=# insert into "user" (account) select 'b';
INSERT 0 1
b=# begin;
BEGIN
b=# insert into "user" (account) select 'B';
INSERT 0 1
b=# select * from "user";
 account | account_uq
---------+------------
 b       | b
 B       | b
(2 rows)

b=# end;
ERROR:  duplicate key value violates unique constraint "another_uq"
DETAIL:  Key (account_uq)=(b) already exists.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM