Skip to content

Commit 20e073d

Browse files
craig[bot]michae2
andcommitted
Merge #145019
145019: opt/norm: add UseSwapMutation normalization rule r=drewkimball a=michae2 Add a new normalization rule which converts Update and Delete expressions to UpdateSwap and DeleteSwap, respectively. With this normalization rule in place, UpdateSwap and DeleteSwap should be available for use by any qualifying UPDATE and DELETE statements. See individual commits for details and release note. Fixes: #144503 Fixes: #85328 Release note: None Co-authored-by: Michael Erickson <michae2@cockroachlabs.com>
2 parents a69ba54 + d015e8f commit 20e073d

File tree

24 files changed

+3284
-35
lines changed

24 files changed

+3284
-35
lines changed

pkg/sql/logictest/testdata/logic_test/information_schema

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4287,6 +4287,7 @@ use_improved_routine_dependency_tracking on
42874287
use_pre_25_2_variadic_builtins off
42884288
use_proc_txn_control_extended_protocol_fix on
42894289
use_soft_limit_for_distribute_scan on
4290+
use_swap_mutations off
42904291
variable_inequality_lookup_join_enabled on
42914292
vector_search_beam_size 32
42924293
vector_search_rerank_multiplier 50

pkg/sql/logictest/testdata/logic_test/pg_catalog

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3243,6 +3243,7 @@ use_improved_routine_dependency_tracking on
32433243
use_pre_25_2_variadic_builtins off NULL NULL NULL string
32443244
use_proc_txn_control_extended_protocol_fix on NULL NULL NULL string
32453245
use_soft_limit_for_distribute_scan on NULL NULL NULL string
3246+
use_swap_mutations off NULL NULL NULL string
32463247
variable_inequality_lookup_join_enabled on NULL NULL NULL string
32473248
vector_search_beam_size 32 NULL NULL NULL string
32483249
vector_search_rerank_multiplier 50 NULL NULL NULL string
@@ -3492,6 +3493,7 @@ use_improved_routine_dependency_tracking on
34923493
use_pre_25_2_variadic_builtins off NULL user NULL off off
34933494
use_proc_txn_control_extended_protocol_fix on NULL user NULL on on
34943495
use_soft_limit_for_distribute_scan on NULL user NULL on on
3496+
use_swap_mutations off NULL user NULL off off
34953497
variable_inequality_lookup_join_enabled on NULL user NULL on on
34963498
vector_search_beam_size 32 NULL user NULL 32 32
34973499
vector_search_rerank_multiplier 50 NULL user NULL 50 50
@@ -3733,6 +3735,7 @@ use_improved_routine_dependency_tracking NULL NULL
37333735
use_pre_25_2_variadic_builtins NULL NULL NULL NULL NULL
37343736
use_proc_txn_control_extended_protocol_fix NULL NULL NULL NULL NULL
37353737
use_soft_limit_for_distribute_scan NULL NULL NULL NULL NULL
3738+
use_swap_mutations NULL NULL NULL NULL NULL
37363739
variable_inequality_lookup_join_enabled NULL NULL NULL NULL NULL
37373740
vector_search_beam_size NULL NULL NULL NULL NULL
37383741
vector_search_rerank_multiplier NULL NULL NULL NULL NULL

