2000-01-05 18:32:18 +01:00
|
|
|
--
|
|
|
|
-- CONSTRAINTS
|
|
|
|
-- Constraints can be specified with:
|
|
|
|
-- - DEFAULT clause
|
|
|
|
-- - CHECK clauses
|
|
|
|
-- - PRIMARY KEY clauses
|
|
|
|
-- - UNIQUE clauses
|
2009-12-07 06:22:23 +01:00
|
|
|
-- - EXCLUDE clauses
|
2000-01-05 18:32:18 +01:00
|
|
|
--
|
|
|
|
--
|
|
|
|
-- DEFAULT syntax
|
|
|
|
--
|
|
|
|
CREATE TABLE DEFAULT_TBL (i int DEFAULT 100,
|
1997-12-05 01:01:22 +01:00
|
|
|
x text DEFAULT 'vadim', f float8 DEFAULT 123.456);
|
2000-01-05 18:32:18 +01:00
|
|
|
INSERT INTO DEFAULT_TBL VALUES (1, 'thomas', 57.0613);
|
|
|
|
INSERT INTO DEFAULT_TBL VALUES (1, 'bruce');
|
|
|
|
INSERT INTO DEFAULT_TBL (i, f) VALUES (2, 987.654);
|
|
|
|
INSERT INTO DEFAULT_TBL (x) VALUES ('marc');
|
|
|
|
INSERT INTO DEFAULT_TBL VALUES (3, null, 1.0);
|
|
|
|
SELECT '' AS five, * FROM DEFAULT_TBL;
|
|
|
|
five | i | x | f
|
|
|
|
------+-----+--------+---------
|
|
|
|
| 1 | thomas | 57.0613
|
|
|
|
| 1 | bruce | 123.456
|
|
|
|
| 2 | vadim | 987.654
|
|
|
|
| 100 | marc | 123.456
|
|
|
|
| 3 | | 1
|
1997-10-17 11:59:09 +02:00
|
|
|
(5 rows)
|
1997-09-16 18:17:19 +02:00
|
|
|
|
2000-01-05 18:32:18 +01:00
|
|
|
CREATE SEQUENCE DEFAULT_SEQ;
|
|
|
|
CREATE TABLE DEFAULTEXPR_TBL (i1 int DEFAULT 100 + (200-199) * 2,
|
1997-12-05 01:01:22 +01:00
|
|
|
i2 int DEFAULT nextval('default_seq'));
|
2000-01-05 18:32:18 +01:00
|
|
|
INSERT INTO DEFAULTEXPR_TBL VALUES (-1, -2);
|
|
|
|
INSERT INTO DEFAULTEXPR_TBL (i1) VALUES (-3);
|
|
|
|
INSERT INTO DEFAULTEXPR_TBL (i2) VALUES (-4);
|
|
|
|
INSERT INTO DEFAULTEXPR_TBL (i2) VALUES (NULL);
|
|
|
|
SELECT '' AS four, * FROM DEFAULTEXPR_TBL;
|
|
|
|
four | i1 | i2
|
|
|
|
------+-----+----
|
|
|
|
| -1 | -2
|
|
|
|
| -3 | 1
|
|
|
|
| 102 | -4
|
|
|
|
| 102 |
|
1997-09-16 18:17:19 +02:00
|
|
|
(4 rows)
|
|
|
|
|
2000-01-05 18:32:18 +01:00
|
|
|
-- syntax errors
|
|
|
|
-- test for extraneous comma
|
|
|
|
CREATE TABLE error_tbl (i int DEFAULT (100, ));
|
2006-03-14 23:48:25 +01:00
|
|
|
ERROR: syntax error at or near ")"
|
2004-03-14 05:25:18 +01:00
|
|
|
LINE 1: CREATE TABLE error_tbl (i int DEFAULT (100, ));
|
2004-05-11 00:44:49 +02:00
|
|
|
^
|
2000-01-05 18:32:18 +01:00
|
|
|
-- this will fail because gram.y uses b_expr not a_expr for defaults,
|
|
|
|
-- to avoid a shift/reduce conflict that arises from NOT NULL being
|
|
|
|
-- part of the column definition syntax:
|
|
|
|
CREATE TABLE error_tbl (b1 bool DEFAULT 1 IN (1, 2));
|
2006-03-14 23:48:25 +01:00
|
|
|
ERROR: syntax error at or near "IN"
|
2004-03-14 05:25:18 +01:00
|
|
|
LINE 1: CREATE TABLE error_tbl (b1 bool DEFAULT 1 IN (1, 2));
|
|
|
|
^
|
2000-01-05 18:32:18 +01:00
|
|
|
-- this should work, however:
|
|
|
|
CREATE TABLE error_tbl (b1 bool DEFAULT (1 IN (1, 2)));
|
|
|
|
DROP TABLE error_tbl;
|
|
|
|
--
|
|
|
|
-- CHECK syntax
|
|
|
|
--
|
|
|
|
CREATE TABLE CHECK_TBL (x int,
|
1997-12-05 01:01:22 +01:00
|
|
|
CONSTRAINT CHECK_CON CHECK (x > 3));
|
2000-01-05 18:32:18 +01:00
|
|
|
INSERT INTO CHECK_TBL VALUES (5);
|
|
|
|
INSERT INTO CHECK_TBL VALUES (4);
|
|
|
|
INSERT INTO CHECK_TBL VALUES (3);
|
2003-09-25 17:48:17 +02:00
|
|
|
ERROR: new row for relation "check_tbl" violates check constraint "check_con"
|
2000-01-05 18:32:18 +01:00
|
|
|
INSERT INTO CHECK_TBL VALUES (2);
|
2003-09-25 17:48:17 +02:00
|
|
|
ERROR: new row for relation "check_tbl" violates check constraint "check_con"
|
2000-01-05 18:32:18 +01:00
|
|
|
INSERT INTO CHECK_TBL VALUES (6);
|
|
|
|
INSERT INTO CHECK_TBL VALUES (1);
|
2003-09-25 17:48:17 +02:00
|
|
|
ERROR: new row for relation "check_tbl" violates check constraint "check_con"
|
2000-01-05 18:32:18 +01:00
|
|
|
SELECT '' AS three, * FROM CHECK_TBL;
|
|
|
|
three | x
|
|
|
|
-------+---
|
|
|
|
| 5
|
|
|
|
| 4
|
|
|
|
| 6
|
1997-12-05 01:01:22 +01:00
|
|
|
(3 rows)
|
|
|
|
|
2000-01-05 18:32:18 +01:00
|
|
|
CREATE SEQUENCE CHECK_SEQ;
|
|
|
|
CREATE TABLE CHECK2_TBL (x int, y text, z int,
|
1997-12-05 01:01:22 +01:00
|
|
|
CONSTRAINT SEQUENCE_CON
|
|
|
|
CHECK (x > 3 and y <> 'check failed' and z < 8));
|
2000-01-05 18:32:18 +01:00
|
|
|
INSERT INTO CHECK2_TBL VALUES (4, 'check ok', -2);
|
|
|
|
INSERT INTO CHECK2_TBL VALUES (1, 'x check failed', -2);
|
2003-09-25 17:48:17 +02:00
|
|
|
ERROR: new row for relation "check2_tbl" violates check constraint "sequence_con"
|
2000-01-05 18:32:18 +01:00
|
|
|
INSERT INTO CHECK2_TBL VALUES (5, 'z check failed', 10);
|
2003-09-25 17:48:17 +02:00
|
|
|
ERROR: new row for relation "check2_tbl" violates check constraint "sequence_con"
|
2000-01-05 18:32:18 +01:00
|
|
|
INSERT INTO CHECK2_TBL VALUES (0, 'check failed', -2);
|
2003-09-25 17:48:17 +02:00
|
|
|
ERROR: new row for relation "check2_tbl" violates check constraint "sequence_con"
|
2000-01-05 18:32:18 +01:00
|
|
|
INSERT INTO CHECK2_TBL VALUES (6, 'check failed', 11);
|
2003-09-25 17:48:17 +02:00
|
|
|
ERROR: new row for relation "check2_tbl" violates check constraint "sequence_con"
|
2000-01-05 18:32:18 +01:00
|
|
|
INSERT INTO CHECK2_TBL VALUES (7, 'check ok', 7);
|
|
|
|
SELECT '' AS two, * from CHECK2_TBL;
|
|
|
|
two | x | y | z
|
|
|
|
-----+---+----------+----
|
|
|
|
| 4 | check ok | -2
|
|
|
|
| 7 | check ok | 7
|
1997-12-05 01:01:22 +01:00
|
|
|
(2 rows)
|
|
|
|
|
2000-01-05 18:32:18 +01:00
|
|
|
--
|
|
|
|
-- Check constraints on INSERT
|
|
|
|
--
|
|
|
|
CREATE SEQUENCE INSERT_SEQ;
|
|
|
|
CREATE TABLE INSERT_TBL (x INT DEFAULT nextval('insert_seq'),
|
2000-01-16 20:57:48 +01:00
|
|
|
y TEXT DEFAULT '-NULL-',
|
|
|
|
z INT DEFAULT -1 * currval('insert_seq'),
|
|
|
|
CONSTRAINT INSERT_CON CHECK (x >= 3 AND y <> 'check failed' AND x < 8),
|
|
|
|
CHECK (x + z = 0));
|
2000-01-05 18:32:18 +01:00
|
|
|
INSERT INTO INSERT_TBL(x,z) VALUES (2, -2);
|
2003-09-25 17:48:17 +02:00
|
|
|
ERROR: new row for relation "insert_tbl" violates check constraint "insert_con"
|
2000-01-05 18:32:18 +01:00
|
|
|
SELECT '' AS zero, * FROM INSERT_TBL;
|
|
|
|
zero | x | y | z
|
|
|
|
------+---+---+---
|
1997-08-28 06:49:34 +02:00
|
|
|
(0 rows)
|
|
|
|
|
2000-01-05 18:32:18 +01:00
|
|
|
SELECT 'one' AS one, nextval('insert_seq');
|
|
|
|
one | nextval
|
|
|
|
-----+---------
|
|
|
|
one | 1
|
1997-08-28 06:49:34 +02:00
|
|
|
(1 row)
|
|
|
|
|
2000-01-05 18:32:18 +01:00
|
|
|
INSERT INTO INSERT_TBL(y) VALUES ('Y');
|
2003-09-25 17:48:17 +02:00
|
|
|
ERROR: new row for relation "insert_tbl" violates check constraint "insert_con"
|
2000-01-05 18:32:18 +01:00
|
|
|
INSERT INTO INSERT_TBL(y) VALUES ('Y');
|
|
|
|
INSERT INTO INSERT_TBL(x,z) VALUES (1, -2);
|
2004-06-10 19:56:03 +02:00
|
|
|
ERROR: new row for relation "insert_tbl" violates check constraint "insert_tbl_check"
|
2000-01-05 18:32:18 +01:00
|
|
|
INSERT INTO INSERT_TBL(z,x) VALUES (-7, 7);
|
|
|
|
INSERT INTO INSERT_TBL VALUES (5, 'check failed', -5);
|
2003-09-25 17:48:17 +02:00
|
|
|
ERROR: new row for relation "insert_tbl" violates check constraint "insert_con"
|
2000-01-05 18:32:18 +01:00
|
|
|
INSERT INTO INSERT_TBL VALUES (7, '!check failed', -7);
|
|
|
|
INSERT INTO INSERT_TBL(y) VALUES ('-!NULL-');
|
|
|
|
SELECT '' AS four, * FROM INSERT_TBL;
|
|
|
|
four | x | y | z
|
|
|
|
------+---+---------------+----
|
|
|
|
| 3 | Y | -3
|
|
|
|
| 7 | -NULL- | -7
|
|
|
|
| 7 | !check failed | -7
|
|
|
|
| 4 | -!NULL- | -4
|
1997-08-28 06:49:34 +02:00
|
|
|
(4 rows)
|
|
|
|
|
2000-01-05 18:32:18 +01:00
|
|
|
INSERT INTO INSERT_TBL(y,z) VALUES ('check failed', 4);
|
2004-06-10 19:56:03 +02:00
|
|
|
ERROR: new row for relation "insert_tbl" violates check constraint "insert_tbl_check"
|
2000-01-05 18:32:18 +01:00
|
|
|
INSERT INTO INSERT_TBL(x,y) VALUES (5, 'check failed');
|
2003-09-25 17:48:17 +02:00
|
|
|
ERROR: new row for relation "insert_tbl" violates check constraint "insert_con"
|
2000-01-05 18:32:18 +01:00
|
|
|
INSERT INTO INSERT_TBL(x,y) VALUES (5, '!check failed');
|
|
|
|
INSERT INTO INSERT_TBL(y) VALUES ('-!NULL-');
|
|
|
|
SELECT '' AS six, * FROM INSERT_TBL;
|
|
|
|
six | x | y | z
|
|
|
|
-----+---+---------------+----
|
|
|
|
| 3 | Y | -3
|
|
|
|
| 7 | -NULL- | -7
|
|
|
|
| 7 | !check failed | -7
|
|
|
|
| 4 | -!NULL- | -4
|
|
|
|
| 5 | !check failed | -5
|
|
|
|
| 6 | -!NULL- | -6
|
1997-10-17 11:59:09 +02:00
|
|
|
(6 rows)
|
1997-08-28 06:49:34 +02:00
|
|
|
|
2000-01-05 18:32:18 +01:00
|
|
|
SELECT 'seven' AS one, nextval('insert_seq');
|
|
|
|
one | nextval
|
|
|
|
-------+---------
|
|
|
|
seven | 7
|
1997-10-17 11:59:09 +02:00
|
|
|
(1 row)
|
|
|
|
|
2000-01-05 18:32:18 +01:00
|
|
|
INSERT INTO INSERT_TBL(y) VALUES ('Y');
|
2003-09-25 17:48:17 +02:00
|
|
|
ERROR: new row for relation "insert_tbl" violates check constraint "insert_con"
|
2000-01-05 18:32:18 +01:00
|
|
|
SELECT 'eight' AS one, currval('insert_seq');
|
|
|
|
one | currval
|
|
|
|
-------+---------
|
|
|
|
eight | 8
|
1997-08-28 06:49:34 +02:00
|
|
|
(1 row)
|
|
|
|
|
2000-01-20 00:55:03 +01:00
|
|
|
-- According to SQL92, it is OK to insert a record that gives rise to NULL
|
|
|
|
-- constraint-condition results. Postgres used to reject this, but it
|
|
|
|
-- was wrong:
|
|
|
|
INSERT INTO INSERT_TBL VALUES (null, null, null);
|
|
|
|
SELECT '' AS nine, * FROM INSERT_TBL;
|
|
|
|
nine | x | y | z
|
|
|
|
------+---+---------------+----
|
|
|
|
| 3 | Y | -3
|
|
|
|
| 7 | -NULL- | -7
|
|
|
|
| 7 | !check failed | -7
|
|
|
|
| 4 | -!NULL- | -4
|
|
|
|
| 5 | !check failed | -5
|
|
|
|
| 6 | -!NULL- | -6
|
|
|
|
| | |
|
|
|
|
(7 rows)
|
|
|
|
|
2000-01-16 20:57:48 +01:00
|
|
|
--
|
|
|
|
-- Check inheritance of defaults and constraints
|
|
|
|
--
|
|
|
|
CREATE TABLE INSERT_CHILD (cx INT default 42,
|
|
|
|
cy INT CHECK (cy > x))
|
|
|
|
INHERITS (INSERT_TBL);
|
|
|
|
INSERT INTO INSERT_CHILD(x,z,cy) VALUES (7,-7,11);
|
|
|
|
INSERT INTO INSERT_CHILD(x,z,cy) VALUES (7,-7,6);
|
2004-06-10 19:56:03 +02:00
|
|
|
ERROR: new row for relation "insert_child" violates check constraint "insert_child_check"
|
2000-01-16 20:57:48 +01:00
|
|
|
INSERT INTO INSERT_CHILD(x,z,cy) VALUES (6,-7,7);
|
2004-06-10 19:56:03 +02:00
|
|
|
ERROR: new row for relation "insert_child" violates check constraint "insert_tbl_check"
|
2000-01-16 20:57:48 +01:00
|
|
|
INSERT INTO INSERT_CHILD(x,y,z,cy) VALUES (6,'check failed',-6,7);
|
2003-09-25 17:48:17 +02:00
|
|
|
ERROR: new row for relation "insert_child" violates check constraint "insert_con"
|
2000-01-16 20:57:48 +01:00
|
|
|
SELECT * FROM INSERT_CHILD;
|
|
|
|
x | y | z | cx | cy
|
|
|
|
---+--------+----+----+----
|
|
|
|
7 | -NULL- | -7 | 42 | 11
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
DROP TABLE INSERT_CHILD;
|
2000-01-05 18:32:18 +01:00
|
|
|
--
|
|
|
|
-- Check constraints on INSERT INTO
|
|
|
|
--
|
|
|
|
DELETE FROM INSERT_TBL;
|
2005-10-03 01:50:16 +02:00
|
|
|
ALTER SEQUENCE INSERT_SEQ RESTART WITH 4;
|
2000-01-05 18:32:18 +01:00
|
|
|
CREATE TABLE tmp (xd INT, yd TEXT, zd INT);
|
|
|
|
INSERT INTO tmp VALUES (null, 'Y', null);
|
|
|
|
INSERT INTO tmp VALUES (5, '!check failed', null);
|
|
|
|
INSERT INTO tmp VALUES (null, 'try again', null);
|
|
|
|
INSERT INTO INSERT_TBL(y) select yd from tmp;
|
|
|
|
SELECT '' AS three, * FROM INSERT_TBL;
|
|
|
|
three | x | y | z
|
|
|
|
-------+---+---------------+----
|
|
|
|
| 4 | Y | -4
|
|
|
|
| 5 | !check failed | -5
|
|
|
|
| 6 | try again | -6
|
1997-08-28 06:49:34 +02:00
|
|
|
(3 rows)
|
|
|
|
|
2000-01-05 18:32:18 +01:00
|
|
|
INSERT INTO INSERT_TBL SELECT * FROM tmp WHERE yd = 'try again';
|
|
|
|
INSERT INTO INSERT_TBL(y,z) SELECT yd, -7 FROM tmp WHERE yd = 'try again';
|
|
|
|
INSERT INTO INSERT_TBL(y,z) SELECT yd, -8 FROM tmp WHERE yd = 'try again';
|
2003-09-25 17:48:17 +02:00
|
|
|
ERROR: new row for relation "insert_tbl" violates check constraint "insert_con"
|
2000-01-05 18:32:18 +01:00
|
|
|
SELECT '' AS four, * FROM INSERT_TBL;
|
|
|
|
four | x | y | z
|
|
|
|
------+---+---------------+----
|
|
|
|
| 4 | Y | -4
|
|
|
|
| 5 | !check failed | -5
|
|
|
|
| 6 | try again | -6
|
2000-01-20 00:55:03 +01:00
|
|
|
| | try again |
|
2000-01-05 18:32:18 +01:00
|
|
|
| 7 | try again | -7
|
2000-01-20 00:55:03 +01:00
|
|
|
(5 rows)
|
1997-09-16 18:17:19 +02:00
|
|
|
|
2000-01-05 18:32:18 +01:00
|
|
|
DROP TABLE tmp;
|
|
|
|
--
|
|
|
|
-- Check constraints on UPDATE
|
|
|
|
--
|
2000-01-20 00:55:03 +01:00
|
|
|
UPDATE INSERT_TBL SET x = NULL WHERE x = 5;
|
2000-01-05 18:32:18 +01:00
|
|
|
UPDATE INSERT_TBL SET x = 6 WHERE x = 6;
|
|
|
|
UPDATE INSERT_TBL SET x = -z, z = -x;
|
|
|
|
UPDATE INSERT_TBL SET x = z, z = x;
|
2003-09-25 17:48:17 +02:00
|
|
|
ERROR: new row for relation "insert_tbl" violates check constraint "insert_con"
|
2000-01-05 18:32:18 +01:00
|
|
|
SELECT * FROM INSERT_TBL;
|
|
|
|
x | y | z
|
|
|
|
---+---------------+----
|
|
|
|
4 | Y | -4
|
2000-01-20 00:55:03 +01:00
|
|
|
| try again |
|
2000-01-05 18:32:18 +01:00
|
|
|
7 | try again | -7
|
2000-01-20 00:55:03 +01:00
|
|
|
5 | !check failed |
|
2000-01-05 18:32:18 +01:00
|
|
|
6 | try again | -6
|
2000-01-20 00:55:03 +01:00
|
|
|
(5 rows)
|
1997-09-16 18:17:19 +02:00
|
|
|
|
2000-01-05 18:32:18 +01:00
|
|
|
-- DROP TABLE INSERT_TBL;
|
|
|
|
--
|
|
|
|
-- Check constraints on COPY FROM
|
|
|
|
--
|
|
|
|
CREATE TABLE COPY_TBL (x INT, y TEXT, z INT,
|
1997-12-05 01:01:22 +01:00
|
|
|
CONSTRAINT COPY_CON
|
|
|
|
CHECK (x > 3 AND y <> 'check failed' AND x < 7 ));
|
2000-10-27 22:00:22 +02:00
|
|
|
COPY COPY_TBL FROM '@abs_srcdir@/data/constro.data';
|
2000-01-05 18:32:18 +01:00
|
|
|
SELECT '' AS two, * FROM COPY_TBL;
|
|
|
|
two | x | y | z
|
|
|
|
-----+---+---------------+---
|
|
|
|
| 4 | !check failed | 5
|
|
|
|
| 6 | OK | 4
|
1997-10-17 11:59:09 +02:00
|
|
|
(2 rows)
|
1997-08-28 06:49:34 +02:00
|
|
|
|
2000-10-27 22:00:22 +02:00
|
|
|
COPY COPY_TBL FROM '@abs_srcdir@/data/constrf.data';
|
2003-09-25 17:48:17 +02:00
|
|
|
ERROR: new row for relation "copy_tbl" violates check constraint "copy_con"
|
2003-09-30 00:06:40 +02:00
|
|
|
CONTEXT: COPY copy_tbl, line 2: "7 check failed 6"
|
2000-01-05 18:32:18 +01:00
|
|
|
SELECT * FROM COPY_TBL;
|
|
|
|
x | y | z
|
|
|
|
---+---------------+---
|
|
|
|
4 | !check failed | 5
|
|
|
|
6 | OK | 4
|
1997-10-17 11:59:09 +02:00
|
|
|
(2 rows)
|
1997-08-28 06:49:34 +02:00
|
|
|
|
2000-01-05 18:32:18 +01:00
|
|
|
--
|
|
|
|
-- Primary keys
|
|
|
|
--
|
|
|
|
CREATE TABLE PRIMARY_TBL (i int PRIMARY KEY, t text);
|
2003-07-19 22:20:53 +02:00
|
|
|
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "primary_tbl_pkey" for table "primary_tbl"
|
2000-01-05 18:32:18 +01:00
|
|
|
INSERT INTO PRIMARY_TBL VALUES (1, 'one');
|
|
|
|
INSERT INTO PRIMARY_TBL VALUES (2, 'two');
|
|
|
|
INSERT INTO PRIMARY_TBL VALUES (1, 'three');
|
2007-06-04 00:16:03 +02:00
|
|
|
ERROR: duplicate key value violates unique constraint "primary_tbl_pkey"
|
2009-08-01 21:59:41 +02:00
|
|
|
DETAIL: Key (i)=(1) already exists.
|
2000-01-05 18:32:18 +01:00
|
|
|
INSERT INTO PRIMARY_TBL VALUES (4, 'three');
|
|
|
|
INSERT INTO PRIMARY_TBL VALUES (5, 'one');
|
|
|
|
INSERT INTO PRIMARY_TBL (t) VALUES ('six');
|
2003-09-25 17:48:17 +02:00
|
|
|
ERROR: null value in column "i" violates not-null constraint
|
2000-01-05 18:32:18 +01:00
|
|
|
SELECT '' AS four, * FROM PRIMARY_TBL;
|
|
|
|
four | i | t
|
|
|
|
------+---+-------
|
|
|
|
| 1 | one
|
|
|
|
| 2 | two
|
|
|
|
| 4 | three
|
|
|
|
| 5 | one
|
1997-12-05 01:01:22 +01:00
|
|
|
(4 rows)
|
|
|
|
|
2000-01-05 18:32:18 +01:00
|
|
|
DROP TABLE PRIMARY_TBL;
|
|
|
|
CREATE TABLE PRIMARY_TBL (i int, t text,
|
|
|
|
PRIMARY KEY(i,t));
|
2003-07-19 22:20:53 +02:00
|
|
|
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "primary_tbl_pkey" for table "primary_tbl"
|
2000-01-05 18:32:18 +01:00
|
|
|
INSERT INTO PRIMARY_TBL VALUES (1, 'one');
|
|
|
|
INSERT INTO PRIMARY_TBL VALUES (2, 'two');
|
|
|
|
INSERT INTO PRIMARY_TBL VALUES (1, 'three');
|
|
|
|
INSERT INTO PRIMARY_TBL VALUES (4, 'three');
|
|
|
|
INSERT INTO PRIMARY_TBL VALUES (5, 'one');
|
|
|
|
INSERT INTO PRIMARY_TBL (t) VALUES ('six');
|
2003-09-25 17:48:17 +02:00
|
|
|
ERROR: null value in column "i" violates not-null constraint
|
2000-01-05 18:32:18 +01:00
|
|
|
SELECT '' AS three, * FROM PRIMARY_TBL;
|
|
|
|
three | i | t
|
|
|
|
-------+---+-------
|
|
|
|
| 1 | one
|
|
|
|
| 2 | two
|
|
|
|
| 1 | three
|
|
|
|
| 4 | three
|
|
|
|
| 5 | one
|
1997-12-05 01:01:22 +01:00
|
|
|
(5 rows)
|
|
|
|
|
2000-01-05 18:32:18 +01:00
|
|
|
DROP TABLE PRIMARY_TBL;
|
|
|
|
--
|
|
|
|
-- Unique keys
|
|
|
|
--
|
|
|
|
CREATE TABLE UNIQUE_TBL (i int UNIQUE, t text);
|
2003-07-19 22:20:53 +02:00
|
|
|
NOTICE: CREATE TABLE / UNIQUE will create implicit index "unique_tbl_i_key" for table "unique_tbl"
|
2000-01-05 18:32:18 +01:00
|
|
|
INSERT INTO UNIQUE_TBL VALUES (1, 'one');
|
|
|
|
INSERT INTO UNIQUE_TBL VALUES (2, 'two');
|
|
|
|
INSERT INTO UNIQUE_TBL VALUES (1, 'three');
|
2007-06-04 00:16:03 +02:00
|
|
|
ERROR: duplicate key value violates unique constraint "unique_tbl_i_key"
|
2009-08-01 21:59:41 +02:00
|
|
|
DETAIL: Key (i)=(1) already exists.
|
2000-01-05 18:32:18 +01:00
|
|
|
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');
|
|
|
|
SELECT '' AS five, * FROM UNIQUE_TBL;
|
|
|
|
five | i | t
|
|
|
|
------+---+-------
|
|
|
|
| 1 | one
|
|
|
|
| 2 | two
|
|
|
|
| 4 | four
|
|
|
|
| 5 | one
|
|
|
|
| | six
|
|
|
|
| | seven
|
1997-12-05 01:01:22 +01:00
|
|
|
(6 rows)
|
|
|
|
|
2000-01-05 18:32:18 +01:00
|
|
|
DROP TABLE UNIQUE_TBL;
|
|
|
|
CREATE TABLE UNIQUE_TBL (i int, t text,
|
|
|
|
UNIQUE(i,t));
|
Adjust naming of indexes and their columns per recent discussion.
Index expression columns are now named after the FigureColname result for
their expressions, rather than always being "pg_expression_N". Digits are
appended to this name if needed to make the column name unique within the
index. (That happens for regular columns too, thus fixing the old problem
that CREATE INDEX fooi ON foo (f1, f1) fails. Before exclusion indexes
there was no real reason to do such a thing, but now maybe there is.)
Default names for indexes and associated constraints now include the column
names of all their columns, not only the first one as in previous practice.
(Of course, this will be truncated as needed to fit in NAMEDATALEN. Also,
pkey indexes retain the historical behavior of not naming specific columns
at all.)
An example of the results:
regression=# create table foo (f1 int, f2 text,
regression(# exclude (f1 with =, lower(f2) with =));
NOTICE: CREATE TABLE / EXCLUDE will create implicit index "foo_f1_lower_exclusion" for table "foo"
CREATE TABLE
regression=# \d foo_f1_lower_exclusion
Index "public.foo_f1_lower_exclusion"
Column | Type | Definition
--------+---------+------------
f1 | integer | f1
lower | text | lower(f2)
btree, for table "public.foo"
2009-12-23 03:35:25 +01:00
|
|
|
NOTICE: CREATE TABLE / UNIQUE will create implicit index "unique_tbl_i_t_key" for table "unique_tbl"
|
2000-01-05 18:32:18 +01:00
|
|
|
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, 'one');
|
Adjust naming of indexes and their columns per recent discussion.
Index expression columns are now named after the FigureColname result for
their expressions, rather than always being "pg_expression_N". Digits are
appended to this name if needed to make the column name unique within the
index. (That happens for regular columns too, thus fixing the old problem
that CREATE INDEX fooi ON foo (f1, f1) fails. Before exclusion indexes
there was no real reason to do such a thing, but now maybe there is.)
Default names for indexes and associated constraints now include the column
names of all their columns, not only the first one as in previous practice.
(Of course, this will be truncated as needed to fit in NAMEDATALEN. Also,
pkey indexes retain the historical behavior of not naming specific columns
at all.)
An example of the results:
regression=# create table foo (f1 int, f2 text,
regression(# exclude (f1 with =, lower(f2) with =));
NOTICE: CREATE TABLE / EXCLUDE will create implicit index "foo_f1_lower_exclusion" for table "foo"
CREATE TABLE
regression=# \d foo_f1_lower_exclusion
Index "public.foo_f1_lower_exclusion"
Column | Type | Definition
--------+---------+------------
f1 | integer | f1
lower | text | lower(f2)
btree, for table "public.foo"
2009-12-23 03:35:25 +01:00
|
|
|
ERROR: duplicate key value violates unique constraint "unique_tbl_i_t_key"
|
2009-08-01 21:59:41 +02:00
|
|
|
DETAIL: Key (i, t)=(1, one) already exists.
|
2000-01-05 18:32:18 +01:00
|
|
|
INSERT INTO UNIQUE_TBL VALUES (5, 'one');
|
|
|
|
INSERT INTO UNIQUE_TBL (t) VALUES ('six');
|
|
|
|
SELECT '' AS five, * FROM UNIQUE_TBL;
|
|
|
|
five | i | t
|
|
|
|
------+---+-------
|
|
|
|
| 1 | one
|
|
|
|
| 2 | two
|
|
|
|
| 1 | three
|
|
|
|
| 5 | one
|
|
|
|
| | six
|
1997-12-05 01:01:22 +01:00
|
|
|
(5 rows)
|
|
|
|
|
2000-01-05 18:32:18 +01:00
|
|
|
DROP TABLE UNIQUE_TBL;
|
2009-07-29 22:56:21 +02:00
|
|
|
--
|
|
|
|
-- Deferrable unique constraints
|
|
|
|
--
|
|
|
|
CREATE TABLE unique_tbl (i int UNIQUE DEFERRABLE, t text);
|
|
|
|
NOTICE: CREATE TABLE / UNIQUE will create implicit index "unique_tbl_i_key" for table "unique_tbl"
|
|
|
|
INSERT INTO unique_tbl VALUES (0, 'one');
|
|
|
|
INSERT INTO unique_tbl VALUES (1, 'two');
|
|
|
|
INSERT INTO unique_tbl VALUES (2, 'tree');
|
|
|
|
INSERT INTO unique_tbl VALUES (3, 'four');
|
|
|
|
INSERT INTO unique_tbl VALUES (4, 'five');
|
|
|
|
BEGIN;
|
|
|
|
-- default is immediate so this should fail right away
|
|
|
|
UPDATE unique_tbl SET i = 1 WHERE i = 0;
|
|
|
|
ERROR: duplicate key value violates unique constraint "unique_tbl_i_key"
|
2009-08-01 21:59:41 +02:00
|
|
|
DETAIL: Key (i)=(1) already exists.
|
2009-07-29 22:56:21 +02:00
|
|
|
ROLLBACK;
|
|
|
|
-- check is done at end of statement, so this should succeed
|
|
|
|
UPDATE unique_tbl SET i = i+1;
|
|
|
|
SELECT * FROM unique_tbl;
|
|
|
|
i | t
|
|
|
|
---+------
|
|
|
|
1 | one
|
|
|
|
2 | two
|
|
|
|
3 | tree
|
|
|
|
4 | four
|
|
|
|
5 | five
|
|
|
|
(5 rows)
|
|
|
|
|
|
|
|
-- explicitly defer the constraint
|
|
|
|
BEGIN;
|
|
|
|
SET CONSTRAINTS unique_tbl_i_key DEFERRED;
|
|
|
|
INSERT INTO unique_tbl VALUES (3, 'three');
|
|
|
|
DELETE FROM unique_tbl WHERE t = 'tree'; -- makes constraint valid again
|
|
|
|
COMMIT; -- should succeed
|
|
|
|
SELECT * FROM unique_tbl;
|
|
|
|
i | t
|
|
|
|
---+-------
|
|
|
|
1 | one
|
|
|
|
2 | two
|
|
|
|
4 | four
|
|
|
|
5 | five
|
|
|
|
3 | three
|
|
|
|
(5 rows)
|
|
|
|
|
|
|
|
-- try adding an initially deferred constraint
|
|
|
|
ALTER TABLE unique_tbl DROP CONSTRAINT unique_tbl_i_key;
|
|
|
|
ALTER TABLE unique_tbl ADD CONSTRAINT unique_tbl_i_key
|
|
|
|
UNIQUE (i) DEFERRABLE INITIALLY DEFERRED;
|
|
|
|
NOTICE: ALTER TABLE / ADD UNIQUE will create implicit index "unique_tbl_i_key" for table "unique_tbl"
|
|
|
|
BEGIN;
|
|
|
|
INSERT INTO unique_tbl VALUES (1, 'five');
|
|
|
|
INSERT INTO unique_tbl VALUES (5, 'one');
|
|
|
|
UPDATE unique_tbl SET i = 4 WHERE i = 2;
|
|
|
|
UPDATE unique_tbl SET i = 2 WHERE i = 4 AND t = 'four';
|
|
|
|
DELETE FROM unique_tbl WHERE i = 1 AND t = 'one';
|
|
|
|
DELETE FROM unique_tbl WHERE i = 5 AND t = 'five';
|
|
|
|
COMMIT;
|
|
|
|
SELECT * FROM unique_tbl;
|
|
|
|
i | t
|
|
|
|
---+-------
|
|
|
|
3 | three
|
|
|
|
1 | five
|
|
|
|
5 | one
|
|
|
|
4 | two
|
|
|
|
2 | four
|
|
|
|
(5 rows)
|
|
|
|
|
|
|
|
-- should fail at commit-time
|
|
|
|
BEGIN;
|
|
|
|
INSERT INTO unique_tbl VALUES (3, 'Three'); -- should succeed for now
|
|
|
|
COMMIT; -- should fail
|
|
|
|
ERROR: duplicate key value violates unique constraint "unique_tbl_i_key"
|
2009-08-01 21:59:41 +02:00
|
|
|
DETAIL: Key (i)=(3) already exists.
|
2009-07-29 22:56:21 +02:00
|
|
|
-- make constraint check immediate
|
|
|
|
BEGIN;
|
|
|
|
SET CONSTRAINTS ALL IMMEDIATE;
|
|
|
|
INSERT INTO unique_tbl VALUES (3, 'Three'); -- should fail
|
|
|
|
ERROR: duplicate key value violates unique constraint "unique_tbl_i_key"
|
2009-08-01 21:59:41 +02:00
|
|
|
DETAIL: Key (i)=(3) already exists.
|
2009-07-29 22:56:21 +02:00
|
|
|
COMMIT;
|
|
|
|
-- forced check when SET CONSTRAINTS is called
|
|
|
|
BEGIN;
|
|
|
|
SET CONSTRAINTS ALL DEFERRED;
|
|
|
|
INSERT INTO unique_tbl VALUES (3, 'Three'); -- should succeed for now
|
|
|
|
SET CONSTRAINTS ALL IMMEDIATE; -- should fail
|
|
|
|
ERROR: duplicate key value violates unique constraint "unique_tbl_i_key"
|
2009-08-01 21:59:41 +02:00
|
|
|
DETAIL: Key (i)=(3) already exists.
|
2009-07-29 22:56:21 +02:00
|
|
|
COMMIT;
|
|
|
|
-- test a HOT update that invalidates the conflicting tuple.
|
|
|
|
-- the trigger should still fire and catch the violation
|
|
|
|
BEGIN;
|
|
|
|
INSERT INTO unique_tbl VALUES (3, 'Three'); -- should succeed for now
|
|
|
|
UPDATE unique_tbl SET t = 'THREE' WHERE i = 3 AND t = 'Three';
|
|
|
|
COMMIT; -- should fail
|
|
|
|
ERROR: duplicate key value violates unique constraint "unique_tbl_i_key"
|
2009-08-01 21:59:41 +02:00
|
|
|
DETAIL: Key (i)=(3) already exists.
|
2009-07-29 22:56:21 +02:00
|
|
|
SELECT * FROM unique_tbl;
|
|
|
|
i | t
|
|
|
|
---+-------
|
|
|
|
3 | three
|
|
|
|
1 | five
|
|
|
|
5 | one
|
|
|
|
4 | two
|
|
|
|
2 | four
|
|
|
|
(5 rows)
|
|
|
|
|
|
|
|
-- test a HOT update that modifies the newly inserted tuple,
|
|
|
|
-- but should succeed because we then remove the other conflicting tuple.
|
|
|
|
BEGIN;
|
|
|
|
INSERT INTO unique_tbl VALUES(3, 'tree'); -- should succeed for now
|
|
|
|
UPDATE unique_tbl SET t = 'threex' WHERE t = 'tree';
|
|
|
|
DELETE FROM unique_tbl WHERE t = 'three';
|
|
|
|
SELECT * FROM unique_tbl;
|
|
|
|
i | t
|
|
|
|
---+--------
|
|
|
|
1 | five
|
|
|
|
5 | one
|
|
|
|
4 | two
|
|
|
|
2 | four
|
|
|
|
3 | threex
|
|
|
|
(5 rows)
|
|
|
|
|
|
|
|
COMMIT;
|
|
|
|
SELECT * FROM unique_tbl;
|
|
|
|
i | t
|
|
|
|
---+--------
|
|
|
|
1 | five
|
|
|
|
5 | one
|
|
|
|
4 | two
|
|
|
|
2 | four
|
|
|
|
3 | threex
|
|
|
|
(5 rows)
|
|
|
|
|
|
|
|
DROP TABLE unique_tbl;
|
2009-12-07 06:22:23 +01:00
|
|
|
--
|
|
|
|
-- EXCLUDE constraints
|
|
|
|
--
|
|
|
|
CREATE TABLE circles (
|
|
|
|
c1 CIRCLE,
|
|
|
|
c2 TEXT,
|
|
|
|
EXCLUDE USING gist
|
2010-01-02 18:53:57 +01:00
|
|
|
(c1 WITH &&, (c2::circle) WITH &&)
|
2009-12-07 06:22:23 +01:00
|
|
|
WHERE (circle_center(c1) <> '(0,0)')
|
|
|
|
);
|
2010-03-22 18:43:28 +01:00
|
|
|
NOTICE: CREATE TABLE / EXCLUDE will create implicit index "circles_c1_c2_excl" for table "circles"
|
2009-12-07 06:22:23 +01:00
|
|
|
-- these should succeed because they don't match the index predicate
|
|
|
|
INSERT INTO circles VALUES('<(0,0), 5>', '<(0,0), 5>');
|
2010-01-02 18:53:57 +01:00
|
|
|
INSERT INTO circles VALUES('<(0,0), 5>', '<(0,0), 4>');
|
2009-12-07 06:22:23 +01:00
|
|
|
-- succeed
|
|
|
|
INSERT INTO circles VALUES('<(10,10), 10>', '<(0,0), 5>');
|
|
|
|
-- fail, overlaps
|
2010-01-02 18:53:57 +01:00
|
|
|
INSERT INTO circles VALUES('<(20,20), 10>', '<(0,0), 4>');
|
2010-03-22 18:43:28 +01:00
|
|
|
ERROR: conflicting key value violates exclusion constraint "circles_c1_c2_excl"
|
2010-01-02 18:53:57 +01:00
|
|
|
DETAIL: Key (c1, (c2::circle))=(<(20,20),10>, <(0,0),4>) conflicts with existing key (c1, (c2::circle))=(<(10,10),10>, <(0,0),5>).
|
2009-12-07 06:22:23 +01:00
|
|
|
-- succeed because c1 doesn't overlap
|
|
|
|
INSERT INTO circles VALUES('<(20,20), 1>', '<(0,0), 5>');
|
2010-01-02 18:53:57 +01:00
|
|
|
-- succeed because c2 doesn't overlap
|
|
|
|
INSERT INTO circles VALUES('<(20,20), 10>', '<(10,10), 5>');
|
2009-12-07 06:22:23 +01:00
|
|
|
-- should fail on existing data without the WHERE clause
|
|
|
|
ALTER TABLE circles ADD EXCLUDE USING gist
|
2010-01-02 18:53:57 +01:00
|
|
|
(c1 WITH &&, (c2::circle) WITH &&);
|
2010-03-22 18:43:28 +01:00
|
|
|
NOTICE: ALTER TABLE / ADD EXCLUDE will create implicit index "circles_c1_c2_excl1" for table "circles"
|
|
|
|
ERROR: could not create exclusion constraint "circles_c1_c2_excl1"
|
2010-01-02 18:53:57 +01:00
|
|
|
DETAIL: Key (c1, (c2::circle))=(<(0,0),5>, <(0,0),5>) conflicts with key (c1, (c2::circle))=(<(0,0),5>, <(0,0),4>).
|
2011-06-06 04:30:04 +02:00
|
|
|
-- try reindexing an existing constraint
|
|
|
|
REINDEX INDEX circles_c1_c2_excl;
|
2009-12-07 06:22:23 +01:00
|
|
|
DROP TABLE circles;
|
|
|
|
-- Check deferred exclusion constraint
|
|
|
|
CREATE TABLE deferred_excl (
|
|
|
|
f1 int,
|
|
|
|
CONSTRAINT deferred_excl_con EXCLUDE (f1 WITH =) INITIALLY DEFERRED
|
|
|
|
);
|
|
|
|
NOTICE: CREATE TABLE / EXCLUDE will create implicit index "deferred_excl_con" for table "deferred_excl"
|
|
|
|
INSERT INTO deferred_excl VALUES(1);
|
|
|
|
INSERT INTO deferred_excl VALUES(2);
|
|
|
|
INSERT INTO deferred_excl VALUES(1); -- fail
|
|
|
|
ERROR: conflicting key value violates exclusion constraint "deferred_excl_con"
|
|
|
|
DETAIL: Key (f1)=(1) conflicts with existing key (f1)=(1).
|
|
|
|
BEGIN;
|
|
|
|
INSERT INTO deferred_excl VALUES(2); -- no fail here
|
|
|
|
COMMIT; -- should fail here
|
|
|
|
ERROR: conflicting key value violates exclusion constraint "deferred_excl_con"
|
|
|
|
DETAIL: Key (f1)=(2) conflicts with existing key (f1)=(2).
|
|
|
|
BEGIN;
|
|
|
|
INSERT INTO deferred_excl VALUES(3);
|
|
|
|
INSERT INTO deferred_excl VALUES(3); -- no fail here
|
|
|
|
COMMIT; -- should fail here
|
|
|
|
ERROR: conflicting key value violates exclusion constraint "deferred_excl_con"
|
|
|
|
DETAIL: Key (f1)=(3) conflicts with existing key (f1)=(3).
|
|
|
|
ALTER TABLE deferred_excl DROP CONSTRAINT deferred_excl_con;
|
|
|
|
-- This should fail, but worth testing because of HOT updates
|
|
|
|
UPDATE deferred_excl SET f1 = 3;
|
|
|
|
ALTER TABLE deferred_excl ADD EXCLUDE (f1 WITH =);
|
2010-03-22 18:43:28 +01:00
|
|
|
NOTICE: ALTER TABLE / ADD EXCLUDE will create implicit index "deferred_excl_f1_excl" for table "deferred_excl"
|
|
|
|
ERROR: could not create exclusion constraint "deferred_excl_f1_excl"
|
2009-12-07 06:22:23 +01:00
|
|
|
DETAIL: Key (f1)=(3) conflicts with key (f1)=(3).
|
|
|
|
DROP TABLE deferred_excl;
|