mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	From Stephan Szabo:
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.
This commit is contained in:
		@@ -8,7 +8,7 @@
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * IDENTIFICATION
 | 
			
		||||
 *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.112 2000/11/16 22:30:19 tgl Exp $
 | 
			
		||||
 *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.113 2000/12/05 19:57:55 tgl Exp $
 | 
			
		||||
 *
 | 
			
		||||
 * NOTES
 | 
			
		||||
 *	  The PerformAddAttribute() code, like most of the relation
 | 
			
		||||
@@ -1287,26 +1287,33 @@ AlterTableAddConstraint(char *relationName,
 | 
			
		||||
				{
 | 
			
		||||
					List	   *attrl;
 | 
			
		||||
 | 
			
		||||
					/* go through the fkconstraint->pk_attrs list */
 | 
			
		||||
					foreach(attrl, fkconstraint->pk_attrs)
 | 
			
		||||
					{
 | 
			
		||||
						Ident *attr=lfirst(attrl);
 | 
			
		||||
						found = false;
 | 
			
		||||
						for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++)
 | 
			
		||||
					/* Make sure this index has the same number of keys -- It obviously
 | 
			
		||||
					 * won't match otherwise. */
 | 
			
		||||
					for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++);
 | 
			
		||||
					if (i!=length(fkconstraint->pk_attrs))
 | 
			
		||||
						found=false;
 | 
			
		||||
					else {
 | 
			
		||||
						/* go through the fkconstraint->pk_attrs list */
 | 
			
		||||
						foreach(attrl, fkconstraint->pk_attrs)
 | 
			
		||||
						{
 | 
			
		||||
							int pkattno = indexStruct->indkey[i];
 | 
			
		||||
							if (pkattno>0)
 | 
			
		||||
							Ident *attr=lfirst(attrl);
 | 
			
		||||
							found = false;
 | 
			
		||||
							for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++)
 | 
			
		||||
							{
 | 
			
		||||
								char *name = NameStr(rel_attrs[pkattno-1]->attname);
 | 
			
		||||
								if (strcmp(name, attr->name)==0)
 | 
			
		||||
								int pkattno = indexStruct->indkey[i];
 | 
			
		||||
								if (pkattno>0)
 | 
			
		||||
								{
 | 
			
		||||
									found = true;
 | 
			
		||||
									break;
 | 
			
		||||
									char *name = NameStr(rel_attrs[pkattno-1]->attname);
 | 
			
		||||
									if (strcmp(name, attr->name)==0)
 | 
			
		||||
									{
 | 
			
		||||
										found = true;
 | 
			
		||||
										break;
 | 
			
		||||
									}
 | 
			
		||||
								}
 | 
			
		||||
							}
 | 
			
		||||
							if (!found)
 | 
			
		||||
								break;
 | 
			
		||||
						}
 | 
			
		||||
						if (!found)
 | 
			
		||||
							break;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				ReleaseSysCache(indexTuple);
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@
 | 
			
		||||
 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
 | 
			
		||||
 * Portions Copyright (c) 1994, Regents of the University of California
 | 
			
		||||
 *
 | 
			
		||||
 *	$Id: analyze.c,v 1.169 2000/12/05 19:15:10 tgl Exp $
 | 
			
		||||
 *	$Id: analyze.c,v 1.170 2000/12/05 19:57:55 tgl Exp $
 | 
			
		||||
 *
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
@@ -1209,18 +1209,26 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
 | 
			
		||||
						List *pkattrs;
 | 
			
		||||
						Ident *pkattr;
 | 
			
		||||
						if (ind->unique) {
 | 
			
		||||
							foreach(pkattrs, fkconstraint->pk_attrs) {
 | 
			
		||||
							int count=0;
 | 
			
		||||
							foreach(indparms, ind->indexParams) {
 | 
			
		||||
								count++;
 | 
			
		||||
							}
 | 
			
		||||
							if (count!=length(fkconstraint->pk_attrs))
 | 
			
		||||
								found=0;
 | 
			
		||||
								pkattr=lfirst(pkattrs);
 | 
			
		||||
								foreach(indparms, ind->indexParams) {
 | 
			
		||||
									indparm=lfirst(indparms);
 | 
			
		||||
									if (strcmp(indparm->name, pkattr->name)==0) {
 | 
			
		||||
										found=1;
 | 
			
		||||
										break;
 | 
			
		||||
							else {
 | 
			
		||||
								foreach(pkattrs, fkconstraint->pk_attrs) {
 | 
			
		||||
									found=0;
 | 
			
		||||
									pkattr=lfirst(pkattrs);
 | 
			
		||||
									foreach(indparms, ind->indexParams) {
 | 
			
		||||
										indparm=lfirst(indparms);
 | 
			
		||||
										if (strcmp(indparm->name, pkattr->name)==0) {
 | 
			
		||||
											found=1;
 | 
			
		||||
											break;
 | 
			
		||||
										}
 | 
			
		||||
									}
 | 
			
		||||
									if (!found)
 | 
			
		||||
										break;
 | 
			
		||||
								}
 | 
			
		||||
								if (!found)
 | 
			
		||||
									break;
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
						if (found)
 | 
			
		||||
@@ -2634,26 +2642,31 @@ transformFkeyCheckAttrs(FkConstraint *fkconstraint)
 | 
			
		||||
		{
 | 
			
		||||
			List *attrl;
 | 
			
		||||
 | 
			
		||||
			/* go through the fkconstraint->pk_attrs list */
 | 
			
		||||
			foreach(attrl, fkconstraint->pk_attrs)
 | 
			
		||||
			{
 | 
			
		||||
				Ident *attr=lfirst(attrl);
 | 
			
		||||
				found = false;
 | 
			
		||||
				for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++)
 | 
			
		||||
			for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++);
 | 
			
		||||
			if (i!=length(fkconstraint->pk_attrs))
 | 
			
		||||
				found=false;
 | 
			
		||||
			else {
 | 
			
		||||
				/* go through the fkconstraint->pk_attrs list */
 | 
			
		||||
				foreach(attrl, fkconstraint->pk_attrs)
 | 
			
		||||
				{
 | 
			
		||||
					int		pkattno = indexStruct->indkey[i];
 | 
			
		||||
					if (pkattno>0)
 | 
			
		||||
					Ident *attr=lfirst(attrl);
 | 
			
		||||
					found = false;
 | 
			
		||||
					for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++)
 | 
			
		||||
					{
 | 
			
		||||
						char *name = NameStr(pkrel_attrs[pkattno - 1]->attname);
 | 
			
		||||
						if (strcmp(name, attr->name)==0)
 | 
			
		||||
						int		pkattno = indexStruct->indkey[i];
 | 
			
		||||
						if (pkattno>0)
 | 
			
		||||
						{
 | 
			
		||||
							found = true;
 | 
			
		||||
							break;
 | 
			
		||||
							char *name = NameStr(pkrel_attrs[pkattno - 1]->attname);
 | 
			
		||||
							if (strcmp(name, attr->name)==0)
 | 
			
		||||
							{
 | 
			
		||||
								found = true;
 | 
			
		||||
								break;
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					if (!found)
 | 
			
		||||
						break;
 | 
			
		||||
				}
 | 
			
		||||
				if (!found)
 | 
			
		||||
					break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		ReleaseSysCache(indexTuple);
 | 
			
		||||
 
 | 
			
		||||
@@ -273,6 +273,9 @@ SELECT unique1 FROM tenk1 WHERE unique1 < 5;
 | 
			
		||||
CREATE TABLE tmp2 (a int primary key);
 | 
			
		||||
NOTICE:  CREATE TABLE/PRIMARY KEY will create implicit index 'tmp2_pkey' for table 'tmp2'
 | 
			
		||||
CREATE TABLE tmp3 (a int, b int);
 | 
			
		||||
CREATE TABLE tmp4 (a int, b int, unique(a,b));
 | 
			
		||||
NOTICE:  CREATE TABLE/UNIQUE will create implicit index 'tmp4_a_key' for table 'tmp4'
 | 
			
		||||
CREATE TABLE tmp5 (a int, b int);
 | 
			
		||||
-- Insert rows into tmp2 (pktable)
 | 
			
		||||
INSERT INTO tmp2 values (1);
 | 
			
		||||
INSERT INTO tmp2 values (2);
 | 
			
		||||
@@ -299,6 +302,13 @@ DELETE FROM tmp3 where a=5;
 | 
			
		||||
-- Try (and succeed)
 | 
			
		||||
ALTER TABLE tmp3 add constraint tmpconstr foreign key (a) references tmp2 match full;
 | 
			
		||||
NOTICE:  ALTER TABLE ... ADD CONSTRAINT will create implicit trigger(s) for FOREIGN KEY check(s)
 | 
			
		||||
-- Try (and fail) to create constraint from tmp5(a) to tmp4(a) - unique constraint on
 | 
			
		||||
-- tmp4 is a,b
 | 
			
		||||
ALTER TABLE tmp5 add constraint tmpconstr foreign key(a) references tmp4(a) match full;
 | 
			
		||||
NOTICE:  ALTER TABLE ... ADD CONSTRAINT will create implicit trigger(s) for FOREIGN KEY check(s)
 | 
			
		||||
ERROR:  UNIQUE constraint matching given keys for referenced table "tmp4" not found
 | 
			
		||||
DROP TABLE tmp5;
 | 
			
		||||
DROP TABLE tmp4;
 | 
			
		||||
DROP TABLE tmp3;
 | 
			
		||||
NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "tmp2"
 | 
			
		||||
NOTICE:  DROP TABLE implicitly drops referential integrity trigger from table "tmp2"
 | 
			
		||||
 
 | 
			
		||||
@@ -703,3 +703,12 @@ ERROR:  table "fktable_fail1" does not exist
 | 
			
		||||
DROP TABLE FKTABLE_FAIL2;
 | 
			
		||||
ERROR:  table "fktable_fail2" does not exist
 | 
			
		||||
DROP TABLE PKTABLE;
 | 
			
		||||
-- Test for referencing column number smaller than referenced constraint
 | 
			
		||||
CREATE TABLE PKTABLE (ptest1 int, ptest2 int, UNIQUE(ptest1, ptest2));
 | 
			
		||||
NOTICE:  CREATE TABLE/UNIQUE will create implicit index 'pktable_ptest1_key' for table 'pktable'
 | 
			
		||||
CREATE TABLE FKTABLE_FAIL1 (ftest1 int REFERENCES pktable(ptest1));
 | 
			
		||||
NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
 | 
			
		||||
ERROR:  UNIQUE constraint matching given keys for referenced table "pktable" not found
 | 
			
		||||
DROP TABLE FKTABLE_FAIL1;
 | 
			
		||||
ERROR:  table "fktable_fail1" does not exist
 | 
			
		||||
DROP TABLE PKTABLE;
 | 
			
		||||
 
 | 
			
		||||
@@ -169,6 +169,10 @@ CREATE TABLE tmp2 (a int primary key);
 | 
			
		||||
 | 
			
		||||
CREATE TABLE tmp3 (a int, b int);
 | 
			
		||||
 | 
			
		||||
CREATE TABLE tmp4 (a int, b int, unique(a,b));
 | 
			
		||||
 | 
			
		||||
CREATE TABLE tmp5 (a int, b int);
 | 
			
		||||
 | 
			
		||||
-- Insert rows into tmp2 (pktable)
 | 
			
		||||
INSERT INTO tmp2 values (1);
 | 
			
		||||
INSERT INTO tmp2 values (2);
 | 
			
		||||
@@ -195,6 +199,15 @@ DELETE FROM tmp3 where a=5;
 | 
			
		||||
-- Try (and succeed)
 | 
			
		||||
ALTER TABLE tmp3 add constraint tmpconstr foreign key (a) references tmp2 match full;
 | 
			
		||||
 | 
			
		||||
-- Try (and fail) to create constraint from tmp5(a) to tmp4(a) - unique constraint on
 | 
			
		||||
-- tmp4 is a,b
 | 
			
		||||
 | 
			
		||||
ALTER TABLE tmp5 add constraint tmpconstr foreign key(a) references tmp4(a) match full;
 | 
			
		||||
 | 
			
		||||
DROP TABLE tmp5;
 | 
			
		||||
 | 
			
		||||
DROP TABLE tmp4;
 | 
			
		||||
 | 
			
		||||
DROP TABLE tmp3;
 | 
			
		||||
 | 
			
		||||
DROP TABLE tmp2;
 | 
			
		||||
 
 | 
			
		||||
@@ -418,3 +418,10 @@ CREATE TABLE FKTABLE_FAIL2 ( ftest1 int, CONSTRAINT fkfail1 FOREIGN KEY (ftest1)
 | 
			
		||||
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;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user