pkg/sql/logictest/testdata/logic_test/show_source

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ use_improved_routine_dependency_tracking on
260260
use_pre_25_2_variadic_builtins off
261261
use_proc_txn_control_extended_protocol_fix on
262262
use_soft_limit_for_distribute_scan on
263+
use_swap_mutations off
263264
variable_inequality_lookup_join_enabled on
264265
vector_search_beam_size 32
265266
vector_search_rerank_multiplier 50
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
# LogicTest: local
2+
3+
statement ok
4+
SET use_swap_mutations = on
5+
6+
# Test that unique indexes work correctly with swap mutations.
7+
8+
statement ok
9+
CREATE TABLE xyz (
10+
x INT PRIMARY KEY,
11+
y INT,
12+
z INT,
13+
UNIQUE INDEX (y),
14+
FAMILY (x, y, z)
15+
)
16+
17+
statement ok
18+
INSERT INTO xyz VALUES (1, 1, 1), (2, 2, 2)
19+
20+
# This statement should fail with a dupe key error.
21+
22+
statement error duplicate key value violates unique constraint "xyz_y_key"
23+
UPDATE xyz SET y = 1 WHERE x = 2 AND y = 2 AND z = 2
24+
25+
query III
26+
SELECT * FROM xyz ORDER BY x
27+
----
28+
1 1 1
29+
2 2 2
30+
31+
# This statement should succeed and modify 0 rows, because no rows have z = 3.
32+
33+
statement ok
34+
UPDATE xyz SET y = 1 WHERE x = 2 AND y = 2 AND z = 3
35+
36+
query III
37+
SELECT * FROM xyz ORDER BY x
38+
----
39+
1 1 1
40+
2 2 2
41+
42+
# Test rollback of swap mutations.
43+
44+
statement ok
45+
BEGIN
46+
47+
statement ok
48+
UPDATE xyz SET z = 11 WHERE x = 1 AND y = 1 AND z = 1
49+
50+
query III
51+
SELECT * FROM xyz ORDER BY x
52+
----
53+
1 1 11
54+
2 2 2
55+
56+
statement ok
57+
SAVEPOINT a
58+
59+
statement ok
60+
UPDATE xyz SET z = 12 WHERE x = 2 AND y = 2 AND z = 2
61+
62+
query III
63+
SELECT * FROM xyz ORDER BY x
64+
----
65+
1 1 11
66+
2 2 12
67+
68+
statement ok
69+
ROLLBACK TO a
70+
71+
statement ok
72+
UPDATE xyz SET z = 21 WHERE x = 1 AND y = 1 AND z = 11
73+
74+
query III
75+
SELECT * FROM xyz ORDER BY x
76+
----
77+
1 1 21
78+
2 2 2
79+
80+
statement ok
81+
SAVEPOINT b
82+
83+
# This should do nothing.
84+
85+
statement ok
86+
UPDATE xyz SET z = 31 WHERE x = 1 AND y = 1 AND z = 11
87+
88+
query III
89+
SELECT * FROM xyz ORDER BY x
90+
----
91+
1 1 21
92+
2 2 2
93+
94+
statement ok
95+
ROLLBACK TO b
96+
97+
query III
98+
SELECT * FROM xyz ORDER BY x
99+
----
100+
1 1 21
101+
2 2 2
102+
103+
statement ok
104+
ROLLBACK TO a
105+
106+
query III
107+
SELECT * FROM xyz ORDER BY x
108+
----
109+
1 1 11
110+
2 2 2
111+
112+
# This should do nothing.
113+
114+
statement ok
115+
UPDATE xyz SET z = 31 WHERE x = 1 AND y = 1 AND z = 21
116+
117+
query III
118+
SELECT * FROM xyz ORDER BY x
119+
----
120+
1 1 11
121+
2 2 2
122+
123+
statement ok
124+
COMMIT
125+
126+
query III
127+
SELECT * FROM xyz ORDER BY x
128+
----
129+
1 1 11
130+
2 2 2
131+
132+
statement ok
133+
CREATE TABLE mno (m INT PRIMARY KEY, n INT, o INT NOT NULL, UNIQUE INDEX (o), INDEX (n), FAMILY (m, n, o))
134+
135+
statement ok
136+
INSERT INTO mno VALUES (3, 3, 3), (4, 4, 4)
137+
138+
statement error pq: duplicate key value violates unique constraint "mno_o_key"\nDETAIL: Key \(o\)=\(4\) already exists\.
139+
UPDATE mno SET o = 4 WHERE m = 3 AND n IS NOT DISTINCT FROM 3 AND o IS NOT DISTINCT FROM 3
140+
141+
query III
142+
SELECT * FROM mno ORDER BY m
143+
----
144+
3 3 3
145+
4 4 4
146+
147+
# The failure of the CPut of the primary index should trump the failure of the
148+
# CPut of the secondary index, meaning the end result should be 0 rows updated
149+
# instead of a dupe key error.
150+
statement ok
151+
UPDATE mno SET o = 4 WHERE m = 3 AND n IS NOT DISTINCT FROM 4 AND o IS NOT DISTINCT FROM 3
152+
153+
query III
154+
SELECT * FROM mno ORDER BY m
155+
----
156+
3 3 3
157+
4 4 4
158+
159+
statement ok
160+
ALTER TABLE mno ADD COLUMN p INT
161+
162+
statement ok
163+
ALTER TABLE mno DROP COLUMN p
164+
165+
statement error pq: duplicate key value violates unique constraint "mno_o_key"\nDETAIL: Key \(o\)=\(4\) already exists\.
166+
UPDATE mno SET o = 4 WHERE m = 3 AND n IS NOT DISTINCT FROM 3 AND o IS NOT DISTINCT FROM 3
167+
168+
query III
169+
SELECT * FROM mno ORDER BY m
170+
----
171+
3 3 3
172+
4 4 4
173+
174+
# Like above, even with the primary index ordered after the unique secondary
175+
# index, the failure of the CPut of the primary index should trump the failure
176+
# of the CPut of the secondary index, so the end result should be 0 rows updated
177+
# instead of a dupe key error.
178+
statement ok
179+
UPDATE mno SET o = 4 WHERE m = 3 AND n IS NOT DISTINCT FROM 4 AND o IS NOT DISTINCT FROM 3
180+
181+
query III
182+
SELECT * FROM mno ORDER BY m
183+
----
184+
3 3 3
185+
4 4 4
186+
187+
statement ok
188+
RESET use_swap_mutations

