Skip to content

Commit bd0e582

Browse files
authored
Merge pull request #152594 from rafiss/blathers/backport-release-25.3-151423
release-25.3: sql: block ALTER TABLE LOCALITY to RBR with sql_safe_updates
2 parents ec40952 + 1692001 commit bd0e582

File tree

4 files changed

+130
-1
lines changed

4 files changed

+130
-1
lines changed
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# LogicTest: multiregion-9node-3region-3azs
2+
#
3+
# Test for blocking ALTER TABLE LOCALITY to REGIONAL BY ROW with sql_safe_updates enabled
4+
# This addresses issue #150945 to prevent DML failures caused by the legacy schema
5+
# changer's simultaneous column addition and primary key alteration.
6+
7+
statement ok
8+
CREATE DATABASE safe_updates_test_db PRIMARY REGION "us-east-1" REGIONS "ap-southeast-2", "ca-central-1" SURVIVE REGION FAILURE
9+
10+
statement ok
11+
USE safe_updates_test_db
12+
13+
# Verify safe updates blocks REGIONAL BY ROW conversion for existing tables.
14+
subtest blocked_by_flag
15+
16+
statement ok
17+
CREATE TABLE t1 (id UUID PRIMARY KEY, s STRING NOT NULL) WITH (schema_locked=false)
18+
19+
statement ok
20+
INSERT INTO t1 SELECT gen_random_uuid(), 'test' FROM generate_series(1, 10)
21+
22+
statement ok
23+
SET sql_safe_updates = true
24+
25+
statement error pq: cannot convert table to REGIONAL BY ROW with sql_safe_updates enabled\nHINT:.*three-step workaround:\n.*1\. ALTER TABLE t1 ADD COLUMN crdb_region.*\n.*2\. ALTER TABLE t1 ALTER COLUMN crdb_region SET DEFAULT.*\n.*3\. ALTER TABLE t1 SET LOCALITY REGIONAL BY ROW;
26+
ALTER TABLE t1 SET LOCALITY REGIONAL BY ROW
27+
28+
subtest end
29+
30+
# Verify the operation works when safe updates are disabled.
31+
subtest works_with_flag_off
32+
33+
statement ok
34+
SET sql_safe_updates = false
35+
36+
statement ok
37+
ALTER TABLE t1 SET LOCALITY REGIONAL BY ROW
38+
39+
statement ok
40+
SET sql_safe_updates = true
41+
42+
# Verify DML operations work correctly after safe conversion
43+
query T
44+
SELECT DISTINCT s FROM t1
45+
----
46+
test
47+
48+
statement ok
49+
UPDATE t1 SET s = 'updated' WHERE s = 'test'
50+
51+
query T
52+
SELECT DISTINCT s FROM t1
53+
----
54+
updated
55+
56+
subtest end
57+
58+
# Verify the safe 3-step workaround works correctly.
59+
subtest not_blocked_if_column_exists_already
60+
61+
statement ok
62+
SET sql_safe_updates = true
63+
64+
statement ok
65+
CREATE TABLE t2 (id UUID PRIMARY KEY, s STRING NOT NULL) WITH (schema_locked=false)
66+
67+
statement ok
68+
INSERT INTO t2 SELECT gen_random_uuid(), 'test' FROM generate_series(1, 10)
69+
70+
# Step 1: Add the region column manually.
71+
statement ok
72+
ALTER TABLE t2 ADD COLUMN crdb_region public.crdb_internal_region NOT VISIBLE NOT NULL DEFAULT 'us-east-1'::public.crdb_internal_region
73+
74+
# Step 2: Update the default expression to use gateway_region().
75+
statement ok
76+
ALTER TABLE t2 ALTER COLUMN crdb_region SET DEFAULT default_to_database_primary_region(gateway_region())::public.crdb_internal_region
77+
78+
# Step 3: Convert to REGIONAL BY ROW (should work now).
79+
statement ok
80+
ALTER TABLE t2 SET LOCALITY REGIONAL BY ROW
81+
82+
# Verify DML operations work after manual workaround
83+
query T
84+
SELECT DISTINCT s FROM t2
85+
----
86+
test
87+
88+
statement ok
89+
UPDATE t2 SET s = 'updated_safe' WHERE s = 'test'
90+
91+
query T
92+
SELECT DISTINCT s FROM t2
93+
----
94+
updated_safe
95+
96+
subtest end

pkg/ccl/logictestccl/tests/multiregion-9node-3region-3azs/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ go_test(
99
"//pkg/ccl/logictestccl:testdata", # keep
1010
],
1111
exec_properties = {"test.Pool": "large"},
12-
shard_count = 31,
12+
shard_count = 32,
1313
tags = ["cpu:4"],
1414
deps = [
1515
"//pkg/base",

pkg/ccl/logictestccl/tests/multiregion-9node-3region-3azs/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/alter_table_locality.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,32 @@ func (n *alterTableSetLocalityNode) alterTableLocalityToRegionalByRow(
281281
)
282282
}
283283
} else {
284+
// Block REGIONAL BY ROW conversion when safe updates are enabled to prevent
285+
// DML failures caused by the legacy schema changer's simultaneous column
286+
// addition and primary key alteration.
287+
// When this operation is implemented in the declarative schema changer, we
288+
// should not need this check since the declarative schema changer should
289+
// handle the element transitions correctly.
290+
if params.p.SessionData().SafeUpdates && !n.tableDesc.Adding() {
291+
primaryRegion, err := n.dbDesc.PrimaryRegionName()
292+
if err != nil {
293+
return err
294+
}
295+
296+
return errors.WithHintf(
297+
pgerror.Newf(
298+
pgcode.InvalidTableDefinition,
299+
"cannot convert table to REGIONAL BY ROW with sql_safe_updates enabled",
300+
),
301+
"To safely convert to REGIONAL BY ROW, either disable sql_safe_updates; or "+
302+
"use the following three-step workaround:\n"+
303+
" 1. ALTER TABLE %[1]s ADD COLUMN %[2]s public.crdb_internal_region NOT VISIBLE NOT NULL DEFAULT '%[3]s'::public.crdb_internal_region;\n"+
304+
" 2. ALTER TABLE %[1]s ALTER COLUMN %[2]s SET DEFAULT default_to_database_primary_region(gateway_region())::public.crdb_internal_region;\n"+
305+
" 3. ALTER TABLE %[1]s SET LOCALITY REGIONAL BY ROW;",
306+
tree.Name(n.tableDesc.GetName()), partColName, primaryRegion,
307+
)
308+
}
309+
284310
// No crdb_region column is found so we are implicitly creating it.
285311
// We insert the column definition before altering the primary key.
286312

0 commit comments

Comments
 (0)