|
8 | 8 | *
|
9 | 9 | *
|
10 | 10 | * IDENTIFICATION
|
11 |
| - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.212 2007/01/25 04:35:10 momjian Exp $ |
| 11 | + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.213 2007/02/02 00:07:02 tgl Exp $ |
12 | 12 | *
|
13 | 13 | *-------------------------------------------------------------------------
|
14 | 14 | */
|
@@ -1964,22 +1964,47 @@ update_ri_trigger_args(Oid relid,
|
1964 | 1964 | void
|
1965 | 1965 | AlterTable(AlterTableStmt *stmt)
|
1966 | 1966 | {
|
1967 |
| - ATController(relation_openrv(stmt->relation, AccessExclusiveLock), |
1968 |
| - stmt->cmds, |
1969 |
| - interpretInhOption(stmt->relation->inhOpt)); |
| 1967 | + Relation rel = relation_openrv(stmt->relation, AccessExclusiveLock); |
| 1968 | + int expected_refcnt; |
| 1969 | + |
| 1970 | + /* |
| 1971 | + * Disallow ALTER TABLE when the current backend has any open reference |
| 1972 | + * to it besides the one we just got (such as an open cursor or active |
| 1973 | + * plan); our AccessExclusiveLock doesn't protect us against stomping on |
| 1974 | + * our own foot, only other people's feet! |
| 1975 | + * |
| 1976 | + * Note: the only case known to cause serious trouble is ALTER COLUMN TYPE, |
| 1977 | + * and some changes are obviously pretty benign, so this could possibly |
| 1978 | + * be relaxed to only error out for certain types of alterations. But |
| 1979 | + * the use-case for allowing any of these things is not obvious, so we |
| 1980 | + * won't work hard at it for now. |
| 1981 | + */ |
| 1982 | + expected_refcnt = rel->rd_isnailed ? 2 : 1; |
| 1983 | + if (rel->rd_refcnt != expected_refcnt) |
| 1984 | + ereport(ERROR, |
| 1985 | + (errcode(ERRCODE_OBJECT_IN_USE), |
| 1986 | + errmsg("relation \"%s\" is being used by active queries in this session", |
| 1987 | + RelationGetRelationName(rel)))); |
| 1988 | + |
| 1989 | + ATController(rel, stmt->cmds, interpretInhOption(stmt->relation->inhOpt)); |
1970 | 1990 | }
|
1971 | 1991 |
|
1972 | 1992 | /*
|
1973 | 1993 | * AlterTableInternal
|
1974 | 1994 | *
|
1975 | 1995 | * ALTER TABLE with target specified by OID
|
| 1996 | + * |
| 1997 | + * We do not reject if the relation is already open, because it's quite |
| 1998 | + * likely that one or more layers of caller have it open. That means it |
| 1999 | + * is unsafe to use this entry point for alterations that could break |
| 2000 | + * existing query plans. |
1976 | 2001 | */
|
1977 | 2002 | void
|
1978 | 2003 | AlterTableInternal(Oid relid, List *cmds, bool recurse)
|
1979 | 2004 | {
|
1980 |
| - ATController(relation_open(relid, AccessExclusiveLock), |
1981 |
| - cmds, |
1982 |
| - recurse); |
| 2005 | + Relation rel = relation_open(relid, AccessExclusiveLock); |
| 2006 | + |
| 2007 | + ATController(rel, cmds, recurse); |
1983 | 2008 | }
|
1984 | 2009 |
|
1985 | 2010 | static void
|
@@ -2929,6 +2954,12 @@ ATSimpleRecursion(List **wqueue, Relation rel,
|
2929 | 2954 | if (childrelid == relid)
|
2930 | 2955 | continue;
|
2931 | 2956 | childrel = relation_open(childrelid, AccessExclusiveLock);
|
| 2957 | + /* check for child relation in use in this session */ |
| 2958 | + if (childrel->rd_refcnt != 1) |
| 2959 | + ereport(ERROR, |
| 2960 | + (errcode(ERRCODE_OBJECT_IN_USE), |
| 2961 | + errmsg("relation \"%s\" is being used by active queries in this session", |
| 2962 | + RelationGetRelationName(childrel)))); |
2932 | 2963 | ATPrepCmd(wqueue, childrel, cmd, false, true);
|
2933 | 2964 | relation_close(childrel, NoLock);
|
2934 | 2965 | }
|
@@ -2960,6 +2991,12 @@ ATOneLevelRecursion(List **wqueue, Relation rel,
|
2960 | 2991 | Relation childrel;
|
2961 | 2992 |
|
2962 | 2993 | childrel = relation_open(childrelid, AccessExclusiveLock);
|
| 2994 | + /* check for child relation in use in this session */ |
| 2995 | + if (childrel->rd_refcnt != 1) |
| 2996 | + ereport(ERROR, |
| 2997 | + (errcode(ERRCODE_OBJECT_IN_USE), |
| 2998 | + errmsg("relation \"%s\" is being used by active queries in this session", |
| 2999 | + RelationGetRelationName(childrel)))); |
2963 | 3000 | ATPrepCmd(wqueue, childrel, cmd, true, true);
|
2964 | 3001 | relation_close(childrel, NoLock);
|
2965 | 3002 | }
|
@@ -3765,6 +3802,12 @@ ATExecDropColumn(Relation rel, const char *colName,
|
3765 | 3802 | Form_pg_attribute childatt;
|
3766 | 3803 |
|
3767 | 3804 | childrel = heap_open(childrelid, AccessExclusiveLock);
|
| 3805 | + /* check for child relation in use in this session */ |
| 3806 | + if (childrel->rd_refcnt != 1) |
| 3807 | + ereport(ERROR, |
| 3808 | + (errcode(ERRCODE_OBJECT_IN_USE), |
| 3809 | + errmsg("relation \"%s\" is being used by active queries in this session", |
| 3810 | + RelationGetRelationName(childrel)))); |
3768 | 3811 |
|
3769 | 3812 | tuple = SearchSysCacheCopyAttName(childrelid, colName);
|
3770 | 3813 | if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
|
|
0 commit comments