github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/ccl/partitionccl/zone_test.go (about) 1 // Copyright 2017 The Cockroach Authors. 2 // 3 // Licensed as a CockroachDB Enterprise file under the Cockroach Community 4 // License (the "License"); you may not use this file except in compliance with 5 // the License. You may obtain a copy of the License at 6 // 7 // https://github.com/cockroachdb/cockroach/blob/master/licenses/CCL.txt 8 9 package partitionccl 10 11 import ( 12 "context" 13 "fmt" 14 "strings" 15 "testing" 16 17 "github.com/cockroachdb/cockroach/pkg/base" 18 "github.com/cockroachdb/cockroach/pkg/config/zonepb" 19 "github.com/cockroachdb/cockroach/pkg/keys" 20 "github.com/cockroachdb/cockroach/pkg/server" 21 "github.com/cockroachdb/cockroach/pkg/settings/cluster" 22 "github.com/cockroachdb/cockroach/pkg/sql" 23 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 24 "github.com/cockroachdb/cockroach/pkg/testutils" 25 "github.com/cockroachdb/cockroach/pkg/testutils/serverutils" 26 "github.com/cockroachdb/cockroach/pkg/testutils/sqlutils" 27 "github.com/cockroachdb/cockroach/pkg/util/encoding" 28 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 29 "github.com/cockroachdb/cockroach/pkg/util/randutil" 30 "github.com/cockroachdb/cockroach/pkg/util/uuid" 31 ) 32 33 func TestValidIndexPartitionSetShowZones(t *testing.T) { 34 defer leaktest.AfterTest(t)() 35 36 s, db, _ := serverutils.StartServer(t, base.TestServerArgs{}) 37 defer s.Stopper().Stop(context.Background()) 38 39 sqlDB := sqlutils.MakeSQLRunner(db) 40 sqlDB.Exec(t, ` 41 CREATE DATABASE d; 42 USE d; 43 CREATE TABLE t (c STRING PRIMARY KEY) PARTITION BY LIST (c) ( 44 PARTITION p0 VALUES IN ('a'), 45 PARTITION p1 VALUES IN (DEFAULT) 46 )`) 47 48 yamlDefault := fmt.Sprintf("gc: {ttlseconds: %d}", s.(*server.TestServer).Cfg.DefaultZoneConfig.GC.TTLSeconds) 49 yamlOverride := "gc: {ttlseconds: 42}" 50 zoneOverride := s.(*server.TestServer).Cfg.DefaultZoneConfig 51 zoneOverride.GC = &zonepb.GCPolicy{TTLSeconds: 42} 52 partialZoneOverride := *zonepb.NewZoneConfig() 53 partialZoneOverride.GC = &zonepb.GCPolicy{TTLSeconds: 42} 54 55 dbID := sqlutils.QueryDatabaseID(t, db, "d") 56 tableID := sqlutils.QueryTableID(t, db, "d", "public", "t") 57 58 defaultRow := sqlutils.ZoneRow{ 59 ID: keys.RootNamespaceID, 60 Config: s.(*server.TestServer).Cfg.DefaultZoneConfig, 61 } 62 defaultOverrideRow := sqlutils.ZoneRow{ 63 ID: keys.RootNamespaceID, 64 Config: zoneOverride, 65 } 66 dbRow := sqlutils.ZoneRow{ 67 ID: dbID, 68 Config: zoneOverride, 69 } 70 tableRow := sqlutils.ZoneRow{ 71 ID: tableID, 72 Config: zoneOverride, 73 } 74 primaryRow := sqlutils.ZoneRow{ 75 ID: tableID, 76 Config: zoneOverride, 77 } 78 p0Row := sqlutils.ZoneRow{ 79 ID: tableID, 80 Config: zoneOverride, 81 } 82 p1Row := sqlutils.ZoneRow{ 83 ID: tableID, 84 Config: zoneOverride, 85 } 86 87 // Partially filled config rows 88 partialDbRow := sqlutils.ZoneRow{ 89 ID: dbID, 90 Config: partialZoneOverride, 91 } 92 partialTableRow := sqlutils.ZoneRow{ 93 ID: tableID, 94 Config: partialZoneOverride, 95 } 96 partialPrimaryRow := sqlutils.ZoneRow{ 97 ID: tableID, 98 Config: partialZoneOverride, 99 } 100 partialP0Row := sqlutils.ZoneRow{ 101 ID: tableID, 102 Config: partialZoneOverride, 103 } 104 partialP1Row := sqlutils.ZoneRow{ 105 ID: tableID, 106 Config: partialZoneOverride, 107 } 108 109 // Remove stock zone configs installed at cluster bootstrap. Otherwise this 110 // test breaks whenever these stock zone configs are adjusted. 111 sqlutils.RemoveAllZoneConfigs(t, sqlDB) 112 113 // Ensure the default is reported for all zones at first. 114 sqlutils.VerifyAllZoneConfigs(t, sqlDB, defaultRow) 115 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "RANGE default", defaultRow) 116 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "DATABASE d", defaultRow) 117 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "TABLE d.t", defaultRow) 118 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "INDEX d.t@primary", defaultRow) 119 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p0 OF TABLE d.t", defaultRow) 120 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p1 OF TABLE d.t", defaultRow) 121 122 // Ensure a database zone config applies to that database, its tables, and its 123 // tables' indices and partitions. 124 sqlutils.SetZoneConfig(t, sqlDB, "DATABASE d", yamlOverride) 125 sqlutils.VerifyAllZoneConfigs(t, sqlDB, defaultRow, partialDbRow) 126 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "DATABASE d", dbRow) 127 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "TABLE d.t", dbRow) 128 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "INDEX d.t@primary", dbRow) 129 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p0 OF TABLE d.t", dbRow) 130 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p1 OF TABLE d.t", dbRow) 131 132 // Ensure a table zone config applies to that table and its indices and 133 // partitions, but no other zones. 134 sqlutils.SetZoneConfig(t, sqlDB, "TABLE d.t", yamlOverride) 135 sqlutils.VerifyAllZoneConfigs(t, sqlDB, defaultRow, partialDbRow, partialTableRow) 136 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "DATABASE d", dbRow) 137 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "TABLE d.t", tableRow) 138 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "INDEX d.t@primary", tableRow) 139 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p0 OF TABLE d.t", tableRow) 140 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p1 OF TABLE d.t", tableRow) 141 142 // Ensure an index zone config applies to that index and its partitions, but 143 // no other zones. 144 sqlutils.SetZoneConfig(t, sqlDB, "INDEX d.t@primary", yamlOverride) 145 sqlutils.VerifyAllZoneConfigs(t, sqlDB, defaultRow, partialDbRow, partialTableRow, partialPrimaryRow) 146 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "DATABASE d", dbRow) 147 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "TABLE d.t", tableRow) 148 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "INDEX d.t@primary", primaryRow) 149 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p0 OF TABLE d.t", primaryRow) 150 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p1 OF TABLE d.t", primaryRow) 151 152 // Ensure a partition zone config applies to that partition, but no other 153 // zones. 154 sqlutils.SetZoneConfig(t, sqlDB, "PARTITION p0 OF TABLE d.t", yamlOverride) 155 sqlutils.VerifyAllZoneConfigs(t, sqlDB, defaultRow, partialDbRow, partialTableRow, partialPrimaryRow, partialP0Row) 156 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "DATABASE d", dbRow) 157 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "TABLE d.t", tableRow) 158 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "INDEX d.t@primary", primaryRow) 159 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p0 OF TABLE d.t", p0Row) 160 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p1 OF TABLE d.t", primaryRow) 161 162 // Ensure updating the default zone propagates to zones without an override, 163 // but not to those with overrides. 164 sqlutils.SetZoneConfig(t, sqlDB, "RANGE default", yamlOverride) 165 sqlutils.VerifyAllZoneConfigs(t, sqlDB, defaultOverrideRow, partialDbRow, partialTableRow, partialPrimaryRow, partialP0Row) 166 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "DATABASE d", dbRow) 167 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "TABLE d.t", tableRow) 168 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "INDEX d.t@primary", primaryRow) 169 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p0 OF TABLE d.t", p0Row) 170 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p1 OF TABLE d.t", primaryRow) 171 172 // Ensure deleting a database zone leaves child overrides in place. 173 sqlutils.DeleteZoneConfig(t, sqlDB, "DATABASE d") 174 sqlutils.VerifyAllZoneConfigs(t, sqlDB, defaultOverrideRow, partialTableRow, partialPrimaryRow, partialP0Row) 175 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "DATABASE d", defaultOverrideRow) 176 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "TABLE d.t", tableRow) 177 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "INDEX d.t@primary", primaryRow) 178 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p0 OF TABLE d.t", p0Row) 179 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p1 OF TABLE d.t", primaryRow) 180 181 // Ensure deleting a table zone leaves child overrides in place. 182 sqlutils.DeleteZoneConfig(t, sqlDB, "TABLE d.t") 183 sqlutils.VerifyAllZoneConfigs(t, sqlDB, defaultOverrideRow, partialPrimaryRow, partialP0Row) 184 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "TABLE d.t", defaultOverrideRow) 185 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "INDEX d.t@primary", primaryRow) 186 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p0 OF TABLE d.t", p0Row) 187 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p1 OF TABLE d.t", primaryRow) 188 189 // Ensure deleting an index zone leaves child overrides in place. 190 sqlutils.DeleteZoneConfig(t, sqlDB, "INDEX d.t@primary") 191 sqlutils.VerifyAllZoneConfigs(t, sqlDB, defaultOverrideRow, partialP0Row) 192 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "INDEX d.t@primary", defaultOverrideRow) 193 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p0 OF TABLE d.t", p0Row) 194 195 // Ensure deleting a partition zone works. 196 sqlutils.DeleteZoneConfig(t, sqlDB, "PARTITION p0 OF TABLE d.t") 197 sqlutils.VerifyAllZoneConfigs(t, sqlDB, defaultOverrideRow) 198 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p0 OF TABLE d.t", defaultOverrideRow) 199 200 // Ensure deleting non-overridden zones is not an error. 201 sqlutils.DeleteZoneConfig(t, sqlDB, "DATABASE d") 202 sqlutils.DeleteZoneConfig(t, sqlDB, "TABLE d.t") 203 sqlutils.DeleteZoneConfig(t, sqlDB, "PARTITION p1 OF TABLE d.t") 204 205 // Ensure updating the default zone config applies to zones that have had 206 // overrides added and removed. 207 sqlutils.SetZoneConfig(t, sqlDB, "RANGE default", yamlDefault) 208 sqlutils.VerifyAllZoneConfigs(t, sqlDB, defaultRow) 209 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "RANGE default", defaultRow) 210 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "DATABASE d", defaultRow) 211 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "TABLE d.t", defaultRow) 212 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "INDEX d.t@primary", defaultRow) 213 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p0 OF TABLE d.t", defaultRow) 214 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p1 OF TABLE d.t", defaultRow) 215 216 // Ensure subzones can be created even when no table zone exists. 217 sqlutils.SetZoneConfig(t, sqlDB, "PARTITION p0 OF TABLE d.t", yamlOverride) 218 sqlutils.SetZoneConfig(t, sqlDB, "PARTITION p1 OF TABLE d.t", yamlOverride) 219 sqlutils.VerifyAllZoneConfigs(t, sqlDB, defaultRow, partialP0Row, partialP1Row) 220 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "TABLE d.t", defaultRow) 221 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p0 OF TABLE d.t", p0Row) 222 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p1 OF TABLE d.t", p1Row) 223 224 // Ensure the shorthand index syntax works. 225 sqlutils.SetZoneConfig(t, sqlDB, `INDEX "primary"`, yamlOverride) 226 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, `INDEX "primary"`, primaryRow) 227 228 // Ensure the session database is respected. 229 sqlutils.SetZoneConfig(t, sqlDB, "PARTITION p0 OF TABLE t", yamlOverride) 230 sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p0 OF TABLE t", p0Row) 231 } 232 233 func TestInvalidIndexPartitionSetShowZones(t *testing.T) { 234 defer leaktest.AfterTest(t)() 235 236 s, db, _ := serverutils.StartServer(t, base.TestServerArgs{}) 237 defer s.Stopper().Stop(context.Background()) 238 239 for i, tc := range []struct { 240 query string 241 err string 242 }{ 243 { 244 "ALTER INDEX foo CONFIGURE ZONE USING DEFAULT", 245 `index "foo" does not exist`, 246 }, 247 { 248 "SHOW ZONE CONFIGURATION FOR INDEX foo", 249 `index "foo" does not exist`, 250 }, 251 { 252 "USE system; ALTER INDEX foo CONFIGURE ZONE USING DEFAULT", 253 `index "foo" does not exist`, 254 }, 255 { 256 "USE system; SHOW ZONE CONFIGURATION FOR INDEX foo", 257 `index "foo" does not exist`, 258 }, 259 { 260 "ALTER PARTITION p0 OF TABLE system.jobs CONFIGURE ZONE = 'foo'", 261 `partition "p0" does not exist`, 262 }, 263 { 264 "SHOW ZONE CONFIGURATION FOR PARTITION p0 OF TABLE system.jobs", 265 `partition "p0" does not exist`, 266 }, 267 } { 268 if _, err := db.Exec(tc.query); !testutils.IsError(err, tc.err) { 269 t.Errorf("#%d: expected error matching %q, but got %v", i, tc.err, err) 270 } 271 } 272 } 273 274 func TestGenerateSubzoneSpans(t *testing.T) { 275 defer leaktest.AfterTest(t)() 276 rng, _ := randutil.NewPseudoRand() 277 278 partitioningTests := allPartitioningTests(rng) 279 for _, test := range partitioningTests { 280 if test.generatedSpans == nil { 281 // The randomized partition tests don't have generatedSpans, and 282 // wouldn't be very interesting to test. 283 continue 284 } 285 t.Run(test.name, func(t *testing.T) { 286 if err := test.parse(); err != nil { 287 t.Fatalf("%+v", err) 288 } 289 clusterID := uuid.MakeV4() 290 hasNewSubzones := false 291 spans, err := sql.GenerateSubzoneSpans( 292 cluster.NoSettings, clusterID, keys.SystemSQLCodec, test.parsed.tableDesc, test.parsed.subzones, hasNewSubzones) 293 if err != nil { 294 t.Fatalf("generating subzone spans: %+v", err) 295 } 296 297 var actual []string 298 for _, span := range spans { 299 subzone := test.parsed.subzones[span.SubzoneIndex] 300 idxDesc, err := test.parsed.tableDesc.FindIndexByID(sqlbase.IndexID(subzone.IndexID)) 301 if err != nil { 302 t.Fatalf("could not find index with ID %d: %+v", subzone.IndexID, err) 303 } 304 305 directions := []encoding.Direction{encoding.Ascending /* index ID */} 306 for _, cd := range idxDesc.ColumnDirections { 307 ed, err := cd.ToEncodingDirection() 308 if err != nil { 309 t.Fatal(err) 310 } 311 directions = append(directions, ed) 312 } 313 314 var subzoneShort string 315 if len(subzone.PartitionName) > 0 { 316 subzoneShort = "." + subzone.PartitionName 317 } else { 318 subzoneShort = "@" + idxDesc.Name 319 } 320 321 // Verify that we're always doing the space savings when we can. 322 if span.Key.PrefixEnd().Equal(span.EndKey) { 323 t.Errorf("endKey should be omitted when equal to key.PrefixEnd [%s, %s)", 324 encoding.PrettyPrintValue(directions, span.Key, "/"), 325 encoding.PrettyPrintValue(directions, span.EndKey, "/")) 326 } 327 if len(span.EndKey) == 0 { 328 span.EndKey = span.Key.PrefixEnd() 329 } 330 331 // TODO(dan): Check that spans are sorted. 332 333 actual = append(actual, fmt.Sprintf("%s %s-%s", subzoneShort, 334 encoding.PrettyPrintValue(directions, span.Key, "/"), 335 encoding.PrettyPrintValue(directions, span.EndKey, "/"))) 336 } 337 338 if len(actual) != len(test.generatedSpans) { 339 t.Fatalf("got \n %v\n expected \n %v", actual, test.generatedSpans) 340 } 341 for i := range actual { 342 if expected := strings.TrimSpace(test.generatedSpans[i]); actual[i] != expected { 343 t.Errorf("%d: got [%s] expected [%s]", i, actual[i], expected) 344 } 345 } 346 }) 347 } 348 }