|
8 | 8 | *
|
9 | 9 | *
|
10 | 10 | * IDENTIFICATION
|
11 |
| - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.111 2004/06/05 19:48:07 tgl Exp $ |
| 11 | + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.112 2004/06/06 20:30:07 tgl Exp $ |
12 | 12 | *
|
13 | 13 | *-------------------------------------------------------------------------
|
14 | 14 | */
|
@@ -194,6 +194,8 @@ static void ATSimpleRecursion(List **wqueue, Relation rel,
|
194 | 194 | AlterTableCmd*cmd,boolrecurse);
|
195 | 195 | staticvoidATOneLevelRecursion(List**wqueue,Relationrel,
|
196 | 196 | AlterTableCmd*cmd);
|
| 197 | +staticvoidfind_composite_type_dependencies(OidtypeOid, |
| 198 | +constchar*origTblName); |
197 | 199 | staticvoidATPrepAddColumn(List**wqueue,Relationrel,boolrecurse,
|
198 | 200 | AlterTableCmd*cmd);
|
199 | 201 | staticvoidATExecAddColumn(AlteredTableInfo*tab,Relationrel,
|
@@ -2281,6 +2283,18 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap)
|
2281 | 2283 | else
|
2282 | 2284 | newrel=NULL;
|
2283 | 2285 |
|
| 2286 | +/* |
| 2287 | + * If we need to rewrite the table, the operation has to be propagated |
| 2288 | + * to tables that use this table's rowtype as a column type. |
| 2289 | + * |
| 2290 | + * (Eventually this will probably become true for scans as well, but |
| 2291 | + * at the moment a composite type does not enforce any constraints, |
| 2292 | + * so it's not necessary/appropriate to enforce them just during ALTER.) |
| 2293 | + */ |
| 2294 | +if (newrel) |
| 2295 | +find_composite_type_dependencies(oldrel->rd_rel->reltype, |
| 2296 | +RelationGetRelationName(oldrel)); |
| 2297 | + |
2284 | 2298 | /*
|
2285 | 2299 | * Generate the constraint and default execution states
|
2286 | 2300 | */
|
@@ -2606,6 +2620,87 @@ ATOneLevelRecursion(List **wqueue, Relation rel,
|
2606 | 2620 | }
|
2607 | 2621 | }
|
2608 | 2622 |
|
| 2623 | + |
| 2624 | +/* |
| 2625 | + * find_composite_type_dependencies |
| 2626 | + * |
| 2627 | + * Check to see if a table's rowtype is being used as a column in some |
| 2628 | + * other table (possibly nested several levels deep in composite types!). |
| 2629 | + * Eventually, we'd like to propagate the check or rewrite operation |
| 2630 | + * into other such tables, but for now, just error out if we find any. |
| 2631 | + * |
| 2632 | + * We assume that functions and views depending on the type are not reasons |
| 2633 | + * to reject the ALTER. (How safe is this really?) |
| 2634 | + */ |
| 2635 | +staticvoid |
| 2636 | +find_composite_type_dependencies(OidtypeOid,constchar*origTblName) |
| 2637 | +{ |
| 2638 | +RelationdepRel; |
| 2639 | +ScanKeyDatakey[2]; |
| 2640 | +SysScanDescdepScan; |
| 2641 | +HeapTupledepTup; |
| 2642 | + |
| 2643 | +/* |
| 2644 | + * We scan pg_depend to find those things that depend on the rowtype. |
| 2645 | + * (We assume we can ignore refobjsubid for a rowtype.) |
| 2646 | + */ |
| 2647 | +depRel=relation_openr(DependRelationName,AccessShareLock); |
| 2648 | + |
| 2649 | +ScanKeyInit(&key[0], |
| 2650 | +Anum_pg_depend_refclassid, |
| 2651 | +BTEqualStrategyNumber,F_OIDEQ, |
| 2652 | +ObjectIdGetDatum(RelOid_pg_type)); |
| 2653 | +ScanKeyInit(&key[1], |
| 2654 | +Anum_pg_depend_refobjid, |
| 2655 | +BTEqualStrategyNumber,F_OIDEQ, |
| 2656 | +ObjectIdGetDatum(typeOid)); |
| 2657 | + |
| 2658 | +depScan=systable_beginscan(depRel,DependReferenceIndex, true, |
| 2659 | +SnapshotNow,2,key); |
| 2660 | + |
| 2661 | +while (HeapTupleIsValid(depTup=systable_getnext(depScan))) |
| 2662 | +{ |
| 2663 | +Form_pg_dependpg_depend= (Form_pg_depend)GETSTRUCT(depTup); |
| 2664 | +Relationrel; |
| 2665 | +Form_pg_attributeatt; |
| 2666 | + |
| 2667 | +/* Ignore dependees that aren't user columns of relations */ |
| 2668 | +/* (we assume system columns are never of rowtypes) */ |
| 2669 | +if (pg_depend->classid!=RelOid_pg_class|| |
| 2670 | +pg_depend->objsubid <=0) |
| 2671 | +continue; |
| 2672 | + |
| 2673 | +rel=relation_open(pg_depend->objid,AccessShareLock); |
| 2674 | +att=rel->rd_att->attrs[pg_depend->objsubid-1]; |
| 2675 | + |
| 2676 | +if (rel->rd_rel->relkind==RELKIND_RELATION) |
| 2677 | +{ |
| 2678 | +ereport(ERROR, |
| 2679 | +(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 2680 | +errmsg("cannot alter table \"%s\" because column \"%s\".\"%s\" uses its rowtype", |
| 2681 | +origTblName, |
| 2682 | +RelationGetRelationName(rel), |
| 2683 | +NameStr(att->attname)))); |
| 2684 | +} |
| 2685 | +elseif (OidIsValid(rel->rd_rel->reltype)) |
| 2686 | +{ |
| 2687 | +/* |
| 2688 | + * A view or composite type itself isn't a problem, but we must |
| 2689 | + * recursively check for indirect dependencies via its rowtype. |
| 2690 | + */ |
| 2691 | +find_composite_type_dependencies(rel->rd_rel->reltype, |
| 2692 | +origTblName); |
| 2693 | +} |
| 2694 | + |
| 2695 | +relation_close(rel,AccessShareLock); |
| 2696 | +} |
| 2697 | + |
| 2698 | +systable_endscan(depScan); |
| 2699 | + |
| 2700 | +relation_close(depRel,AccessShareLock); |
| 2701 | +} |
| 2702 | + |
| 2703 | + |
2609 | 2704 | /*
|
2610 | 2705 | * ALTER TABLE ADD COLUMN
|
2611 | 2706 | *
|
|