mirror of
https://github.com/postgres/postgres.git
synced 2026-02-19 02:29:10 -05:00
I believe this should fix the issue that Philip Warner noticed about the check for unique constraints meeting the referenced keys of a foreign key constraint allowing the specification of a subset of a foreign key instead of rejecting it. I also added tests for a base case of this to the foreign key and alter table tests and patches for expected output.
427 lines
12 KiB
SQL
427 lines
12 KiB
SQL
--
|
|
-- FOREIGN KEY
|
|
--
|
|
|
|
-- MATCH FULL
|
|
--
|
|
-- First test, check and cascade
|
|
--
|
|
CREATE TABLE PKTABLE ( ptest1 int PRIMARY KEY, ptest2 text );
|
|
CREATE TABLE FKTABLE ( ftest1 int REFERENCES PKTABLE MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, ftest2 int );
|
|
|
|
-- Insert test data into PKTABLE
|
|
INSERT INTO PKTABLE VALUES (1, 'Test1');
|
|
INSERT INTO PKTABLE VALUES (2, 'Test2');
|
|
INSERT INTO PKTABLE VALUES (3, 'Test3');
|
|
INSERT INTO PKTABLE VALUES (4, 'Test4');
|
|
INSERT INTO PKTABLE VALUES (5, 'Test5');
|
|
|
|
-- Insert successful rows into FK TABLE
|
|
INSERT INTO FKTABLE VALUES (1, 2);
|
|
INSERT INTO FKTABLE VALUES (2, 3);
|
|
INSERT INTO FKTABLE VALUES (3, 4);
|
|
INSERT INTO FKTABLE VALUES (NULL, 1);
|
|
|
|
-- Insert a failed row into FK TABLE
|
|
INSERT INTO FKTABLE VALUES (100, 2);
|
|
|
|
-- Check FKTABLE
|
|
SELECT * FROM FKTABLE;
|
|
|
|
-- Delete a row from PK TABLE
|
|
DELETE FROM PKTABLE WHERE ptest1=1;
|
|
|
|
-- Check FKTABLE for removal of matched row
|
|
SELECT * FROM FKTABLE;
|
|
|
|
-- Update a row from PK TABLE
|
|
UPDATE PKTABLE SET ptest1=1 WHERE ptest1=2;
|
|
|
|
-- Check FKTABLE for update of matched row
|
|
SELECT * FROM FKTABLE;
|
|
|
|
DROP TABLE PKTABLE;
|
|
DROP TABLE FKTABLE;
|
|
|
|
--
|
|
-- check set NULL and table constraint on multiple columns
|
|
--
|
|
CREATE TABLE PKTABLE ( ptest1 int, ptest2 int, ptest3 text, PRIMARY KEY(ptest1, ptest2) );
|
|
CREATE TABLE FKTABLE ( ftest1 int, ftest2 int, ftest3 int, CONSTRAINT constrname FOREIGN KEY(ftest1, ftest2)
|
|
REFERENCES PKTABLE MATCH FULL ON DELETE SET NULL ON UPDATE SET NULL);
|
|
|
|
-- Insert test data into PKTABLE
|
|
INSERT INTO PKTABLE VALUES (1, 2, 'Test1');
|
|
INSERT INTO PKTABLE VALUES (1, 3, 'Test1-2');
|
|
INSERT INTO PKTABLE VALUES (2, 4, 'Test2');
|
|
INSERT INTO PKTABLE VALUES (3, 6, 'Test3');
|
|
INSERT INTO PKTABLE VALUES (4, 8, 'Test4');
|
|
INSERT INTO PKTABLE VALUES (5, 10, 'Test5');
|
|
|
|
-- Insert successful rows into FK TABLE
|
|
INSERT INTO FKTABLE VALUES (1, 2, 4);
|
|
INSERT INTO FKTABLE VALUES (1, 3, 5);
|
|
INSERT INTO FKTABLE VALUES (2, 4, 8);
|
|
INSERT INTO FKTABLE VALUES (3, 6, 12);
|
|
INSERT INTO FKTABLE VALUES (NULL, NULL, 0);
|
|
|
|
-- Insert failed rows into FK TABLE
|
|
INSERT INTO FKTABLE VALUES (100, 2, 4);
|
|
INSERT INTO FKTABLE VALUES (2, 2, 4);
|
|
INSERT INTO FKTABLE VALUES (NULL, 2, 4);
|
|
INSERT INTO FKTABLE VALUES (1, NULL, 4);
|
|
|
|
-- Check FKTABLE
|
|
SELECT * FROM FKTABLE;
|
|
|
|
-- Delete a row from PK TABLE
|
|
DELETE FROM PKTABLE WHERE ptest1=1 and ptest2=2;
|
|
|
|
-- Check FKTABLE for removal of matched row
|
|
SELECT * FROM FKTABLE;
|
|
|
|
-- Delete another row from PK TABLE
|
|
DELETE FROM PKTABLE WHERE ptest1=5 and ptest2=10;
|
|
|
|
-- Check FKTABLE (should be no change)
|
|
SELECT * FROM FKTABLE;
|
|
|
|
-- Update a row from PK TABLE
|
|
UPDATE PKTABLE SET ptest1=1 WHERE ptest1=2;
|
|
|
|
-- Check FKTABLE for update of matched row
|
|
SELECT * FROM FKTABLE;
|
|
|
|
DROP TABLE PKTABLE;
|
|
DROP TABLE FKTABLE;
|
|
|
|
--
|
|
-- check set default and table constraint on multiple columns
|
|
--
|
|
CREATE TABLE PKTABLE ( ptest1 int, ptest2 int, ptest3 text, PRIMARY KEY(ptest1, ptest2) );
|
|
CREATE TABLE FKTABLE ( ftest1 int DEFAULT -1, ftest2 int DEFAULT -2, ftest3 int, CONSTRAINT constrname2 FOREIGN KEY(ftest1, ftest2)
|
|
REFERENCES PKTABLE MATCH FULL ON DELETE SET DEFAULT ON UPDATE SET DEFAULT);
|
|
|
|
-- Insert a value in PKTABLE for default
|
|
INSERT INTO PKTABLE VALUES (-1, -2, 'The Default!');
|
|
|
|
-- Insert test data into PKTABLE
|
|
INSERT INTO PKTABLE VALUES (1, 2, 'Test1');
|
|
INSERT INTO PKTABLE VALUES (1, 3, 'Test1-2');
|
|
INSERT INTO PKTABLE VALUES (2, 4, 'Test2');
|
|
INSERT INTO PKTABLE VALUES (3, 6, 'Test3');
|
|
INSERT INTO PKTABLE VALUES (4, 8, 'Test4');
|
|
INSERT INTO PKTABLE VALUES (5, 10, 'Test5');
|
|
|
|
-- Insert successful rows into FK TABLE
|
|
INSERT INTO FKTABLE VALUES (1, 2, 4);
|
|
INSERT INTO FKTABLE VALUES (1, 3, 5);
|
|
INSERT INTO FKTABLE VALUES (2, 4, 8);
|
|
INSERT INTO FKTABLE VALUES (3, 6, 12);
|
|
INSERT INTO FKTABLE VALUES (NULL, NULL, 0);
|
|
|
|
-- Insert failed rows into FK TABLE
|
|
INSERT INTO FKTABLE VALUES (100, 2, 4);
|
|
INSERT INTO FKTABLE VALUES (2, 2, 4);
|
|
INSERT INTO FKTABLE VALUES (NULL, 2, 4);
|
|
INSERT INTO FKTABLE VALUES (1, NULL, 4);
|
|
|
|
-- Check FKTABLE
|
|
SELECT * FROM FKTABLE;
|
|
|
|
-- Delete a row from PK TABLE
|
|
DELETE FROM PKTABLE WHERE ptest1=1 and ptest2=2;
|
|
|
|
-- Check FKTABLE to check for removal
|
|
SELECT * FROM FKTABLE;
|
|
|
|
-- Delete another row from PK TABLE
|
|
DELETE FROM PKTABLE WHERE ptest1=5 and ptest2=10;
|
|
|
|
-- Check FKTABLE (should be no change)
|
|
SELECT * FROM FKTABLE;
|
|
|
|
-- Update a row from PK TABLE
|
|
UPDATE PKTABLE SET ptest1=1 WHERE ptest1=2;
|
|
|
|
-- Check FKTABLE for update of matched row
|
|
SELECT * FROM FKTABLE;
|
|
|
|
DROP TABLE PKTABLE;
|
|
DROP TABLE FKTABLE;
|
|
|
|
|
|
--
|
|
-- First test, check with no on delete or on update
|
|
--
|
|
CREATE TABLE PKTABLE ( ptest1 int PRIMARY KEY, ptest2 text );
|
|
CREATE TABLE FKTABLE ( ftest1 int REFERENCES PKTABLE MATCH FULL, ftest2 int );
|
|
|
|
-- Insert test data into PKTABLE
|
|
INSERT INTO PKTABLE VALUES (1, 'Test1');
|
|
INSERT INTO PKTABLE VALUES (2, 'Test2');
|
|
INSERT INTO PKTABLE VALUES (3, 'Test3');
|
|
INSERT INTO PKTABLE VALUES (4, 'Test4');
|
|
INSERT INTO PKTABLE VALUES (5, 'Test5');
|
|
|
|
-- Insert successful rows into FK TABLE
|
|
INSERT INTO FKTABLE VALUES (1, 2);
|
|
INSERT INTO FKTABLE VALUES (2, 3);
|
|
INSERT INTO FKTABLE VALUES (3, 4);
|
|
INSERT INTO FKTABLE VALUES (NULL, 1);
|
|
|
|
-- Insert a failed row into FK TABLE
|
|
INSERT INTO FKTABLE VALUES (100, 2);
|
|
|
|
-- Check FKTABLE
|
|
SELECT * FROM FKTABLE;
|
|
|
|
-- Check PKTABLE
|
|
SELECT * FROM PKTABLE;
|
|
|
|
-- Delete a row from PK TABLE (should fail)
|
|
DELETE FROM PKTABLE WHERE ptest1=1;
|
|
|
|
-- Delete a row from PK TABLE (should succeed)
|
|
DELETE FROM PKTABLE WHERE ptest1=5;
|
|
|
|
-- Check PKTABLE for deletes
|
|
SELECT * FROM PKTABLE;
|
|
|
|
-- Update a row from PK TABLE (should fail)
|
|
UPDATE PKTABLE SET ptest1=0 WHERE ptest1=2;
|
|
|
|
-- Update a row from PK TABLE (should succeed)
|
|
UPDATE PKTABLE SET ptest1=0 WHERE ptest1=4;
|
|
|
|
-- Check PKTABLE for updates
|
|
SELECT * FROM PKTABLE;
|
|
|
|
DROP TABLE PKTABLE;
|
|
DROP TABLE FKTABLE;
|
|
|
|
|
|
-- MATCH unspecified
|
|
|
|
-- Base test restricting update/delete
|
|
CREATE TABLE PKTABLE ( ptest1 int, ptest2 int, ptest3 int, ptest4 text, PRIMARY KEY(ptest1, ptest2, ptest3) );
|
|
CREATE TABLE FKTABLE ( ftest1 int, ftest2 int, ftest3 int, ftest4 int, CONSTRAINT constrname3
|
|
FOREIGN KEY(ftest1, ftest2, ftest3) REFERENCES PKTABLE);
|
|
|
|
-- Insert Primary Key values
|
|
INSERT INTO PKTABLE VALUES (1, 2, 3, 'test1');
|
|
INSERT INTO PKTABLE VALUES (1, 3, 3, 'test2');
|
|
INSERT INTO PKTABLE VALUES (2, 3, 4, 'test3');
|
|
INSERT INTO PKTABLE VALUES (2, 4, 5, 'test4');
|
|
|
|
-- Insert Foreign Key values
|
|
INSERT INTO FKTABLE VALUES (1, 2, 3, 1);
|
|
INSERT INTO FKTABLE VALUES (NULL, 2, 3, 2);
|
|
INSERT INTO FKTABLE VALUES (2, NULL, 3, 3);
|
|
INSERT INTO FKTABLE VALUES (NULL, 2, 7, 4);
|
|
INSERT INTO FKTABLE VALUES (NULL, 3, 4, 5);
|
|
|
|
-- Insert a failed values
|
|
INSERT INTO FKTABLE VALUES (1, 2, 7, 6);
|
|
|
|
-- Show FKTABLE
|
|
SELECT * from FKTABLE;
|
|
|
|
-- Try to update something that should fail
|
|
UPDATE PKTABLE set ptest2=5 where ptest2=2;
|
|
|
|
-- Try to update something that should succeed
|
|
UPDATE PKTABLE set ptest1=1 WHERE ptest2=3;
|
|
|
|
-- Try to delete something that should fail
|
|
DELETE FROM PKTABLE where ptest1=1 and ptest2=2 and ptest3=3;
|
|
|
|
-- Try to delete something that should work
|
|
DELETE FROM PKTABLE where ptest1=2;
|
|
|
|
-- Show PKTABLE and FKTABLE
|
|
SELECT * from PKTABLE;
|
|
|
|
SELECT * from FKTABLE;
|
|
|
|
DROP TABLE FKTABLE;
|
|
DROP TABLE PKTABLE;
|
|
|
|
-- cascade update/delete
|
|
CREATE TABLE PKTABLE ( ptest1 int, ptest2 int, ptest3 int, ptest4 text, PRIMARY KEY(ptest1, ptest2, ptest3) );
|
|
CREATE TABLE FKTABLE ( ftest1 int, ftest2 int, ftest3 int, ftest4 int, CONSTRAINT constrname3
|
|
FOREIGN KEY(ftest1, ftest2, ftest3) REFERENCES PKTABLE
|
|
ON DELETE CASCADE ON UPDATE CASCADE);
|
|
|
|
-- Insert Primary Key values
|
|
INSERT INTO PKTABLE VALUES (1, 2, 3, 'test1');
|
|
INSERT INTO PKTABLE VALUES (1, 3, 3, 'test2');
|
|
INSERT INTO PKTABLE VALUES (2, 3, 4, 'test3');
|
|
INSERT INTO PKTABLE VALUES (2, 4, 5, 'test4');
|
|
|
|
-- Insert Foreign Key values
|
|
INSERT INTO FKTABLE VALUES (1, 2, 3, 1);
|
|
INSERT INTO FKTABLE VALUES (NULL, 2, 3, 2);
|
|
INSERT INTO FKTABLE VALUES (2, NULL, 3, 3);
|
|
INSERT INTO FKTABLE VALUES (NULL, 2, 7, 4);
|
|
INSERT INTO FKTABLE VALUES (NULL, 3, 4, 5);
|
|
|
|
-- Insert a failed values
|
|
INSERT INTO FKTABLE VALUES (1, 2, 7, 6);
|
|
|
|
-- Show FKTABLE
|
|
SELECT * from FKTABLE;
|
|
|
|
-- Try to update something that will cascade
|
|
UPDATE PKTABLE set ptest2=5 where ptest2=2;
|
|
|
|
-- Try to update something that should not cascade
|
|
UPDATE PKTABLE set ptest1=1 WHERE ptest2=3;
|
|
|
|
-- Show PKTABLE and FKTABLE
|
|
SELECT * from PKTABLE;
|
|
SELECT * from FKTABLE;
|
|
|
|
-- Try to delete something that should cascade
|
|
DELETE FROM PKTABLE where ptest1=1 and ptest2=5 and ptest3=3;
|
|
|
|
-- Show PKTABLE and FKTABLE
|
|
SELECT * from PKTABLE;
|
|
SELECT * from FKTABLE;
|
|
|
|
-- Try to delete something that should not have a cascade
|
|
DELETE FROM PKTABLE where ptest1=2;
|
|
|
|
-- Show PKTABLE and FKTABLE
|
|
SELECT * from PKTABLE;
|
|
SELECT * from FKTABLE;
|
|
|
|
DROP TABLE FKTABLE;
|
|
DROP TABLE PKTABLE;
|
|
|
|
-- set null update / set default delete
|
|
CREATE TABLE PKTABLE ( ptest1 int, ptest2 int, ptest3 int, ptest4 text, PRIMARY KEY(ptest1, ptest2, ptest3) );
|
|
CREATE TABLE FKTABLE ( ftest1 int DEFAULT 0, ftest2 int, ftest3 int, ftest4 int, CONSTRAINT constrname3
|
|
FOREIGN KEY(ftest1, ftest2, ftest3) REFERENCES PKTABLE
|
|
ON DELETE SET DEFAULT ON UPDATE SET NULL);
|
|
|
|
-- Insert Primary Key values
|
|
INSERT INTO PKTABLE VALUES (1, 2, 3, 'test1');
|
|
INSERT INTO PKTABLE VALUES (1, 3, 3, 'test2');
|
|
INSERT INTO PKTABLE VALUES (2, 3, 4, 'test3');
|
|
INSERT INTO PKTABLE VALUES (2, 4, 5, 'test4');
|
|
|
|
-- Insert Foreign Key values
|
|
INSERT INTO FKTABLE VALUES (1, 2, 3, 1);
|
|
INSERT INTO FKTABLE VALUES (2, 3, 4, 1);
|
|
INSERT INTO FKTABLE VALUES (NULL, 2, 3, 2);
|
|
INSERT INTO FKTABLE VALUES (2, NULL, 3, 3);
|
|
INSERT INTO FKTABLE VALUES (NULL, 2, 7, 4);
|
|
INSERT INTO FKTABLE VALUES (NULL, 3, 4, 5);
|
|
|
|
-- Insert a failed values
|
|
INSERT INTO FKTABLE VALUES (1, 2, 7, 6);
|
|
|
|
-- Show FKTABLE
|
|
SELECT * from FKTABLE;
|
|
|
|
-- Try to update something that will set null
|
|
UPDATE PKTABLE set ptest2=5 where ptest2=2;
|
|
|
|
-- Try to update something that should not set null
|
|
UPDATE PKTABLE set ptest2=2 WHERE ptest2=3 and ptest1=1;
|
|
|
|
-- Show PKTABLE and FKTABLE
|
|
SELECT * from PKTABLE;
|
|
SELECT * from FKTABLE;
|
|
|
|
-- Try to delete something that should set default
|
|
DELETE FROM PKTABLE where ptest1=2 and ptest2=3 and ptest3=4;
|
|
|
|
-- Show PKTABLE and FKTABLE
|
|
SELECT * from PKTABLE;
|
|
SELECT * from FKTABLE;
|
|
|
|
-- Try to delete something that should not set default
|
|
DELETE FROM PKTABLE where ptest2=5;
|
|
|
|
-- Show PKTABLE and FKTABLE
|
|
SELECT * from PKTABLE;
|
|
SELECT * from FKTABLE;
|
|
|
|
DROP TABLE FKTABLE;
|
|
DROP TABLE PKTABLE;
|
|
|
|
-- set default update / set null delete
|
|
CREATE TABLE PKTABLE ( ptest1 int, ptest2 int, ptest3 int, ptest4 text, PRIMARY KEY(ptest1, ptest2, ptest3) );
|
|
CREATE TABLE FKTABLE ( ftest1 int DEFAULT 0, ftest2 int DEFAULT -1, ftest3 int, ftest4 int, CONSTRAINT constrname3
|
|
FOREIGN KEY(ftest1, ftest2, ftest3) REFERENCES PKTABLE
|
|
ON DELETE SET NULL ON UPDATE SET DEFAULT);
|
|
|
|
-- Insert Primary Key values
|
|
INSERT INTO PKTABLE VALUES (1, 2, 3, 'test1');
|
|
INSERT INTO PKTABLE VALUES (1, 3, 3, 'test2');
|
|
INSERT INTO PKTABLE VALUES (2, 3, 4, 'test3');
|
|
INSERT INTO PKTABLE VALUES (2, 4, 5, 'test4');
|
|
INSERT INTO PKTABLE VALUES (2, -1, 5, 'test5');
|
|
|
|
-- Insert Foreign Key values
|
|
INSERT INTO FKTABLE VALUES (1, 2, 3, 1);
|
|
INSERT INTO FKTABLE VALUES (2, 3, 4, 1);
|
|
INSERT INTO FKTABLE VALUES (2, 4, 5, 1);
|
|
INSERT INTO FKTABLE VALUES (NULL, 2, 3, 2);
|
|
INSERT INTO FKTABLE VALUES (2, NULL, 3, 3);
|
|
INSERT INTO FKTABLE VALUES (NULL, 2, 7, 4);
|
|
INSERT INTO FKTABLE VALUES (NULL, 3, 4, 5);
|
|
|
|
-- Insert a failed values
|
|
INSERT INTO FKTABLE VALUES (1, 2, 7, 6);
|
|
|
|
-- Show FKTABLE
|
|
SELECT * from FKTABLE;
|
|
|
|
-- Try to update something that will fail
|
|
UPDATE PKTABLE set ptest2=5 where ptest2=2;
|
|
|
|
-- Try to update something that will set default
|
|
UPDATE PKTABLE set ptest1=0, ptest2=5, ptest3=10 where ptest2=2;
|
|
UPDATE PKTABLE set ptest2=10 where ptest2=4;
|
|
|
|
-- Try to update something that should not set default
|
|
UPDATE PKTABLE set ptest2=2 WHERE ptest2=3 and ptest1=1;
|
|
|
|
-- Show PKTABLE and FKTABLE
|
|
SELECT * from PKTABLE;
|
|
SELECT * from FKTABLE;
|
|
|
|
-- Try to delete something that should set null
|
|
DELETE FROM PKTABLE where ptest1=2 and ptest2=3 and ptest3=4;
|
|
|
|
-- Show PKTABLE and FKTABLE
|
|
SELECT * from PKTABLE;
|
|
SELECT * from FKTABLE;
|
|
|
|
-- Try to delete something that should not set null
|
|
DELETE FROM PKTABLE where ptest2=5;
|
|
|
|
-- Show PKTABLE and FKTABLE
|
|
SELECT * from PKTABLE;
|
|
SELECT * from FKTABLE;
|
|
|
|
DROP TABLE FKTABLE;
|
|
DROP TABLE PKTABLE;
|
|
|
|
CREATE TABLE PKTABLE (ptest1 int PRIMARY KEY);
|
|
CREATE TABLE FKTABLE_FAIL1 ( ftest1 int, CONSTRAINT fkfail1 FOREIGN KEY (ftest2) REFERENCES PKTABLE);
|
|
CREATE TABLE FKTABLE_FAIL2 ( ftest1 int, CONSTRAINT fkfail1 FOREIGN KEY (ftest1) REFERENCES PKTABLE(ptest2));
|
|
|
|
DROP TABLE FKTABLE_FAIL1;
|
|
DROP TABLE FKTABLE_FAIL2;
|
|
DROP TABLE PKTABLE;
|
|
|
|
-- Test for referencing column number smaller than referenced constraint
|
|
CREATE TABLE PKTABLE (ptest1 int, ptest2 int, UNIQUE(ptest1, ptest2));
|
|
CREATE TABLE FKTABLE_FAIL1 (ftest1 int REFERENCES pktable(ptest1));
|
|
|
|
DROP TABLE FKTABLE_FAIL1;
|
|
DROP TABLE PKTABLE;
|