pkg/sql/logictest/tests/local/generated_test.go

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/sql/opt/column_meta.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,25 @@ func (ocl OptionalColList) ToSet() ColSet {
163163
return r
164164
}
165165

166+
// CopyAndMaybeRemapColumns copies this OptionalColList, remapping any columns
167+
// present in the provided ColMap.
168+
func (ocl OptionalColList) CopyAndMaybeRemapColumns(m ColMap) (res OptionalColList) {
169+
if len(ocl) == 0 {
170+
return nil
171+
}
172+
res = make(OptionalColList, len(ocl))
173+
for i, col := range ocl {
174+
if col != 0 {
175+
if val, ok := m.Get(int(col)); ok {
176+
res[i] = ColumnID(val)
177+
} else {
178+
res[i] = col
179+
}
180+
}
181+
}
182+
return res
183+
}
184+
166185
// ColumnMeta stores information about one of the columns stored in the
167186
// metadata.
168187
type ColumnMeta struct {

pkg/sql/opt/exec/execbuilder/mutation.go

Lines changed: 55 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -463,19 +463,37 @@ func (b *Builder) buildUpdate(upd *memo.UpdateExpr) (_ execPlan, outputCols colO
463463
}
464464
}
465465

466-
node, err := b.factory.ConstructUpdate(
467-
input.root,
468-
tab,
469-
fetchColOrds,
470-
updateColOrds,
471-
returnColOrds,
472-
checkOrds,
473-
passthroughCols,
474-
upd.UniqueWithTombstoneIndexes,
475-
lockedIndexes,
476-
b.allowAutoCommit && len(upd.UniqueChecks) == 0 &&
477-
len(upd.FKChecks) == 0 && len(upd.FKCascades) == 0 && upd.AfterTriggers == nil,
478-
)
466+
allowAutoCommit := b.allowAutoCommit && len(upd.UniqueChecks) == 0 &&
467+
len(upd.FKChecks) == 0 && len(upd.FKCascades) == 0 && upd.AfterTriggers == nil
468+
var node exec.Node
469+
if upd.Swap {
470+
if !checkOrds.Empty() || len(upd.UniqueWithTombstoneIndexes) != 0 {
471+
return execPlan{}, colOrdMap{}, errors.AssertionFailedf("update swap does not support checks")
472+
}
473+
node, err = b.factory.ConstructUpdateSwap(
474+
input.root,
475+
tab,
476+
fetchColOrds,
477+
updateColOrds,
478+
returnColOrds,
479+
passthroughCols,
480+
lockedIndexes,
481+
allowAutoCommit,
482+
)
483+
} else {
484+
node, err = b.factory.ConstructUpdate(
485+
input.root,
486+
tab,
487+
fetchColOrds,
488+
updateColOrds,
489+
returnColOrds,
490+
checkOrds,
491+
passthroughCols,
492+
upd.UniqueWithTombstoneIndexes,
493+
lockedIndexes,
494+
allowAutoCommit,
495+
)
496+
}
479497
if err != nil {
480498
return execPlan{}, colOrdMap{}, err
481499
}
@@ -624,16 +642,30 @@ func (b *Builder) buildDelete(del *memo.DeleteExpr) (_ execPlan, outputCols colO
624642
}
625643
}
626644

627-
node, err := b.factory.ConstructDelete(
628-
input.root,
629-
tab,
630-
fetchColOrds,
631-
returnColOrds,
632-
passthroughCols,
633-
lockedIndexes,
634-
b.allowAutoCommit && len(del.FKChecks) == 0 &&
635-
len(del.FKCascades) == 0 && del.AfterTriggers == nil,
636-
)
645+
allowAutoCommit := b.allowAutoCommit && len(del.FKChecks) == 0 &&
646+
len(del.FKCascades) == 0 && del.AfterTriggers == nil
647+
var node exec.Node
648+
if del.Swap {
649+
node, err = b.factory.ConstructDeleteSwap(
650+
input.root,
651+
tab,
652+
fetchColOrds,
653+
returnColOrds,
654+
passthroughCols,
655+
lockedIndexes,
656+
allowAutoCommit,
657+
)
658+
} else {
659+
node, err = b.factory.ConstructDelete(
660+
input.root,
661+
tab,
662+
fetchColOrds,
663+
returnColOrds,
664+
passthroughCols,
665+
lockedIndexes,
666+
allowAutoCommit,
667+
)
668+
}
637669
if err != nil {
638670
return execPlan{}, colOrdMap{}, err
639671
}

0 commit comments

Comments
 (0)