From 44b973b91029cb5aecf09d589bdf3f05cfddaa60 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 5 Nov 2020 11:44:32 -0500 Subject: [PATCH] Don't throw an error for LOCK TABLE on a self-referential view. LOCK TABLE has complained about "infinite recursion" when applied to a self-referential view, ever since we made it recurse into views in v11. However, that breaks pg_dump's new assumption that it's okay to lock every relation. There doesn't seem to be any good reason to throw an error: if we just abandon the recursion, we've still satisfied the requirement of locking every referenced relation. Per bug #16703 from Andrew Bille (via Alexander Lakhin). Discussion: https://postgr.es/m/16703-e348f58aab3cf6cc@postgresql.org --- src/backend/commands/lockcmds.c | 21 ++++++++++++--------- src/test/regress/expected/lock.out | 4 +--- src/test/regress/sql/lock.sql | 2 +- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/backend/commands/lockcmds.c b/src/backend/commands/lockcmds.c index f64246dba39..0cd762ea5b4 100644 --- a/src/backend/commands/lockcmds.c +++ b/src/backend/commands/lockcmds.c @@ -32,7 +32,8 @@ static void LockTableRecurse(Oid reloid, LOCKMODE lockmode, bool nowait); static AclResult LockTableAclCheck(Oid relid, LOCKMODE lockmode, Oid userid); static void RangeVarCallbackForLockTable(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg); -static void LockViewRecurse(Oid reloid, LOCKMODE lockmode, bool nowait, List *ancestor_views); +static void LockViewRecurse(Oid reloid, LOCKMODE lockmode, bool nowait, + List *ancestor_views); /* * LOCK TABLE @@ -195,12 +196,12 @@ LockViewRecurse_walker(Node *node, LockViewRecurse_context *context) strcmp(rte->eref->aliasname, "new") == 0)) continue; - /* Check infinite recursion in the view definition. */ + /* + * We might be dealing with a self-referential view. If so, we + * can just stop recursing, since we already locked it. + */ if (list_member_oid(context->ancestor_views, relid)) - ereport(ERROR, - (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("infinite recursion detected in rules for relation \"%s\"", - get_rel_name(relid)))); + continue; /* Check permissions with the view owner's privilege. */ aclresult = LockTableAclCheck(relid, context->lockmode, context->viewowner); @@ -218,7 +219,8 @@ LockViewRecurse_walker(Node *node, LockViewRecurse_context *context) get_rel_name(relid)))); if (rte->relkind == RELKIND_VIEW) - LockViewRecurse(relid, context->lockmode, context->nowait, context->ancestor_views); + LockViewRecurse(relid, context->lockmode, context->nowait, + context->ancestor_views); else if (rte->inh) LockTableRecurse(relid, context->lockmode, context->nowait); } @@ -235,13 +237,14 @@ LockViewRecurse_walker(Node *node, LockViewRecurse_context *context) } static void -LockViewRecurse(Oid reloid, LOCKMODE lockmode, bool nowait, List *ancestor_views) +LockViewRecurse(Oid reloid, LOCKMODE lockmode, bool nowait, + List *ancestor_views) { LockViewRecurse_context context; - Relation view; Query *viewquery; + /* caller has already locked the view */ view = table_open(reloid, NoLock); viewquery = get_view_query(view); diff --git a/src/test/regress/expected/lock.out b/src/test/regress/expected/lock.out index 1d6a4e9f1e0..f39280a4fa6 100644 --- a/src/test/regress/expected/lock.out +++ b/src/test/regress/expected/lock.out @@ -124,16 +124,14 @@ select relname from pg_locks l, pg_class c (2 rows) ROLLBACK; --- detecting infinite recursions in view definitions +-- Verify that we cope with infinite recursion in view definitions. CREATE OR REPLACE VIEW lock_view2 AS SELECT * from lock_view3; BEGIN TRANSACTION; LOCK TABLE lock_view2 IN EXCLUSIVE MODE; -ERROR: infinite recursion detected in rules for relation "lock_view2" ROLLBACK; CREATE VIEW lock_view7 AS SELECT * from lock_view2; BEGIN TRANSACTION; LOCK TABLE lock_view7 IN EXCLUSIVE MODE; -ERROR: infinite recursion detected in rules for relation "lock_view2" ROLLBACK; -- Verify that we can lock a table with inheritance children. CREATE TABLE lock_tbl2 (b BIGINT) INHERITS (lock_tbl1); diff --git a/src/test/regress/sql/lock.sql b/src/test/regress/sql/lock.sql index 98d13fc8e1e..4f032f1c2e4 100644 --- a/src/test/regress/sql/lock.sql +++ b/src/test/regress/sql/lock.sql @@ -87,7 +87,7 @@ select relname from pg_locks l, pg_class c where l.relation = c.oid and relname like '%lock_%' and mode = 'ExclusiveLock' order by relname; ROLLBACK; --- detecting infinite recursions in view definitions +-- Verify that we cope with infinite recursion in view definitions. CREATE OR REPLACE VIEW lock_view2 AS SELECT * from lock_view3; BEGIN TRANSACTION; LOCK TABLE lock_view2 IN EXCLUSIVE MODE;