github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/mutations/mutations.go (about) 1 // Copyright 2019 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 mutations 12 13 import ( 14 "bytes" 15 "encoding/json" 16 "math/rand" 17 "regexp" 18 "sort" 19 "strings" 20 21 "github.com/cockroachdb/cockroach/pkg/sql/parser" 22 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 23 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 24 "github.com/cockroachdb/cockroach/pkg/sql/stats" 25 "github.com/cockroachdb/cockroach/pkg/util/encoding" 26 ) 27 28 var ( 29 // StatisticsMutator adds ALTER TABLE INJECT STATISTICS statements. 30 StatisticsMutator MultiStatementMutation = statisticsMutator 31 32 // ForeignKeyMutator adds ALTER TABLE ADD FOREIGN KEY statements. 33 ForeignKeyMutator MultiStatementMutation = foreignKeyMutator 34 35 // ColumnFamilyMutator modifies a CREATE TABLE statement without any FAMILY 36 // definitions to have random FAMILY definitions. 37 ColumnFamilyMutator StatementMutator = sqlbase.ColumnFamilyMutator 38 39 // IndexStoringMutator modifies the STORING clause of CREATE INDEX and 40 // indexes in CREATE TABLE. 41 IndexStoringMutator MultiStatementMutation = sqlbase.IndexStoringMutator 42 43 // PostgresMutator modifies strings such that they execute identically 44 // in both Postgres and Cockroach (however this mutator does not remove 45 // features not supported by Postgres; use PostgresCreateTableMutator 46 // for those). 47 PostgresMutator StatementStringMutator = postgresMutator 48 49 // PostgresCreateTableMutator modifies CREATE TABLE statements to 50 // remove any features not supported by Postgres that would change 51 // results (like descending primary keys). This should be used on the 52 // output of sqlbase.RandCreateTable. 53 PostgresCreateTableMutator MultiStatementMutation = postgresCreateTableMutator 54 ) 55 56 var ( 57 // These are used in pkg/compose/compare/compare/compare_test.go, but 58 // it has a build tag so it's not detected by the linter. 59 _ = IndexStoringMutator 60 _ = PostgresCreateTableMutator 61 ) 62 63 // StatementMutator defines a func that can change a statement. 64 type StatementMutator func(rng *rand.Rand, stmt tree.Statement) (changed bool) 65 66 // MultiStatementMutation defines a func that can return a list of new and/or mutated statements. 67 type MultiStatementMutation func(rng *rand.Rand, stmts []tree.Statement) (mutated []tree.Statement, changed bool) 68 69 // Mutate implements the Mutator interface. 70 func (sm StatementMutator) Mutate( 71 rng *rand.Rand, stmts []tree.Statement, 72 ) (mutated []tree.Statement, changed bool) { 73 for _, stmt := range stmts { 74 sc := sm(rng, stmt) 75 changed = changed || sc 76 } 77 return stmts, changed 78 } 79 80 // Mutate implements the Mutator interface. 81 func (msm MultiStatementMutation) Mutate( 82 rng *rand.Rand, stmts []tree.Statement, 83 ) (mutated []tree.Statement, changed bool) { 84 return msm(rng, stmts) 85 } 86 87 // Apply executes all mutators on stmts. It returns the (possibly mutated and 88 // changed in place) statements and a boolean indicating whether any changes 89 // were made. 90 func Apply( 91 rng *rand.Rand, stmts []tree.Statement, mutators ...sqlbase.Mutator, 92 ) (mutated []tree.Statement, changed bool) { 93 var mc bool 94 for _, m := range mutators { 95 stmts, mc = m.Mutate(rng, stmts) 96 changed = changed || mc 97 } 98 return stmts, changed 99 } 100 101 // StringMutator defines a mutator that works on strings. 102 type StringMutator interface { 103 MutateString(*rand.Rand, string) (mutated string, changed bool) 104 } 105 106 // StatementStringMutator defines a func that mutates a string. 107 type StatementStringMutator func(*rand.Rand, string) string 108 109 // Mutate implements the Mutator interface. 110 func (sm StatementStringMutator) Mutate( 111 rng *rand.Rand, stmts []tree.Statement, 112 ) (mutated []tree.Statement, changed bool) { 113 panic("can only be used with MutateString") 114 } 115 116 // MutateString implements the StringMutator interface. 117 func (sm StatementStringMutator) MutateString( 118 rng *rand.Rand, q string, 119 ) (mutated string, changed bool) { 120 newq := sm(rng, q) 121 return newq, newq != q 122 } 123 124 // ApplyString executes all mutators on input. A mutator can also be a 125 // StringMutator which will operate after all other mutators. 126 func ApplyString( 127 rng *rand.Rand, input string, mutators ...sqlbase.Mutator, 128 ) (output string, changed bool) { 129 parsed, err := parser.Parse(input) 130 if err != nil { 131 return input, false 132 } 133 134 stmts := make([]tree.Statement, len(parsed)) 135 for i, p := range parsed { 136 stmts[i] = p.AST 137 } 138 139 var normalMutators []sqlbase.Mutator 140 var stringMutators []StringMutator 141 for _, m := range mutators { 142 if sm, ok := m.(StringMutator); ok { 143 stringMutators = append(stringMutators, sm) 144 } else { 145 normalMutators = append(normalMutators, m) 146 } 147 } 148 stmts, changed = Apply(rng, stmts, normalMutators...) 149 if changed { 150 var sb strings.Builder 151 for _, s := range stmts { 152 sb.WriteString(s.String()) 153 sb.WriteString(";\n") 154 } 155 input = sb.String() 156 } 157 for _, m := range stringMutators { 158 s, ch := m.MutateString(rng, input) 159 if ch { 160 input = s 161 changed = true 162 } 163 } 164 return input, changed 165 } 166 167 // randNonNegInt returns a random non-negative integer. It attempts to 168 // distribute it over powers of 10. 169 func randNonNegInt(rng *rand.Rand) int64 { 170 var v int64 171 if n := rng.Intn(20); n == 0 { 172 // v == 0 173 } else if n <= 10 { 174 v = rng.Int63n(10) + 1 175 for i := 0; i < n; i++ { 176 v *= 10 177 } 178 } else { 179 v = rng.Int63() 180 } 181 return v 182 } 183 184 func statisticsMutator( 185 rng *rand.Rand, stmts []tree.Statement, 186 ) (mutated []tree.Statement, changed bool) { 187 for _, stmt := range stmts { 188 create, ok := stmt.(*tree.CreateTable) 189 if !ok { 190 continue 191 } 192 alter := &tree.AlterTable{ 193 Table: create.Table.ToUnresolvedObjectName(), 194 } 195 rowCount := randNonNegInt(rng) 196 cols := map[tree.Name]*tree.ColumnTableDef{} 197 colStats := map[tree.Name]*stats.JSONStatistic{} 198 makeHistogram := func(col *tree.ColumnTableDef) { 199 // If an index appeared before a column definition, col 200 // can be nil. 201 if col == nil { 202 return 203 } 204 n := rng.Intn(10) 205 seen := map[string]bool{} 206 colType := tree.MustBeStaticallyKnownType(col.Type) 207 h := stats.HistogramData{ 208 ColumnType: colType, 209 } 210 for i := 0; i < n; i++ { 211 upper := sqlbase.RandDatumWithNullChance(rng, colType, 0) 212 if upper == tree.DNull { 213 continue 214 } 215 enc, err := sqlbase.EncodeTableKey(nil, upper, encoding.Ascending) 216 if err != nil { 217 panic(err) 218 } 219 if es := string(enc); seen[es] { 220 continue 221 } else { 222 seen[es] = true 223 } 224 numRange := randNonNegInt(rng) 225 var distinctRange float64 226 // distinctRange should be <= numRange. 227 switch rng.Intn(3) { 228 case 0: 229 // 0 230 case 1: 231 distinctRange = float64(numRange) 232 default: 233 distinctRange = rng.Float64() * float64(numRange) 234 } 235 236 h.Buckets = append(h.Buckets, stats.HistogramData_Bucket{ 237 NumEq: randNonNegInt(rng), 238 NumRange: numRange, 239 DistinctRange: distinctRange, 240 UpperBound: enc, 241 }) 242 } 243 sort.Slice(h.Buckets, func(i, j int) bool { 244 return bytes.Compare(h.Buckets[i].UpperBound, h.Buckets[j].UpperBound) < 0 245 }) 246 // The first bucket must have numrange = 0, and thus 247 // distinctrange = 0 as well. 248 if len(h.Buckets) > 0 { 249 h.Buckets[0].NumRange = 0 250 h.Buckets[0].DistinctRange = 0 251 } 252 stat := colStats[col.Name] 253 if err := stat.SetHistogram(&h); err != nil { 254 panic(err) 255 } 256 } 257 for _, def := range create.Defs { 258 switch def := def.(type) { 259 case *tree.ColumnTableDef: 260 var nullCount, distinctCount uint64 261 if rowCount > 0 { 262 if def.Nullable.Nullability != tree.NotNull { 263 nullCount = uint64(rng.Int63n(rowCount)) 264 } 265 distinctCount = uint64(rng.Int63n(rowCount)) 266 } 267 cols[def.Name] = def 268 colStats[def.Name] = &stats.JSONStatistic{ 269 Name: "__auto__", 270 CreatedAt: "2000-01-01 00:00:00+00:00", 271 RowCount: uint64(rowCount), 272 Columns: []string{def.Name.String()}, 273 DistinctCount: distinctCount, 274 NullCount: nullCount, 275 } 276 if def.Unique || def.PrimaryKey.IsPrimaryKey { 277 makeHistogram(def) 278 } 279 case *tree.IndexTableDef: 280 makeHistogram(cols[def.Columns[0].Column]) 281 case *tree.UniqueConstraintTableDef: 282 makeHistogram(cols[def.Columns[0].Column]) 283 } 284 } 285 if len(colStats) > 0 { 286 var allStats []*stats.JSONStatistic 287 for _, cs := range colStats { 288 allStats = append(allStats, cs) 289 } 290 b, err := json.Marshal(allStats) 291 if err != nil { 292 // Should not happen. 293 panic(err) 294 } 295 alter.Cmds = append(alter.Cmds, &tree.AlterTableInjectStats{ 296 Stats: tree.NewDString(string(b)), 297 }) 298 stmts = append(stmts, alter) 299 changed = true 300 } 301 } 302 return stmts, changed 303 } 304 305 func foreignKeyMutator( 306 rng *rand.Rand, stmts []tree.Statement, 307 ) (mutated []tree.Statement, changed bool) { 308 // Find columns in the tables. 309 cols := map[tree.TableName][]*tree.ColumnTableDef{} 310 byName := map[tree.TableName]*tree.CreateTable{} 311 312 // Keep track of referencing columns since we have a limitation that a 313 // column can only be used by one FK. 314 usedCols := map[tree.TableName]map[tree.Name]bool{} 315 316 // Keep track of table dependencies to prevent circular dependencies. 317 dependsOn := map[tree.TableName]map[tree.TableName]bool{} 318 319 var tables []*tree.CreateTable 320 for _, stmt := range stmts { 321 table, ok := stmt.(*tree.CreateTable) 322 if !ok { 323 continue 324 } 325 tables = append(tables, table) 326 byName[table.Table] = table 327 usedCols[table.Table] = map[tree.Name]bool{} 328 dependsOn[table.Table] = map[tree.TableName]bool{} 329 for _, def := range table.Defs { 330 switch def := def.(type) { 331 case *tree.ColumnTableDef: 332 cols[table.Table] = append(cols[table.Table], def) 333 } 334 } 335 } 336 if len(tables) == 0 { 337 return stmts, false 338 } 339 340 toNames := func(cols []*tree.ColumnTableDef) tree.NameList { 341 names := make(tree.NameList, len(cols)) 342 for i, c := range cols { 343 names[i] = c.Name 344 } 345 return names 346 } 347 348 // We cannot mutate the table definitions themselves because 1) we 349 // don't know the order of dependencies (i.e., table 1 could reference 350 // table 4 which doesn't exist yet) and relatedly 2) we don't prevent 351 // circular dependencies. Instead, add new ALTER TABLE commands to the 352 // end of a list of statements. 353 354 // Create some FKs. 355 for rng.Intn(2) == 0 { 356 // Choose a random table. 357 table := tables[rng.Intn(len(tables))] 358 // Choose a random column subset. 359 var fkCols []*tree.ColumnTableDef 360 for _, c := range cols[table.Table] { 361 if usedCols[table.Table][c.Name] { 362 continue 363 } 364 fkCols = append(fkCols, c) 365 } 366 if len(fkCols) == 0 { 367 continue 368 } 369 rng.Shuffle(len(fkCols), func(i, j int) { 370 fkCols[i], fkCols[j] = fkCols[j], fkCols[i] 371 }) 372 // Pick some randomly short prefix. I'm sure there's a closed 373 // form solution to this with a single call to rng.Intn but I'm 374 // not sure what to search for. 375 i := 1 376 for len(fkCols) > i && rng.Intn(2) == 0 { 377 i++ 378 } 379 fkCols = fkCols[:i] 380 381 // Check if a table has the needed column types. 382 LoopTable: 383 for refTable, refCols := range cols { 384 // Prevent circular and self references because 385 // generating valid INSERTs could become impossible or 386 // difficult algorithmically. 387 if refTable == table.Table || len(refCols) < len(fkCols) { 388 continue 389 } 390 391 { 392 // To prevent circular references, find all transitive 393 // dependencies of refTable and make sure none of them 394 // are table. 395 stack := []tree.TableName{refTable} 396 for i := 0; i < len(stack); i++ { 397 curTable := stack[i] 398 if curTable == table.Table { 399 // table was trying to add a dependency 400 // to refTable, but refTable already 401 // depends on table (directly or 402 // indirectly). 403 continue LoopTable 404 } 405 for t := range dependsOn[curTable] { 406 stack = append(stack, t) 407 } 408 } 409 } 410 411 // We found a table with enough columns. Check if it 412 // has some columns that are needed types. In order 413 // to not use columns multiple times, keep track of 414 // available columns. 415 availCols := append([]*tree.ColumnTableDef(nil), refCols...) 416 var usingCols []*tree.ColumnTableDef 417 for len(availCols) > 0 && len(usingCols) < len(fkCols) { 418 fkCol := fkCols[len(usingCols)] 419 found := false 420 for refI, refCol := range availCols { 421 fkColType := tree.MustBeStaticallyKnownType(fkCol.Type) 422 refColType := tree.MustBeStaticallyKnownType(refCol.Type) 423 if fkColType.Equivalent(refColType) { 424 usingCols = append(usingCols, refCol) 425 availCols = append(availCols[:refI], availCols[refI+1:]...) 426 found = true 427 break 428 } 429 } 430 if !found { 431 continue LoopTable 432 } 433 } 434 // If we didn't find enough columns, try another table. 435 if len(usingCols) != len(fkCols) { 436 continue 437 } 438 439 // Found a suitable table. 440 // TODO(mjibson): prevent the creation of unneeded 441 // unique indexes. One may already exist with the 442 // correct prefix. 443 ref := byName[refTable] 444 refColumns := make(tree.IndexElemList, len(usingCols)) 445 for i, c := range usingCols { 446 refColumns[i].Column = c.Name 447 } 448 for _, c := range fkCols { 449 usedCols[table.Table][c.Name] = true 450 } 451 dependsOn[table.Table][ref.Table] = true 452 ref.Defs = append(ref.Defs, &tree.UniqueConstraintTableDef{ 453 IndexTableDef: tree.IndexTableDef{ 454 Columns: refColumns, 455 }, 456 }) 457 458 match := tree.MatchSimple 459 // TODO(mjibson): Set match once #42498 is fixed. 460 var actions tree.ReferenceActions 461 if rng.Intn(2) == 0 { 462 actions.Delete = randAction(rng, table) 463 } 464 if rng.Intn(2) == 0 { 465 actions.Update = randAction(rng, table) 466 } 467 stmts = append(stmts, &tree.AlterTable{ 468 Table: table.Table.ToUnresolvedObjectName(), 469 Cmds: tree.AlterTableCmds{&tree.AlterTableAddConstraint{ 470 ConstraintDef: &tree.ForeignKeyConstraintTableDef{ 471 Table: ref.Table, 472 FromCols: toNames(fkCols), 473 ToCols: toNames(usingCols), 474 Actions: actions, 475 Match: match, 476 }, 477 }}, 478 }) 479 changed = true 480 break 481 } 482 } 483 484 return stmts, changed 485 } 486 487 func randAction(rng *rand.Rand, table *tree.CreateTable) tree.ReferenceAction { 488 const highestAction = tree.Cascade 489 // Find a valid action. Depending on the random action chosen, we have 490 // to verify some validity conditions. 491 Loop: 492 for { 493 action := tree.ReferenceAction(rng.Intn(int(highestAction + 1))) 494 for _, def := range table.Defs { 495 col, ok := def.(*tree.ColumnTableDef) 496 if !ok { 497 continue 498 } 499 switch action { 500 case tree.SetNull: 501 if col.Nullable.Nullability == tree.NotNull { 502 continue Loop 503 } 504 case tree.SetDefault: 505 if col.DefaultExpr.Expr == nil && col.Nullable.Nullability == tree.NotNull { 506 continue Loop 507 } 508 } 509 } 510 return action 511 } 512 } 513 514 var postgresMutatorAtIndex = regexp.MustCompile(`@[\[\]\w]+`) 515 516 func postgresMutator(rng *rand.Rand, q string) string { 517 q, _ = ApplyString(rng, q, postgresStatementMutator) 518 519 for from, to := range map[string]string{ 520 ":::": "::", 521 "STRING": "TEXT", 522 "BYTES": "BYTEA", 523 "FLOAT4": "FLOAT8", 524 "INT2": "INT8", 525 "INT4": "INT8", 526 "STORING": "INCLUDE", 527 } { 528 q = strings.Replace(q, from, to, -1) 529 } 530 q = postgresMutatorAtIndex.ReplaceAllString(q, "") 531 return q 532 } 533 534 // postgresStatementMutator removes cockroach-only things from CREATE TABLE and 535 // ALTER TABLE. 536 var postgresStatementMutator MultiStatementMutation = func(rng *rand.Rand, stmts []tree.Statement) (mutated []tree.Statement, changed bool) { 537 for _, stmt := range stmts { 538 switch stmt := stmt.(type) { 539 case *tree.SetClusterSetting: 540 continue 541 case *tree.CreateTable: 542 if stmt.Interleave != nil { 543 stmt.Interleave = nil 544 changed = true 545 } 546 if stmt.PartitionBy != nil { 547 stmt.PartitionBy = nil 548 changed = true 549 } 550 for i := 0; i < len(stmt.Defs); i++ { 551 switch def := stmt.Defs[i].(type) { 552 case *tree.FamilyTableDef: 553 // Remove. 554 stmt.Defs = append(stmt.Defs[:i], stmt.Defs[i+1:]...) 555 i-- 556 changed = true 557 case *tree.ColumnTableDef: 558 if def.HasColumnFamily() { 559 def.Family.Name = "" 560 def.Family.Create = false 561 changed = true 562 } 563 case *tree.UniqueConstraintTableDef: 564 if def.Interleave != nil { 565 def.Interleave = nil 566 changed = true 567 } 568 if def.PartitionBy != nil { 569 def.PartitionBy = nil 570 changed = true 571 } 572 } 573 } 574 case *tree.AlterTable: 575 for i := 0; i < len(stmt.Cmds); i++ { 576 // Postgres doesn't have alter stats. 577 if _, ok := stmt.Cmds[i].(*tree.AlterTableInjectStats); ok { 578 stmt.Cmds = append(stmt.Cmds[:i], stmt.Cmds[i+1:]...) 579 i-- 580 changed = true 581 } 582 } 583 // If there are no commands, don't add this statement. 584 if len(stmt.Cmds) == 0 { 585 continue 586 } 587 } 588 mutated = append(mutated, stmt) 589 } 590 return mutated, changed 591 } 592 593 func postgresCreateTableMutator( 594 rng *rand.Rand, stmts []tree.Statement, 595 ) (mutated []tree.Statement, changed bool) { 596 for _, stmt := range stmts { 597 mutated = append(mutated, stmt) 598 switch stmt := stmt.(type) { 599 case *tree.CreateTable: 600 var newdefs tree.TableDefs 601 for _, def := range stmt.Defs { 602 switch def := def.(type) { 603 case *tree.IndexTableDef: 604 // Postgres doesn't support 605 // indexes in CREATE TABLE, 606 // so split them out to their 607 // own statement. 608 mutated = append(mutated, &tree.CreateIndex{ 609 Name: def.Name, 610 Table: stmt.Table, 611 Inverted: def.Inverted, 612 Columns: def.Columns, 613 Storing: def.Storing, 614 }) 615 changed = true 616 case *tree.UniqueConstraintTableDef: 617 if def.PrimaryKey { 618 // Postgres doesn't support descending PKs. 619 for i, col := range def.Columns { 620 if col.Direction != tree.DefaultDirection { 621 def.Columns[i].Direction = tree.DefaultDirection 622 changed = true 623 } 624 } 625 if def.Name != "" { 626 // Unset Name here because 627 // constaint names cannot 628 // be shared among tables, 629 // so multiple PK constraints 630 // named "primary" is an error. 631 def.Name = "" 632 changed = true 633 } 634 newdefs = append(newdefs, def) 635 break 636 } 637 mutated = append(mutated, &tree.CreateIndex{ 638 Name: def.Name, 639 Table: stmt.Table, 640 Unique: true, 641 Inverted: def.Inverted, 642 Columns: def.Columns, 643 Storing: def.Storing, 644 }) 645 changed = true 646 default: 647 newdefs = append(newdefs, def) 648 } 649 } 650 stmt.Defs = newdefs 651 } 652 } 653 return mutated, changed 654 }