|
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, bool recurse);
|
195 | 195 | static void ATOneLevelRecursion(List **wqueue, Relation rel,
|
196 | 196 | AlterTableCmd *cmd);
|
| 197 | +static void find_composite_type_dependencies(Oid typeOid, |
| 198 | + const char *origTblName); |
197 | 199 | static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse,
|
198 | 200 | AlterTableCmd *cmd);
|
199 | 201 | static void ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
|
@@ -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 | +static void |
| 2636 | +find_composite_type_dependencies(Oid typeOid, const char *origTblName) |
| 2637 | +{ |
| 2638 | + Relation depRel; |
| 2639 | + ScanKeyData key[2]; |
| 2640 | + SysScanDesc depScan; |
| 2641 | + HeapTuple depTup; |
| 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_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup); |
| 2664 | + Relation rel; |
| 2665 | + Form_pg_attribute att; |
| 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 | + else if (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 | *
|
|
0 commit comments