Skip to content

Commit a696b72

Browse files
committed
sql/schemachanger: fix unusable secondary indexes during pk swap
Previously, the declarative schema changer during ALTER PRIMARY KEY, the declarative schema changer would make the new primary index public and then work on creating replacement secondary indexes. This could lead to broken behaviour where you could be left with either unusable old secondary indexes (causing trouble for DML queries) or potential validation errors. To address this, this patch adjusts the rules so that the new primary index is kept at a validated state, while replacement secondary indexes are constructed. This guarantees that all secondary indexes are usable during a PK swap, and the new primary key and replacement secondary indexes are swapped in an atomic fashion. Fixes: #133129 Fixes: #130165 Release note (bug fix): Addressed a bug where secondary indexes could be unusable by DML while a primary key swap was occurring, if the new primary key did not contain columns from the old primary key.
1 parent 7e7c816 commit a696b72

File tree

98 files changed

+8093
-2560
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

98 files changed

+8093
-2560
lines changed

pkg/ccl/schemachangerccl/backup_base_generated_test.go

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

pkg/sql/schemachanger/scplan/internal/rules/current/dep_add_index.go

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ func init() {
203203
func init() {
204204

205205
registerDepRule(
206-
"primary index with new columns should exist before secondary indexes",
206+
"primary index with new columns should validated before secondary indexes",
207207
scgraph.Precedence,
208208
"primary-index", "secondary-index",
209209
func(from, to NodeVars) rel.Clauses {
@@ -216,7 +216,27 @@ func init() {
216216
to, screl.SourceIndexID,
217217
"primary-index-id",
218218
),
219-
StatusesToPublicOrTransient(from, scpb.Status_PUBLIC, to, scpb.Status_BACKFILL_ONLY),
219+
StatusesToPublicOrTransient(from, scpb.Status_VALIDATED, to, scpb.Status_BACKFILL_ONLY),
220+
}
221+
})
222+
223+
// This rule guarantees that the primary index can only go public, once the
224+
// secondary index is ready to go public.
225+
registerDepRule(
226+
"secondary indexes should be in a validated state before primary indexes can go public",
227+
scgraph.Precedence,
228+
"secondary-index", "primary-index",
229+
func(from, to NodeVars) rel.Clauses {
230+
return rel.Clauses{
231+
from.Type((*scpb.SecondaryIndex)(nil)),
232+
to.Type((*scpb.PrimaryIndex)(nil)),
233+
JoinOnDescID(from, to, "table-id"),
234+
JoinOn(
235+
from, screl.SourceIndexID,
236+
to, screl.IndexID,
237+
"primary-index-id",
238+
),
239+
StatusesToPublicOrTransient(from, scpb.Status_VALIDATED, to, scpb.Status_PUBLIC),
220240
}
221241
})
222242

@@ -234,7 +254,7 @@ func init() {
234254
to, screl.SourceIndexID,
235255
"primary-index-id",
236256
),
237-
StatusesToPublicOrTransient(from, scpb.Status_PUBLIC, to, scpb.Status_DELETE_ONLY),
257+
StatusesToPublicOrTransient(from, scpb.Status_VALIDATED, to, scpb.Status_DELETE_ONLY),
238258
}
239259
})
240260
}

pkg/sql/schemachanger/scplan/internal/rules/current/testdata/deprules

