diff --git a/doc/src/sgml/ref/lock.sgml b/doc/src/sgml/ref/lock.sgml index 10f1427f9f..a225cea63b 100644 --- a/doc/src/sgml/ref/lock.sgml +++ b/doc/src/sgml/ref/lock.sgml @@ -16,7 +16,7 @@ PostgreSQL documentation LOCK - lock a named relation (table, etc) + lock a table @@ -34,9 +34,7 @@ LOCK [ TABLE ] [ ONLY ] name [ * ] Description - LOCK TABLE obtains a table-level lock on a - relation (table, partitioned table, foreign table, view, - materialized view, index, composite type, sequence), waiting + LOCK TABLE obtains a table-level lock, waiting if necessary for any conflicting locks to be released. If NOWAIT is specified, LOCK TABLE does not wait to acquire the desired lock: if it @@ -117,18 +115,17 @@ LOCK [ TABLE ] [ ONLY ] name [ * ] name - The name (optionally schema-qualified) of an existing relation to - lock. If ONLY is specified before a table name, only that + The name (optionally schema-qualified) of an existing table to + lock. If ONLY is specified before the table name, only that table is locked. If ONLY is not specified, the table and all its descendant tables (if any) are locked. Optionally, * can be specified after the table name to explicitly indicate that - descendant tables are included. When locking a view, all relations appearing - in the view definition are locked, regardless of ONLY. + descendant tables are included. The command LOCK TABLE a, b; is equivalent to - LOCK TABLE a; LOCK TABLE b;. The relations are locked + LOCK TABLE a; LOCK TABLE b;. The tables are locked one-by-one in the order specified in the LOCK TABLE command. diff --git a/src/backend/commands/lockcmds.c b/src/backend/commands/lockcmds.c index dbd8cf4706..46ada49f4b 100644 --- a/src/backend/commands/lockcmds.c +++ b/src/backend/commands/lockcmds.c @@ -95,6 +95,14 @@ RangeVarCallbackForLockTable(const RangeVar *rv, Oid relid, Oid oldrelid, return; /* woops, concurrently dropped; no permissions * check */ + /* Currently, we only allow plain tables or views to be locked */ + if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE && + relkind != RELKIND_VIEW) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is not a table or a view", + rv->relname))); + /* * Make note if a temporary relation has been accessed in this * transaction. @@ -201,13 +209,11 @@ LockViewRecurse_walker(Node *node, LockViewRecurse_context *context) foreach(rtable, query->rtable) { RangeTblEntry *rte = lfirst(rtable); - Oid relid; AclResult aclresult; - /* ignore all non-relation RTEs */ - if (rte->rtekind != RTE_RELATION) - continue; - relid = rte->relid; + Oid relid = rte->relid; + char relkind = rte->relkind; + char *relname = get_rel_name(relid); /* * The OLD and NEW placeholder entries in the view's rtable are @@ -217,6 +223,11 @@ LockViewRecurse_walker(Node *node, LockViewRecurse_context *context) (!strcmp(rte->eref->aliasname, "old") || !strcmp(rte->eref->aliasname, "new"))) continue; + /* Currently, we only allow plain tables or views to be locked. */ + if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE && + relkind != RELKIND_VIEW) + continue; + /* * We might be dealing with a self-referential view. If so, we * can just stop recursing, since we already locked it. @@ -227,8 +238,7 @@ LockViewRecurse_walker(Node *node, LockViewRecurse_context *context) /* Check permissions with the view owner's privilege. */ aclresult = LockTableAclCheck(relid, context->lockmode, context->viewowner); if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, get_relkind_objtype(rte->relkind), - get_rel_name(relid)); + aclcheck_error(aclresult, get_relkind_objtype(relkind), relname); /* We have enough rights to lock the relation; do so. */ if (!context->nowait) @@ -237,9 +247,9 @@ LockViewRecurse_walker(Node *node, LockViewRecurse_context *context) ereport(ERROR, (errcode(ERRCODE_LOCK_NOT_AVAILABLE), errmsg("could not obtain lock on relation \"%s\"", - get_rel_name(relid)))); + relname))); - if (rte->relkind == RELKIND_VIEW) + if (relkind == RELKIND_VIEW) LockViewRecurse(relid, context->lockmode, context->nowait, context->ancestor_views); else if (rte->inh) diff --git a/src/test/regress/expected/lock.out b/src/test/regress/expected/lock.out index 25117b5f61..0ed982d195 100644 --- a/src/test/regress/expected/lock.out +++ b/src/test/regress/expected/lock.out @@ -12,9 +12,6 @@ CREATE VIEW lock_view3 AS SELECT * from lock_view2; CREATE VIEW lock_view4 AS SELECT (select a from lock_tbl1a limit 1) from lock_tbl1; CREATE VIEW lock_view5 AS SELECT * from lock_tbl1 where a in (select * from lock_tbl1a); CREATE VIEW lock_view6 AS SELECT * from (select * from lock_tbl1) sub; -CREATE MATERIALIZED VIEW lock_mv1 AS SELECT * FROM lock_view6; -CREATE INDEX lock_mvi1 ON lock_mv1 (a); -CREATE SEQUENCE lock_seq; CREATE ROLE regress_rol_lock1; ALTER ROLE regress_rol_lock1 SET search_path = lock_schema1; GRANT USAGE ON SCHEMA lock_schema1 TO regress_rol_lock1; @@ -151,16 +148,9 @@ BEGIN; LOCK TABLE ONLY lock_tbl1; ROLLBACK; RESET ROLE; --- Lock other relations -BEGIN TRANSACTION; -LOCK TABLE lock_mv1; -LOCK TABLE lock_mvi1; -LOCK TABLE lock_seq; -ROLLBACK; -- -- Clean up -- -DROP MATERIALIZED VIEW lock_mv1; DROP VIEW lock_view7; DROP VIEW lock_view6; DROP VIEW lock_view5; @@ -172,7 +162,6 @@ DROP TABLE lock_tbl3; DROP TABLE lock_tbl2; DROP TABLE lock_tbl1; DROP TABLE lock_tbl1a; -DROP SEQUENCE lock_seq; DROP SCHEMA lock_schema1 CASCADE; DROP ROLE regress_rol_lock1; -- atomic ops tests diff --git a/src/test/regress/sql/lock.sql b/src/test/regress/sql/lock.sql index 5fe18a1aff..c04e4ca999 100644 --- a/src/test/regress/sql/lock.sql +++ b/src/test/regress/sql/lock.sql @@ -13,9 +13,6 @@ CREATE VIEW lock_view3 AS SELECT * from lock_view2; CREATE VIEW lock_view4 AS SELECT (select a from lock_tbl1a limit 1) from lock_tbl1; CREATE VIEW lock_view5 AS SELECT * from lock_tbl1 where a in (select * from lock_tbl1a); CREATE VIEW lock_view6 AS SELECT * from (select * from lock_tbl1) sub; -CREATE MATERIALIZED VIEW lock_mv1 AS SELECT * FROM lock_view6; -CREATE INDEX lock_mvi1 ON lock_mv1 (a); -CREATE SEQUENCE lock_seq; CREATE ROLE regress_rol_lock1; ALTER ROLE regress_rol_lock1 SET search_path = lock_schema1; GRANT USAGE ON SCHEMA lock_schema1 TO regress_rol_lock1; @@ -116,18 +113,9 @@ LOCK TABLE ONLY lock_tbl1; ROLLBACK; RESET ROLE; --- Lock other relations -BEGIN TRANSACTION; -LOCK TABLE lock_mv1; -LOCK TABLE lock_mvi1; -LOCK TABLE lock_seq; -ROLLBACK; - - -- -- Clean up -- -DROP MATERIALIZED VIEW lock_mv1; DROP VIEW lock_view7; DROP VIEW lock_view6; DROP VIEW lock_view5; @@ -138,7 +126,6 @@ DROP TABLE lock_tbl3; DROP TABLE lock_tbl2; DROP TABLE lock_tbl1; DROP TABLE lock_tbl1a; -DROP SEQUENCE lock_seq; DROP SCHEMA lock_schema1 CASCADE; DROP ROLE regress_rol_lock1;