diff --git a/pkg/sql/catalog/descpb/locking.proto b/pkg/sql/catalog/descpb/locking.proto index 84dd9edaaeb4..79ba3bd07536 100644 --- a/pkg/sql/catalog/descpb/locking.proto +++ b/pkg/sql/catalog/descpb/locking.proto @@ -115,7 +115,7 @@ enum ScanLockingStrength { // on each key scanned. FOR_UPDATE = 4; } - + // LockingWaitPolicy controls the policy used for handling conflicting locks // held by other active transactions when attempting to lock rows due to FOR // UPDATE/SHARE clauses (i.e. it represents the NOWAIT and SKIP LOCKED options). diff --git a/pkg/sql/opt/exec/execbuilder/mutation.go b/pkg/sql/opt/exec/execbuilder/mutation.go index 899a0ab99980..34b298564888 100644 --- a/pkg/sql/opt/exec/execbuilder/mutation.go +++ b/pkg/sql/opt/exec/execbuilder/mutation.go @@ -973,7 +973,7 @@ func (b *Builder) canAutoCommit(rel memo.RelExpr) bool { // forUpdateLocking is the row-level locking mode used by mutations during their // initial row scan, when such locking is deemed desirable. The locking mode is -// equivalent that used by a SELECT ... FOR UPDATE statement. +// equivalent that used by a SELECT ... FOR UPDATE statement except not durable. var forUpdateLocking = opt.Locking{Strength: tree.ForUpdate} // shouldApplyImplicitLockingToMutationInput determines whether or not the diff --git a/pkg/sql/opt/exec/execbuilder/relational.go b/pkg/sql/opt/exec/execbuilder/relational.go index c089ce911d30..8f5c2dbc03cf 100644 --- a/pkg/sql/opt/exec/execbuilder/relational.go +++ b/pkg/sql/opt/exec/execbuilder/relational.go @@ -620,7 +620,7 @@ func (b *Builder) scanParams( locking := scan.Locking if b.forceForUpdateLocking { - locking = forUpdateLocking + locking = locking.Max(forUpdateLocking) } b.ContainsNonDefaultKeyLocking = b.ContainsNonDefaultKeyLocking || locking.IsLocking() diff --git a/pkg/sql/opt/exec/execbuilder/testdata/select_for_update b/pkg/sql/opt/exec/execbuilder/testdata/select_for_update index e36bae6c8e19..c45ce69a9304 100644 --- a/pkg/sql/opt/exec/execbuilder/testdata/select_for_update +++ b/pkg/sql/opt/exec/execbuilder/testdata/select_for_update @@ -28,6 +28,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t FOR NO KEY UPDATE @@ -41,6 +42,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for no key update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t FOR SHARE @@ -54,6 +56,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for share + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t FOR KEY SHARE @@ -67,6 +70,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for key share + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t FOR KEY SHARE FOR SHARE @@ -80,6 +84,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for share + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t FOR KEY SHARE FOR SHARE FOR NO KEY UPDATE @@ -93,6 +98,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for no key update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t FOR KEY SHARE FOR SHARE FOR NO KEY UPDATE FOR UPDATE @@ -106,6 +112,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t FOR UPDATE OF t @@ -119,6 +126,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query error pgcode 42P01 relation "t2" in FOR UPDATE clause not found in FROM clause EXPLAIN (VERBOSE) SELECT * FROM t FOR UPDATE OF t2 @@ -139,6 +147,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t WHERE a = 1 FOR UPDATE @@ -152,6 +161,7 @@ vectorized: true table: t@t_pkey spans: /1/0 locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t WHERE a = 1 FOR NO KEY UPDATE @@ -165,6 +175,7 @@ vectorized: true table: t@t_pkey spans: /1/0 locking strength: for no key update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t WHERE a = 1 FOR SHARE @@ -178,6 +189,7 @@ vectorized: true table: t@t_pkey spans: /1/0 locking strength: for share + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t WHERE a = 1 FOR KEY SHARE @@ -191,6 +203,7 @@ vectorized: true table: t@t_pkey spans: /1/0 locking strength: for key share + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t WHERE a = 1 FOR KEY SHARE FOR SHARE @@ -204,6 +217,7 @@ vectorized: true table: t@t_pkey spans: /1/0 locking strength: for share + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t WHERE a = 1 FOR KEY SHARE FOR SHARE FOR NO KEY UPDATE @@ -217,6 +231,7 @@ vectorized: true table: t@t_pkey spans: /1/0 locking strength: for no key update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t WHERE a = 1 FOR KEY SHARE FOR SHARE FOR NO KEY UPDATE FOR UPDATE @@ -230,6 +245,7 @@ vectorized: true table: t@t_pkey spans: /1/0 locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t WHERE a = 1 FOR UPDATE OF t @@ -243,6 +259,7 @@ vectorized: true table: t@t_pkey spans: /1/0 locking strength: for update + locking durability: guaranteed query error pgcode 42P01 relation "t2" in FOR UPDATE clause not found in FROM clause EXPLAIN (VERBOSE) SELECT * FROM t WHERE a = 1 FOR UPDATE OF t2 @@ -263,6 +280,7 @@ vectorized: true table: t@t_pkey spans: /1/0 locking strength: for update + locking durability: guaranteed # ------------------------------------------------------------------------------ # Tests with table aliases. @@ -280,6 +298,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query error pgcode 42P01 relation "t" in FOR UPDATE clause not found in FROM clause EXPLAIN (VERBOSE) SELECT * FROM t AS t2 FOR UPDATE OF t @@ -296,6 +315,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM [$t_id AS t] FOR UPDATE @@ -309,6 +329,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM [$t_id AS t] FOR UPDATE OF t @@ -322,6 +343,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query error pgcode 42P01 relation "t2" in FOR UPDATE clause not found in FROM clause EXPLAIN (VERBOSE) SELECT * FROM [$t_id AS t] FOR UPDATE OF t2 @@ -342,6 +364,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM v FOR UPDATE OF v @@ -355,6 +378,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query error pgcode 42P01 relation "v2" in FOR UPDATE clause not found in FROM clause EXPLAIN (VERBOSE) SELECT * FROM v FOR UPDATE OF v2 @@ -381,6 +405,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query error pgcode 42P01 relation "v" in FOR UPDATE clause not found in FROM clause EXPLAIN (VERBOSE) SELECT * FROM v AS v2 FOR UPDATE OF v @@ -397,6 +422,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed # ------------------------------------------------------------------------------ # Tests with subqueries. @@ -418,6 +444,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM (SELECT a FROM t FOR UPDATE) @@ -431,6 +458,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM (SELECT a FROM t FOR NO KEY UPDATE) FOR KEY SHARE @@ -444,6 +472,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for no key update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM (SELECT a FROM t FOR KEY SHARE) FOR NO KEY UPDATE @@ -457,6 +486,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for no key update + locking durability: guaranteed query error pgcode 42P01 relation "t" in FOR UPDATE clause not found in FROM clause EXPLAIN (VERBOSE) SELECT * FROM (SELECT a FROM t) FOR UPDATE OF t @@ -473,6 +503,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM (SELECT a FROM t) AS r FOR UPDATE @@ -486,6 +517,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM (SELECT a FROM t FOR UPDATE) AS r @@ -499,6 +531,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query error pgcode 42P01 relation "t" in FOR UPDATE clause not found in FROM clause EXPLAIN (VERBOSE) SELECT * FROM (SELECT a FROM t) AS r FOR UPDATE OF t @@ -515,6 +548,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT (SELECT a FROM t) FOR UPDATE @@ -574,6 +608,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query error pgcode 42P01 relation "t" in FOR UPDATE clause not found in FROM clause EXPLAIN (VERBOSE) SELECT (SELECT a FROM t) FOR UPDATE OF t @@ -607,6 +642,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT (SELECT a FROM t) AS r FOR UPDATE @@ -666,6 +702,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query error pgcode 42P01 relation "t" in FOR UPDATE clause not found in FROM clause EXPLAIN (VERBOSE) SELECT (SELECT a FROM t) AS r FOR UPDATE OF t @@ -699,6 +736,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t WHERE a IN (SELECT a FROM t) FOR UPDATE @@ -712,6 +750,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t WHERE a IN (SELECT a FROM t FOR UPDATE) @@ -737,6 +776,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t WHERE a IN (SELECT a FROM t FOR UPDATE OF t) @@ -766,6 +806,7 @@ vectorized: true │ equality: (b) = (a) │ equality cols are key │ locking strength: for update + │ locking durability: guaranteed │ └── • distinct │ columns: (b) @@ -805,6 +846,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t WHERE a IN (SELECT b FROM t) FOR UPDATE OF t @@ -822,6 +864,7 @@ vectorized: true │ equality: (b) = (a) │ equality cols are key │ locking strength: for update + │ locking durability: guaranteed │ └── • distinct │ columns: (b) @@ -861,6 +904,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed # ------------------------------------------------------------------------------ # Tests with common-table expressions. @@ -934,6 +978,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) WITH cte AS (SELECT a FROM t FOR UPDATE) SELECT * FROM cte @@ -964,6 +1009,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed # Verify that the unused CTE doesn't get eliminated. # TODO(radu): we should at least not buffer the rows in this case. @@ -998,6 +1044,7 @@ vectorized: true table: t@t_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed # ------------------------------------------------------------------------------ # Tests with joins. @@ -1027,6 +1074,7 @@ vectorized: true │ table: t@t_pkey │ spans: FULL SCAN │ locking strength: for update + │ locking durability: guaranteed │ └── • scan columns: (a, b, c) @@ -1035,6 +1083,7 @@ vectorized: true table: u@u_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t JOIN u USING (a) FOR UPDATE OF t @@ -1060,6 +1109,7 @@ vectorized: true │ table: t@t_pkey │ spans: FULL SCAN │ locking strength: for update + │ locking durability: guaranteed │ └── • scan columns: (a, b, c) @@ -1099,6 +1149,7 @@ vectorized: true table: u@u_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t JOIN u USING (a) FOR UPDATE OF t, u @@ -1124,6 +1175,7 @@ vectorized: true │ table: t@t_pkey │ spans: FULL SCAN │ locking strength: for update + │ locking durability: guaranteed │ └── • scan columns: (a, b, c) @@ -1132,6 +1184,7 @@ vectorized: true table: u@u_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t JOIN u USING (a) FOR UPDATE OF t FOR SHARE OF u @@ -1157,6 +1210,7 @@ vectorized: true │ table: t@t_pkey │ spans: FULL SCAN │ locking strength: for update + │ locking durability: guaranteed │ └── • scan columns: (a, b, c) @@ -1165,6 +1219,7 @@ vectorized: true table: u@u_pkey spans: FULL SCAN locking strength: for share + locking durability: guaranteed query error pgcode 42P01 relation "t2" in FOR UPDATE clause not found in FROM clause EXPLAIN (VERBOSE) SELECT * FROM t JOIN u USING (a) FOR UPDATE OF t2 FOR SHARE OF u2 @@ -1193,6 +1248,7 @@ vectorized: true │ table: t@t_pkey │ spans: FULL SCAN │ locking strength: for update + │ locking durability: guaranteed │ └── • scan columns: (a, b, c) @@ -1201,6 +1257,7 @@ vectorized: true table: u@u_pkey spans: FULL SCAN locking strength: for share + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t JOIN u USING (a) FOR KEY SHARE FOR UPDATE @@ -1226,6 +1283,7 @@ vectorized: true │ table: t@t_pkey │ spans: FULL SCAN │ locking strength: for update + │ locking durability: guaranteed │ └── • scan columns: (a, b, c) @@ -1234,6 +1292,7 @@ vectorized: true table: u@u_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t JOIN u USING (a) FOR KEY SHARE FOR NO KEY UPDATE OF t @@ -1259,6 +1318,7 @@ vectorized: true │ table: t@t_pkey │ spans: FULL SCAN │ locking strength: for no key update + │ locking durability: guaranteed │ └── • scan columns: (a, b, c) @@ -1267,6 +1327,7 @@ vectorized: true table: u@u_pkey spans: FULL SCAN locking strength: for key share + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t JOIN u USING (a) FOR SHARE FOR NO KEY UPDATE OF t FOR UPDATE OF u @@ -1292,6 +1353,7 @@ vectorized: true │ table: t@t_pkey │ spans: FULL SCAN │ locking strength: for no key update + │ locking durability: guaranteed │ └── • scan columns: (a, b, c) @@ -1300,6 +1362,7 @@ vectorized: true table: u@u_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed # ------------------------------------------------------------------------------ # Tests with joins of aliased tables and aliased joins. @@ -1329,6 +1392,7 @@ vectorized: true │ table: t@t_pkey │ spans: FULL SCAN │ locking strength: for update + │ locking durability: guaranteed │ └── • scan columns: (a, b, c) @@ -1337,6 +1401,7 @@ vectorized: true table: u@u_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query error pgcode 42P01 relation "t" in FOR UPDATE clause not found in FROM clause EXPLAIN (VERBOSE) SELECT * FROM t AS t2 JOIN u AS u2 USING (a) FOR UPDATE OF t @@ -1371,6 +1436,7 @@ vectorized: true │ table: t@t_pkey │ spans: FULL SCAN │ locking strength: for update + │ locking durability: guaranteed │ └── • scan columns: (a, b, c) @@ -1410,6 +1476,7 @@ vectorized: true table: u@u_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t AS t2 JOIN u AS u2 USING (a) FOR UPDATE OF t2, u2 @@ -1435,6 +1502,7 @@ vectorized: true │ table: t@t_pkey │ spans: FULL SCAN │ locking strength: for update + │ locking durability: guaranteed │ └── • scan columns: (a, b, c) @@ -1443,6 +1511,7 @@ vectorized: true table: u@u_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed # Postgres doesn't support applying locking clauses to joins. The following # queries all return the error: "FOR UPDATE cannot be applied to a join". @@ -1472,6 +1541,7 @@ vectorized: true │ table: t@t_pkey │ spans: FULL SCAN │ locking strength: for update + │ locking durability: guaranteed │ └── • scan columns: (a, b, c) @@ -1480,6 +1550,7 @@ vectorized: true table: u@u_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query error pgcode 42P01 relation "t" in FOR UPDATE clause not found in FROM clause EXPLAIN (VERBOSE) SELECT * FROM (t JOIN u AS u2 USING (a)) j FOR UPDATE OF t @@ -1514,6 +1585,7 @@ vectorized: true │ table: t@t_pkey │ spans: FULL SCAN │ locking strength: for update + │ locking durability: guaranteed │ └── • scan columns: (a, b, c) @@ -1522,6 +1594,7 @@ vectorized: true table: u@u_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed # ------------------------------------------------------------------------------ # Tests with lateral joins. @@ -1543,6 +1616,7 @@ vectorized: true │ table: t@t_pkey │ spans: FULL SCAN │ locking strength: for update +│ locking durability: guaranteed │ └── • scan columns: (a, b, c) @@ -1550,6 +1624,7 @@ vectorized: true table: u@u_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t, u FOR UPDATE OF t @@ -1567,6 +1642,7 @@ vectorized: true │ table: t@t_pkey │ spans: FULL SCAN │ locking strength: for update +│ locking durability: guaranteed │ └── • scan columns: (a, b, c) @@ -1590,6 +1666,7 @@ vectorized: true │ table: t@t_pkey │ spans: FULL SCAN │ locking strength: for share +│ locking durability: guaranteed │ └── • scan columns: (a, b, c) @@ -1597,6 +1674,7 @@ vectorized: true table: u@u_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t, LATERAL (SELECT * FROM u) sub FOR UPDATE @@ -1614,6 +1692,7 @@ vectorized: true │ table: t@t_pkey │ spans: FULL SCAN │ locking strength: for update +│ locking durability: guaranteed │ └── • scan columns: (a, b, c) @@ -1621,6 +1700,7 @@ vectorized: true table: u@u_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed query error pgcode 42P01 relation "u" in FOR UPDATE clause not found in FROM clause EXPLAIN (VERBOSE) SELECT * FROM t, LATERAL (SELECT * FROM u) sub FOR UPDATE OF u @@ -1647,6 +1727,7 @@ vectorized: true table: u@u_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed # ------------------------------------------------------------------------------ # Tests with index joins. @@ -1672,6 +1753,7 @@ vectorized: true │ table: indexed@indexed_pkey │ key columns: a │ locking strength: for update +│ locking durability: guaranteed │ └── • scan columns: (a, b) @@ -1679,6 +1761,7 @@ vectorized: true table: indexed@b_idx spans: /2-/3 locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM indexed WHERE b BETWEEN 2 AND 10 FOR UPDATE @@ -1692,6 +1775,7 @@ vectorized: true │ table: indexed@indexed_pkey │ key columns: a │ locking strength: for update +│ locking durability: guaranteed │ └── • scan columns: (a, b) @@ -1699,6 +1783,7 @@ vectorized: true table: indexed@b_idx spans: /2-/11 locking strength: for update + locking durability: guaranteed # ------------------------------------------------------------------------------ # Tests with lookup joins. @@ -1720,6 +1805,7 @@ vectorized: true │ equality: (b) = (a) │ equality cols are key │ locking strength: for update + │ locking durability: guaranteed │ └── • scan columns: (a, b) @@ -1727,6 +1813,7 @@ vectorized: true table: t@t_pkey spans: /2/0 locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT c FROM t JOIN u ON t.b = u.a WHERE t.a BETWEEN 2 AND 10 FOR UPDATE @@ -1744,6 +1831,7 @@ vectorized: true │ equality: (b) = (a) │ equality cols are key │ locking strength: for update + │ locking durability: guaranteed │ └── • scan columns: (a, b) @@ -1752,6 +1840,7 @@ vectorized: true spans: /2-/11 parallel locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t JOIN indexed ON t.b = indexed.b WHERE t.a = 2 FOR UPDATE @@ -1766,6 +1855,7 @@ vectorized: true │ equality: (a) = (a) │ equality cols are key │ locking strength: for update +│ locking durability: guaranteed │ └── • lookup join (inner) │ columns: (a, b, a, b) @@ -1773,6 +1863,7 @@ vectorized: true │ table: indexed@b_idx │ equality: (b) = (b) │ locking strength: for update + │ locking durability: guaranteed │ └── • scan columns: (a, b) @@ -1780,6 +1871,7 @@ vectorized: true table: t@t_pkey spans: /2/0 locking strength: for update + locking durability: guaranteed # ------------------------------------------------------------------------------ # Tests with inverted filters and joins. @@ -1806,6 +1898,7 @@ vectorized: true │ equality: (a) = (a) │ equality cols are key │ locking strength: for update +│ locking durability: guaranteed │ └── • project │ columns: (a) @@ -1817,10 +1910,12 @@ vectorized: true left columns: (a, b_inverted_key) left fixed values: 1 column left locking strength: for update + left locking durability: guaranteed right table: inverted@b_inv right columns: (a, b_inverted_key) right fixed values: 1 column right locking strength: for update + right locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM inverted WHERE b <@ '{1, 2}' FOR UPDATE @@ -1839,6 +1934,7 @@ vectorized: true │ table: inverted@inverted_pkey │ key columns: a │ locking strength: for update + │ locking durability: guaranteed │ └── • project │ columns: (a) @@ -1855,6 +1951,7 @@ vectorized: true table: inverted@b_inv spans: /[]-/"D" /1-/3 locking strength: for update + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM inverted@b_inv AS i1, inverted AS i2 WHERE i1.b @> i2.b FOR UPDATE @@ -1873,6 +1970,7 @@ vectorized: true │ equality cols are key │ pred: b @> b │ locking strength: for update + │ locking durability: guaranteed │ └── • project │ columns: (a, b, c, a) @@ -1883,6 +1981,7 @@ vectorized: true │ table: inverted@b_inv │ inverted expr: b_inverted_key @> b │ locking strength: for update + │ locking durability: guaranteed │ └── • scan columns: (a, b, c) @@ -1890,6 +1989,7 @@ vectorized: true table: inverted@inverted_pkey spans: FULL SCAN locking strength: for update + locking durability: guaranteed # ------------------------------------------------------------------------------ # Tests with zigzag joins. @@ -1923,10 +2023,12 @@ vectorized: true left columns: (a, b) left fixed values: 1 column left locking strength: for update + left locking durability: guaranteed right table: zigzag@c_idx right columns: (a, c) right fixed values: 1 column right locking strength: for update + right locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * from zigzag where d @> '{"a": {"b": "c"}, "f": "g"}' FOR UPDATE @@ -1941,6 +2043,7 @@ vectorized: true │ equality: (a) = (a) │ equality cols are key │ locking strength: for update +│ locking durability: guaranteed │ └── • project │ columns: (a) @@ -1952,10 +2055,12 @@ vectorized: true left columns: (a, d_inverted_key) left fixed values: 1 column left locking strength: for update + left locking durability: guaranteed right table: zigzag@d_idx right columns: (a, d_inverted_key) right fixed values: 1 column right locking strength: for update + right locking durability: guaranteed # ------------------------------------------------------------------------------ # Tests with the NOWAIT lock wait policy. @@ -1974,6 +2079,7 @@ vectorized: true spans: FULL SCAN locking strength: for update locking wait policy: nowait + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t FOR NO KEY UPDATE NOWAIT @@ -1988,6 +2094,7 @@ vectorized: true spans: FULL SCAN locking strength: for no key update locking wait policy: nowait + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t FOR SHARE NOWAIT @@ -2002,6 +2109,7 @@ vectorized: true spans: FULL SCAN locking strength: for share locking wait policy: nowait + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t FOR KEY SHARE NOWAIT @@ -2016,6 +2124,7 @@ vectorized: true spans: FULL SCAN locking strength: for key share locking wait policy: nowait + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t FOR KEY SHARE FOR SHARE NOWAIT @@ -2030,6 +2139,7 @@ vectorized: true spans: FULL SCAN locking strength: for share locking wait policy: nowait + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t FOR KEY SHARE FOR SHARE NOWAIT FOR NO KEY UPDATE @@ -2044,6 +2154,7 @@ vectorized: true spans: FULL SCAN locking strength: for no key update locking wait policy: nowait + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t FOR KEY SHARE FOR SHARE NOWAIT FOR NO KEY UPDATE FOR UPDATE NOWAIT @@ -2058,6 +2169,7 @@ vectorized: true spans: FULL SCAN locking strength: for update locking wait policy: nowait + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t FOR UPDATE OF t NOWAIT @@ -2072,6 +2184,7 @@ vectorized: true spans: FULL SCAN locking strength: for update locking wait policy: nowait + locking durability: guaranteed query error pgcode 42P01 relation "t2" in FOR UPDATE clause not found in FROM clause EXPLAIN (VERBOSE) SELECT * FROM t FOR UPDATE OF t2 NOWAIT @@ -2093,6 +2206,7 @@ vectorized: true spans: FULL SCAN locking strength: for update locking wait policy: nowait + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t WHERE a = 1 FOR UPDATE NOWAIT @@ -2107,6 +2221,7 @@ vectorized: true spans: /1/0 locking strength: for update locking wait policy: nowait + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t WHERE a = 1 FOR NO KEY UPDATE NOWAIT @@ -2121,6 +2236,7 @@ vectorized: true spans: /1/0 locking strength: for no key update locking wait policy: nowait + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t WHERE a = 1 FOR SHARE NOWAIT @@ -2135,6 +2251,7 @@ vectorized: true spans: /1/0 locking strength: for share locking wait policy: nowait + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t WHERE a = 1 FOR KEY SHARE NOWAIT @@ -2149,6 +2266,7 @@ vectorized: true spans: /1/0 locking strength: for key share locking wait policy: nowait + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t WHERE a = 1 FOR KEY SHARE FOR SHARE NOWAIT @@ -2163,6 +2281,7 @@ vectorized: true spans: /1/0 locking strength: for share locking wait policy: nowait + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t WHERE a = 1 FOR KEY SHARE FOR SHARE FOR NO KEY UPDATE NOWAIT @@ -2177,6 +2296,7 @@ vectorized: true spans: /1/0 locking strength: for no key update locking wait policy: nowait + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t WHERE a = 1 FOR KEY SHARE FOR SHARE FOR NO KEY UPDATE FOR UPDATE NOWAIT @@ -2191,6 +2311,7 @@ vectorized: true spans: /1/0 locking strength: for update locking wait policy: nowait + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t WHERE a = 1 FOR UPDATE OF t NOWAIT @@ -2205,6 +2326,7 @@ vectorized: true spans: /1/0 locking strength: for update locking wait policy: nowait + locking durability: guaranteed query error pgcode 42P01 relation "t2" in FOR UPDATE clause not found in FROM clause EXPLAIN (VERBOSE) SELECT * FROM t WHERE a = 1 FOR UPDATE OF t2 NOWAIT @@ -2226,6 +2348,7 @@ vectorized: true spans: /1/0 locking strength: for update locking wait policy: nowait + locking durability: guaranteed # ------------------------------------------------------------------------------ # Tests with the SKIP LOCKED lock wait policy. @@ -2244,6 +2367,7 @@ vectorized: true spans: FULL SCAN locking strength: for update locking wait policy: skip locked + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t FOR NO KEY UPDATE SKIP LOCKED @@ -2258,6 +2382,7 @@ vectorized: true spans: FULL SCAN locking strength: for no key update locking wait policy: skip locked + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t FOR SHARE SKIP LOCKED @@ -2272,6 +2397,7 @@ vectorized: true spans: FULL SCAN locking strength: for share locking wait policy: skip locked + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t FOR KEY SHARE SKIP LOCKED @@ -2286,6 +2412,7 @@ vectorized: true spans: FULL SCAN locking strength: for key share locking wait policy: skip locked + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t FOR KEY SHARE FOR SHARE SKIP LOCKED @@ -2300,6 +2427,7 @@ vectorized: true spans: FULL SCAN locking strength: for share locking wait policy: skip locked + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t FOR KEY SHARE FOR SHARE SKIP LOCKED FOR NO KEY UPDATE @@ -2314,6 +2442,7 @@ vectorized: true spans: FULL SCAN locking strength: for no key update locking wait policy: skip locked + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t FOR KEY SHARE FOR SHARE SKIP LOCKED FOR NO KEY UPDATE FOR UPDATE SKIP LOCKED @@ -2328,6 +2457,7 @@ vectorized: true spans: FULL SCAN locking strength: for update locking wait policy: skip locked + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t FOR UPDATE OF t SKIP LOCKED @@ -2342,6 +2472,7 @@ vectorized: true spans: FULL SCAN locking strength: for update locking wait policy: skip locked + locking durability: guaranteed query error pgcode 42P01 relation "t2" in FOR UPDATE clause not found in FROM clause EXPLAIN (VERBOSE) SELECT * FROM t FOR UPDATE OF t2 SKIP LOCKED @@ -2363,6 +2494,7 @@ vectorized: true spans: FULL SCAN locking strength: for update locking wait policy: skip locked + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t WHERE a = 1 FOR UPDATE SKIP LOCKED @@ -2377,6 +2509,7 @@ vectorized: true spans: /1/0 locking strength: for update locking wait policy: skip locked + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t WHERE a = 1 FOR NO KEY UPDATE SKIP LOCKED @@ -2391,6 +2524,7 @@ vectorized: true spans: /1/0 locking strength: for no key update locking wait policy: skip locked + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t WHERE a = 1 FOR SHARE SKIP LOCKED @@ -2405,6 +2539,7 @@ vectorized: true spans: /1/0 locking strength: for share locking wait policy: skip locked + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t WHERE a = 1 FOR KEY SHARE SKIP LOCKED @@ -2419,6 +2554,7 @@ vectorized: true spans: /1/0 locking strength: for key share locking wait policy: skip locked + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t WHERE a = 1 FOR KEY SHARE FOR SHARE SKIP LOCKED @@ -2433,6 +2569,7 @@ vectorized: true spans: /1/0 locking strength: for share locking wait policy: skip locked + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t WHERE a = 1 FOR KEY SHARE FOR SHARE FOR NO KEY UPDATE SKIP LOCKED @@ -2447,6 +2584,7 @@ vectorized: true spans: /1/0 locking strength: for no key update locking wait policy: skip locked + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t WHERE a = 1 FOR KEY SHARE FOR SHARE FOR NO KEY UPDATE FOR UPDATE SKIP LOCKED @@ -2461,6 +2599,7 @@ vectorized: true spans: /1/0 locking strength: for update locking wait policy: skip locked + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM t WHERE a = 1 FOR UPDATE OF t SKIP LOCKED @@ -2475,6 +2614,7 @@ vectorized: true spans: /1/0 locking strength: for update locking wait policy: skip locked + locking durability: guaranteed query error pgcode 42P01 relation "t2" in FOR UPDATE clause not found in FROM clause EXPLAIN (VERBOSE) SELECT * FROM t WHERE a = 1 FOR UPDATE OF t2 SKIP LOCKED @@ -2496,6 +2636,7 @@ vectorized: true spans: /1/0 locking strength: for update locking wait policy: skip locked + locking durability: guaranteed # Tests with a secondary index. @@ -2512,6 +2653,7 @@ vectorized: true spans: /2-/3 locking strength: for update locking wait policy: skip locked + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM u WHERE b = 2 FOR UPDATE SKIP LOCKED @@ -2526,6 +2668,7 @@ vectorized: true │ key columns: a │ locking strength: for update │ locking wait policy: skip locked +│ locking durability: guaranteed │ └── • scan columns: (a, b) @@ -2534,6 +2677,7 @@ vectorized: true spans: /2-/3 locking strength: for update locking wait policy: skip locked + locking durability: guaranteed query T EXPLAIN (VERBOSE) SELECT * FROM u WHERE b = 2 LIMIT 1 FOR UPDATE SKIP LOCKED @@ -2552,6 +2696,7 @@ vectorized: true │ key columns: a │ locking strength: for update │ locking wait policy: skip locked + │ locking durability: guaranteed │ └── • scan columns: (a, b) @@ -2560,3 +2705,4 @@ vectorized: true spans: /2-/3 locking strength: for update locking wait policy: skip locked + locking durability: guaranteed diff --git a/pkg/sql/opt/exec/explain/emit.go b/pkg/sql/opt/exec/explain/emit.go index 9667fc013e39..ed3ecf8e5e2e 100644 --- a/pkg/sql/opt/exec/explain/emit.go +++ b/pkg/sql/opt/exec/explain/emit.go @@ -1051,12 +1051,16 @@ func (e *emitter) emitLockingPolicy(locking opt.Locking) { func (e *emitter) emitLockingPolicyWithPrefix(keyPrefix string, locking opt.Locking) { strength := descpb.ToScanLockingStrength(locking.Strength) waitPolicy := descpb.ToScanLockingWaitPolicy(locking.WaitPolicy) + durability := locking.Durability if strength != descpb.ScanLockingStrength_FOR_NONE { e.ob.Attr(keyPrefix+"locking strength", strength.PrettyString()) } if waitPolicy != descpb.ScanLockingWaitPolicy_BLOCK { e.ob.Attr(keyPrefix+"locking wait policy", waitPolicy.PrettyString()) } + if durability != tree.LockDurabilityBestEffort { + e.ob.Attr(keyPrefix+"locking durability", durability.String()) + } } func (e *emitter) emitTuples(rows tree.ExprContainer, numColumns int) { diff --git a/pkg/sql/opt/locking.go b/pkg/sql/opt/locking.go index e898d99fde11..b74e1548440f 100644 --- a/pkg/sql/opt/locking.go +++ b/pkg/sql/opt/locking.go @@ -13,7 +13,7 @@ package opt import "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" // Locking represents the row-level locking properties of a relational operator. -// Each relational operator clause consist of two different row-level locking +// Each relational operator clause consists of three different row-level locking // properties. type Locking struct { // The first property is locking strength (see tree.LockingStrength). Locking @@ -43,6 +43,23 @@ type Locking struct { // NOWAIT // WaitPolicy tree.LockingWaitPolicy + + // The third property is the durability of the locking. A durable lock always + // persists until commit time, while a non-durable lock may sometimes be lost + // before commit. We currently only require durable locks for SELECT FOR + // UPDATE statements under SNAPSHOT and READ COMMITTED isolation. Other + // locking statements, such as UPDATE, rely on the durability of intents for + // correctness, rather than the durability of locks. + Durability tree.LockingDurability +} + +// Max returns the maximum of two locks. +func (l Locking) Max(l2 Locking) Locking { + return Locking{ + Strength: l.Strength.Max(l2.Strength), + WaitPolicy: l.WaitPolicy.Max(l2.WaitPolicy), + Durability: l.Durability.Max(l.Durability), + } } // IsLocking returns whether the receiver is configured to use a row-level diff --git a/pkg/sql/opt/optbuilder/locking.go b/pkg/sql/opt/optbuilder/locking.go index 8c56336a03b7..183767b6b5a9 100644 --- a/pkg/sql/opt/optbuilder/locking.go +++ b/pkg/sql/opt/optbuilder/locking.go @@ -78,6 +78,7 @@ func (lm lockingSpec) get() opt.Locking { return opt.Locking{ Strength: spec.Strength, WaitPolicy: spec.WaitPolicy, + Durability: tree.LockDurabilityGuaranteed, } } return opt.Locking{} diff --git a/pkg/sql/sem/tree/select.go b/pkg/sql/sem/tree/select.go index a40426a4d07b..f3f77e9c66a3 100644 --- a/pkg/sql/sem/tree/select.go +++ b/pkg/sql/sem/tree/select.go @@ -1199,6 +1199,37 @@ func (p LockingWaitPolicy) Max(p2 LockingWaitPolicy) LockingWaitPolicy { return LockingWaitPolicy(max(byte(p), byte(p2))) } +// LockingDurability represents the durability of a lock. It is currently not +// exposed through SQL, but is instead set according to statement type and +// isolation level. It is included here for completeness. +type LockingDurability byte + +const ( + // LockDurabilityBestEffort represents the default: make a best-effort attempt + // to hold the lock until commit while keeping it unreplicated and + // in-memory. This must not be used when correctness depends on locking. + LockDurabilityBestEffort LockingDurability = iota + + // LockDurabilityGuaranteed guarantees that if the transaction commits, the + // lock was held until commit. This must be used when correctness depends on + // locking. + LockDurabilityGuaranteed +) + +var lockingDurabilityName = [...]string{ + LockDurabilityBestEffort: "best-effort", + LockDurabilityGuaranteed: "guaranteed", +} + +func (d LockingDurability) String() string { + return lockingDurabilityName[d] +} + +// Max returns the maximum of the two locking durabilities. +func (d LockingDurability) Max(d2 LockingDurability) LockingDurability { + return LockingDurability(max(byte(d), byte(d2))) +} + func max(a, b byte) byte { if a > b { return a