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
This commit is contained in:
Tom Lane 2020-11-05 11:44:32 -05:00
parent 02c9386ca4
commit 44b973b910
3 changed files with 14 additions and 13 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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;