Commit 5b7bfc39 authored by Tom Lane's avatar Tom Lane

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
parent 48e12913
...@@ -32,7 +32,8 @@ static void LockTableRecurse(Oid reloid, LOCKMODE lockmode, bool nowait); ...@@ -32,7 +32,8 @@ static void LockTableRecurse(Oid reloid, LOCKMODE lockmode, bool nowait);
static AclResult LockTableAclCheck(Oid relid, LOCKMODE lockmode, Oid userid); static AclResult LockTableAclCheck(Oid relid, LOCKMODE lockmode, Oid userid);
static void RangeVarCallbackForLockTable(const RangeVar *rv, Oid relid, static void RangeVarCallbackForLockTable(const RangeVar *rv, Oid relid,
Oid oldrelid, void *arg); 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 * LOCK TABLE
...@@ -195,12 +196,12 @@ LockViewRecurse_walker(Node *node, LockViewRecurse_context *context) ...@@ -195,12 +196,12 @@ LockViewRecurse_walker(Node *node, LockViewRecurse_context *context)
strcmp(rte->eref->aliasname, "new") == 0)) strcmp(rte->eref->aliasname, "new") == 0))
continue; 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)) if (list_member_oid(context->ancestor_views, relid))
ereport(ERROR, continue;
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("infinite recursion detected in rules for relation \"%s\"",
get_rel_name(relid))));
/* Check permissions with the view owner's privilege. */ /* Check permissions with the view owner's privilege. */
aclresult = LockTableAclCheck(relid, context->lockmode, context->viewowner); aclresult = LockTableAclCheck(relid, context->lockmode, context->viewowner);
...@@ -218,7 +219,8 @@ LockViewRecurse_walker(Node *node, LockViewRecurse_context *context) ...@@ -218,7 +219,8 @@ LockViewRecurse_walker(Node *node, LockViewRecurse_context *context)
get_rel_name(relid)))); get_rel_name(relid))));
if (rte->relkind == RELKIND_VIEW) 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) else if (rte->inh)
LockTableRecurse(relid, context->lockmode, context->nowait); LockTableRecurse(relid, context->lockmode, context->nowait);
} }
...@@ -235,13 +237,14 @@ LockViewRecurse_walker(Node *node, LockViewRecurse_context *context) ...@@ -235,13 +237,14 @@ LockViewRecurse_walker(Node *node, LockViewRecurse_context *context)
} }
static void 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; LockViewRecurse_context context;
Relation view; Relation view;
Query *viewquery; Query *viewquery;
/* caller has already locked the view */
view = table_open(reloid, NoLock); view = table_open(reloid, NoLock);
viewquery = get_view_query(view); viewquery = get_view_query(view);
......
...@@ -124,16 +124,14 @@ select relname from pg_locks l, pg_class c ...@@ -124,16 +124,14 @@ select relname from pg_locks l, pg_class c
(2 rows) (2 rows)
ROLLBACK; 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; CREATE OR REPLACE VIEW lock_view2 AS SELECT * from lock_view3;
BEGIN TRANSACTION; BEGIN TRANSACTION;
LOCK TABLE lock_view2 IN EXCLUSIVE MODE; LOCK TABLE lock_view2 IN EXCLUSIVE MODE;
ERROR: infinite recursion detected in rules for relation "lock_view2"
ROLLBACK; ROLLBACK;
CREATE VIEW lock_view7 AS SELECT * from lock_view2; CREATE VIEW lock_view7 AS SELECT * from lock_view2;
BEGIN TRANSACTION; BEGIN TRANSACTION;
LOCK TABLE lock_view7 IN EXCLUSIVE MODE; LOCK TABLE lock_view7 IN EXCLUSIVE MODE;
ERROR: infinite recursion detected in rules for relation "lock_view2"
ROLLBACK; ROLLBACK;
-- Verify that we can lock a table with inheritance children. -- Verify that we can lock a table with inheritance children.
CREATE TABLE lock_tbl2 (b BIGINT) INHERITS (lock_tbl1); CREATE TABLE lock_tbl2 (b BIGINT) INHERITS (lock_tbl1);
......
...@@ -87,7 +87,7 @@ select relname from pg_locks l, pg_class c ...@@ -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' where l.relation = c.oid and relname like '%lock_%' and mode = 'ExclusiveLock'
order by relname; order by relname;
ROLLBACK; 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; CREATE OR REPLACE VIEW lock_view2 AS SELECT * from lock_view3;
BEGIN TRANSACTION; BEGIN TRANSACTION;
LOCK TABLE lock_view2 IN EXCLUSIVE MODE; LOCK TABLE lock_view2 IN EXCLUSIVE MODE;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment