mirror of
https://github.com/postgres/postgres.git
synced 2025-07-03 20:02:46 +03:00
Obtain required table lock during cross-table constraint updates.
Sometimes a table's constraint may depend on a column of another table, so that we have to update the constraint when changing the referenced column's type. We need to have lock on the constraint's table to do that. ATPostAlterTypeCleanup believed that this case was only possible for FOREIGN KEY constraints, but it's wrong at least for CHECK and EXCLUDE constraints; and in general, we'd probably need exclusive lock to alter any sort of constraint. So just remove the contype check and acquire lock for any other table. This prevents a "you don't have lock" assertion failure, though no ill effect is observed in production builds. We'll error out later anyway because we don't presently support physically altering column types within stored composite columns. But the catalog-munging is basically all there, so we may as well make that part work. Bug: #18970 Reported-by: Alexander Lakhin <exclusion@gmail.com> Diagnosed-by: jian he <jian.universality@gmail.com> Author: Tom Lane <tgl@sss.pgh.pa.us> Discussion: https://postgr.es/m/18970-a7d1cfe1f8d5d8d9@postgresql.org Backpatch-through: 13
This commit is contained in:
@ -15415,9 +15415,12 @@ ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
|
|||||||
/*
|
/*
|
||||||
* Re-parse the index and constraint definitions, and attach them to the
|
* Re-parse the index and constraint definitions, and attach them to the
|
||||||
* appropriate work queue entries. We do this before dropping because in
|
* appropriate work queue entries. We do this before dropping because in
|
||||||
* the case of a FOREIGN KEY constraint, we might not yet have exclusive
|
* the case of a constraint on another table, we might not yet have
|
||||||
* lock on the table the constraint is attached to, and we need to get
|
* exclusive lock on the table the constraint is attached to, and we need
|
||||||
* that before reparsing/dropping.
|
* to get that before reparsing/dropping. (That's possible at least for
|
||||||
|
* FOREIGN KEY, CHECK, and EXCLUSION constraints; in non-FK cases it
|
||||||
|
* requires a dependency on the target table's composite type in the other
|
||||||
|
* table's constraint expressions.)
|
||||||
*
|
*
|
||||||
* We can't rely on the output of deparsing to tell us which relation to
|
* We can't rely on the output of deparsing to tell us which relation to
|
||||||
* operate on, because concurrent activity might have made the name
|
* operate on, because concurrent activity might have made the name
|
||||||
@ -15433,7 +15436,6 @@ ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
|
|||||||
Form_pg_constraint con;
|
Form_pg_constraint con;
|
||||||
Oid relid;
|
Oid relid;
|
||||||
Oid confrelid;
|
Oid confrelid;
|
||||||
char contype;
|
|
||||||
bool conislocal;
|
bool conislocal;
|
||||||
|
|
||||||
tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(oldId));
|
tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(oldId));
|
||||||
@ -15450,7 +15452,6 @@ ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
|
|||||||
elog(ERROR, "could not identify relation associated with constraint %u", oldId);
|
elog(ERROR, "could not identify relation associated with constraint %u", oldId);
|
||||||
}
|
}
|
||||||
confrelid = con->confrelid;
|
confrelid = con->confrelid;
|
||||||
contype = con->contype;
|
|
||||||
conislocal = con->conislocal;
|
conislocal = con->conislocal;
|
||||||
ReleaseSysCache(tup);
|
ReleaseSysCache(tup);
|
||||||
|
|
||||||
@ -15468,12 +15469,12 @@ ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When rebuilding an FK constraint that references the table we're
|
* When rebuilding another table's constraint that references the
|
||||||
* modifying, we might not yet have any lock on the FK's table, so get
|
* table we're modifying, we might not yet have any lock on the other
|
||||||
* one now. We'll need AccessExclusiveLock for the DROP CONSTRAINT
|
* table, so get one now. We'll need AccessExclusiveLock for the DROP
|
||||||
* step, so there's no value in asking for anything weaker.
|
* CONSTRAINT step, so there's no value in asking for anything weaker.
|
||||||
*/
|
*/
|
||||||
if (relid != tab->relid && contype == CONSTRAINT_FOREIGN)
|
if (relid != tab->relid)
|
||||||
LockRelationOid(relid, AccessExclusiveLock);
|
LockRelationOid(relid, AccessExclusiveLock);
|
||||||
|
|
||||||
ATPostAlterTypeParse(oldId, relid, confrelid,
|
ATPostAlterTypeParse(oldId, relid, confrelid,
|
||||||
|
@ -4745,6 +4745,13 @@ alter table attbl alter column p1 set data type bigint;
|
|||||||
alter table atref alter column c1 set data type bigint;
|
alter table atref alter column c1 set data type bigint;
|
||||||
drop table attbl, atref;
|
drop table attbl, atref;
|
||||||
/* End test case for bug #17409 */
|
/* End test case for bug #17409 */
|
||||||
|
/* Test case for bug #18970 */
|
||||||
|
create table attbl(a int);
|
||||||
|
create table atref(b attbl check ((b).a is not null));
|
||||||
|
alter table attbl alter column a type numeric; -- someday this should work
|
||||||
|
ERROR: cannot alter table "attbl" because column "atref.b" uses its row type
|
||||||
|
drop table attbl, atref;
|
||||||
|
/* End test case for bug #18970 */
|
||||||
-- Test that ALTER TABLE rewrite preserves a clustered index
|
-- Test that ALTER TABLE rewrite preserves a clustered index
|
||||||
-- for normal indexes and indexes on constraints.
|
-- for normal indexes and indexes on constraints.
|
||||||
create table alttype_cluster (a int);
|
create table alttype_cluster (a int);
|
||||||
|
@ -3069,6 +3069,15 @@ drop table attbl, atref;
|
|||||||
|
|
||||||
/* End test case for bug #17409 */
|
/* End test case for bug #17409 */
|
||||||
|
|
||||||
|
/* Test case for bug #18970 */
|
||||||
|
|
||||||
|
create table attbl(a int);
|
||||||
|
create table atref(b attbl check ((b).a is not null));
|
||||||
|
alter table attbl alter column a type numeric; -- someday this should work
|
||||||
|
drop table attbl, atref;
|
||||||
|
|
||||||
|
/* End test case for bug #18970 */
|
||||||
|
|
||||||
-- Test that ALTER TABLE rewrite preserves a clustered index
|
-- Test that ALTER TABLE rewrite preserves a clustered index
|
||||||
-- for normal indexes and indexes on constraints.
|
-- for normal indexes and indexes on constraints.
|
||||||
create table alttype_cluster (a int);
|
create table alttype_cluster (a int);
|
||||||
|
Reference in New Issue
Block a user