github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/drop_test.go (about) 1 // Copyright 2015 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package sql_test 12 13 import ( 14 "context" 15 gosql "database/sql" 16 "fmt" 17 "math/rand" 18 "regexp" 19 "testing" 20 21 "github.com/cockroachdb/cockroach/pkg/base" 22 "github.com/cockroachdb/cockroach/pkg/config/zonepb" 23 "github.com/cockroachdb/cockroach/pkg/jobs" 24 "github.com/cockroachdb/cockroach/pkg/jobs/jobspb" 25 "github.com/cockroachdb/cockroach/pkg/keys" 26 "github.com/cockroachdb/cockroach/pkg/kv" 27 "github.com/cockroachdb/cockroach/pkg/kv/kvserver" 28 "github.com/cockroachdb/cockroach/pkg/roachpb" 29 "github.com/cockroachdb/cockroach/pkg/security" 30 "github.com/cockroachdb/cockroach/pkg/server" 31 "github.com/cockroachdb/cockroach/pkg/sql" 32 "github.com/cockroachdb/cockroach/pkg/sql/execinfra" 33 "github.com/cockroachdb/cockroach/pkg/sql/gcjob" 34 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 35 "github.com/cockroachdb/cockroach/pkg/sql/sqltestutils" 36 "github.com/cockroachdb/cockroach/pkg/sql/tests" 37 "github.com/cockroachdb/cockroach/pkg/sqlmigrations" 38 "github.com/cockroachdb/cockroach/pkg/testutils" 39 "github.com/cockroachdb/cockroach/pkg/testutils/jobutils" 40 "github.com/cockroachdb/cockroach/pkg/testutils/serverutils" 41 "github.com/cockroachdb/cockroach/pkg/testutils/sqlutils" 42 "github.com/cockroachdb/cockroach/pkg/testutils/testcluster" 43 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 44 "github.com/cockroachdb/cockroach/pkg/util/protoutil" 45 "github.com/cockroachdb/cockroach/pkg/util/syncutil" 46 "github.com/cockroachdb/cockroach/pkg/util/tracing" 47 "github.com/cockroachdb/cockroach/pkg/util/uuid" 48 "github.com/cockroachdb/errors" 49 "github.com/opentracing/opentracing-go" 50 "github.com/stretchr/testify/require" 51 ) 52 53 // Returns an error if a zone config for the specified table or 54 // database ID doesn't match the expected parameter. If expected 55 // is nil, then we verify no zone config exists. 56 func zoneExists(sqlDB *gosql.DB, expected *zonepb.ZoneConfig, id sqlbase.ID) error { 57 rows, err := sqlDB.Query(`SELECT * FROM system.zones WHERE id = $1`, id) 58 if err != nil { 59 return err 60 } 61 defer rows.Close() 62 if exists := (expected != nil); exists != rows.Next() { 63 return errors.Errorf("zone config exists = %v", exists) 64 } 65 if expected != nil { 66 // Ensure that the zone config matches. 67 var storedID sqlbase.ID 68 var val []byte 69 if err := rows.Scan(&storedID, &val); err != nil { 70 return errors.Errorf("row scan failed: %s", err) 71 } 72 if storedID != id { 73 return errors.Errorf("e = %d, v = %d", id, storedID) 74 } 75 var cfg zonepb.ZoneConfig 76 if err := protoutil.Unmarshal(val, &cfg); err != nil { 77 return err 78 } 79 if !expected.Equal(cfg) { 80 return errors.Errorf("e = %v, v = %v", expected, cfg) 81 } 82 } 83 return nil 84 } 85 86 // Returns an error if a descriptor "exists" for the table id. 87 func descExists(sqlDB *gosql.DB, exists bool, id sqlbase.ID) error { 88 rows, err := sqlDB.Query(`SELECT * FROM system.descriptor WHERE id = $1`, id) 89 if err != nil { 90 return err 91 } 92 defer rows.Close() 93 if exists != rows.Next() { 94 return errors.Errorf("descriptor exists = %v", exists) 95 } 96 return nil 97 } 98 99 func TestDropDatabase(t *testing.T) { 100 defer leaktest.AfterTest(t)() 101 params, _ := tests.CreateTestServerParams() 102 s, sqlDB, kvDB := serverutils.StartServer(t, params) 103 defer s.Stopper().Stop(context.Background()) 104 ctx := context.Background() 105 106 // Fix the column families so the key counts below don't change if the 107 // family heuristics are updated. 108 if _, err := sqlDB.Exec(` 109 CREATE DATABASE t; 110 CREATE TABLE t.kv (k CHAR PRIMARY KEY, v CHAR, FAMILY (k), FAMILY (v)); 111 INSERT INTO t.kv VALUES ('c', 'e'), ('a', 'c'), ('b', 'd'); 112 `); err != nil { 113 t.Fatal(err) 114 } 115 116 dbNameKey := sqlbase.NewDatabaseKey("t").Key(keys.SystemSQLCodec) 117 r, err := kvDB.Get(ctx, dbNameKey) 118 if err != nil { 119 t.Fatal(err) 120 } 121 if !r.Exists() { 122 t.Fatalf(`database "t" does not exist`) 123 } 124 dbDescKey := sqlbase.MakeDescMetadataKey(keys.SystemSQLCodec, sqlbase.ID(r.ValueInt())) 125 desc := &sqlbase.Descriptor{} 126 if err := kvDB.GetProto(ctx, dbDescKey, desc); err != nil { 127 t.Fatal(err) 128 } 129 dbDesc := desc.GetDatabase() 130 131 tbNameKey := sqlbase.NewPublicTableKey(dbDesc.ID, "kv").Key(keys.SystemSQLCodec) 132 gr, err := kvDB.Get(ctx, tbNameKey) 133 if err != nil { 134 t.Fatal(err) 135 } 136 if !gr.Exists() { 137 t.Fatalf(`table "kv" does not exist`) 138 } 139 tbDescKey := sqlbase.MakeDescMetadataKey(keys.SystemSQLCodec, sqlbase.ID(gr.ValueInt())) 140 ts, err := kvDB.GetProtoTs(ctx, tbDescKey, desc) 141 if err != nil { 142 t.Fatal(err) 143 } 144 tbDesc := desc.Table(ts) 145 146 // Add a zone config for both the table and database. 147 cfg := zonepb.DefaultZoneConfig() 148 buf, err := protoutil.Marshal(&cfg) 149 if err != nil { 150 t.Fatal(err) 151 } 152 if _, err := sqlDB.Exec(`INSERT INTO system.zones VALUES ($1, $2)`, tbDesc.ID, buf); err != nil { 153 t.Fatal(err) 154 } 155 if _, err := sqlDB.Exec(`INSERT INTO system.zones VALUES ($1, $2)`, dbDesc.ID, buf); err != nil { 156 t.Fatal(err) 157 } 158 159 if err := zoneExists(sqlDB, &cfg, tbDesc.ID); err != nil { 160 t.Fatal(err) 161 } 162 if err := zoneExists(sqlDB, &cfg, dbDesc.ID); err != nil { 163 t.Fatal(err) 164 } 165 166 tableSpan := tbDesc.TableSpan(keys.SystemSQLCodec) 167 tests.CheckKeyCount(t, kvDB, tableSpan, 6) 168 169 if _, err := sqlDB.Exec(`DROP DATABASE t RESTRICT`); !testutils.IsError(err, 170 `database "t" is not empty`) { 171 t.Fatal(err) 172 } 173 174 if _, err := sqlDB.Exec(`DROP DATABASE t CASCADE`); err != nil { 175 t.Fatal(err) 176 } 177 178 // Data is not deleted. 179 tests.CheckKeyCount(t, kvDB, tableSpan, 6) 180 181 if err := descExists(sqlDB, true, tbDesc.ID); err != nil { 182 t.Fatal(err) 183 } 184 185 if gr, err := kvDB.Get(ctx, tbNameKey); err != nil { 186 t.Fatal(err) 187 } else if gr.Exists() { 188 t.Fatalf("table descriptor key still exists after database is dropped") 189 } 190 191 if err := descExists(sqlDB, false, dbDesc.ID); err != nil { 192 t.Fatal(err) 193 } 194 // Database zone config is removed once all table data and zone configs are removed. 195 if err := zoneExists(sqlDB, &cfg, dbDesc.ID); err != nil { 196 t.Fatal(err) 197 } 198 199 if gr, err := kvDB.Get(ctx, dbNameKey); err != nil { 200 t.Fatal(err) 201 } else if gr.Exists() { 202 t.Fatalf("database descriptor key still exists after database is dropped") 203 } 204 205 if err := zoneExists(sqlDB, &cfg, tbDesc.ID); err != nil { 206 t.Fatal(err) 207 } 208 209 sqlRun := sqlutils.MakeSQLRunner(sqlDB) 210 // There are no more namespace entries referencing this database as its 211 // parent. 212 namespaceQuery := fmt.Sprintf(`SELECT * FROM system.namespace WHERE "parentID" = %d`, dbDesc.ID) 213 sqlRun.CheckQueryResults(t, namespaceQuery, [][]string{}) 214 215 // Job still running, waiting for GC. 216 // TODO (lucy): Maybe this test API should use an offset starting 217 // from the most recent job instead. 218 if err := jobutils.VerifySystemJob(t, sqlRun, 0, jobspb.TypeSchemaChange, jobs.StatusSucceeded, jobs.Record{ 219 Username: security.RootUser, 220 Description: "DROP DATABASE t CASCADE", 221 DescriptorIDs: sqlbase.IDs{ 222 tbDesc.ID, 223 }, 224 }); err != nil { 225 t.Fatal(err) 226 } 227 } 228 229 // Test that an empty, dropped database's zone config gets deleted immediately. 230 func TestDropDatabaseEmpty(t *testing.T) { 231 defer leaktest.AfterTest(t)() 232 params, _ := tests.CreateTestServerParams() 233 s, sqlDB, kvDB := serverutils.StartServer(t, params) 234 defer s.Stopper().Stop(context.Background()) 235 ctx := context.Background() 236 237 if _, err := sqlDB.Exec(` 238 CREATE DATABASE t; 239 `); err != nil { 240 t.Fatal(err) 241 } 242 243 dKey := sqlbase.NewDatabaseKey("t") 244 r, err := kvDB.Get(ctx, dKey.Key(keys.SystemSQLCodec)) 245 if err != nil { 246 t.Fatal(err) 247 } 248 if !r.Exists() { 249 t.Fatalf(`database "t" does not exist`) 250 } 251 dbID := sqlbase.ID(r.ValueInt()) 252 253 if cfg, err := sqltestutils.AddDefaultZoneConfig(sqlDB, dbID); err != nil { 254 t.Fatal(err) 255 } else if err := zoneExists(sqlDB, &cfg, dbID); err != nil { 256 t.Fatal(err) 257 } 258 259 if _, err := sqlDB.Exec(`DROP DATABASE t`); err != nil { 260 t.Fatal(err) 261 } 262 263 if err := descExists(sqlDB, false, dbID); err != nil { 264 t.Fatal(err) 265 } 266 267 if err := zoneExists(sqlDB, nil, dbID); err != nil { 268 t.Fatal(err) 269 } 270 } 271 272 // Test that a dropped database's data gets deleted properly. 273 func TestDropDatabaseDeleteData(t *testing.T) { 274 defer leaktest.AfterTest(t)() 275 276 defer gcjob.SetSmallMaxGCIntervalForTest()() 277 278 params, _ := tests.CreateTestServerParams() 279 s, sqlDB, kvDB := serverutils.StartServer(t, params) 280 defer s.Stopper().Stop(context.Background()) 281 ctx := context.Background() 282 283 // Disable strict GC TTL enforcement because we're going to shove a zero-value 284 // TTL into the system with AddImmediateGCZoneConfig. 285 defer sqltestutils.DisableGCTTLStrictEnforcement(t, sqlDB)() 286 287 // Fix the column families so the key counts below don't change if the 288 // family heuristics are updated. 289 if _, err := sqlDB.Exec(` 290 CREATE DATABASE t; 291 CREATE TABLE t.kv (k CHAR PRIMARY KEY, v CHAR, FAMILY (k), FAMILY (v)); 292 INSERT INTO t.kv VALUES ('c', 'e'), ('a', 'c'), ('b', 'd'); 293 CREATE TABLE t.kv2 (k CHAR PRIMARY KEY, v CHAR, FAMILY (k), FAMILY (v)); 294 INSERT INTO t.kv2 VALUES ('c', 'd'), ('a', 'b'), ('e', 'a'); 295 `); err != nil { 296 t.Fatal(err) 297 } 298 299 dKey := sqlbase.NewDatabaseKey("t") 300 r, err := kvDB.Get(ctx, dKey.Key(keys.SystemSQLCodec)) 301 if err != nil { 302 t.Fatal(err) 303 } 304 if !r.Exists() { 305 t.Fatalf(`database "t" does not exist`) 306 } 307 dbDescKey := sqlbase.MakeDescMetadataKey(keys.SystemSQLCodec, sqlbase.ID(r.ValueInt())) 308 desc := &sqlbase.Descriptor{} 309 if err := kvDB.GetProto(ctx, dbDescKey, desc); err != nil { 310 t.Fatal(err) 311 } 312 dbDesc := desc.GetDatabase() 313 314 tKey := sqlbase.NewPublicTableKey(dbDesc.ID, "kv") 315 gr, err := kvDB.Get(ctx, tKey.Key(keys.SystemSQLCodec)) 316 if err != nil { 317 t.Fatal(err) 318 } 319 if !gr.Exists() { 320 t.Fatalf(`table "kv" does not exist`) 321 } 322 tbDescKey := sqlbase.MakeDescMetadataKey(keys.SystemSQLCodec, sqlbase.ID(gr.ValueInt())) 323 ts, err := kvDB.GetProtoTs(ctx, tbDescKey, desc) 324 if err != nil { 325 t.Fatal(err) 326 } 327 tbDesc := desc.Table(ts) 328 329 t2Key := sqlbase.NewPublicTableKey(dbDesc.ID, "kv2") 330 gr2, err := kvDB.Get(ctx, t2Key.Key(keys.SystemSQLCodec)) 331 if err != nil { 332 t.Fatal(err) 333 } 334 if !gr2.Exists() { 335 t.Fatalf(`table "kv2" does not exist`) 336 } 337 tb2DescKey := sqlbase.MakeDescMetadataKey(keys.SystemSQLCodec, sqlbase.ID(gr2.ValueInt())) 338 ts, err = kvDB.GetProtoTs(ctx, tb2DescKey, desc) 339 if err != nil { 340 t.Fatal(err) 341 } 342 tb2Desc := desc.Table(ts) 343 344 tableSpan := tbDesc.TableSpan(keys.SystemSQLCodec) 345 table2Span := tb2Desc.TableSpan(keys.SystemSQLCodec) 346 tests.CheckKeyCount(t, kvDB, tableSpan, 6) 347 tests.CheckKeyCount(t, kvDB, table2Span, 6) 348 349 if _, err := sqltestutils.AddDefaultZoneConfig(sqlDB, dbDesc.ID); err != nil { 350 t.Fatal(err) 351 } 352 353 if _, err := sqlDB.Exec(`DROP DATABASE t RESTRICT`); !testutils.IsError(err, 354 `database "t" is not empty`) { 355 t.Fatal(err) 356 } 357 358 if _, err := sqlDB.Exec(`DROP DATABASE t CASCADE`); err != nil { 359 t.Fatal(err) 360 } 361 362 tests.CheckKeyCount(t, kvDB, tableSpan, 6) 363 tests.CheckKeyCount(t, kvDB, table2Span, 6) 364 365 // TODO (lucy): Maybe this test API should use an offset starting 366 // from the most recent job instead. 367 const migrationJobOffset = 0 368 sqlRun := sqlutils.MakeSQLRunner(sqlDB) 369 if err := jobutils.VerifySystemJob(t, sqlRun, migrationJobOffset, jobspb.TypeSchemaChange, jobs.StatusSucceeded, jobs.Record{ 370 Username: security.RootUser, 371 Description: "DROP DATABASE t CASCADE", 372 DescriptorIDs: sqlbase.IDs{ 373 tbDesc.ID, tb2Desc.ID, 374 }, 375 }); err != nil { 376 t.Fatal(err) 377 } 378 379 // Push a new zone config for the table with TTL=0 so the data is 380 // deleted immediately. 381 if _, err := sqltestutils.AddImmediateGCZoneConfig(sqlDB, tbDesc.ID); err != nil { 382 t.Fatal(err) 383 } 384 385 testutils.SucceedsSoon(t, func() error { 386 if err := descExists(sqlDB, false, tbDesc.ID); err != nil { 387 return err 388 } 389 390 return zoneExists(sqlDB, nil, tbDesc.ID) 391 }) 392 393 // Table 1 data is deleted. 394 tests.CheckKeyCount(t, kvDB, tableSpan, 0) 395 tests.CheckKeyCount(t, kvDB, table2Span, 6) 396 397 def := zonepb.DefaultZoneConfig() 398 if err := zoneExists(sqlDB, &def, dbDesc.ID); err != nil { 399 t.Fatal(err) 400 } 401 402 testutils.SucceedsSoon(t, func() error { 403 return jobutils.VerifySystemJob(t, sqlRun, 0, jobspb.TypeSchemaChangeGC, jobs.StatusRunning, jobs.Record{ 404 Username: security.RootUser, 405 Description: "GC for DROP DATABASE t CASCADE", 406 DescriptorIDs: sqlbase.IDs{ 407 tbDesc.ID, tb2Desc.ID, 408 }, 409 }) 410 }) 411 412 if _, err := sqltestutils.AddImmediateGCZoneConfig(sqlDB, tb2Desc.ID); err != nil { 413 t.Fatal(err) 414 } 415 if _, err := sqltestutils.AddImmediateGCZoneConfig(sqlDB, dbDesc.ID); err != nil { 416 t.Fatal(err) 417 } 418 419 testutils.SucceedsSoon(t, func() error { 420 if err := descExists(sqlDB, false, tb2Desc.ID); err != nil { 421 return err 422 } 423 424 return zoneExists(sqlDB, nil, tb2Desc.ID) 425 }) 426 427 // Table 2 data is deleted. 428 tests.CheckKeyCount(t, kvDB, table2Span, 0) 429 430 if err := jobutils.VerifySystemJob(t, sqlRun, migrationJobOffset, jobspb.TypeSchemaChange, jobs.StatusSucceeded, jobs.Record{ 431 Username: security.RootUser, 432 Description: "DROP DATABASE t CASCADE", 433 DescriptorIDs: sqlbase.IDs{ 434 tbDesc.ID, tb2Desc.ID, 435 }, 436 }); err != nil { 437 t.Fatal(err) 438 } 439 440 // Database zone config is removed once all table data and zone configs are removed. 441 if err := zoneExists(sqlDB, nil, dbDesc.ID); err != nil { 442 t.Fatal(err) 443 } 444 } 445 446 // Tests that SHOW TABLES works correctly when a database is recreated 447 // during the time the underlying tables are still being deleted. 448 func TestShowTablesAfterRecreateDatabase(t *testing.T) { 449 defer leaktest.AfterTest(t)() 450 params, _ := tests.CreateTestServerParams() 451 // Turn off the application of schema changes so that tables do not 452 // get completely dropped. 453 params.Knobs = base.TestingKnobs{ 454 SQLSchemaChanger: &sql.SchemaChangerTestingKnobs{ 455 SchemaChangeJobNoOp: func() bool { 456 return true 457 }, 458 }, 459 } 460 s, sqlDB, _ := serverutils.StartServer(t, params) 461 defer s.Stopper().Stop(context.Background()) 462 463 if _, err := sqlDB.Exec(` 464 CREATE DATABASE t; 465 CREATE TABLE t.kv (k CHAR PRIMARY KEY, v CHAR); 466 INSERT INTO t.kv VALUES ('c', 'e'), ('a', 'c'), ('b', 'd'); 467 `); err != nil { 468 t.Fatal(err) 469 } 470 471 if _, err := sqlDB.Exec(` 472 DROP DATABASE t CASCADE; 473 CREATE DATABASE t; 474 `); err != nil { 475 t.Fatal(err) 476 } 477 478 rows, err := sqlDB.Query(` 479 SET DATABASE=t; 480 SHOW TABLES; 481 `) 482 if err != nil { 483 t.Fatal(err) 484 } 485 defer rows.Close() 486 if rows.Next() { 487 t.Fatal("table should be invisible through SHOW TABLES") 488 } 489 } 490 491 func TestDropIndex(t *testing.T) { 492 defer leaktest.AfterTest(t)() 493 const chunkSize = 200 494 params, _ := tests.CreateTestServerParams() 495 emptySpan := true 496 clearIndexAttempt := false 497 params.Knobs = base.TestingKnobs{ 498 SQLSchemaChanger: &sql.SchemaChangerTestingKnobs{ 499 BackfillChunkSize: chunkSize, 500 }, 501 DistSQL: &execinfra.TestingKnobs{ 502 RunBeforeBackfillChunk: func(sp roachpb.Span) error { 503 if clearIndexAttempt && (sp.Key != nil || sp.EndKey != nil) { 504 emptySpan = false 505 } 506 return nil 507 }, 508 }, 509 } 510 s, sqlDB, kvDB := serverutils.StartServer(t, params) 511 defer s.Stopper().Stop(context.Background()) 512 513 // Disable strict GC TTL enforcement because we're going to shove a zero-value 514 // TTL into the system with AddImmediateGCZoneConfig. 515 defer sqltestutils.DisableGCTTLStrictEnforcement(t, sqlDB)() 516 517 numRows := 2*chunkSize + 1 518 if err := tests.CreateKVTable(sqlDB, "kv", numRows); err != nil { 519 t.Fatal(err) 520 } 521 tableDesc := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "t", "kv") 522 tests.CheckKeyCount(t, kvDB, tableDesc.TableSpan(keys.SystemSQLCodec), 3*numRows) 523 idx, _, err := tableDesc.FindIndexByName("foo") 524 if err != nil { 525 t.Fatal(err) 526 } 527 indexSpan := tableDesc.IndexSpan(keys.SystemSQLCodec, idx.ID) 528 tests.CheckKeyCount(t, kvDB, indexSpan, numRows) 529 if _, err := sqlDB.Exec(`DROP INDEX t.kv@foo`); err != nil { 530 t.Fatal(err) 531 } 532 533 tableDesc = sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "t", "kv") 534 if _, _, err := tableDesc.FindIndexByName("foo"); err == nil { 535 t.Fatalf("table descriptor still contains index after index is dropped") 536 } 537 // Index data hasn't been deleted. 538 tests.CheckKeyCount(t, kvDB, indexSpan, numRows) 539 tests.CheckKeyCount(t, kvDB, tableDesc.TableSpan(keys.SystemSQLCodec), 3*numRows) 540 541 // TODO (lucy): Maybe this test API should use an offset starting 542 // from the most recent job instead. 543 const migrationJobOffset = 0 544 sqlRun := sqlutils.MakeSQLRunner(sqlDB) 545 if err := jobutils.VerifySystemJob(t, sqlRun, migrationJobOffset+1, jobspb.TypeSchemaChange, jobs.StatusSucceeded, jobs.Record{ 546 Username: security.RootUser, 547 Description: `DROP INDEX t.public.kv@foo`, 548 DescriptorIDs: sqlbase.IDs{ 549 tableDesc.ID, 550 }, 551 }); err != nil { 552 t.Fatal(err) 553 } 554 555 if _, err := sqlDB.Exec(`CREATE INDEX foo on t.kv (v);`); err != nil { 556 t.Fatal(err) 557 } 558 559 tableDesc = sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "t", "kv") 560 newIdx, _, err := tableDesc.FindIndexByName("foo") 561 if err != nil { 562 t.Fatal(err) 563 } 564 newIdxSpan := tableDesc.IndexSpan(keys.SystemSQLCodec, newIdx.ID) 565 tests.CheckKeyCount(t, kvDB, newIdxSpan, numRows) 566 tests.CheckKeyCount(t, kvDB, tableDesc.TableSpan(keys.SystemSQLCodec), 4*numRows) 567 568 clearIndexAttempt = true 569 // Add a zone config for the table. 570 if _, err := sqltestutils.AddImmediateGCZoneConfig(sqlDB, tableDesc.ID); err != nil { 571 t.Fatal(err) 572 } 573 574 testutils.SucceedsSoon(t, func() error { 575 return jobutils.VerifySystemJob(t, sqlRun, migrationJobOffset+1, jobspb.TypeSchemaChange, jobs.StatusSucceeded, jobs.Record{ 576 Username: security.RootUser, 577 Description: `DROP INDEX t.public.kv@foo`, 578 DescriptorIDs: sqlbase.IDs{ 579 tableDesc.ID, 580 }, 581 }) 582 }) 583 584 testutils.SucceedsSoon(t, func() error { 585 return jobutils.VerifySystemJob(t, sqlRun, 0, jobspb.TypeSchemaChangeGC, jobs.StatusSucceeded, jobs.Record{ 586 Username: security.RootUser, 587 Description: `GC for DROP INDEX t.public.kv@foo`, 588 DescriptorIDs: sqlbase.IDs{ 589 tableDesc.ID, 590 }, 591 }) 592 }) 593 594 if !emptySpan { 595 t.Fatalf("tried to clear index with non-empty resume span") 596 } 597 598 tests.CheckKeyCount(t, kvDB, newIdxSpan, numRows) 599 tests.CheckKeyCount(t, kvDB, indexSpan, 0) 600 tests.CheckKeyCount(t, kvDB, tableDesc.TableSpan(keys.SystemSQLCodec), 3*numRows) 601 } 602 603 func TestDropIndexWithZoneConfigOSS(t *testing.T) { 604 defer leaktest.AfterTest(t)() 605 606 const chunkSize = 200 607 const numRows = 2*chunkSize + 1 608 609 params, _ := tests.CreateTestServerParams() 610 params.Knobs = base.TestingKnobs{ 611 SQLSchemaChanger: &sql.SchemaChangerTestingKnobs{BackfillChunkSize: chunkSize}, 612 } 613 s, sqlDBRaw, kvDB := serverutils.StartServer(t, params) 614 sqlDB := sqlutils.MakeSQLRunner(sqlDBRaw) 615 defer s.Stopper().Stop(context.Background()) 616 617 // Create a test table with a secondary index. 618 if err := tests.CreateKVTable(sqlDBRaw, "kv", numRows); err != nil { 619 t.Fatal(err) 620 } 621 tableDesc := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "t", "kv") 622 indexDesc, _, err := tableDesc.FindIndexByName("foo") 623 if err != nil { 624 t.Fatal(err) 625 } 626 indexSpan := tableDesc.IndexSpan(keys.SystemSQLCodec, indexDesc.ID) 627 tests.CheckKeyCount(t, kvDB, indexSpan, numRows) 628 629 // Hack in zone configs for the primary and secondary indexes. (You need a CCL 630 // binary to do this properly.) Dropping the index will thus require 631 // regenerating the zone config's SubzoneSpans, which will fail with a "CCL 632 // required" error. 633 zoneConfig := zonepb.ZoneConfig{ 634 Subzones: []zonepb.Subzone{ 635 {IndexID: uint32(tableDesc.PrimaryIndex.ID), Config: s.(*server.TestServer).Cfg.DefaultZoneConfig}, 636 {IndexID: uint32(indexDesc.ID), Config: s.(*server.TestServer).Cfg.DefaultZoneConfig}, 637 }, 638 } 639 zoneConfigBytes, err := protoutil.Marshal(&zoneConfig) 640 if err != nil { 641 t.Fatal(err) 642 } 643 sqlDB.Exec(t, `INSERT INTO system.zones VALUES ($1, $2)`, tableDesc.ID, zoneConfigBytes) 644 if !sqlutils.ZoneConfigExists(t, sqlDB, "INDEX t.public.kv@foo") { 645 t.Fatal("zone config for index does not exist") 646 } 647 648 // Verify that dropping the index works. 649 _, err = sqlDBRaw.Exec(`DROP INDEX t.kv@foo`) 650 require.NoError(t, err) 651 652 // Verify that the index and its zone config still exist. 653 if sqlutils.ZoneConfigExists(t, sqlDB, "INDEX t.public.kv@foo") { 654 t.Fatal("zone config for index still exists") 655 } 656 tests.CheckKeyCount(t, kvDB, indexSpan, numRows) 657 // TODO(benesch): Run scrub here. It can't currently handle the way t.kv 658 // declares column families. 659 660 tableDesc = sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "t", "kv") 661 if _, _, err := tableDesc.FindIndexByName("foo"); err == nil { 662 t.Fatalf("table descriptor still contains index after index is dropped") 663 } 664 } 665 666 func TestDropIndexInterleaved(t *testing.T) { 667 defer leaktest.AfterTest(t)() 668 const chunkSize = 200 669 params, _ := tests.CreateTestServerParams() 670 params.Knobs = base.TestingKnobs{ 671 SQLSchemaChanger: &sql.SchemaChangerTestingKnobs{ 672 BackfillChunkSize: chunkSize, 673 }, 674 } 675 s, sqlDB, kvDB := serverutils.StartServer(t, params) 676 defer s.Stopper().Stop(context.Background()) 677 678 numRows := 2*chunkSize + 1 679 tests.CreateKVInterleavedTable(t, sqlDB, numRows) 680 681 tableDesc := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "t", "kv") 682 tableSpan := tableDesc.TableSpan(keys.SystemSQLCodec) 683 684 tests.CheckKeyCount(t, kvDB, tableSpan, 3*numRows) 685 686 if _, err := sqlDB.Exec(`DROP INDEX t.intlv@intlv_idx`); err != nil { 687 t.Fatal(err) 688 } 689 tests.CheckKeyCount(t, kvDB, tableSpan, 2*numRows) 690 691 // Ensure that index is not active. 692 tableDesc = sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "t", "intlv") 693 if _, _, err := tableDesc.FindIndexByName("intlv_idx"); err == nil { 694 t.Fatalf("table descriptor still contains index after index is dropped") 695 } 696 } 697 698 // Tests DROP TABLE and also checks that the table data is not deleted 699 // via the synchronous path. 700 func TestDropTable(t *testing.T) { 701 defer leaktest.AfterTest(t)() 702 params, _ := tests.CreateTestServerParams() 703 s, sqlDB, kvDB := serverutils.StartServer(t, params) 704 defer s.Stopper().Stop(context.Background()) 705 ctx := context.Background() 706 707 numRows := 2*sql.TableTruncateChunkSize + 1 708 if err := tests.CreateKVTable(sqlDB, "kv", numRows); err != nil { 709 t.Fatal(err) 710 } 711 712 tableDesc := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "t", "kv") 713 nameKey := sqlbase.NewPublicTableKey(keys.MinNonPredefinedUserDescID, "kv").Key(keys.SystemSQLCodec) 714 gr, err := kvDB.Get(ctx, nameKey) 715 716 if err != nil { 717 t.Fatal(err) 718 } 719 720 if !gr.Exists() { 721 t.Fatalf("Name entry %q does not exist", nameKey) 722 } 723 724 // Add a zone config for the table. 725 cfg, err := sqltestutils.AddDefaultZoneConfig(sqlDB, tableDesc.ID) 726 if err != nil { 727 t.Fatal(err) 728 } 729 730 if err := zoneExists(sqlDB, &cfg, tableDesc.ID); err != nil { 731 t.Fatal(err) 732 } 733 734 tableSpan := tableDesc.TableSpan(keys.SystemSQLCodec) 735 tests.CheckKeyCount(t, kvDB, tableSpan, 3*numRows) 736 if _, err := sqlDB.Exec(`DROP TABLE t.kv`); err != nil { 737 t.Fatal(err) 738 } 739 740 // Test that deleted table cannot be used. This prevents 741 // regressions where name -> descriptor ID caches might make 742 // this statement erronously work. 743 if _, err := sqlDB.Exec( 744 `SELECT * FROM t.kv`, 745 ); !testutils.IsError(err, `relation "t.kv" does not exist`) { 746 t.Fatalf("different error than expected: %+v", err) 747 } 748 749 if gr, err := kvDB.Get(ctx, nameKey); err != nil { 750 t.Fatal(err) 751 } else if gr.Exists() { 752 t.Fatalf("table namekey still exists") 753 } 754 755 // Job still running, waiting for GC. 756 sqlRun := sqlutils.MakeSQLRunner(sqlDB) 757 if err := jobutils.VerifySystemJob(t, sqlRun, 1, jobspb.TypeSchemaChange, jobs.StatusSucceeded, jobs.Record{ 758 Username: security.RootUser, 759 Description: `DROP TABLE t.public.kv`, 760 DescriptorIDs: sqlbase.IDs{ 761 tableDesc.ID, 762 }, 763 }); err != nil { 764 t.Fatal(err) 765 } 766 767 // Can create a table with the same name. 768 if err := tests.CreateKVTable(sqlDB, "kv", numRows); err != nil { 769 t.Fatal(err) 770 } 771 772 // A lot of garbage has been left behind to be cleaned up by the 773 // asynchronous path. 774 tests.CheckKeyCount(t, kvDB, tableSpan, 3*numRows) 775 776 if err := descExists(sqlDB, true, tableDesc.ID); err != nil { 777 t.Fatal(err) 778 } 779 780 if err := zoneExists(sqlDB, &cfg, tableDesc.ID); err != nil { 781 t.Fatal(err) 782 } 783 } 784 785 // Test that after a DROP TABLE the table eventually gets deleted. 786 func TestDropTableDeleteData(t *testing.T) { 787 defer leaktest.AfterTest(t)() 788 params, _ := tests.CreateTestServerParams() 789 790 defer gcjob.SetSmallMaxGCIntervalForTest()() 791 792 s, sqlDB, kvDB := serverutils.StartServer(t, params) 793 defer s.Stopper().Stop(context.Background()) 794 ctx := context.Background() 795 796 // Disable strict GC TTL enforcement because we're going to shove a zero-value 797 // TTL into the system with AddImmediateGCZoneConfig. 798 defer sqltestutils.DisableGCTTLStrictEnforcement(t, sqlDB)() 799 800 const numRows = 2*sql.TableTruncateChunkSize + 1 801 const numKeys = 3 * numRows 802 const numTables = 5 803 var descs []*sqlbase.TableDescriptor 804 for i := 0; i < numTables; i++ { 805 tableName := fmt.Sprintf("test%d", i) 806 if err := tests.CreateKVTable(sqlDB, tableName, numRows); err != nil { 807 t.Fatal(err) 808 } 809 810 descs = append(descs, sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "t", tableName)) 811 812 nameKey := sqlbase.NewPublicTableKey(keys.MinNonPredefinedUserDescID, tableName).Key(keys.SystemSQLCodec) 813 gr, err := kvDB.Get(ctx, nameKey) 814 if err != nil { 815 t.Fatal(err) 816 } 817 if !gr.Exists() { 818 t.Fatalf("Name entry %q does not exist", nameKey) 819 } 820 821 tableSpan := descs[i].TableSpan(keys.SystemSQLCodec) 822 tests.CheckKeyCount(t, kvDB, tableSpan, numKeys) 823 824 if _, err := sqlDB.Exec(fmt.Sprintf(`DROP TABLE t.%s`, tableName)); err != nil { 825 t.Fatal(err) 826 } 827 } 828 829 // TODO (lucy): Maybe this test API should use an offset starting 830 // from the most recent job instead. 831 const migrationJobOffset = 0 832 833 // Data hasn't been GC-ed. 834 sqlRun := sqlutils.MakeSQLRunner(sqlDB) 835 for i := 0; i < numTables; i++ { 836 if err := descExists(sqlDB, true, descs[i].ID); err != nil { 837 t.Fatal(err) 838 } 839 tableSpan := descs[i].TableSpan(keys.SystemSQLCodec) 840 tests.CheckKeyCount(t, kvDB, tableSpan, numKeys) 841 842 if err := jobutils.VerifySystemJob(t, sqlRun, 2*i+1+migrationJobOffset, jobspb.TypeSchemaChange, jobs.StatusSucceeded, jobs.Record{ 843 Username: security.RootUser, 844 Description: fmt.Sprintf(`DROP TABLE t.public.%s`, descs[i].GetName()), 845 DescriptorIDs: sqlbase.IDs{ 846 descs[i].ID, 847 }, 848 }); err != nil { 849 t.Fatal(err) 850 } 851 } 852 853 // The closure pushes a zone config reducing the TTL to 0 for descriptor i. 854 pushZoneCfg := func(i int) { 855 if _, err := sqltestutils.AddImmediateGCZoneConfig(sqlDB, descs[i].ID); err != nil { 856 t.Fatal(err) 857 } 858 } 859 860 checkTableGCed := func(i int) { 861 testutils.SucceedsSoon(t, func() error { 862 if err := descExists(sqlDB, false, descs[i].ID); err != nil { 863 return err 864 } 865 866 return zoneExists(sqlDB, nil, descs[i].ID) 867 }) 868 tableSpan := descs[i].TableSpan(keys.SystemSQLCodec) 869 tests.CheckKeyCount(t, kvDB, tableSpan, 0) 870 871 // Ensure that the job is marked as succeeded. 872 if err := jobutils.VerifySystemJob(t, sqlRun, 2*i+1+migrationJobOffset, jobspb.TypeSchemaChange, jobs.StatusSucceeded, jobs.Record{ 873 Username: security.RootUser, 874 Description: fmt.Sprintf(`DROP TABLE t.public.%s`, descs[i].GetName()), 875 DescriptorIDs: sqlbase.IDs{ 876 descs[i].ID, 877 }, 878 }); err != nil { 879 t.Fatal(err) 880 } 881 882 // Ensure that the job is marked as succeeded. 883 testutils.SucceedsSoon(t, func() error { 884 return jobutils.VerifySystemJob(t, sqlRun, i, jobspb.TypeSchemaChangeGC, jobs.StatusSucceeded, jobs.Record{ 885 Username: security.RootUser, 886 Description: fmt.Sprintf(`GC for DROP TABLE t.public.%s`, descs[i].GetName()), 887 DescriptorIDs: sqlbase.IDs{ 888 descs[i].ID, 889 }, 890 }) 891 }) 892 } 893 894 // Push a new zone config for a few tables with TTL=0 so the data 895 // is deleted immediately. 896 barrier := rand.Intn(numTables) 897 for i := 0; i < barrier; i++ { 898 pushZoneCfg(i) 899 } 900 901 // Check GC worked! 902 for i := 0; i < numTables; i++ { 903 if i < barrier { 904 checkTableGCed(i) 905 } else { 906 // Data still present for tables past barrier. 907 tableSpan := descs[i].TableSpan(keys.SystemSQLCodec) 908 tests.CheckKeyCount(t, kvDB, tableSpan, numKeys) 909 } 910 } 911 912 // Push the rest of the zone configs and check all the data gets GC-ed. 913 for i := barrier; i < numTables; i++ { 914 pushZoneCfg(i) 915 } 916 for i := barrier; i < numTables; i++ { 917 checkTableGCed(i) 918 } 919 } 920 921 func writeTableDesc(ctx context.Context, db *kv.DB, tableDesc *sqlbase.TableDescriptor) error { 922 return db.Txn(ctx, func(ctx context.Context, txn *kv.Txn) error { 923 if err := txn.SetSystemConfigTrigger(); err != nil { 924 return err 925 } 926 tableDesc.ModificationTime = txn.CommitTimestamp() 927 return txn.Put(ctx, sqlbase.MakeDescMetadataKey(keys.SystemSQLCodec, tableDesc.ID), sqlbase.WrapDescriptor(tableDesc)) 928 }) 929 } 930 931 // TestDropTableWhileUpgradingFormat ensures that it's safe for a migration to 932 // upgrade the table descriptor's format while the table is scheduled to be 933 // dropped. 934 // 935 // The new format must be backwards-compatible with the old format, but that's 936 // true in general. 937 func TestDropTableWhileUpgradingFormat(t *testing.T) { 938 defer leaktest.AfterTest(t)() 939 ctx := context.Background() 940 941 defer gcjob.SetSmallMaxGCIntervalForTest()() 942 943 params, _ := tests.CreateTestServerParams() 944 params.Knobs = base.TestingKnobs{ 945 SQLMigrationManager: &sqlmigrations.MigrationManagerTestingKnobs{ 946 DisableBackfillMigrations: true, 947 }, 948 } 949 950 s, sqlDBRaw, kvDB := serverutils.StartServer(t, params) 951 defer s.Stopper().Stop(ctx) 952 sqlDB := sqlutils.MakeSQLRunner(sqlDBRaw) 953 954 // Disable strict GC TTL enforcement because we're going to shove a zero-value 955 // TTL into the system with AddImmediateGCZoneConfig. 956 defer sqltestutils.DisableGCTTLStrictEnforcement(t, sqlDBRaw)() 957 958 const numRows = 100 959 sqlutils.CreateTable(t, sqlDBRaw, "t", "a INT", numRows, sqlutils.ToRowFn(sqlutils.RowIdxFn)) 960 961 // Give the table an old format version. 962 tableDesc := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "test", "t") 963 tableDesc.FormatVersion = sqlbase.FamilyFormatVersion 964 tableDesc.Version++ 965 if err := writeTableDesc(ctx, kvDB, tableDesc); err != nil { 966 t.Fatal(err) 967 } 968 969 tableSpan := tableDesc.TableSpan(keys.SystemSQLCodec) 970 tests.CheckKeyCount(t, kvDB, tableSpan, numRows) 971 972 sqlDB.Exec(t, `DROP TABLE test.t`) 973 974 // Simulate a migration upgrading the table descriptor's format version after 975 // the table has been dropped but before the truncation has occurred. 976 var err error 977 tableDesc, err = sqlbase.GetTableDescFromID(ctx, kvDB.NewTxn(ctx, ""), keys.SystemSQLCodec, tableDesc.ID) 978 if err != nil { 979 t.Fatal(err) 980 } 981 if !tableDesc.Dropped() { 982 t.Fatalf("expected descriptor to be in DROP state, but was in %s", tableDesc.State) 983 } 984 tableDesc.FormatVersion = sqlbase.InterleavedFormatVersion 985 tableDesc.Version++ 986 if err := writeTableDesc(ctx, kvDB, tableDesc); err != nil { 987 t.Fatal(err) 988 } 989 990 // Set TTL so the data is deleted immediately. 991 if _, err := sqltestutils.AddImmediateGCZoneConfig(sqlDBRaw, tableDesc.ID); err != nil { 992 t.Fatal(err) 993 } 994 995 // Allow the schema change to proceed and verify that the data is eventually 996 // deleted, despite the interleaved modification to the table descriptor. 997 testutils.SucceedsSoon(t, func() error { 998 return descExists(sqlDBRaw, false, tableDesc.ID) 999 }) 1000 tests.CheckKeyCount(t, kvDB, tableSpan, 0) 1001 } 1002 1003 // Tests dropping a table that is interleaved within 1004 // another table. 1005 func TestDropTableInterleavedDeleteData(t *testing.T) { 1006 defer leaktest.AfterTest(t)() 1007 params, _ := tests.CreateTestServerParams() 1008 1009 defer gcjob.SetSmallMaxGCIntervalForTest()() 1010 1011 s, sqlDB, kvDB := serverutils.StartServer(t, params) 1012 defer s.Stopper().Stop(context.Background()) 1013 1014 numRows := 2*sql.TableTruncateChunkSize + 1 1015 tests.CreateKVInterleavedTable(t, sqlDB, numRows) 1016 1017 tableDesc := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "t", "kv") 1018 tableDescInterleaved := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "t", "intlv") 1019 tableSpan := tableDesc.TableSpan(keys.SystemSQLCodec) 1020 1021 tests.CheckKeyCount(t, kvDB, tableSpan, 3*numRows) 1022 if _, err := sqlDB.Exec(`DROP TABLE t.intlv`); err != nil { 1023 t.Fatal(err) 1024 } 1025 1026 // Test that deleted table cannot be used. This prevents regressions where 1027 // name -> descriptor ID caches might make this statement erronously work. 1028 if _, err := sqlDB.Exec(`SELECT * FROM t.intlv`); !testutils.IsError( 1029 err, `relation "t.intlv" does not exist`, 1030 ) { 1031 t.Fatalf("different error than expected: %v", err) 1032 } 1033 1034 if _, err := sqltestutils.AddImmediateGCZoneConfig(sqlDB, tableDescInterleaved.ID); err != nil { 1035 t.Fatal(err) 1036 } 1037 1038 testutils.SucceedsSoon(t, func() error { 1039 return descExists(sqlDB, false, tableDescInterleaved.ID) 1040 }) 1041 1042 tests.CheckKeyCount(t, kvDB, tableSpan, numRows) 1043 } 1044 1045 func TestDropTableInTxn(t *testing.T) { 1046 defer leaktest.AfterTest(t)() 1047 params, _ := tests.CreateTestServerParams() 1048 s, sqlDB, _ := serverutils.StartServer(t, params) 1049 defer s.Stopper().Stop(context.Background()) 1050 1051 if _, err := sqlDB.Exec(` 1052 CREATE DATABASE t; 1053 CREATE TABLE t.kv (k CHAR PRIMARY KEY, v CHAR); 1054 `); err != nil { 1055 t.Fatal(err) 1056 } 1057 1058 tx, err := sqlDB.Begin() 1059 if err != nil { 1060 t.Fatal(err) 1061 } 1062 1063 if _, err := tx.Exec(`DROP TABLE t.kv`); err != nil { 1064 t.Fatal(err) 1065 } 1066 1067 // We might still be able to read/write in the table inside this transaction 1068 // until the schema changer runs, but we shouldn't be able to ALTER it. 1069 if _, err := tx.Exec(`ALTER TABLE t.kv ADD COLUMN w CHAR`); !testutils.IsError(err, 1070 `relation "t.kv" does not exist`) { 1071 t.Fatalf("different error than expected: %v", err) 1072 } 1073 1074 // Can't commit after ALTER errored, so we ROLLBACK. 1075 if err := tx.Rollback(); err != nil { 1076 t.Fatal(err) 1077 } 1078 1079 } 1080 1081 // Tests DROP DATABASE after DROP TABLE just before the table name has been 1082 // recycle. 1083 func TestDropDatabaseAfterDropTable(t *testing.T) { 1084 defer leaktest.AfterTest(t)() 1085 // Disable schema change execution so that the dropped table name 1086 // doesn't get recycled. 1087 params, _ := tests.CreateTestServerParams() 1088 params.Knobs = base.TestingKnobs{ 1089 SQLSchemaChanger: &sql.SchemaChangerTestingKnobs{ 1090 SchemaChangeJobNoOp: func() bool { 1091 return true 1092 }, 1093 }, 1094 } 1095 s, sqlDB, kvDB := serverutils.StartServer(t, params) 1096 defer s.Stopper().Stop(context.Background()) 1097 1098 if err := tests.CreateKVTable(sqlDB, "kv", 100); err != nil { 1099 t.Fatal(err) 1100 } 1101 1102 tableDesc := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "t", "kv") 1103 1104 if _, err := sqlDB.Exec(`DROP TABLE t.kv`); err != nil { 1105 t.Fatal(err) 1106 } 1107 1108 if _, err := sqlDB.Exec(`DROP DATABASE t`); err != nil { 1109 t.Fatal(err) 1110 } 1111 1112 // Job still running, waiting for draining names. 1113 // TODO (lucy): Maybe this test API should use an offset starting 1114 // from the most recent job instead. 1115 sqlRun := sqlutils.MakeSQLRunner(sqlDB) 1116 if err := jobutils.VerifySystemJob( 1117 t, sqlRun, 1, jobspb.TypeSchemaChange, jobs.StatusSucceeded, 1118 jobs.Record{ 1119 Username: security.RootUser, 1120 Description: "DROP TABLE t.public.kv", 1121 DescriptorIDs: sqlbase.IDs{ 1122 tableDesc.ID, 1123 }, 1124 }); err != nil { 1125 t.Fatal(err) 1126 } 1127 } 1128 1129 func TestDropAndCreateTable(t *testing.T) { 1130 defer leaktest.AfterTest(t)() 1131 params, _ := tests.CreateTestServerParams() 1132 params.UseDatabase = "test" 1133 s, db, _ := serverutils.StartServer(t, params) 1134 defer s.Stopper().Stop(context.Background()) 1135 1136 if _, err := db.Exec(`CREATE DATABASE test`); err != nil { 1137 t.Fatal(err) 1138 } 1139 1140 for i := 0; i < 20; i++ { 1141 if _, err := db.Exec(`DROP TABLE IF EXISTS foo`); err != nil { 1142 t.Fatal(err) 1143 } 1144 if _, err := db.Exec(`CREATE TABLE foo (k INT PRIMARY KEY)`); err != nil { 1145 t.Fatal(err) 1146 } 1147 if _, err := db.Exec(`INSERT INTO foo VALUES (1), (2), (3)`); err != nil { 1148 t.Fatal(err) 1149 } 1150 } 1151 } 1152 1153 func TestDropAndCreateDatabase(t *testing.T) { 1154 defer leaktest.AfterTest(t)() 1155 1156 ctx := context.Background() 1157 s, db, _ := serverutils.StartServer(t, base.TestServerArgs{UseDatabase: `test`}) 1158 defer s.Stopper().Stop(ctx) 1159 sqlDB := sqlutils.MakeSQLRunner(db) 1160 1161 for i := 0; i < 20; i++ { 1162 sqlDB.Exec(t, `DROP DATABASE IF EXISTS test`) 1163 sqlDB.Exec(t, `CREATE DATABASE test`) 1164 sqlDB.Exec(t, `CREATE TABLE foo (a INT PRIMARY KEY)`) 1165 sqlDB.Exec(t, `INSERT INTO foo VALUES (1), (2), (3)`) 1166 } 1167 } 1168 1169 // Test commands while a table is being dropped. 1170 func TestCommandsWhileTableBeingDropped(t *testing.T) { 1171 defer leaktest.AfterTest(t)() 1172 1173 params, _ := tests.CreateTestServerParams() 1174 // Block schema changers so that the table we're about to DROP is not 1175 // actually dropped; it will be left in the "deleted" state. 1176 params.Knobs = base.TestingKnobs{ 1177 SQLSchemaChanger: &sql.SchemaChangerTestingKnobs{ 1178 SchemaChangeJobNoOp: func() bool { 1179 return true 1180 }, 1181 }, 1182 } 1183 s, db, _ := serverutils.StartServer(t, params) 1184 defer s.Stopper().Stop(context.Background()) 1185 1186 sql := ` 1187 CREATE DATABASE test; 1188 CREATE TABLE test.t(a INT PRIMARY KEY); 1189 ` 1190 if _, err := db.Exec(sql); err != nil { 1191 t.Fatal(err) 1192 } 1193 1194 // DROP the table 1195 if _, err := db.Exec(`DROP TABLE test.t`); err != nil { 1196 t.Fatal(err) 1197 } 1198 1199 // Check that SHOW TABLES marks a dropped table with the " (dropped)" 1200 // suffix. 1201 rows, err := db.Query(`SHOW TABLES FROM test`) 1202 if err != nil { 1203 t.Fatal(err) 1204 } 1205 defer rows.Close() 1206 if rows.Next() { 1207 t.Fatal("table should be invisible through SHOW TABLES") 1208 } 1209 1210 // Check that CREATE TABLE with the same name returns a proper error. 1211 if _, err := db.Exec(`CREATE TABLE test.t(a INT PRIMARY KEY)`); !testutils.IsError(err, `relation "t" already exists`) { 1212 t.Fatal(err) 1213 } 1214 1215 // Check that DROP TABLE with the same name returns a proper error. 1216 if _, err := db.Exec(`DROP TABLE test.t`); !testutils.IsError(err, `relation "test.t" does not exist`) { 1217 t.Fatal(err) 1218 } 1219 } 1220 1221 // Tests name reuse if a DROP VIEW|TABLE succeeds but fails 1222 // before running the schema changer. Tests name GC via the 1223 // asynchrous schema change path. 1224 // TODO (lucy): This started as a test verifying that draining names still works 1225 // in the async schema changer, which no longer exists. Should the test still 1226 // exist? 1227 func TestDropNameReuse(t *testing.T) { 1228 defer leaktest.AfterTest(t)() 1229 1230 params, _ := tests.CreateTestServerParams() 1231 params.Knobs = base.TestingKnobs{ 1232 SQLMigrationManager: &sqlmigrations.MigrationManagerTestingKnobs{ 1233 DisableBackfillMigrations: true, 1234 }, 1235 } 1236 1237 s, db, _ := serverutils.StartServer(t, params) 1238 defer s.Stopper().Stop(context.Background()) 1239 1240 sql := ` 1241 CREATE DATABASE test; 1242 CREATE TABLE test.t(a INT PRIMARY KEY); 1243 CREATE VIEW test.acol(a) AS SELECT a FROM test.t; 1244 ` 1245 if _, err := db.Exec(sql); err != nil { 1246 t.Fatal(err) 1247 } 1248 1249 // DROP the view. 1250 if _, err := db.Exec(`DROP VIEW test.acol`); err != nil { 1251 t.Fatal(err) 1252 } 1253 1254 testutils.SucceedsSoon(t, func() error { 1255 _, err := db.Exec(`CREATE TABLE test.acol(a INT PRIMARY KEY);`) 1256 return err 1257 }) 1258 1259 // DROP the table. 1260 if _, err := db.Exec(`DROP TABLE test.t`); err != nil { 1261 t.Fatal(err) 1262 } 1263 1264 testutils.SucceedsSoon(t, func() error { 1265 _, err := db.Exec(`CREATE TABLE test.t(a INT PRIMARY KEY);`) 1266 return err 1267 }) 1268 } 1269 1270 // TestDropIndexHandlesRetriableErrors is a regression test against #48474. 1271 // The bug was that retriable errors, which are generally possible, were being 1272 // treated as assertion failures. 1273 func TestDropIndexHandlesRetriableErrors(t *testing.T) { 1274 defer leaktest.AfterTest(t)() 1275 1276 ctx := context.Background() 1277 rf := newDynamicRequestFilter() 1278 tc := testcluster.StartTestCluster(t, 1, base.TestClusterArgs{ 1279 ServerArgs: base.TestServerArgs{ 1280 Knobs: base.TestingKnobs{ 1281 Store: &kvserver.StoreTestingKnobs{ 1282 TestingRequestFilter: rf.filter, 1283 }, 1284 }, 1285 }, 1286 }) 1287 defer tc.Stopper().Stop(ctx) 1288 1289 // What we want to do is have a transaction which does the planning work to 1290 // drop an index. Then we want to expose the execution of the DROP INDEX to 1291 // an error when retrieving the mutable table descriptor. We'll do this by 1292 // injecting a ReadWithinUncertainty error underneath the DROP INDEX 1293 // after planning has concluded. 1294 1295 tdb := sqlutils.MakeSQLRunner(tc.ServerConn(0)) 1296 tdb.Exec(t, "CREATE TABLE foo (i INT PRIMARY KEY, j INT, INDEX j_idx (j))") 1297 1298 var tableID uint32 1299 tdb.QueryRow(t, ` 1300 SELECT 1301 table_id 1302 FROM 1303 crdb_internal.tables 1304 WHERE 1305 name = $1 AND database_name = current_database();`, 1306 "foo").Scan(&tableID) 1307 1308 // Start the user transaction and enable tracing as we'll use the trace 1309 // to determine when planning has concluded. 1310 txn, err := tc.ServerConn(0).Begin() 1311 require.NoError(t, err) 1312 _, err = txn.Exec("SET TRACING = on") 1313 require.NoError(t, err) 1314 // Let's find out our transaction ID for our transaction by running a query. 1315 // We'll also use this query to install a refresh span over the table data. 1316 // Inject a request filter to snag the transaction ID. 1317 tablePrefix := keys.SystemSQLCodec.TablePrefix(tableID) 1318 tableSpan := roachpb.Span{ 1319 Key: tablePrefix, 1320 EndKey: tablePrefix.PrefixEnd(), 1321 } 1322 var filterState struct { 1323 syncutil.Mutex 1324 txnID uuid.UUID 1325 } 1326 getTxnID := func() uuid.UUID { 1327 filterState.Lock() 1328 defer filterState.Unlock() 1329 return filterState.txnID 1330 } 1331 rf.setFilter(func(ctx context.Context, request roachpb.BatchRequest) *roachpb.Error { 1332 if request.Txn == nil || request.Txn.Name != sql.SQLTxnName { 1333 return nil 1334 } 1335 filterState.Lock() 1336 defer filterState.Unlock() 1337 if filterState.txnID != (uuid.UUID{}) { 1338 return nil 1339 } 1340 if scanRequest, ok := request.GetArg(roachpb.Scan); ok { 1341 scan := scanRequest.(*roachpb.ScanRequest) 1342 if scan.Span().Overlaps(tableSpan) { 1343 filterState.txnID = request.Txn.ID 1344 } 1345 } 1346 return nil 1347 }) 1348 1349 // Run the scan of the table to activate the filter as well as add the 1350 // refresh span over the table data. 1351 var trash int 1352 require.Equal(t, gosql.ErrNoRows, 1353 txn.QueryRow("SELECT * FROM foo").Scan(&trash)) 1354 rf.setFilter(nil) 1355 require.NotEqual(t, uuid.UUID{}, getTxnID()) 1356 1357 // Perform a write after the above read so that a refresh will fail and 1358 // observe its timestamp. 1359 tdb.Exec(t, "INSERT INTO foo VALUES (1)") 1360 var afterInsertStr string 1361 tdb.QueryRow(t, "SELECT cluster_logical_timestamp()").Scan(&afterInsertStr) 1362 afterInsert, err := sql.ParseHLC(afterInsertStr) 1363 require.NoError(t, err) 1364 1365 // Now set up a filter to detect when the DROP INDEX execution will begin 1366 // and inject an error forcing a refresh above the conflicting write which 1367 // will fail. We'll want to ensure that we get a retriable error. 1368 // Use the below pattern to detect when the user transaction has finished 1369 // planning and is now executing. 1370 dropIndexPlanningEndsRE := regexp.MustCompile("(?s)planning starts: DROP INDEX.*planning ends") 1371 rf.setFilter(func(ctx context.Context, request roachpb.BatchRequest) *roachpb.Error { 1372 if request.Txn == nil { 1373 return nil 1374 } 1375 filterState.Lock() 1376 defer filterState.Unlock() 1377 if filterState.txnID != request.Txn.ID { 1378 return nil 1379 } 1380 sp := opentracing.SpanFromContext(ctx) 1381 rec := tracing.GetRecording(sp) 1382 if !dropIndexPlanningEndsRE.MatchString(rec.String()) { 1383 return nil 1384 } 1385 if getRequest, ok := request.GetArg(roachpb.Get); ok { 1386 put := getRequest.(*roachpb.GetRequest) 1387 if put.Key.Equal(sqlbase.MakeDescMetadataKey(keys.SystemSQLCodec, sqlbase.ID(tableID))) { 1388 filterState.txnID = uuid.UUID{} 1389 return roachpb.NewError(roachpb.NewReadWithinUncertaintyIntervalError( 1390 request.Txn.ReadTimestamp, afterInsert, request.Txn)) 1391 } 1392 } 1393 return nil 1394 }) 1395 1396 _, err = txn.Exec("DROP INDEX foo@j_idx") 1397 require.Truef(t, isRetryableErr(err), "drop index error: %v", err) 1398 require.NoError(t, txn.Rollback()) 1399 }