Skip to content

Commit c308da0

Browse files
committed
sql: account for duplicate partition names in subzone span gen
This patch fixes a bug during GenerateSubzoneSpans that does not correctly distinguish between partitions of the same name across indexes. The issue was introduced when we relaxed restrictions on partition name reuse across indexes of a table (#39332). Epic: CRDB-43310 Fixes: #128692 Release note (bug fix): Configuring replication controls on a partition name of an index that is not unique across all indexes will correctly impact only that partition.
1 parent c794734 commit c308da0

File tree

3 files changed

+63
-18
lines changed

3 files changed

+63
-18
lines changed

pkg/ccl/spanconfigccl/spanconfigsqltranslatorccl/testdata/partitions

+23
Original file line numberDiff line numberDiff line change
@@ -253,3 +253,26 @@ translate database=db table=part
253253
/Table/111/2/{51-60} range default
254254
/Table/111/2/6{0-1} num_replicas=11
255255
/Table/11{1/2/61-2} range default
256+
257+
exec-sql
258+
CREATE TABLE db.foo(i INT PRIMARY KEY, j INT) PARTITION BY LIST (i) (
259+
PARTITION p VALUES IN (1, 5)
260+
);
261+
CREATE INDEX idx ON db.foo(j) PARTITION BY LIST (j) (
262+
PARTITION p VALUES IN (2, 4)
263+
);
264+
ALTER PARTITION p OF INDEX db.foo@foo_pkey CONFIGURE ZONE USING gc.ttlseconds = 2;
265+
ALTER PARTITION p OF INDEX db.foo@idx CONFIGURE ZONE USING gc.ttlseconds = 5;
266+
----
267+
268+
translate database=db table=foo
269+
----
270+
/Table/112{-/1/1} range default
271+
/Table/112/1/{1-2} ttl_seconds=2
272+
/Table/112/1/{2-5} range default
273+
/Table/112/1/{5-6} ttl_seconds=2
274+
/Table/112/{1/6-2/2} range default
275+
/Table/112/2/{2-3} ttl_seconds=5
276+
/Table/112/2/{3-4} range default
277+
/Table/112/2/{4-5} ttl_seconds=5
278+
/Table/11{2/2/5-3} range default

pkg/sql/partition_utils.go

+20-9
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ import (
1818
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
1919
)
2020

21+
// partitionKey is used to group a partition's name and its index ID for
22+
// indexing into a map.
23+
type partitionKey struct {
24+
indexID descpb.IndexID
25+
name string
26+
}
27+
2128
// GenerateSubzoneSpans constructs from a TableDescriptor the entries mapping
2229
// zone config spans to subzones for use in the SubzoneSpans field of
2330
// zonepb.ZoneConfig. SubzoneSpans controls which splits are created, so only
@@ -76,10 +83,11 @@ func GenerateSubzoneSpans(
7683
a := &tree.DatumAlloc{}
7784

7885
subzoneIndexByIndexID := make(map[descpb.IndexID]int32)
79-
subzoneIndexByPartition := make(map[string]int32)
86+
subzoneIndexByPartition := make(map[partitionKey]int32)
8087
for i, subzone := range subzones {
8188
if len(subzone.PartitionName) > 0 {
82-
subzoneIndexByPartition[subzone.PartitionName] = int32(i)
89+
partKey := partitionKey{indexID: descpb.IndexID(subzone.IndexID), name: subzone.PartitionName}
90+
subzoneIndexByPartition[partKey] = int32(i)
8391
} else {
8492
subzoneIndexByIndexID[descpb.IndexID(subzone.IndexID)] = int32(i)
8593
}
@@ -140,7 +148,8 @@ func GenerateSubzoneSpans(
140148
}
141149
var ok bool
142150
if subzone := payloads[0].(zonepb.Subzone); len(subzone.PartitionName) > 0 {
143-
subzoneSpan.SubzoneIndex, ok = subzoneIndexByPartition[subzone.PartitionName]
151+
partKey := partitionKey{indexID: descpb.IndexID(subzone.IndexID), name: subzone.PartitionName}
152+
subzoneSpan.SubzoneIndex, ok = subzoneIndexByPartition[partKey]
144153
} else {
145154
subzoneSpan.SubzoneIndex, ok = subzoneIndexByIndexID[descpb.IndexID(subzone.IndexID)]
146155
}
@@ -165,7 +174,7 @@ func indexCoveringsForPartitioning(
165174
tableDesc catalog.TableDescriptor,
166175
idx catalog.Index,
167176
part catalog.Partitioning,
168-
relevantPartitions map[string]int32,
177+
relevantPartitions map[partitionKey]int32,
169178
prefixDatums []tree.Datum,
170179
) ([]covering.Covering, error) {
171180
if part.NumColumns() == 0 {
@@ -191,10 +200,11 @@ func indexCoveringsForPartitioning(
191200
if err != nil {
192201
return err
193202
}
194-
if _, ok := relevantPartitions[name]; ok {
203+
partKey := partitionKey{indexID: idx.GetID(), name: name}
204+
if _, ok := relevantPartitions[partKey]; ok {
195205
listCoverings[len(t.Datums)] = append(listCoverings[len(t.Datums)], covering.Range{
196206
Start: keyPrefix, End: roachpb.Key(keyPrefix).PrefixEnd(),
197-
Payload: zonepb.Subzone{PartitionName: name},
207+
Payload: zonepb.Subzone{IndexID: uint32(idx.GetID()), PartitionName: name},
198208
})
199209
}
200210
newPrefixDatums := append(prefixDatums, t.Datums...)
@@ -219,7 +229,8 @@ func indexCoveringsForPartitioning(
219229

220230
if part.NumRanges() > 0 {
221231
err := part.ForEachRange(func(name string, from, to []byte) error {
222-
if _, ok := relevantPartitions[name]; !ok {
232+
partKey := partitionKey{indexID: idx.GetID(), name: name}
233+
if _, ok := relevantPartitions[partKey]; !ok {
223234
return nil
224235
}
225236
_, fromKey, err := rowenc.DecodePartitionTuple(
@@ -232,10 +243,10 @@ func indexCoveringsForPartitioning(
232243
if err != nil {
233244
return err
234245
}
235-
if _, ok := relevantPartitions[name]; ok {
246+
if _, ok := relevantPartitions[partKey]; ok {
236247
coverings = append(coverings, covering.Covering{{
237248
Start: fromKey, End: toKey,
238-
Payload: zonepb.Subzone{PartitionName: name},
249+
Payload: zonepb.Subzone{IndexID: uint32(idx.GetID()), PartitionName: name},
239250
}})
240251
}
241252
return nil

pkg/sql/schemachanger/scbuild/internal/scbuildstmt/zone_config_helpers.go

+20-9
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,13 @@ func accumulateNewUniqueConstraints(currentZone, newZone *zonepb.ZoneConfig) []z
710710
return retConstraints
711711
}
712712

713+
// partitionKey is used to group a partition's name and its index ID for
714+
// indexing into a map.
715+
type partitionKey struct {
716+
indexID descpb.IndexID
717+
name string
718+
}
719+
713720
// generateSubzoneSpans constructs from a TableID the entries mapping
714721
// zone config spans to subzones for use in the SubzoneSpans field of
715722
// zonepb.ZoneConfig. SubzoneSpans controls which splits are created, so only
@@ -764,10 +771,11 @@ func generateSubzoneSpans(
764771
}
765772

766773
subzoneIndexByIndexID := make(map[descpb.IndexID]int32)
767-
subzoneIndexByPartition := make(map[string]int32)
774+
subzoneIndexByPartition := make(map[partitionKey]int32)
768775
for i, subzone := range subzones {
769776
if len(subzone.PartitionName) > 0 {
770-
subzoneIndexByPartition[subzone.PartitionName] = int32(i)
777+
partKey := partitionKey{indexID: descpb.IndexID(subzone.IndexID), name: subzone.PartitionName}
778+
subzoneIndexByPartition[partKey] = int32(i)
771779
} else {
772780
subzoneIndexByIndexID[descpb.IndexID(subzone.IndexID)] = int32(i)
773781
}
@@ -827,7 +835,8 @@ func generateSubzoneSpans(
827835
}
828836
var ok bool
829837
if subzone := payloads[0].(zonepb.Subzone); len(subzone.PartitionName) > 0 {
830-
subzoneSpan.SubzoneIndex, ok = subzoneIndexByPartition[subzone.PartitionName]
838+
partKey := partitionKey{indexID: descpb.IndexID(subzone.IndexID), name: subzone.PartitionName}
839+
subzoneSpan.SubzoneIndex, ok = subzoneIndexByPartition[partKey]
831840
} else {
832841
subzoneSpan.SubzoneIndex, ok = subzoneIndexByIndexID[descpb.IndexID(subzone.IndexID)]
833842
}
@@ -853,7 +862,7 @@ func indexCoveringsForPartitioning(
853862
indexID catid.IndexID,
854863
index []*scpb.IndexColumn,
855864
part catalog.Partitioning,
856-
relevantPartitions map[string]int32,
865+
relevantPartitions map[partitionKey]int32,
857866
prefixDatums []tree.Datum,
858867
) ([]covering.Covering, error) {
859868
if part.NumColumns() == 0 {
@@ -879,10 +888,11 @@ func indexCoveringsForPartitioning(
879888
if err != nil {
880889
return err
881890
}
882-
if _, ok := relevantPartitions[name]; ok {
891+
partKey := partitionKey{indexID: indexID, name: name}
892+
if _, ok := relevantPartitions[partKey]; ok {
883893
listCoverings[len(t.Datums)] = append(listCoverings[len(t.Datums)], covering.Range{
884894
Start: keyPrefix, End: roachpb.Key(keyPrefix).PrefixEnd(),
885-
Payload: zonepb.Subzone{PartitionName: name},
895+
Payload: zonepb.Subzone{IndexID: uint32(indexID), PartitionName: name},
886896
})
887897
}
888898
newPrefixDatums := append(prefixDatums, t.Datums...)
@@ -907,7 +917,8 @@ func indexCoveringsForPartitioning(
907917

908918
if part.NumRanges() > 0 {
909919
err := part.ForEachRange(func(name string, from, to []byte) error {
910-
if _, ok := relevantPartitions[name]; !ok {
920+
partKey := partitionKey{indexID: indexID, name: name}
921+
if _, ok := relevantPartitions[partKey]; !ok {
911922
return nil
912923
}
913924
_, fromKey, err := decodePartitionTuple(
@@ -920,10 +931,10 @@ func indexCoveringsForPartitioning(
920931
if err != nil {
921932
return err
922933
}
923-
if _, ok := relevantPartitions[name]; ok {
934+
if _, ok := relevantPartitions[partKey]; ok {
924935
coverings = append(coverings, covering.Covering{{
925936
Start: fromKey, End: toKey,
926-
Payload: zonepb.Subzone{PartitionName: name},
937+
Payload: zonepb.Subzone{IndexID: uint32(indexID), PartitionName: name},
927938
}})
928939
}
929940
return nil

0 commit comments

Comments
 (0)