Lines changed: 62 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4031,21 +4031,6 @@ deprules
40314031
- $old-index-Node[CurrentStatus] = PUBLIC
40324032
- joinTargetNode($new-index, $new-index-Target, $new-index-Node)
40334033
- joinTargetNode($old-index, $old-index-Target, $old-index-Node)
4034-
- name: primary index with new columns should exist before secondary indexes
4035-
from: primary-index-Node
4036-
kind: Precedence
4037-
to: secondary-index-Node
4038-
query:
4039-
- $primary-index[Type] = '*scpb.PrimaryIndex'
4040-
- $secondary-index[Type] = '*scpb.SecondaryIndex'
4041-
- joinOnDescID($primary-index, $secondary-index, $table-id)
4042-
- $primary-index[IndexID] = $primary-index-id
4043-
- $secondary-index[SourceIndexID] = $primary-index-id
4044-
- ToPublicOrTransient($primary-index-Target, $secondary-index-Target)
4045-
- $primary-index-Node[CurrentStatus] = PUBLIC
4046-
- $secondary-index-Node[CurrentStatus] = BACKFILL_ONLY
4047-
- joinTargetNode($primary-index, $primary-index-Target, $primary-index-Node)
4048-
- joinTargetNode($secondary-index, $secondary-index-Target, $secondary-index-Node)
40494034
- name: primary index with new columns should exist before temp indexes
40504035
from: primary-index-Node
40514036
kind: Precedence
@@ -4057,10 +4042,25 @@ deprules
40574042
- $primary-index[IndexID] = $primary-index-id
40584043
- $temp-index[SourceIndexID] = $primary-index-id
40594044
- ToPublicOrTransient($primary-index-Target, $temp-index-Target)
4060-
- $primary-index-Node[CurrentStatus] = PUBLIC
4045+
- $primary-index-Node[CurrentStatus] = VALIDATED
40614046
- $temp-index-Node[CurrentStatus] = DELETE_ONLY
40624047
- joinTargetNode($primary-index, $primary-index-Target, $primary-index-Node)
40634048
- joinTargetNode($temp-index, $temp-index-Target, $temp-index-Node)
4049+
- name: primary index with new columns should validated before secondary indexes
4050+
from: primary-index-Node
4051+
kind: Precedence
4052+
to: secondary-index-Node
4053+
query:
4054+
- $primary-index[Type] = '*scpb.PrimaryIndex'
4055+
- $secondary-index[Type] = '*scpb.SecondaryIndex'
4056+
- joinOnDescID($primary-index, $secondary-index, $table-id)
4057+
- $primary-index[IndexID] = $primary-index-id
4058+
- $secondary-index[SourceIndexID] = $primary-index-id
4059+
- ToPublicOrTransient($primary-index-Target, $secondary-index-Target)
4060+
- $primary-index-Node[CurrentStatus] = VALIDATED
4061+
- $secondary-index-Node[CurrentStatus] = BACKFILL_ONLY
4062+
- joinTargetNode($primary-index, $primary-index-Target, $primary-index-Node)
4063+
- joinTargetNode($secondary-index, $secondary-index-Target, $secondary-index-Node)
40644064
- name: relation dropped before dependent column
40654065
from: descriptor-Node
40664066
kind: Precedence
@@ -4462,6 +4462,21 @@ deprules
44624462
- isIndexKeyColumnKey(*scpb.IndexColumn)($index-column)
44634463
- joinTargetNode($index, $index-Target, $index-Node)
44644464
- joinTargetNode($column, $column-Target, $column-Node)
4465+
- name: secondary indexes should be in a validated state before primary indexes can go public
4466+
from: secondary-index-Node
4467+
kind: Precedence
4468+
to: primary-index-Node
4469+
query:
4470+
- $secondary-index[Type] = '*scpb.SecondaryIndex'
4471+
- $primary-index[Type] = '*scpb.PrimaryIndex'
4472+
- joinOnDescID($secondary-index, $primary-index, $table-id)
4473+
- $secondary-index[SourceIndexID] = $primary-index-id
4474+
- $primary-index[IndexID] = $primary-index-id
4475+
- ToPublicOrTransient($secondary-index-Target, $primary-index-Target)
4476+
- $secondary-index-Node[CurrentStatus] = VALIDATED
4477+
- $primary-index-Node[CurrentStatus] = PUBLIC
4478+
- joinTargetNode($secondary-index, $secondary-index-Target, $secondary-index-Node)
4479+
- joinTargetNode($primary-index, $primary-index-Target, $primary-index-Node)
44654480
- name: simple constraint public right before its dependents
44664481
from: simple-constraint-Node
44674482
kind: SameStagePrecedence
@@ -8687,21 +8702,6 @@ deprules
86878702
- $old-index-Node[CurrentStatus] = PUBLIC
86888703
- joinTargetNode($new-index, $new-index-Target, $new-index-Node)
86898704
- joinTargetNode($old-index, $old-index-Target, $old-index-Node)
8690-
- name: primary index with new columns should exist before secondary indexes
8691-
from: primary-index-Node
8692-
kind: Precedence
8693-
to: secondary-index-Node
8694-
query:
8695-
- $primary-index[Type] = '*scpb.PrimaryIndex'
8696-
- $secondary-index[Type] = '*scpb.SecondaryIndex'
8697-
- joinOnDescID($primary-index, $secondary-index, $table-id)
8698-
- $primary-index[IndexID] = $primary-index-id
8699-
- $secondary-index[SourceIndexID] = $primary-index-id
8700-
- ToPublicOrTransient($primary-index-Target, $secondary-index-Target)
8701-
- $primary-index-Node[CurrentStatus] = PUBLIC
8702-
- $secondary-index-Node[CurrentStatus] = BACKFILL_ONLY
8703-
- joinTargetNode($primary-index, $primary-index-Target, $primary-index-Node)
8704-
- joinTargetNode($secondary-index, $secondary-index-Target, $secondary-index-Node)
87058705
- name: primary index with new columns should exist before temp indexes
87068706
from: primary-index-Node
87078707
kind: Precedence
@@ -8713,10 +8713,25 @@ deprules
87138713
- $primary-index[IndexID] = $primary-index-id
87148714
- $temp-index[SourceIndexID] = $primary-index-id
87158715
- ToPublicOrTransient($primary-index-Target, $temp-index-Target)
8716-
- $primary-index-Node[CurrentStatus] = PUBLIC
8716+
- $primary-index-Node[CurrentStatus] = VALIDATED
87178717
- $temp-index-Node[CurrentStatus] = DELETE_ONLY
87188718
- joinTargetNode($primary-index, $primary-index-Target, $primary-index-Node)
87198719
- joinTargetNode($temp-index, $temp-index-Target, $temp-index-Node)
8720+
- name: primary index with new columns should validated before secondary indexes
8721+
from: primary-index-Node
8722+
kind: Precedence
8723+
to: secondary-index-Node
8724+
query:
8725+
- $primary-index[Type] = '*scpb.PrimaryIndex'
8726+
- $secondary-index[Type] = '*scpb.SecondaryIndex'
8727+
- joinOnDescID($primary-index, $secondary-index, $table-id)
8728+
- $primary-index[IndexID] = $primary-index-id
8729+
- $secondary-index[SourceIndexID] = $primary-index-id
8730+
- ToPublicOrTransient($primary-index-Target, $secondary-index-Target)
8731+
- $primary-index-Node[CurrentStatus] = VALIDATED
8732+
- $secondary-index-Node[CurrentStatus] = BACKFILL_ONLY
8733+
- joinTargetNode($primary-index, $primary-index-Target, $primary-index-Node)
8734+
- joinTargetNode($secondary-index, $secondary-index-Target, $secondary-index-Node)
87208735
- name: relation dropped before dependent column
87218736
from: descriptor-Node
87228737
kind: Precedence
@@ -9118,6 +9133,21 @@ deprules
91189133
- isIndexKeyColumnKey(*scpb.IndexColumn)($index-column)
91199134
- joinTargetNode($index, $index-Target, $index-Node)
91209135
- joinTargetNode($column, $column-Target, $column-Node)
9136+
- name: secondary indexes should be in a validated state before primary indexes can go public
9137+
from: secondary-index-Node
9138+
kind: Precedence
9139+
to: primary-index-Node
9140+
query:
9141+
- $secondary-index[Type] = '*scpb.SecondaryIndex'
9142+
- $primary-index[Type] = '*scpb.PrimaryIndex'
9143+
- joinOnDescID($secondary-index, $primary-index, $table-id)
9144+
- $secondary-index[SourceIndexID] = $primary-index-id
9145+
- $primary-index[IndexID] = $primary-index-id
9146+
- ToPublicOrTransient($secondary-index-Target, $primary-index-Target)
9147+
- $secondary-index-Node[CurrentStatus] = VALIDATED
9148+
- $primary-index-Node[CurrentStatus] = PUBLIC
9149+
- joinTargetNode($secondary-index, $secondary-index-Target, $secondary-index-Node)
9150+
- joinTargetNode($primary-index, $primary-index-Target, $primary-index-Node)
91219151
- name: simple constraint public right before its dependents
91229152
from: simple-constraint-Node
91239153
kind: SameStagePrecedence

0 commit comments

Comments
 (0)