Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/generated/sql/bnf/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ FILES = [
"legacy_transaction_stmt",
"like_table_option_list",
"limit_clause",
"lock_stmt",
"move_cursor_stmt",
"nonpreparable_set_stmt",
"not_null_column_level",
Expand Down
5 changes: 5 additions & 0 deletions docs/generated/sql/bnf/lock_stmt.bnf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
lock_stmt ::=
'LOCK' opt_table relation_expr_list 'IN' lock_mode 'MODE'
| 'LOCK' opt_table relation_expr_list 'IN' lock_mode 'MODE' 'NOWAIT'
| 'LOCK' opt_table relation_expr_list
| 'LOCK' opt_table relation_expr_list 'NOWAIT'
47 changes: 34 additions & 13 deletions docs/generated/sql/bnf/stmt_block.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ stmt_without_legacy_transaction ::=
| declare_cursor_stmt
| fetch_cursor_stmt
| move_cursor_stmt
| lock_stmt
| unlisten_stmt
| show_commit_timestamp_stmt

Expand Down Expand Up @@ -180,6 +181,12 @@ fetch_cursor_stmt ::=
move_cursor_stmt ::=
'MOVE' cursor_movement_specifier

lock_stmt ::=
'LOCK' opt_table relation_expr_list 'IN' lock_mode 'MODE'
| 'LOCK' opt_table relation_expr_list 'IN' lock_mode 'MODE' 'NOWAIT'
| 'LOCK' opt_table relation_expr_list
| 'LOCK' opt_table relation_expr_list 'NOWAIT'

unlisten_stmt ::=
'UNLISTEN' type_name
| 'UNLISTEN' '*'
Expand Down Expand Up @@ -550,6 +557,23 @@ cursor_movement_specifier ::=
| 'FIRST' opt_from_or_in cursor_name
| 'LAST' opt_from_or_in cursor_name

opt_table ::=
'TABLE'
|

relation_expr_list ::=
( relation_expr ) ( ( ',' relation_expr ) )*

lock_mode ::=
'ACCESS' 'SHARE'
| 'ROW' 'SHARE'
| 'ROW' 'EXCLUSIVE'
| 'SHARE' 'UPDATE' 'EXCLUSIVE'
| 'SHARE' 'ROW' 'EXCLUSIVE'
| 'SHARE'
| 'EXCLUSIVE'
| 'ACCESS' 'EXCLUSIVE'

opt_transaction ::=
'TRANSACTION'
| 'WORK'
Expand Down Expand Up @@ -1073,13 +1097,6 @@ show_default_privileges_stmt ::=
show_inspect_errors_stmt ::=
'SHOW' 'INSPECT' 'ERRORS' opt_for_table_clause opt_for_job_clause opt_with_details

opt_table ::=
'TABLE'
|

relation_expr_list ::=
( relation_expr ) ( ( ',' relation_expr ) )*

set_clause_list ::=
( set_clause ) ( ( ',' set_clause ) )*

Expand Down Expand Up @@ -1236,6 +1253,7 @@ unreserved_keyword ::=
| 'ESCAPE'
| 'EXCLUDE'
| 'EXCLUDING'
| 'EXCLUSIVE'
| 'EXPLICIT'
| 'EXECUTE'
| 'EXECUTION'
Expand Down Expand Up @@ -1333,6 +1351,7 @@ unreserved_keyword ::=
| 'LINESTRINGZ'
| 'LINESTRINGZM'
| 'LIST'
| 'LOCK'
| 'LOCAL'
| 'LOCKED'
| 'LOGICAL'
Expand Down Expand Up @@ -1752,6 +1771,12 @@ opt_forward_backward ::=
signed_iconst64 ::=
signed_iconst

relation_expr ::=
table_name
| table_name '*'
| 'ONLY' table_name
| 'ONLY' '(' table_name ')'

alter_table_stmt ::=
alter_onetable_stmt
| alter_split_stmt
Expand Down Expand Up @@ -2325,12 +2350,6 @@ opt_with_details ::=
'WITH' 'DETAILS'
|

relation_expr ::=
table_name
| table_name '*'
| 'ONLY' table_name
| 'ONLY' '(' table_name ')'

set_clause ::=
single_set_clause
| multiple_set_clause
Expand Down Expand Up @@ -4233,6 +4252,7 @@ bare_label_keywords ::=
| 'ESCAPE'
| 'EXCLUDE'
| 'EXCLUDING'
| 'EXCLUSIVE'
| 'EXPLICIT'
| 'EXECUTE'
| 'EXECUTION'
Expand Down Expand Up @@ -4364,6 +4384,7 @@ bare_label_keywords ::=
| 'LINESTRINGZ'
| 'LINESTRINGZM'
| 'LIST'
| 'LOCK'
| 'LOCAL'
| 'LOCALITY'
| 'LOCALTIME'
Expand Down
1 change: 1 addition & 0 deletions docs/generated/sql/bnf/stmt_without_legacy_transaction.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ stmt_without_legacy_transaction ::=
| declare_cursor_stmt
| fetch_cursor_stmt
| move_cursor_stmt
| lock_stmt
| unlisten_stmt
| show_commit_timestamp_stmt
1 change: 1 addition & 0 deletions pkg/gen/bnf.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ BNF_SRCS = [
"//docs/generated/sql/bnf:legacy_transaction_stmt.bnf",
"//docs/generated/sql/bnf:like_table_option_list.bnf",
"//docs/generated/sql/bnf:limit_clause.bnf",
"//docs/generated/sql/bnf:lock_stmt.bnf",
"//docs/generated/sql/bnf:move_cursor_stmt.bnf",
"//docs/generated/sql/bnf:nonpreparable_set_stmt.bnf",
"//docs/generated/sql/bnf:not_null_column_level.bnf",
Expand Down
1 change: 1 addition & 0 deletions pkg/gen/diagrams.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ DIAGRAMS_SRCS = [
"//docs/generated/sql/bnf:legacy_transaction.html",
"//docs/generated/sql/bnf:like_table_option_list.html",
"//docs/generated/sql/bnf:limit_clause.html",
"//docs/generated/sql/bnf:lock.html",
"//docs/generated/sql/bnf:move_cursor.html",
"//docs/generated/sql/bnf:nonpreparable_set.html",
"//docs/generated/sql/bnf:not_null_column_level.html",
Expand Down
1 change: 1 addition & 0 deletions pkg/gen/docs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ DOCS_SRCS = [
"//docs/generated/sql/bnf:legacy_transaction_stmt.bnf",
"//docs/generated/sql/bnf:like_table_option_list.bnf",
"//docs/generated/sql/bnf:limit_clause.bnf",
"//docs/generated/sql/bnf:lock_stmt.bnf",
"//docs/generated/sql/bnf:move_cursor_stmt.bnf",
"//docs/generated/sql/bnf:nonpreparable_set_stmt.bnf",
"//docs/generated/sql/bnf:not_null_column_level.bnf",
Expand Down
1 change: 1 addition & 0 deletions pkg/sql/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ go_library(
"join.go",
"join_predicate.go",
"limit.go",
"lock_table.go",
"lookup_join.go",
"max_one_row.go",
"mem_metrics.go",
Expand Down
26 changes: 26 additions & 0 deletions pkg/sql/lock_table.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright 2026 The Cockroach Authors.
//
// Use of this software is governed by the CockroachDB Software License
// included in the /LICENSE file.

package sql

import (
"context"

"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode"
"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror"
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
"github.com/cockroachdb/cockroach/pkg/sql/sessiondatapb"
)

func (p *planner) LockTable(ctx context.Context, n *tree.LockTable) (planNode, error) {
if sessiondatapb.IsPgDumpCompatibilityEnabled(p.SessionData().PgDumpCompatibility) {
// CockroachDB uses MVCC, so all lock modes are implicitly satisfied
// by the concurrency control system. This is a no-op for pg_dump
// compatibility.
return newZeroNode(nil /* columns */), nil
}
return nil, pgerror.New(pgcode.FeatureNotSupported,
"LOCK TABLE is not supported")
}
18 changes: 18 additions & 0 deletions pkg/sql/logictest/testdata/logic_test/pg_catalog
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,24 @@ SELECT * FROM pg_catalog.pg_matviews
schemaname matviewname matviewowner tablespace hasindexes ispopulated definition
public mv1 root NULL false true SELECT 1;

# When pg_dump_compatibility is enabled, view definitions should use
# schema-qualified names (no database prefix).
statement ok
SET pg_dump_compatibility = 'postgres'

query T
SELECT definition FROM pg_catalog.pg_views WHERE viewname = 'v1'
----
SELECT p, a, b, c FROM public.t1;

query T
SELECT definition FROM pg_catalog.pg_matviews WHERE matviewname = 'mv1'
----
SELECT 1;

statement ok
SET pg_dump_compatibility = 'off'

## pg_catalog.pg_class

query TTBOOOO colnames,rowsort
Expand Down
18 changes: 11 additions & 7 deletions pkg/sql/logictest/testdata/logic_test/system_columns
Original file line number Diff line number Diff line change
Expand Up @@ -406,14 +406,19 @@ SELECT bool_and(tableoid = $is_tables_oid2) FROM information_schema.tables
----
true

# crdb_internal tables should also be unaffected.
let $crdb_tables_oid
SELECT oid FROM pg_class WHERE relname = 'tables' AND relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'crdb_internal')
# crdb_internal tables should be hidden from pg_class so pg_dump does
# not try to dump them.
query I
SELECT count(*) FROM pg_class WHERE relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'crdb_internal')
----
0

query B
SELECT bool_and(tableoid = $crdb_tables_oid) FROM crdb_internal.tables
# crdb_internal and information_schema functions should be hidden from
# pg_proc so pg_dump does not try to dump them.
query I
SELECT count(*) FROM pg_proc WHERE pronamespace IN (SELECT oid FROM pg_namespace WHERE nspname IN ('crdb_internal', 'information_schema'))
----
true
0

# Additional pg_catalog tables should also have remapped tableoids.
query O
Expand Down Expand Up @@ -522,5 +527,4 @@ SET pg_dump_compatibility = 'off'

statement ok
DROP TABLE t_schema_locked

subtest end
68 changes: 68 additions & 0 deletions pkg/sql/logictest/testdata/logic_test/table
Original file line number Diff line number Diff line change
Expand Up @@ -694,3 +694,71 @@ query I
SELECT estimated_row_count FROM crdb_internal.table_row_statistics WHERE table_name = 't'
----
10

subtest lock_table

# LOCK TABLE is not supported by default.
statement error pgcode 0A000 LOCK TABLE is not supported
LOCK TABLE t IN ACCESS SHARE MODE

# Bare LOCK (without IN ... MODE) is also not supported by default.
statement error pgcode 0A000 LOCK TABLE is not supported
LOCK t

statement ok
SET pg_dump_compatibility = 'postgres'

# LOCK TABLE is a no-op when pg_dump_compatibility is enabled.
statement ok
LOCK TABLE t IN ACCESS SHARE MODE

# Multiple tables work too (pg_dump batches locks).
statement ok
LOCK TABLE t, pg_class IN ACCESS SHARE MODE

# NOWAIT variant also works.
statement ok
LOCK TABLE t IN ACCESS SHARE MODE NOWAIT

# All lock modes are accepted.
statement ok
LOCK TABLE t IN ROW SHARE MODE

statement ok
LOCK TABLE t IN ROW EXCLUSIVE MODE

statement ok
LOCK TABLE t IN SHARE UPDATE EXCLUSIVE MODE

statement ok
LOCK TABLE t IN SHARE MODE

statement ok
LOCK TABLE t IN SHARE ROW EXCLUSIVE MODE

statement ok
LOCK TABLE t IN EXCLUSIVE MODE

statement ok
LOCK TABLE t IN ACCESS EXCLUSIVE MODE

# Bare LOCK (no IN ... MODE) defaults to ACCESS EXCLUSIVE.
statement ok
LOCK t

# Bare LOCK with NOWAIT.
statement ok
LOCK t NOWAIT

# TABLE keyword is optional.
statement ok
LOCK TABLE t

statement ok
SET pg_dump_compatibility = 'off'

# Verify LOCK TABLE is rejected again after disabling compat mode.
statement error pgcode 0A000 LOCK TABLE is not supported
LOCK TABLE t IN ACCESS SHARE MODE

subtest end
3 changes: 3 additions & 0 deletions pkg/sql/opaque.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,8 @@ func planOpaque(ctx context.Context, p *planner, stmt tree.Statement) (planNode,
return p.ShowCreateTrigger(ctx, n)
case *tree.Truncate:
return p.Truncate(ctx, n)
case *tree.LockTable:
return p.LockTable(ctx, n)
case *tree.Unlisten:
return p.Unlisten(ctx, n)
case *pgrepltree.IdentifySystem:
Expand Down Expand Up @@ -457,6 +459,7 @@ func init() {
&tree.ShowTransactionStatus{},
&tree.ShowTriggers{},
&tree.ShowCreateTrigger{},
&tree.LockTable{},
&tree.Truncate{},
&tree.Unlisten{},

Expand Down
Loading
Loading