diff --git a/pkg/ccl/logictestccl/testdata/logic_test/zone b/pkg/ccl/logictestccl/testdata/logic_test/zone index 77a9c4b70cfd..e4489367cc08 100644 --- a/pkg/ccl/logictestccl/testdata/logic_test/zone +++ b/pkg/ccl/logictestccl/testdata/logic_test/zone @@ -644,8 +644,6 @@ TABLE system.public.tenant_usage TABLE system.public.transaction_activity NULL system transaction_activity NULL NULL TABLE system.public.transaction_statistics NULL system transaction_statistics NULL NULL TABLE test.public.t NULL test t NULL NULL -TABLE test.public.t36642 NULL test t36642 NULL NULL -TABLE test.public.t36644 NULL test t36644 NULL NULL # Test the zone information being displayed in SHOW CREATE statement ok @@ -1272,3 +1270,33 @@ PARTITION one OF TABLE t_69647 ALTER PARTITION one OF TABLE t_69647 CONFIGURE Z num_replicas = 3, constraints = '[]', lease_preferences = '[]' + +subtest regression_130605 + +statement ok +CREATE DATABASE foo; +USE foo; +CREATE TABLE foob (i int, j int); + +# Setting a subzone configuration on a table should mark the table's zone +# configuration as a subzone placeholder. This means that the table's zone +# configuration is not "set" yet and we should just show its parent's zone +# configuration. +statement ok +ALTER INDEX foob@foob_pkey CONFIGURE ZONE USING num_replicas = 8; + +statement ok +ALTER DATABASE foo CONFIGURE ZONE USING num_replicas = 11; + +query TT +SHOW ZONE CONFIGURATION FOR TABLE foob; +---- +DATABASE foo ALTER DATABASE foo CONFIGURE ZONE USING + range_min_bytes = 134217728, + range_max_bytes = 536870912, + gc.ttlseconds = 14400, + num_replicas = 11, + constraints = '[]', + lease_preferences = '[]' + +subtest end diff --git a/pkg/ccl/spanconfigccl/spanconfigsqltranslatorccl/testdata/indexes b/pkg/ccl/spanconfigccl/spanconfigsqltranslatorccl/testdata/indexes index 774dd284d021..e2125da719ad 100644 --- a/pkg/ccl/spanconfigccl/spanconfigsqltranslatorccl/testdata/indexes +++ b/pkg/ccl/spanconfigccl/spanconfigsqltranslatorccl/testdata/indexes @@ -6,7 +6,13 @@ exec-sql CREATE DATABASE db; CREATE TABLE db.t(i INT PRIMARY KEY, j INT); CREATE INDEX idx ON db.t (j); +---- + +exec-sql ALTER DATABASE db CONFIGURE ZONE USING num_replicas=7; +---- + +exec-sql ALTER INDEX db.t@idx CONFIGURE ZONE USING num_voters = 5; ---- @@ -59,6 +65,9 @@ translate database=db table=t # continues to hold a placeholder zone config. exec-sql ALTER DATABASE db CONFIGURE ZONE USING gc.ttlseconds = 3600; +---- + +exec-sql ALTER INDEX db.t@idx CONFIGURE ZONE USING gc.ttlseconds = 25 ---- @@ -92,3 +101,24 @@ translate database=db table=t /Table/106{-/2} range_max_bytes=100000000 range_min_bytes=1000 ttl_seconds=3600 num_replicas=7 /Table/106/{2-3} range_max_bytes=100000000 range_min_bytes=1000 ttl_seconds=25 num_replicas=7 num_voters=5 /Table/10{6/3-7} range_max_bytes=100000000 range_min_bytes=1000 ttl_seconds=3600 num_replicas=7 + +# Configure a zone config field on each index on a table to ensure that both +# indexes have their own zone configs. +exec-sql +CREATE TABLE db.t_indexes (k INT PRIMARY KEY, v INT, INDEX idx (v)); +---- + +exec-sql +ALTER INDEX db.t_indexes@t_indexes_pkey CONFIGURE ZONE USING num_replicas = 4; +---- + +exec-sql +ALTER INDEX db.t_indexes@idx CONFIGURE ZONE USING num_replicas = 5; +---- + +translate database=db table=t_indexes +---- +/Table/107{-/1} ttl_seconds=3600 num_replicas=7 +/Table/107/{1-2} ttl_seconds=3600 num_replicas=4 +/Table/107/{2-3} ttl_seconds=3600 num_replicas=5 +/Table/10{7/3-8} ttl_seconds=3600 num_replicas=7 diff --git a/pkg/ccl/spanconfigccl/spanconfigsqltranslatorccl/testdata/partitions b/pkg/ccl/spanconfigccl/spanconfigsqltranslatorccl/testdata/partitions index 6dadcbeabe8e..be84bb50b96a 100644 --- a/pkg/ccl/spanconfigccl/spanconfigsqltranslatorccl/testdata/partitions +++ b/pkg/ccl/spanconfigccl/spanconfigsqltranslatorccl/testdata/partitions @@ -32,7 +32,13 @@ translate database=db table=person exec-sql ALTER PARTITION default OF TABLE db.person CONFIGURE ZONE USING gc.ttlseconds = 1; +---- + +exec-sql ALTER PARTITION australia OF TABLE db.person CONFIGURE ZONE USING gc.ttlseconds = 2; +---- + +exec-sql ALTER PARTITION north_america OF TABLE db.person CONFIGURE ZONE USING gc.ttlseconds = 3; ---- @@ -52,8 +58,17 @@ translate database=db table=person exec-sql ALTER PARTITION old_au OF TABLE db.person CONFIGURE ZONE USING gc.ttlseconds = 4; +---- + +exec-sql ALTER PARTITION yung_au OF TABLE db.person CONFIGURE ZONE USING gc.ttlseconds = 5; +---- + +exec-sql ALTER PARTITION old_na OF TABLE db.person CONFIGURE ZONE USING gc.ttlseconds = 6; +---- + +exec-sql ALTER PARTITION yung_na OF TABLE db.person CONFIGURE ZONE USING gc.ttlseconds = 7; ---- @@ -87,8 +102,17 @@ CREATE TABLE db.list_default_then_range ( PARTITION P2N1N2 VALUES FROM (10) TO (maxvalue) ) ); +---- + +exec-sql ALTER PARTITION P1N1 OF TABLE db.list_default_then_range CONFIGURE ZONE USING gc.ttlseconds = 4; +---- + +exec-sql ALTER PARTITION P1N1N2 OF TABLE db.list_default_then_range CONFIGURE ZONE USING gc.ttlseconds = 5; +---- + +exec-sql ALTER PARTITION P2N1N2 OF TABLE db.list_default_then_range CONFIGURE ZONE USING gc.ttlseconds = 6; ---- @@ -112,7 +136,13 @@ translate database=db table=list_multi_column_partitions exec-sql ALTER TABLE db.list_multi_column_partitions CONFIGURE ZONE USING gc.ttlseconds = 3; +---- + +exec-sql ALTER PARTITION default OF TABLE db.list_multi_column_partitions CONFIGURE ZONE USING gc.ttlseconds = 1; +---- + +exec-sql ALTER PARTITION six_and_seven OF TABLE db.list_multi_column_partitions CONFIGURE ZONE USING gc.ttlseconds = 2; ---- @@ -130,9 +160,21 @@ CREATE TABLE db.partition_by_list(i INT PRIMARY KEY, j INT) PARTITION BY LIST (i PARTITION four_and_three VALUES IN (4, 3), PARTITION everything_else VALUES IN (6, default) ); +---- + +exec-sql ALTER TABLE db.partition_by_list CONFIGURE ZONE USING gc.ttlseconds = 1; +---- + +exec-sql ALTER PARTITION one_and_five OF TABLE db.partition_by_list CONFIGURE ZONE USING gc.ttlseconds = 2; +---- + +exec-sql ALTER PARTITION four_and_three OF TABLE db.partition_by_list CONFIGURE ZONE USING gc.ttlseconds = 3; +---- + +exec-sql ALTER PARTITION everything_else OF TABLE db.partition_by_list CONFIGURE ZONE USING gc.ttlseconds = 4; ---- @@ -153,8 +195,17 @@ exec-sql CREATE TABLE db.test(i INT PRIMARY KEY, j INT) PARTITION BY LIST (i) ( PARTITION one_and_five VALUES IN (1, 5) ); +---- + +exec-sql ALTER PARTITION one_and_five OF TABLE db.test CONFIGURE ZONE USING gc.ttlseconds = 2; +---- + +exec-sql ALTER INDEX db.test@test_pkey CONFIGURE ZONE USING num_replicas = 4; +---- + +exec-sql ALTER PARTITION one_and_five OF TABLE db.test CONFIGURE ZONE USING gc.ttlseconds = 3; ---- diff --git a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/database_zone_config.go b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/database_zone_config.go index 16e853c055e5..9ddba5aabb96 100644 --- a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/database_zone_config.go +++ b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/database_zone_config.go @@ -118,7 +118,7 @@ func (dzo *databaseZoneConfigObj) retrieveCompleteZoneConfig( if getInheritedDefault { zc, err = dzo.getInheritedDefaultZoneConfig(b) } else { - zc, _, err = dzo.getZoneConfig(b, false /* inheritDefaultRange */) + zc, err = dzo.getZoneConfig(b, false /* inheritDefaultRange */) } if err != nil { return nil, nil, err @@ -140,7 +140,7 @@ func (dzo *databaseZoneConfigObj) completeZoneConfig(b BuildCtx, zone *zonepb.Zo if zone.IsComplete() { return nil } - defaultZone, _, err := dzo.getZoneConfig(b, true /* inheritDefaultRange */) + defaultZone, err := dzo.getZoneConfig(b, true /* inheritDefaultRange */) if err != nil { return err } @@ -156,42 +156,36 @@ func (dzo *databaseZoneConfigObj) getInheritedDefaultZoneConfig( b BuildCtx, ) (*zonepb.ZoneConfig, error) { // Get the zone config of the DEFAULT RANGE. - zc, _, err := dzo.getZoneConfig(b, true /* inheritDefaultRange */) + zc, err := dzo.getZoneConfig(b, true /* inheritDefaultRange */) return zc, err } func (dzo *databaseZoneConfigObj) getZoneConfig( b BuildCtx, inheritDefaultRange bool, -) (*zonepb.ZoneConfig, *zonepb.ZoneConfig, error) { - var subzones []zonepb.Subzone - zc, subzones, err := lookUpSystemZonesTable(b, dzo, inheritDefaultRange) +) (*zonepb.ZoneConfig, error) { + zc, _, err := lookUpSystemZonesTable(b, dzo, inheritDefaultRange, false /* isSubzoneConfig */) if err != nil { - return nil, nil, err + return nil, err } - - // If the zone config exists, we know that it is not a subzone placeholder. + // If the zone config exists, return. if zc != nil { - return zc, nil, err + return zc, err } - zc = zonepb.NewZoneConfig() - zc.Subzones = subzones - subzone := zc - - // No zone config for this ID. Retrieve the default zone config, but only as - // long as that wasn't the ID we were trying to retrieve + // Otherwise, no zone config for this ID. Retrieve the default zone config, + // but only as long as that wasn't the ID we were trying to retrieve // (to avoid infinite recursion). if !inheritDefaultRange { - zc, _, err := dzo.getZoneConfig(b, true /* inheritDefaultRange */) + zc, err = dzo.getZoneConfig(b, true /* inheritDefaultRange */) if err != nil { - return nil, nil, err + return nil, err } - return zc, subzone, nil + return zc, nil } // `targetID == keys.RootNamespaceID` but that zc config is not found // in `system.zones` table. Return a special, recognizable error! - return nil, nil, sqlerrors.ErrNoZoneConfigApplies + return nil, sqlerrors.ErrNoZoneConfigApplies } func (dzo *databaseZoneConfigObj) applyZoneConfig( diff --git a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/index_zone_config.go b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/index_zone_config.go index ffa177b9b805..c23b77b1dc33 100644 --- a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/index_zone_config.go +++ b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/index_zone_config.go @@ -43,7 +43,7 @@ func (izo *indexZoneConfigObj) addZoneConfigToBuildCtx(b BuildCtx) scpb.Element subzones = parentZoneConfig.Subzones } - ss, err := generateSubzoneSpans(b, izo.tableID, subzones, izo.indexID, "") + ss, err := generateSubzoneSpans(b, izo.tableID, subzones) if err != nil { panic(err) } @@ -67,14 +67,23 @@ func (izo *indexZoneConfigObj) retrievePartialZoneConfig(b BuildCtx) *zonepb.Zon return b.QueryByID(id).FilterIndexZoneConfig() }, sameIdx) + // Since we will be performing a subzone config update, we need to retrieve + // its parent's (table's) zone config for later use. This is because we need + // context of any existing subzone spans to generate an accurate subzone span + // for this subzone. + _ = izo.tableZoneConfigObj.retrievePartialZoneConfig(b) + + var partialZone *zonepb.ZoneConfig if mostRecentElem != nil { - idxZc := zonepb.NewZoneConfig() - idxZc.Subzones = []zonepb.Subzone{mostRecentElem.Subzone} - izo.zoneConfig = idxZc + // Construct a zone config placeholder with the correct subzone. This + // will be what we return. + partialZone = zonepb.NewZoneConfig() + partialZone.DeleteTableConfig() + partialZone.Subzones = []zonepb.Subzone{mostRecentElem.Subzone} + izo.indexSubzone = &mostRecentElem.Subzone izo.seqNum = mostRecentElem.SeqNum } - - return izo.zoneConfig + return partialZone } func (izo *indexZoneConfigObj) retrieveCompleteZoneConfig( @@ -86,7 +95,11 @@ func (izo *indexZoneConfigObj) retrieveCompleteZoneConfig( if getInheritedDefault { zc, err = izo.getInheritedDefaultZoneConfig(b) } else { - zc, placeholder, err = izo.getZoneConfig(b, false /* inheritDefaultRange */) + zc, err = izo.tableZoneConfigObj.getZoneConfig(b, false /* inheritDefaultRange */) + if err != nil { + return nil, nil, err + } + placeholder, err = izo.getZoneConfig(b, false /* inheritDefaultRange */) } if err != nil { return nil, nil, err @@ -146,6 +159,20 @@ func (izo *indexZoneConfigObj) getInheritedFieldsForPartialSubzone( return &zoneInheritedFields, nil } +func (izo *indexZoneConfigObj) getZoneConfig( + b BuildCtx, inheritDefaultRange bool, +) (*zonepb.ZoneConfig, error) { + _, subzones, err := lookUpSystemZonesTable(b, izo, inheritDefaultRange, true /* isSubzoneConfig */) + if err != nil { + return nil, err + } + subzoneConfig := zonepb.NewZoneConfig() + subzoneConfig.DeleteTableConfig() + subzoneConfig.Subzones = subzones + + return subzoneConfig, nil +} + func (izo *indexZoneConfigObj) applyZoneConfig( b BuildCtx, n *tree.SetZoneConfig, diff --git a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/table_zone_config.go b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/table_zone_config.go index b8fa2a0f1dab..3b3c8504bc20 100644 --- a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/table_zone_config.go +++ b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/table_zone_config.go @@ -121,7 +121,7 @@ func (tzo *tableZoneConfigObj) completeZoneConfig(b BuildCtx, zone *zonepb.ZoneC // For tables, inherit from the database. dbID := mustRetrieveNamespaceElem(b, tzo.getTargetID()).DatabaseID dzo := databaseZoneConfigObj{databaseID: dbID} - dbZone, _, err := dzo.getZoneConfig(b, false /* inheritDefaultRange */) + dbZone, err := dzo.getZoneConfig(b, false /* inheritDefaultRange */) if err != nil { return err } @@ -130,7 +130,7 @@ func (tzo *tableZoneConfigObj) completeZoneConfig(b BuildCtx, zone *zonepb.ZoneC if zone.IsComplete() { return nil } - defaultZone, _, err := tzo.getZoneConfig(b, true /* inheritDefaultRange */) + defaultZone, err := tzo.getZoneConfig(b, true /* inheritDefaultRange */) if err != nil { return err } @@ -148,37 +148,31 @@ func (tzo *tableZoneConfigObj) getInheritedDefaultZoneConfig( targetID := tzo.getTargetID() parentDBID := mustRetrieveNamespaceElem(b, targetID).DatabaseID dzo := databaseZoneConfigObj{databaseID: parentDBID} - zc, _, err = dzo.getZoneConfig(b, false /* inheritDefaultRange */) + zc, err = dzo.getZoneConfig(b, false /* inheritDefaultRange */) return zc, err } func (tzo *tableZoneConfigObj) getZoneConfig( b BuildCtx, inheritDefaultRange bool, -) (*zonepb.ZoneConfig, *zonepb.ZoneConfig, error) { - var subzones []zonepb.Subzone - zc, subzones, err := lookUpSystemZonesTable(b, tzo, inheritDefaultRange) +) (*zonepb.ZoneConfig, error) { + zc, _, err := lookUpSystemZonesTable(b, tzo, inheritDefaultRange, false /* isSubzoneConfig */) if err != nil { - return nil, nil, err + return nil, err } - - // If the zone config exists, we know that it is not a subzone placeholder. - if zc != nil { - return zc, nil, err + // If the zone config exists and is not a subzone placeholder, return. + if zc != nil && !zc.IsSubzonePlaceholder() { + return zc, err } - zc = zonepb.NewZoneConfig() - zc.Subzones = subzones - subzone := zc - - // Since our target is a table, recursively get the zone config of its parent - // database. + // Otherwise, since our target is a table, recursively get the zone config + // of its parent database. parentDBID := mustRetrieveNamespaceElem(b, tzo.getTargetID()).DatabaseID dzo := databaseZoneConfigObj{databaseID: parentDBID} - zc, _, err = dzo.getZoneConfig(b, inheritDefaultRange) + zc, err = dzo.getZoneConfig(b, inheritDefaultRange) if err != nil { - return nil, nil, err + return nil, err } - return zc, subzone, nil + return zc, nil } func (tzo *tableZoneConfigObj) applyZoneConfig( diff --git a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/zone_config_helpers.go b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/zone_config_helpers.go index 85ea3faf7d4a..46fae9ed8732 100644 --- a/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/zone_config_helpers.go +++ b/pkg/sql/schemachanger/scbuild/internal/scbuildstmt/zone_config_helpers.go @@ -108,11 +108,7 @@ type zoneConfigRetriever interface { // (if our target is a database). // - Otherwise, we will just return the found zone config // (so `subzoneId` and `subzone` will be nil). - getZoneConfig(b BuildCtx, inheritDefaultRange bool) ( - *zonepb.ZoneConfig, - *zonepb.ZoneConfig, - error, - ) + getZoneConfig(b BuildCtx, inheritDefaultRange bool) (*zonepb.ZoneConfig, error) } type zoneConfigMutator interface { @@ -399,7 +395,7 @@ func fillIndexAndPartitionFromZoneSpecifier( // table by `targetID`. // If `targetID` is not found, a nil `zone` is returned. func lookUpSystemZonesTable( - b BuildCtx, objType zoneConfigObject, inheritDefaultRange bool, + b BuildCtx, objType zoneConfigObject, inheritDefaultRange bool, isSubzoneConfig bool, ) (zone *zonepb.ZoneConfig, subzones []zonepb.Subzone, err error) { // Get the zone config of the DEFAULT RANGE if inheritDefaultRange { @@ -411,9 +407,9 @@ func lookUpSystemZonesTable( } else { // It's a descriptor-backed target (i.e. a database ID or a table ID) zone = objType.retrievePartialZoneConfig(b) - // If we are dealing with Index subzones, clear out the zone config and + // If we are dealing with index subzones, clear out the zone config and // just use the subzones. - if _, ok := objType.(*indexZoneConfigObj); ok { + if isSubzoneConfig { if zone != nil && zone.Subzones != nil { subzones = zone.Subzones zone = nil @@ -675,11 +671,7 @@ func accumulateNewUniqueConstraints(currentZone, newZone *zonepb.ZoneConfig) []z // the common prefix (the encoded table ID) and if `EndKey` is equal to // `Key.PrefixEnd()` it is omitted. func generateSubzoneSpans( - b BuildCtx, - tableID catid.DescID, - subzones []zonepb.Subzone, - indexID catid.IndexID, - partitionName string, + b BuildCtx, tableID catid.DescID, subzones []zonepb.Subzone, ) ([]zonepb.SubzoneSpan, error) { if err := base.CheckEnterpriseEnabled(b.ClusterSettings(), "replication zones on indexes or partitions"); err != nil { diff --git a/pkg/sql/schemachanger/scdeps/exec_deps.go b/pkg/sql/schemachanger/scdeps/exec_deps.go index 75ecd9006a8c..78eef6773c61 100644 --- a/pkg/sql/schemachanger/scdeps/exec_deps.go +++ b/pkg/sql/schemachanger/scdeps/exec_deps.go @@ -260,8 +260,9 @@ func (d *txnDeps) UpdateSubzoneConfig( rawBytes = oldZc.GetRawBytesInStorage() zc = oldZc.ZoneConfigProto() } else { - // If no zone config exists, create a new one. - zc = &zonepb.ZoneConfig{} + // If no zone config exists, create a new one that is a subzone placeholder. + zc = zonepb.NewZoneConfig() + zc.DeleteTableConfig() } // Update the subzones in the zone config. diff --git a/pkg/sql/schemachanger/scdeps/sctestdeps/test_deps.go b/pkg/sql/schemachanger/scdeps/sctestdeps/test_deps.go index e345ebbe3ec0..ba772137d4e5 100644 --- a/pkg/sql/schemachanger/scdeps/sctestdeps/test_deps.go +++ b/pkg/sql/schemachanger/scdeps/sctestdeps/test_deps.go @@ -835,6 +835,7 @@ func (s *TestState) UpdateSubzoneConfig( zc = czc } else { zc = zonepb.NewZoneConfig() + zc.DeleteTableConfig() zc.Subzones = subzones zc.SubzoneSpans = subzoneSpans }