From eeb93c89831d8f933c70f2ac74369a1c7b1dbdd8 Mon Sep 17 00:00:00 2001 From: Arul Ajmani Date: Thu, 28 Sep 2023 19:44:10 -0500 Subject: [PATCH] sql: use the correct locking strength for FOR SHARE clause Previously, FOR SHARE and FOR KEY SHARE would use non-locking KV scans. Now that the lock table supports shared locks, we can use lock.Shared as the locking strength for KV scans. This patch does that, and in doing so, wires up SHARED locks end to end. By default, we turn off this functionality for serializable transactions. Instead, it's gated behind a session setting called `enable_shared_locking_for_serializable`. Informs #91545 Release note (sql change): SELECT FOR SHARE and SELECT FOR UPDATE previously did not acquire any locks. Users issuing these statements would expect them to acquire shared locks (multiple readers allowed, no writers though). This patch switches over the behavior to acquire such read locks. For serializable transactions, we default to the old behaviour, unless the `enable_shared_locking_for_serializable` session setting is set to true. We'll probably switch this behavior in the future, but for now, given shared locks are a preview feature, we gate things behind a session setting. --- .../tests/3node-tenant/generated_test.go | 7 ++ pkg/sql/exec_util.go | 4 + .../testdata/logic_test/information_schema | 1 + .../logictest/testdata/logic_test/pg_catalog | 3 + .../testdata/logic_test/select_for_share | 119 ++++++++++++++++++ .../testdata/logic_test/select_for_update | 6 + .../logictest/testdata/logic_test/show_source | 1 + .../tests/fakedist-disk/generated_test.go | 7 ++ .../tests/fakedist-vec-off/generated_test.go | 7 ++ .../tests/fakedist/generated_test.go | 7 ++ .../generated_test.go | 7 ++ .../tests/local-vec-off/generated_test.go | 7 ++ .../logictest/tests/local/generated_test.go | 7 ++ pkg/sql/opt/exec/execbuilder/testdata/fk | 5 + .../execbuilder/testdata/fk_read_committed | 5 + .../execbuilder/testdata/select_for_update | 20 +++ pkg/sql/opt/memo/memo.go | 3 + pkg/sql/opt/optbuilder/BUILD.bazel | 1 + pkg/sql/opt/optbuilder/select.go | 21 ++++ pkg/sql/row/locking.go | 4 +- .../local_only_session_data.proto | 10 +- pkg/sql/vars.go | 17 +++ 22 files changed, 265 insertions(+), 4 deletions(-) create mode 100644 pkg/sql/logictest/testdata/logic_test/select_for_share diff --git a/pkg/ccl/logictestccl/tests/3node-tenant/generated_test.go b/pkg/ccl/logictestccl/tests/3node-tenant/generated_test.go index 027c6485e9d4..5e239a045977 100644 --- a/pkg/ccl/logictestccl/tests/3node-tenant/generated_test.go +++ b/pkg/ccl/logictestccl/tests/3node-tenant/generated_test.go @@ -1668,6 +1668,13 @@ func TestTenantLogic_select( runLogicTest(t, "select") } +func TestTenantLogic_select_for_share( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runLogicTest(t, "select_for_share") +} + func TestTenantLogic_select_for_update( t *testing.T, ) { diff --git a/pkg/sql/exec_util.go b/pkg/sql/exec_util.go index 06170bce1cf7..aeb18d4dc82f 100644 --- a/pkg/sql/exec_util.go +++ b/pkg/sql/exec_util.go @@ -3638,6 +3638,10 @@ func (m *sessionDataMutator) SetDurableLockingForSerializable(val bool) { m.data.DurableLockingForSerializable = val } +func (m *sessionDataMutator) SetSharedLockingForSerializable(val bool) { + m.data.SharedLockingForSerializable = val +} + // Utility functions related to scrubbing sensitive information on SQL Stats. // quantizeCounts ensures that the Count field in the diff --git a/pkg/sql/logictest/testdata/logic_test/information_schema b/pkg/sql/logictest/testdata/logic_test/information_schema index 5ee6a43bd512..0b75145b3d1c 100644 --- a/pkg/sql/logictest/testdata/logic_test/information_schema +++ b/pkg/sql/logictest/testdata/logic_test/information_schema @@ -5346,6 +5346,7 @@ enable_insert_fast_path on enable_multiple_modifications_of_table off enable_multiregion_placement_policy off enable_seqscan on +enable_shared_locking_for_serializable off enable_super_regions off enable_zigzag_join off enforce_home_region off diff --git a/pkg/sql/logictest/testdata/logic_test/pg_catalog b/pkg/sql/logictest/testdata/logic_test/pg_catalog index 5080a200fb8f..960cc8768c2d 100644 --- a/pkg/sql/logictest/testdata/logic_test/pg_catalog +++ b/pkg/sql/logictest/testdata/logic_test/pg_catalog @@ -2788,6 +2788,7 @@ enable_insert_fast_path on N enable_multiple_modifications_of_table off NULL NULL NULL string enable_multiregion_placement_policy off NULL NULL NULL string enable_seqscan on NULL NULL NULL string +enable_shared_locking_for_serializable off NULL NULL NULL string enable_super_regions off NULL NULL NULL string enable_zigzag_join off NULL NULL NULL string enforce_home_region off NULL NULL NULL string @@ -2949,6 +2950,7 @@ enable_insert_fast_path on N enable_multiple_modifications_of_table off NULL user NULL off off enable_multiregion_placement_policy off NULL user NULL off off enable_seqscan on NULL user NULL on on +enable_shared_locking_for_serializable off NULL user NULL off off enable_super_regions off NULL user NULL off off enable_zigzag_join off NULL user NULL off off enforce_home_region off NULL user NULL off off @@ -3107,6 +3109,7 @@ enable_insert_fast_path NULL NULL NULL enable_multiple_modifications_of_table NULL NULL NULL NULL NULL enable_multiregion_placement_policy NULL NULL NULL NULL NULL enable_seqscan NULL NULL NULL NULL NULL +enable_shared_locking_for_serializable NULL NULL NULL NULL NULL enable_super_regions NULL NULL NULL NULL NULL enable_zigzag_join NULL NULL NULL NULL NULL enforce_home_region NULL NULL NULL NULL NULL diff --git a/pkg/sql/logictest/testdata/logic_test/select_for_share b/pkg/sql/logictest/testdata/logic_test/select_for_share new file mode 100644 index 000000000000..a5b6a5a4a15f --- /dev/null +++ b/pkg/sql/logictest/testdata/logic_test/select_for_share @@ -0,0 +1,119 @@ +# LogicTest: !local-mixed-22.2-23.1 + +statement ok +CREATE TABLE t(a INT PRIMARY KEY); +INSERT INTO t VALUES(1); +GRANT ALL ON t TO testuser; +CREATE USER testuser2 WITH VIEWACTIVITY; +GRANT SYSTEM MODIFYCLUSTERSETTING TO testuser; +GRANT ALL ON t TO testuser2; + +user testuser + +statement ok +SET enable_shared_locking_for_serializable = true; + +statement ok +BEGIN + +query I +SELECT * FROM t WHERE a = 1 FOR SHARE; +---- +1 + +# Start another transaction to show multiple transactions can acquire SHARED +# locks at the same time. + +user root + +statement ok +SET enable_shared_locking_for_serializable = true; + +statement ok +BEGIN + +query I +SELECT * FROM t WHERE a = 1 FOR SHARE; +---- +1 + +user testuser2 + +statement async writeReq count 1 +UPDATE t SET a = 2 WHERE a = 1 + +# TODO(arul): Until https://github.com/cockroachdb/cockroach/issues/107766 is +# addressed, we'll incorrectly report shared locks as having "Exclusive" lock +# strength; We'll also only report a single holder (the other row in there is +# the waiting UPDATE request, not the second shared lock holder). However, +# having this query in here is useful to make sure there are locks and waiters +# on our key, meaning setting the cluster setting above actually did something; +# otherwise, had we used non-locking reads, we'd have failed here. +query TTTTTTTBB colnames,retry,rowsort +SELECT database_name, schema_name, table_name, lock_key_pretty, lock_strength, durability, isolation_level, granted, contended FROM crdb_internal.cluster_locks +---- +database_name schema_name table_name lock_key_pretty lock_strength durability isolation_level granted contended +test public t /Table/106/1/1/0 Exclusive Unreplicated SERIALIZABLE true true +test public t /Table/106/1/1/0 Exclusive Unreplicated SERIALIZABLE false true + +# Commit the first transaction and rollback the second. + +user testuser + +statement ok +COMMIT + +user root + +statement ok +ROLLBACK + +user testuser2 + +# Now that both the transactions that issued shared lock reads have been +# finalized, the write should be able to proceed. + +awaitstatement writeReq + +query I +SELECT * FROM t; +---- +2 + +# ------------------------------------------------------------------------------ +# Tests to ensure the enable_shared_locking_for_serializable session variable +# works as expected. +# ----------------------------------------------------------------------------- + +user testuser + +statement ok +SET enable_shared_locking_for_serializable = false + +statement ok +BEGIN ISOLATION LEVEL SERIALIZABLE + +query I +SELECT * FROM t WHERE a = 2 FOR SHARE +---- +2 + +user testuser2 + +query TTTTTTTBB colnames,retry,rowsort +SELECT database_name, schema_name, table_name, lock_key_pretty, lock_strength, durability, isolation_level, granted, contended FROM crdb_internal.cluster_locks +---- +database_name schema_name table_name lock_key_pretty lock_strength durability isolation_level granted contended + +user testuser + +statement ok +COMMIT + +# TODO(arul): Add a test to show that the session setting doesn't apply to read +# committed transactions. We currently can't issue SELECT FOR SHARE statements +# in read committed transactions because durable locking hasn't been fully +# hooked up. + + + diff --git a/pkg/sql/logictest/testdata/logic_test/select_for_update b/pkg/sql/logictest/testdata/logic_test/select_for_update index 05c97d5be5b6..10b28f135bee 100644 --- a/pkg/sql/logictest/testdata/logic_test/select_for_update +++ b/pkg/sql/logictest/testdata/logic_test/select_for_update @@ -1,3 +1,7 @@ +# TODO(arul): remove this before merging. +statement ok +SET enable_shared_locking_for_serializable = true + query I SELECT 1 FOR UPDATE ---- @@ -293,6 +297,7 @@ ROLLBACK statement ok BEGIN READ ONLY +skipif config local-mixed-22.2-23.1 statement error cannot execute FOR SHARE in a read-only transaction SELECT * FROM t FOR SHARE @@ -302,6 +307,7 @@ ROLLBACK statement ok BEGIN READ ONLY +skipif config local-mixed-22.2-23.1 statement error cannot execute FOR KEY SHARE in a read-only transaction SELECT * FROM t FOR KEY SHARE diff --git a/pkg/sql/logictest/testdata/logic_test/show_source b/pkg/sql/logictest/testdata/logic_test/show_source index d2678ec90dc3..5fa2d34141a7 100644 --- a/pkg/sql/logictest/testdata/logic_test/show_source +++ b/pkg/sql/logictest/testdata/logic_test/show_source @@ -70,6 +70,7 @@ enable_insert_fast_path on enable_multiple_modifications_of_table off enable_multiregion_placement_policy off enable_seqscan on +enable_shared_locking_for_serializable off enable_super_regions off enable_zigzag_join off enforce_home_region off diff --git a/pkg/sql/logictest/tests/fakedist-disk/generated_test.go b/pkg/sql/logictest/tests/fakedist-disk/generated_test.go index 88e18d338e3c..a91fb52c46f8 100644 --- a/pkg/sql/logictest/tests/fakedist-disk/generated_test.go +++ b/pkg/sql/logictest/tests/fakedist-disk/generated_test.go @@ -1646,6 +1646,13 @@ func TestLogic_select( runLogicTest(t, "select") } +func TestLogic_select_for_share( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runLogicTest(t, "select_for_share") +} + func TestLogic_select_for_update( t *testing.T, ) { diff --git a/pkg/sql/logictest/tests/fakedist-vec-off/generated_test.go b/pkg/sql/logictest/tests/fakedist-vec-off/generated_test.go index 926db53b5f10..46f39ea75dd7 100644 --- a/pkg/sql/logictest/tests/fakedist-vec-off/generated_test.go +++ b/pkg/sql/logictest/tests/fakedist-vec-off/generated_test.go @@ -1646,6 +1646,13 @@ func TestLogic_select( runLogicTest(t, "select") } +func TestLogic_select_for_share( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runLogicTest(t, "select_for_share") +} + func TestLogic_select_for_update( t *testing.T, ) { diff --git a/pkg/sql/logictest/tests/fakedist/generated_test.go b/pkg/sql/logictest/tests/fakedist/generated_test.go index f49d57d715cf..d550d4637344 100644 --- a/pkg/sql/logictest/tests/fakedist/generated_test.go +++ b/pkg/sql/logictest/tests/fakedist/generated_test.go @@ -1660,6 +1660,13 @@ func TestLogic_select( runLogicTest(t, "select") } +func TestLogic_select_for_share( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runLogicTest(t, "select_for_share") +} + func TestLogic_select_for_update( t *testing.T, ) { diff --git a/pkg/sql/logictest/tests/local-legacy-schema-changer/generated_test.go b/pkg/sql/logictest/tests/local-legacy-schema-changer/generated_test.go index 69939d73d853..367c3db3f00b 100644 --- a/pkg/sql/logictest/tests/local-legacy-schema-changer/generated_test.go +++ b/pkg/sql/logictest/tests/local-legacy-schema-changer/generated_test.go @@ -1632,6 +1632,13 @@ func TestLogic_select( runLogicTest(t, "select") } +func TestLogic_select_for_share( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runLogicTest(t, "select_for_share") +} + func TestLogic_select_for_update( t *testing.T, ) { diff --git a/pkg/sql/logictest/tests/local-vec-off/generated_test.go b/pkg/sql/logictest/tests/local-vec-off/generated_test.go index 29fe95596431..f757a8da6084 100644 --- a/pkg/sql/logictest/tests/local-vec-off/generated_test.go +++ b/pkg/sql/logictest/tests/local-vec-off/generated_test.go @@ -1660,6 +1660,13 @@ func TestLogic_select( runLogicTest(t, "select") } +func TestLogic_select_for_share( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runLogicTest(t, "select_for_share") +} + func TestLogic_select_for_update( t *testing.T, ) { diff --git a/pkg/sql/logictest/tests/local/generated_test.go b/pkg/sql/logictest/tests/local/generated_test.go index 523563e3db47..430d8cf08889 100644 --- a/pkg/sql/logictest/tests/local/generated_test.go +++ b/pkg/sql/logictest/tests/local/generated_test.go @@ -1807,6 +1807,13 @@ func TestLogic_select( runLogicTest(t, "select") } +func TestLogic_select_for_share( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runLogicTest(t, "select_for_share") +} + func TestLogic_select_for_update( t *testing.T, ) { diff --git a/pkg/sql/opt/exec/execbuilder/testdata/fk b/pkg/sql/opt/exec/execbuilder/testdata/fk index 50811f307971..c1a7b24f1d01 100644 --- a/pkg/sql/opt/exec/execbuilder/testdata/fk +++ b/pkg/sql/opt/exec/execbuilder/testdata/fk @@ -46,6 +46,11 @@ vectorized: true statement ok SET enable_implicit_fk_locking_for_serializable = true +# We need to enable shared locks for serializable transactions for this to have +# a meaningful effect. +statement ok +SET enable_shared_locking_for_serializable=true + query T EXPLAIN INSERT INTO child VALUES (1,1), (2,2) ---- diff --git a/pkg/sql/opt/exec/execbuilder/testdata/fk_read_committed b/pkg/sql/opt/exec/execbuilder/testdata/fk_read_committed index 7f2634b3bb2d..6c68b3c7915f 100644 --- a/pkg/sql/opt/exec/execbuilder/testdata/fk_read_committed +++ b/pkg/sql/opt/exec/execbuilder/testdata/fk_read_committed @@ -49,6 +49,11 @@ insert cookies statement ok SET enable_implicit_fk_locking_for_serializable = true +# We als need to enable shared locks for serializable transactions for this to +# have a meaningful effect. +statement ok +SET enable_shared_locking_for_serializable=true + query T EXPLAIN (OPT) INSERT INTO cookies VALUES (1, 1) ---- diff --git a/pkg/sql/opt/exec/execbuilder/testdata/select_for_update b/pkg/sql/opt/exec/execbuilder/testdata/select_for_update index f771b31b2188..1273c9fe943b 100644 --- a/pkg/sql/opt/exec/execbuilder/testdata/select_for_update +++ b/pkg/sql/opt/exec/execbuilder/testdata/select_for_update @@ -42,6 +42,26 @@ vectorized: true spans: FULL SCAN locking strength: for no key update +# By default, SELECT FOR SHARE doesn't acquire any locks. + +query T +EXPLAIN (VERBOSE) SELECT * FROM t FOR SHARE +---- +distribution: local +vectorized: true +· +• scan + columns: (a, b) + estimated row count: 1,000 (missing stats) + table: t@t_pkey + spans: FULL SCAN + +# However, if the session setting is configured to do so, SELECT FOR SHARE will +# acquire shared locks. + +statement ok +SET enable_shared_locking_for_serializable = true + query T EXPLAIN (VERBOSE) SELECT * FROM t FOR SHARE ---- diff --git a/pkg/sql/opt/memo/memo.go b/pkg/sql/opt/memo/memo.go index 566a4e804e25..c9210dd25ed4 100644 --- a/pkg/sql/opt/memo/memo.go +++ b/pkg/sql/opt/memo/memo.go @@ -171,6 +171,7 @@ type Memo struct { useImprovedJoinElimination bool implicitFKLockingForSerializable bool durableLockingForSerializable bool + sharedLockingForSerializable bool // txnIsoLevel is the isolation level under which the plan was created. This // affects the planning of some locking operations, so it must be included in @@ -240,6 +241,7 @@ func (m *Memo) Init(ctx context.Context, evalCtx *eval.Context) { useImprovedJoinElimination: evalCtx.SessionData().OptimizerUseImprovedJoinElimination, implicitFKLockingForSerializable: evalCtx.SessionData().ImplicitFKLockingForSerializable, durableLockingForSerializable: evalCtx.SessionData().DurableLockingForSerializable, + sharedLockingForSerializable: evalCtx.SessionData().SharedLockingForSerializable, txnIsoLevel: evalCtx.TxnIsoLevel, } m.metadata.Init() @@ -383,6 +385,7 @@ func (m *Memo) IsStale( m.useImprovedJoinElimination != evalCtx.SessionData().OptimizerUseImprovedJoinElimination || m.implicitFKLockingForSerializable != evalCtx.SessionData().ImplicitFKLockingForSerializable || m.durableLockingForSerializable != evalCtx.SessionData().DurableLockingForSerializable || + m.sharedLockingForSerializable != evalCtx.SessionData().SharedLockingForSerializable || m.txnIsoLevel != evalCtx.TxnIsoLevel { return true, nil } diff --git a/pkg/sql/opt/optbuilder/BUILD.bazel b/pkg/sql/opt/optbuilder/BUILD.bazel index 9acbe42ef2e3..d84931a653be 100644 --- a/pkg/sql/opt/optbuilder/BUILD.bazel +++ b/pkg/sql/opt/optbuilder/BUILD.bazel @@ -50,6 +50,7 @@ go_library( importpath = "github.com/cockroachdb/cockroach/pkg/sql/opt/optbuilder", visibility = ["//visibility:public"], deps = [ + "//pkg/clusterversion", "//pkg/kv/kvserver/concurrency/isolation", "//pkg/server/telemetry", "//pkg/settings", diff --git a/pkg/sql/opt/optbuilder/select.go b/pkg/sql/opt/optbuilder/select.go index 7ee9b6338750..4bf0930e9b7c 100644 --- a/pkg/sql/opt/optbuilder/select.go +++ b/pkg/sql/opt/optbuilder/select.go @@ -14,6 +14,7 @@ import ( "context" "fmt" + "github.com/cockroachdb/cockroach/pkg/clusterversion" "github.com/cockroachdb/cockroach/pkg/kv/kvserver/concurrency/isolation" "github.com/cockroachdb/cockroach/pkg/server/telemetry" "github.com/cockroachdb/cockroach/pkg/sql/catalog/catpb" @@ -697,6 +698,7 @@ func (b *Builder) buildScan( } if locking.isSet() { private.Locking = locking.get() + // TODO(arul): This needs a cluster version check. if b.evalCtx.TxnIsoLevel != isolation.Serializable || b.evalCtx.SessionData().DurableLockingForSerializable { // Under weaker isolation levels we use fully-durable locks for SELECT FOR @@ -715,6 +717,25 @@ func (b *Builder) buildScan( // best-effort locks for better performance.) private.Locking.Durability = tree.LockDurabilityGuaranteed } + // Check if we can actually use shared locks here, or we need to use + // non-locking reads instead. + if private.Locking.Strength == tree.ForShare || private.Locking.Strength == tree.ForKeyShare { + // Shared locks weren't a thing prior to v23.2, so we must use non-locking + // reads. + if !b.evalCtx.Settings.Version.IsActive(context.TODO(), clusterversion.V23_2) || + // And in >= v23.2, their locking behavior for serializable transactions + // is dictated by session setting. + (b.evalCtx.TxnIsoLevel == isolation.Serializable && + !b.evalCtx.SessionData().SharedLockingForSerializable) { + private.Locking.Strength = tree.ForNone + // Key locking strength and durability go hand in hand. If we're + // overriding what should have been a shared locking read to + // non-locking, we also need to reset the lock durability; otherwise, KV + // won't be too happy if we start asking for nonsensical "replicated + // non-locking locks". + private.Locking.Durability = tree.LockDurabilityBestEffort + } + } if private.Locking.WaitPolicy == tree.LockWaitSkipLocked && tab.FamilyCount() > 1 { // TODO(rytaft): We may be able to support this if enough columns are // pruned that only a single family is scanned. diff --git a/pkg/sql/row/locking.go b/pkg/sql/row/locking.go index 88f79b052854..cd53755d41a8 100644 --- a/pkg/sql/row/locking.go +++ b/pkg/sql/row/locking.go @@ -27,9 +27,7 @@ func GetKeyLockingStrength(lockStrength descpb.ScanLockingStrength) lock.Strengt // Promote to FOR_SHARE. fallthrough case descpb.ScanLockingStrength_FOR_SHARE: - // We currently perform no per-key locking when FOR_SHARE is used - // because Shared locks have not yet been implemented. - return lock.None + return lock.Shared case descpb.ScanLockingStrength_FOR_NO_KEY_UPDATE: // Promote to FOR_UPDATE. diff --git a/pkg/sql/sessiondatapb/local_only_session_data.proto b/pkg/sql/sessiondatapb/local_only_session_data.proto index a63208ed4e4e..b99b3463d6fb 100644 --- a/pkg/sql/sessiondatapb/local_only_session_data.proto +++ b/pkg/sql/sessiondatapb/local_only_session_data.proto @@ -420,9 +420,17 @@ message LocalOnlySessionData { // DurableLockingForSerializable is true if we should use durable locking for // SELECT FOR UPDATE statements, SELECT FOR SHARE statements, and constraint // checks under serializable isolation. (Serializable isolation does not - // require locking for correctness, so by default we use best-effor locks for + // require locking for correctness, so by default we use best-effort locks for // better performance.) Weaker isolation levels always use durable locking. bool durable_locking_for_serializable = 109; + // SharedLockingForSerializable, if set to true, means SELECT FOR SHARE and + // SELECT FOR KEY SHARE statements issued by transactions that run with + // serializable isolation will acquire shared locks; otherwise, they'll + // perform non-locking reads. + // + // Weaker isolation levels always acquire shared locks for SELECT FOR SHARE + // and SELECT FOR KEY SHARE statements, regardless of this session setting. + bool shared_locking_for_serializable = 112; // MaxRetriesForReadCommitted indicates the maximum number of // automatic retries to perform for statements in explicit READ COMMITTED // transactions that see a transaction retry error. diff --git a/pkg/sql/vars.go b/pkg/sql/vars.go index e04c01411646..3f020a15257e 100644 --- a/pkg/sql/vars.go +++ b/pkg/sql/vars.go @@ -2910,6 +2910,23 @@ var varGen = map[string]sessionVar{ }, GlobalDefault: globalFalse, }, + + // CockroachDB extension. + `enable_shared_locking_for_serializable`: { + GetStringVal: makePostgresBoolGetStringValFn(`enable_shared_locking_for_serializable`), + Set: func(_ context.Context, m sessionDataMutator, s string) error { + b, err := paramparse.ParseBoolVar("enable_shared_locking_for_serializable", s) + if err != nil { + return err + } + m.SetSharedLockingForSerializable(b) + return nil + }, + Get: func(evalCtx *extendedEvalContext, _ *kv.Txn) (string, error) { + return formatBoolAsPostgresSetting(evalCtx.SessionData().SharedLockingForSerializable), nil + }, + GlobalDefault: globalFalse, + }, } func ReplicationModeFromString(s string) (sessiondatapb.ReplicationMode, error) {