|
8 | 8 | * |
9 | 9 | * |
10 | 10 | * IDENTIFICATION |
11 | | - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.204 2006/10/06 17:13:59 petere Exp $ |
| 11 | + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.205 2006/10/11 16:42:58 tgl Exp $ |
12 | 12 | * |
13 | 13 | *------------------------------------------------------------------------- |
14 | 14 | */ |
@@ -163,6 +163,8 @@ static List *MergeAttributes(List *schema, List *supers, bool istemp, |
163 | 163 | List**supOids,List**supconstr,int*supOidCount); |
164 | 164 | staticvoidMergeConstraintsIntoExisting(Relationchild_rel,Relationparent_rel); |
165 | 165 | staticvoidMergeAttributesIntoExisting(Relationchild_rel,Relationparent_rel); |
| 166 | +staticvoidadd_nonduplicate_constraint(Constraint*cdef, |
| 167 | +ConstrCheck*check,int*ncheck); |
166 | 168 | staticboolchange_varattnos_walker(Node*node,constAttrNumber*newattno); |
167 | 169 | staticvoidStoreCatalogInheritance(OidrelationId,List*supers); |
168 | 170 | staticvoidStoreCatalogInheritance1(OidrelationId,OidparentOid, |
@@ -285,7 +287,6 @@ DefineRelation(CreateStmt *stmt, char relkind) |
285 | 287 | List*rawDefaults; |
286 | 288 | Datumreloptions; |
287 | 289 | ListCell*listptr; |
288 | | -inti; |
289 | 290 | AttrNumberattnum; |
290 | 291 |
|
291 | 292 | /* |
@@ -378,49 +379,35 @@ DefineRelation(CreateStmt *stmt, char relkind) |
378 | 379 | localHasOids=interpretOidsOption(stmt->options); |
379 | 380 | descriptor->tdhasoid= (localHasOids||parentOidCount>0); |
380 | 381 |
|
381 | | -if (old_constraints!=NIL) |
| 382 | +if (old_constraints||stmt->constraints) |
382 | 383 | { |
383 | | -ConstrCheck*check= (ConstrCheck*) |
384 | | -palloc0(list_length(old_constraints)*sizeof(ConstrCheck)); |
| 384 | +ConstrCheck*check; |
385 | 385 | intncheck=0; |
386 | 386 |
|
| 387 | +/* make array that's certainly big enough */ |
| 388 | +check= (ConstrCheck*) |
| 389 | +palloc((list_length(old_constraints)+ |
| 390 | +list_length(stmt->constraints))*sizeof(ConstrCheck)); |
| 391 | +/* deal with constraints from MergeAttributes */ |
387 | 392 | foreach(listptr,old_constraints) |
388 | 393 | { |
389 | 394 | Constraint*cdef= (Constraint*)lfirst(listptr); |
390 | | -booldup= false; |
391 | 395 |
|
392 | | -if (cdef->contype!=CONSTR_CHECK) |
393 | | -continue; |
394 | | -Assert(cdef->name!=NULL); |
395 | | -Assert(cdef->raw_expr==NULL&&cdef->cooked_expr!=NULL); |
| 396 | +if (cdef->contype==CONSTR_CHECK) |
| 397 | +add_nonduplicate_constraint(cdef,check,&ncheck); |
| 398 | +} |
| 399 | +/* |
| 400 | + * analyze.c might have passed some precooked constraints too, |
| 401 | + * due to LIKE tab INCLUDING CONSTRAINTS |
| 402 | + */ |
| 403 | +foreach(listptr,stmt->constraints) |
| 404 | +{ |
| 405 | +Constraint*cdef= (Constraint*)lfirst(listptr); |
396 | 406 |
|
397 | | -/* |
398 | | - * In multiple-inheritance situations, it's possible to inherit |
399 | | - * the same grandparent constraint through multiple parents. |
400 | | - * Hence, discard inherited constraints that match as to both name |
401 | | - * and expression.Otherwise, gripe if the names conflict. |
402 | | - */ |
403 | | -for (i=0;i<ncheck;i++) |
404 | | -{ |
405 | | -if (strcmp(check[i].ccname,cdef->name)!=0) |
406 | | -continue; |
407 | | -if (strcmp(check[i].ccbin,cdef->cooked_expr)==0) |
408 | | -{ |
409 | | -dup= true; |
410 | | -break; |
411 | | -} |
412 | | -ereport(ERROR, |
413 | | -(errcode(ERRCODE_DUPLICATE_OBJECT), |
414 | | -errmsg("duplicate check constraint name \"%s\"", |
415 | | -cdef->name))); |
416 | | -} |
417 | | -if (!dup) |
418 | | -{ |
419 | | -check[ncheck].ccname=cdef->name; |
420 | | -check[ncheck].ccbin=pstrdup(cdef->cooked_expr); |
421 | | -ncheck++; |
422 | | -} |
| 407 | +if (cdef->contype==CONSTR_CHECK&&cdef->cooked_expr!=NULL) |
| 408 | +add_nonduplicate_constraint(cdef,check,&ncheck); |
423 | 409 | } |
| 410 | +/* if we found any, insert 'em into the descriptor */ |
424 | 411 | if (ncheck>0) |
425 | 412 | { |
426 | 413 | if (descriptor->constr==NULL) |
@@ -1118,66 +1105,57 @@ MergeAttributes(List *schema, List *supers, bool istemp, |
1118 | 1105 | returnschema; |
1119 | 1106 | } |
1120 | 1107 |
|
| 1108 | + |
1121 | 1109 | /* |
1122 | | - * Varattnos of pg_constraint.conbin must be rewritten when subclasses inherit |
1123 | | - * constraints from parent classes, since the inherited attributes could |
1124 | | - * be given different column numbers in multiple-inheritance cases. |
1125 | | - * |
1126 | | - * Note that the passed node tree is modified in place! |
1127 | | - * |
1128 | | - * This function is used elsewhere such as in analyze.c |
1129 | | - * |
| 1110 | + * In multiple-inheritance situations, it's possible to inherit |
| 1111 | + * the same grandparent constraint through multiple parents. |
| 1112 | + * Hence, we want to discard inherited constraints that match as to |
| 1113 | + * both name and expression. Otherwise, gripe if there are conflicting |
| 1114 | + * names. Nonconflicting constraints are added to the array check[] |
| 1115 | + * of length *ncheck ... caller must ensure there is room! |
1130 | 1116 | */ |
1131 | | - |
1132 | | -void |
1133 | | -change_varattnos_of_a_node(Node*node,constAttrNumber*newattno) |
| 1117 | +staticvoid |
| 1118 | +add_nonduplicate_constraint(Constraint*cdef,ConstrCheck*check,int*ncheck) |
1134 | 1119 | { |
1135 | | -change_varattnos_walker(node,newattno); |
1136 | | -} |
1137 | | - |
1138 | | -/* Generate a map for change_varattnos_of_a_node from two tupledesc's. */ |
| 1120 | +inti; |
1139 | 1121 |
|
1140 | | -AttrNumber* |
1141 | | -varattnos_map(TupleDescold,TupleDescnew) |
1142 | | -{ |
1143 | | -inti, |
1144 | | -j; |
1145 | | -AttrNumber*attmap=palloc0(sizeof(AttrNumber)*old->natts); |
| 1122 | +/* Should only see precooked constraints here */ |
| 1123 | +Assert(cdef->contype==CONSTR_CHECK); |
| 1124 | +Assert(cdef->name!=NULL); |
| 1125 | +Assert(cdef->raw_expr==NULL&&cdef->cooked_expr!=NULL); |
1146 | 1126 |
|
1147 | | -for (i=1;i <=old->natts;i++) |
| 1127 | +for (i=0;i<*ncheck;i++) |
1148 | 1128 | { |
1149 | | -if (old->attrs[i-1]->attisdropped) |
1150 | | -{ |
1151 | | -attmap[i-1]=0; |
| 1129 | +if (strcmp(check[i].ccname,cdef->name)!=0) |
1152 | 1130 | continue; |
1153 | | -} |
1154 | | -for (j=1;j <=new->natts;j++) |
1155 | | -if (!strcmp(NameStr(old->attrs[i-1]->attname),NameStr(new->attrs[j-1]->attname))) |
1156 | | -attmap[i-1]=j; |
| 1131 | +if (strcmp(check[i].ccbin,cdef->cooked_expr)==0) |
| 1132 | +return;/* duplicate constraint, so ignore it */ |
| 1133 | +ereport(ERROR, |
| 1134 | +(errcode(ERRCODE_DUPLICATE_OBJECT), |
| 1135 | +errmsg("duplicate check constraint name \"%s\"", |
| 1136 | +cdef->name))); |
1157 | 1137 | } |
1158 | | -returnattmap; |
| 1138 | +/* No match on name, so add it to array */ |
| 1139 | +check[*ncheck].ccname=cdef->name; |
| 1140 | +check[*ncheck].ccbin=pstrdup(cdef->cooked_expr); |
| 1141 | +(*ncheck)++; |
1159 | 1142 | } |
1160 | 1143 |
|
| 1144 | + |
1161 | 1145 | /* |
1162 | | - * Generate a map for change_varattnos_of_a_node from a tupledesc and a list of |
1163 | | - * ColumnDefs |
| 1146 | + * Replace varattno values in an expression tree according to the given |
| 1147 | + * map array, that is, varattno N is replaced by newattno[N-1]. It is |
| 1148 | + * caller's responsibility to ensure that the array is long enough to |
| 1149 | + * define values for all user varattnos present in the tree. System column |
| 1150 | + * attnos remain unchanged. |
| 1151 | + * |
| 1152 | + * Note that the passed node tree is modified in-place! |
1164 | 1153 | */ |
1165 | | -AttrNumber* |
1166 | | -varattnos_map_schema(TupleDescold,List*schema) |
| 1154 | +void |
| 1155 | +change_varattnos_of_a_node(Node*node,constAttrNumber*newattno) |
1167 | 1156 | { |
1168 | | -inti; |
1169 | | -AttrNumber*attmap=palloc0(sizeof(AttrNumber)*old->natts); |
1170 | | - |
1171 | | -for (i=1;i <=old->natts;i++) |
1172 | | -{ |
1173 | | -if (old->attrs[i-1]->attisdropped) |
1174 | | -{ |
1175 | | -attmap[i-1]=0; |
1176 | | -continue; |
1177 | | -} |
1178 | | -attmap[i-1]=findAttrByName(NameStr(old->attrs[i-1]->attname),schema); |
1179 | | -} |
1180 | | -returnattmap; |
| 1157 | +/* no setup needed, so away we go */ |
| 1158 | +(void)change_varattnos_walker(node,newattno); |
1181 | 1159 | } |
1182 | 1160 |
|
1183 | 1161 | staticbool |
@@ -1206,6 +1184,59 @@ change_varattnos_walker(Node *node, const AttrNumber *newattno) |
1206 | 1184 | (void*)newattno); |
1207 | 1185 | } |
1208 | 1186 |
|
| 1187 | +/* |
| 1188 | + * Generate a map for change_varattnos_of_a_node from old and new TupleDesc's, |
| 1189 | + * matching according to column name. |
| 1190 | + */ |
| 1191 | +AttrNumber* |
| 1192 | +varattnos_map(TupleDescold,TupleDescnew) |
| 1193 | +{ |
| 1194 | +AttrNumber*attmap; |
| 1195 | +inti, |
| 1196 | +j; |
| 1197 | + |
| 1198 | +attmap= (AttrNumber*)palloc0(sizeof(AttrNumber)*old->natts); |
| 1199 | +for (i=1;i <=old->natts;i++) |
| 1200 | +{ |
| 1201 | +if (old->attrs[i-1]->attisdropped) |
| 1202 | +continue;/* leave the entry as zero */ |
| 1203 | + |
| 1204 | +for (j=1;j <=new->natts;j++) |
| 1205 | +{ |
| 1206 | +if (strcmp(NameStr(old->attrs[i-1]->attname), |
| 1207 | +NameStr(new->attrs[j-1]->attname))==0) |
| 1208 | +{ |
| 1209 | +attmap[i-1]=j; |
| 1210 | +break; |
| 1211 | +} |
| 1212 | +} |
| 1213 | +} |
| 1214 | +returnattmap; |
| 1215 | +} |
| 1216 | + |
| 1217 | +/* |
| 1218 | + * Generate a map for change_varattnos_of_a_node from a TupleDesc and a list |
| 1219 | + * of ColumnDefs |
| 1220 | + */ |
| 1221 | +AttrNumber* |
| 1222 | +varattnos_map_schema(TupleDescold,List*schema) |
| 1223 | +{ |
| 1224 | +AttrNumber*attmap; |
| 1225 | +inti; |
| 1226 | + |
| 1227 | +attmap= (AttrNumber*)palloc0(sizeof(AttrNumber)*old->natts); |
| 1228 | +for (i=1;i <=old->natts;i++) |
| 1229 | +{ |
| 1230 | +if (old->attrs[i-1]->attisdropped) |
| 1231 | +continue;/* leave the entry as zero */ |
| 1232 | + |
| 1233 | +attmap[i-1]=findAttrByName(NameStr(old->attrs[i-1]->attname), |
| 1234 | +schema); |
| 1235 | +} |
| 1236 | +returnattmap; |
| 1237 | +} |
| 1238 | + |
| 1239 | + |
1209 | 1240 | /* |
1210 | 1241 | * StoreCatalogInheritance |
1211 | 1242 | *Updates the system catalogs with proper inheritance information. |
|