Adjusting this function was overlooked in commit
94aa7cc5f. The only
visible symptom (so far) is that INSERT ... ON CONFLICT could go into
an endless loop when inserting a null that has a conflict.
Richard Guo and Tom Lane, per bug #17558 from Andrew Kesper
Discussion: https://postgr.es/m/17558-
3f6599ffcf52fd4a@postgresql.org
}
/*
- * If any of the input values are NULL, the constraint check is assumed to
- * pass (i.e., we assume the operators are strict).
+ * If any of the input values are NULL, and the index uses the default
+ * nulls-are-distinct mode, the constraint check is assumed to pass (i.e.,
+ * we assume the operators are strict). Otherwise, we interpret the
+ * constraint as specifying IS NULL for each column whose input value is
+ * NULL.
*/
- for (i = 0; i < indnkeyatts; i++)
+ if (!indexInfo->ii_NullsNotDistinct)
{
- if (isnull[i])
- return true;
+ for (i = 0; i < indnkeyatts; i++)
+ {
+ if (isnull[i])
+ return true;
+ }
}
/*
for (i = 0; i < indnkeyatts; i++)
{
ScanKeyEntryInitialize(&scankeys[i],
- 0,
+ isnull[i] ? SK_ISNULL | SK_SEARCHNULL : 0,
i + 1,
constr_strats[i],
InvalidOid,
CREATE TABLE UNIQUE_TBL (i int UNIQUE NULLS NOT DISTINCT, t text);
INSERT INTO UNIQUE_TBL VALUES (1, 'one');
INSERT INTO UNIQUE_TBL VALUES (2, 'two');
-INSERT INTO UNIQUE_TBL VALUES (1, 'three');
+INSERT INTO UNIQUE_TBL VALUES (1, 'three'); -- fail
ERROR: duplicate key value violates unique constraint "unique_tbl_i_key"
DETAIL: Key (i)=(1) already exists.
INSERT INTO UNIQUE_TBL VALUES (4, 'four');
INSERT INTO UNIQUE_TBL VALUES (5, 'one');
INSERT INTO UNIQUE_TBL (t) VALUES ('six');
-INSERT INTO UNIQUE_TBL (t) VALUES ('seven');
+INSERT INTO UNIQUE_TBL (t) VALUES ('seven'); -- fail
ERROR: duplicate key value violates unique constraint "unique_tbl_i_key"
DETAIL: Key (i)=(null) already exists.
+INSERT INTO UNIQUE_TBL (t) VALUES ('eight') ON CONFLICT DO NOTHING; -- no-op
SELECT * FROM UNIQUE_TBL;
i | t
---+------
INSERT INTO UNIQUE_TBL VALUES (1, 'one');
INSERT INTO UNIQUE_TBL VALUES (2, 'two');
-INSERT INTO UNIQUE_TBL VALUES (1, 'three');
+INSERT INTO UNIQUE_TBL VALUES (1, 'three'); -- fail
INSERT INTO UNIQUE_TBL VALUES (4, 'four');
INSERT INTO UNIQUE_TBL VALUES (5, 'one');
INSERT INTO UNIQUE_TBL (t) VALUES ('six');
-INSERT INTO UNIQUE_TBL (t) VALUES ('seven');
+INSERT INTO UNIQUE_TBL (t) VALUES ('seven'); -- fail
+INSERT INTO UNIQUE_TBL (t) VALUES ('eight') ON CONFLICT DO NOTHING; -- no-op
SELECT * FROM UNIQUE_TBL;