aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2020-11-05 11:44:32 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2020-11-05 11:44:32 -0500
commit44b973b91029cb5aecf09d589bdf3f05cfddaa60 (patch)
treefa216a3dad59fe5048bc373f548baee8b3936ff0
parent02c9386ca4f706364904be2720e2d09916e2b619 (diff)
downloadpostgresql-44b973b91029cb5aecf09d589bdf3f05cfddaa60.tar.gz
postgresql-44b973b91029cb5aecf09d589bdf3f05cfddaa60.zip
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
-rw-r--r--src/backend/commands/lockcmds.c21
-rw-r--r--src/test/regress/expected/lock.out4
-rw-r--r--src/test/regress/sql/lock.sql2
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;