|
6 | 6 | * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
7 | 7 | * Portions Copyright (c) 1994, Regents of the University of California
|
8 | 8 | *
|
9 |
| - * $Id: analyze.c,v 1.155 2000/08/22 12:59:04 ishii Exp $ |
| 9 | + * $Id: analyze.c,v 1.156 2000/08/29 04:20:44 momjian Exp $ |
10 | 10 | *
|
11 | 11 | *-------------------------------------------------------------------------
|
12 | 12 | */
|
@@ -52,6 +52,7 @@ static void transformForUpdate(Query *qry, List *forUpdate);
|
52 | 52 | static void transformFkeyGetPrimaryKey(FkConstraint *fkconstraint);
|
53 | 53 | static void transformConstraintAttrs(List *constraintList);
|
54 | 54 | static void transformColumnType(ParseState *pstate, ColumnDef *column);
|
| 55 | +static void transformFkeyCheckAttrs(FkConstraint *fkconstraint); |
55 | 56 |
|
56 | 57 | /* kluge to return extra info from transformCreateStmt() */
|
57 | 58 | static List *extras_before;
|
@@ -1062,6 +1063,33 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
|
1062 | 1063 | if (fkconstraint->constr_name == NULL)
|
1063 | 1064 | fkconstraint->constr_name = "<unnamed>";
|
1064 | 1065 |
|
| 1066 | + /* |
| 1067 | + * Check to see if the attributes mentioned by the constraint |
| 1068 | + * actually exist on this table. |
| 1069 | + */ |
| 1070 | + if (fkconstraint->fk_attrs!=NIL) { |
| 1071 | + int found=0; |
| 1072 | + List *cols; |
| 1073 | + List *fkattrs; |
| 1074 | + Ident *fkattr; |
| 1075 | + ColumnDef *col; |
| 1076 | + foreach(fkattrs, fkconstraint->fk_attrs) { |
| 1077 | + found=0; |
| 1078 | + fkattr=lfirst(fkattrs); |
| 1079 | + foreach(cols, columns) { |
| 1080 | + col=lfirst(cols); |
| 1081 | + if (strcmp(col->colname, fkattr->name)==0) { |
| 1082 | + found=1; |
| 1083 | + break; |
| 1084 | + } |
| 1085 | + } |
| 1086 | + if (!found) |
| 1087 | + break; |
| 1088 | + } |
| 1089 | + if (!found) |
| 1090 | + elog(ERROR, "columns referenced in foreign key constraint not found."); |
| 1091 | + } |
| 1092 | + |
1065 | 1093 | /*
|
1066 | 1094 | * If the attribute list for the referenced table was omitted,
|
1067 | 1095 | * lookup for the definition of the primary key. If the
|
@@ -1096,7 +1124,43 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
|
1096 | 1124 | fkconstraint->pktable_name);
|
1097 | 1125 | }
|
1098 | 1126 | }
|
1099 |
| - |
| 1127 | + else { |
| 1128 | + if (strcmp(fkconstraint->pktable_name, stmt->relname)!=0) |
| 1129 | + transformFkeyCheckAttrs(fkconstraint); |
| 1130 | + else { |
| 1131 | + /* Get a unique/pk constraint from above */ |
| 1132 | + List *index; |
| 1133 | + int found=0; |
| 1134 | + foreach(index, ilist) |
| 1135 | + { |
| 1136 | + IndexStmt *ind=lfirst(index); |
| 1137 | + IndexElem *indparm; |
| 1138 | + List *indparms; |
| 1139 | + List *pkattrs; |
| 1140 | + Ident *pkattr; |
| 1141 | + if (ind->unique) { |
| 1142 | + foreach(pkattrs, fkconstraint->pk_attrs) { |
| 1143 | + found=0; |
| 1144 | + pkattr=lfirst(pkattrs); |
| 1145 | + foreach(indparms, ind->indexParams) { |
| 1146 | + indparm=lfirst(indparms); |
| 1147 | + if (strcmp(indparm->name, pkattr->name)==0) { |
| 1148 | + found=1; |
| 1149 | + break; |
| 1150 | + } |
| 1151 | + } |
| 1152 | + if (!found) |
| 1153 | + break; |
| 1154 | + } |
| 1155 | + } |
| 1156 | + if (found) |
| 1157 | + break; |
| 1158 | + } |
| 1159 | + if (!found) |
| 1160 | + elog(ERROR, "UNIQUE constraint matching given keys for referenced table \"%s\" not found", |
| 1161 | + fkconstraint->pktable_name); |
| 1162 | + } |
| 1163 | + } |
1100 | 1164 | /*
|
1101 | 1165 | * Build a CREATE CONSTRAINT TRIGGER statement for the CHECK
|
1102 | 1166 | * action.
|
@@ -2029,6 +2093,89 @@ transformForUpdate(Query *qry, List *forUpdate)
|
2029 | 2093 | }
|
2030 | 2094 |
|
2031 | 2095 |
|
| 2096 | +/* |
| 2097 | + * transformFkeyCheckAttrs - |
| 2098 | + * |
| 2099 | + * Try to make sure that the attributes of a referenced table |
| 2100 | + * belong to a unique (or primary key) constraint. |
| 2101 | + * |
| 2102 | + */ |
| 2103 | +static void |
| 2104 | +transformFkeyCheckAttrs(FkConstraint *fkconstraint) |
| 2105 | +{ |
| 2106 | + Relation pkrel; |
| 2107 | + Form_pg_attribute *pkrel_attrs; |
| 2108 | + List *indexoidlist, |
| 2109 | + *indexoidscan; |
| 2110 | + Form_pg_index indexStruct = NULL; |
| 2111 | + int i; |
| 2112 | + int found=0; |
| 2113 | + |
| 2114 | + /* ---------- |
| 2115 | + * Open the referenced table and get the attributes list |
| 2116 | + * ---------- |
| 2117 | + */ |
| 2118 | + pkrel = heap_openr(fkconstraint->pktable_name, AccessShareLock); |
| 2119 | + if (pkrel == NULL) |
| 2120 | + elog(ERROR, "referenced table \"%s\" not found", |
| 2121 | + fkconstraint->pktable_name); |
| 2122 | + pkrel_attrs = pkrel->rd_att->attrs; |
| 2123 | + |
| 2124 | + /* ---------- |
| 2125 | + * Get the list of index OIDs for the table from the relcache, |
| 2126 | + * and look up each one in the pg_index syscache for each unique |
| 2127 | + * one, and then compare the attributes we were given to those |
| 2128 | + * defined. |
| 2129 | + * ---------- |
| 2130 | + */ |
| 2131 | + indexoidlist = RelationGetIndexList(pkrel); |
| 2132 | + |
| 2133 | + foreach(indexoidscan, indexoidlist) |
| 2134 | + { |
| 2135 | + Oid indexoid = lfirsti(indexoidscan); |
| 2136 | + HeapTuple indexTuple; |
| 2137 | + List *attrl; |
| 2138 | + indexTuple = SearchSysCacheTuple(INDEXRELID, |
| 2139 | + ObjectIdGetDatum(indexoid), |
| 2140 | + 0, 0, 0); |
| 2141 | + if (!HeapTupleIsValid(indexTuple)) |
| 2142 | + elog(ERROR, "transformFkeyGetPrimaryKey: index %u not found", |
| 2143 | + indexoid); |
| 2144 | + indexStruct = (Form_pg_index) GETSTRUCT(indexTuple); |
| 2145 | + |
| 2146 | + if (indexStruct->indisunique) { |
| 2147 | + /* go through the fkconstraint->pk_attrs list */ |
| 2148 | + foreach(attrl, fkconstraint->pk_attrs) { |
| 2149 | + Ident *attr=lfirst(attrl); |
| 2150 | + found=0; |
| 2151 | + for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++) |
| 2152 | + { |
| 2153 | + int pkattno = indexStruct->indkey[i]; |
| 2154 | + if (pkattno>0) { |
| 2155 | + char *name = NameStr(pkrel_attrs[pkattno - 1]->attname); |
| 2156 | + if (strcmp(name, attr->name)==0) { |
| 2157 | + found=1; |
| 2158 | + break; |
| 2159 | + } |
| 2160 | + } |
| 2161 | + } |
| 2162 | + if (!found) |
| 2163 | + break; |
| 2164 | + } |
| 2165 | + } |
| 2166 | + if (found) |
| 2167 | + break; |
| 2168 | + indexStruct = NULL; |
| 2169 | + } |
| 2170 | + if (!found) |
| 2171 | + elog(ERROR, "UNIQUE constraint matching given keys for referenced table \"%s\" not found", |
| 2172 | + fkconstraint->pktable_name); |
| 2173 | + |
| 2174 | + freeList(indexoidlist); |
| 2175 | + heap_close(pkrel, AccessShareLock); |
| 2176 | +} |
| 2177 | + |
| 2178 | + |
2032 | 2179 | /*
|
2033 | 2180 | * transformFkeyGetPrimaryKey -
|
2034 | 2181 | *
|
|
0 commit comments