github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/testutils/testcat/create_table.go (about) 1 // Copyright 2018 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 testcat 12 13 import ( 14 "fmt" 15 "strings" 16 17 "github.com/cockroachdb/cockroach/pkg/config/zonepb" 18 "github.com/cockroachdb/cockroach/pkg/sql/opt/cat" 19 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 20 "github.com/cockroachdb/cockroach/pkg/sql/types" 21 "github.com/cockroachdb/cockroach/pkg/util" 22 ) 23 24 type indexType int 25 26 const ( 27 primaryIndex indexType = iota 28 uniqueIndex 29 nonUniqueIndex 30 ) 31 32 type colType int 33 34 const ( 35 // keyCol is part of both lax and strict keys. 36 keyCol colType = iota 37 // strictKeyCol is only part of strict key. 38 strictKeyCol 39 // nonKeyCol is not part of lax or strict key. 40 nonKeyCol 41 ) 42 43 var uniqueRowIDString = "unique_rowid()" 44 45 // CreateTable creates a test table from a parsed DDL statement and adds it to 46 // the catalog. This is intended for testing, and is not a complete (and 47 // probably not fully correct) implementation. It just has to be "good enough". 48 func (tc *Catalog) CreateTable(stmt *tree.CreateTable) *Table { 49 stmt.HoistConstraints() 50 51 // Update the table name to include catalog and schema if not provided. 52 tc.qualifyTableName(&stmt.Table) 53 54 // Assume that every table in the "system" or "information_schema" catalog 55 // is a virtual table. This is a simplified assumption for testing purposes. 56 if stmt.Table.CatalogName == "system" || stmt.Table.SchemaName == "information_schema" { 57 return tc.createVirtualTable(stmt) 58 } 59 60 tab := &Table{TabID: tc.nextStableID(), TabName: stmt.Table, Catalog: tc} 61 62 // TODO(andyk): For now, just remember that the table was interleaved. In the 63 // future, it may be necessary to extract additional metadata. 64 if stmt.Interleave != nil { 65 tab.interleaved = true 66 } 67 68 // Add non-mutation columns. 69 for _, def := range stmt.Defs { 70 switch def := def.(type) { 71 case *tree.ColumnTableDef: 72 if !isMutationColumn(def) { 73 tab.addColumn(def) 74 } 75 } 76 } 77 78 // If there is no primary index, add the hidden rowid column. 79 hasPrimaryIndex := false 80 for _, def := range stmt.Defs { 81 switch def := def.(type) { 82 case *tree.ColumnTableDef: 83 if def.PrimaryKey.IsPrimaryKey { 84 hasPrimaryIndex = true 85 } 86 87 case *tree.UniqueConstraintTableDef: 88 if def.PrimaryKey { 89 hasPrimaryIndex = true 90 } 91 } 92 } 93 94 if !hasPrimaryIndex { 95 rowid := &Column{ 96 Ordinal: tab.ColumnCount(), 97 Name: "rowid", 98 Type: types.Int, 99 Hidden: true, 100 DefaultExpr: &uniqueRowIDString, 101 } 102 tab.Columns = append(tab.Columns, rowid) 103 } 104 105 // Add any mutation columns (after any hidden rowid column). 106 for _, def := range stmt.Defs { 107 switch def := def.(type) { 108 case *tree.ColumnTableDef: 109 if isMutationColumn(def) { 110 tab.addColumn(def) 111 } 112 } 113 } 114 115 // Add the primary index. 116 if hasPrimaryIndex { 117 for _, def := range stmt.Defs { 118 switch def := def.(type) { 119 case *tree.ColumnTableDef: 120 if def.PrimaryKey.IsPrimaryKey { 121 // Add the primary index over the single column. 122 tab.addPrimaryColumnIndex(string(def.Name)) 123 } 124 125 case *tree.UniqueConstraintTableDef: 126 if def.PrimaryKey { 127 tab.addIndex(&def.IndexTableDef, primaryIndex) 128 } 129 } 130 } 131 } else { 132 tab.addPrimaryColumnIndex("rowid") 133 } 134 if stmt.PartitionBy != nil { 135 tab.Indexes[0].partitionBy = stmt.PartitionBy 136 } 137 138 // Add check constraints. 139 for _, def := range stmt.Defs { 140 switch def := def.(type) { 141 case *tree.CheckConstraintTableDef: 142 tab.Checks = append(tab.Checks, cat.CheckConstraint{ 143 Constraint: serializeTableDefExpr(def.Expr), 144 Validated: validatedCheckConstraint(def), 145 }) 146 } 147 } 148 149 // Search for index and family definitions. 150 for _, def := range stmt.Defs { 151 switch def := def.(type) { 152 case *tree.UniqueConstraintTableDef: 153 if !def.PrimaryKey { 154 tab.addIndex(&def.IndexTableDef, uniqueIndex) 155 } 156 157 case *tree.IndexTableDef: 158 tab.addIndex(def, nonUniqueIndex) 159 160 case *tree.FamilyTableDef: 161 tab.addFamily(def) 162 163 case *tree.ColumnTableDef: 164 if def.Unique { 165 tab.addIndex( 166 &tree.IndexTableDef{ 167 Name: tree.Name(fmt.Sprintf("%s_%s_key", stmt.Table.ObjectName, def.Name)), 168 Columns: tree.IndexElemList{{Column: def.Name}}, 169 }, 170 uniqueIndex, 171 ) 172 } 173 } 174 } 175 176 // If there are columns missing from explicit family definitions, add them 177 // to family 0 (ensure that one exists). 178 if len(tab.Families) == 0 { 179 tab.Families = []*Family{{FamName: "primary", Ordinal: 0, table: tab}} 180 } 181 OuterLoop: 182 for colOrd, col := range tab.Columns { 183 for _, fam := range tab.Families { 184 for _, famCol := range fam.Columns { 185 if col.Name == string(famCol.ColName()) { 186 continue OuterLoop 187 } 188 } 189 } 190 tab.Families[0].Columns = append(tab.Families[0].Columns, 191 cat.FamilyColumn{Column: col, Ordinal: colOrd}) 192 } 193 194 // Search for foreign key constraints. We want to process them after first 195 // processing all the indexes (otherwise the foreign keys could add 196 // unnecessary indexes). 197 for _, def := range stmt.Defs { 198 switch def := def.(type) { 199 case *tree.ForeignKeyConstraintTableDef: 200 tc.resolveFK(tab, def) 201 } 202 } 203 204 // Add the new table to the catalog. 205 tc.AddTable(tab) 206 207 return tab 208 } 209 210 func (tc *Catalog) createVirtualTable(stmt *tree.CreateTable) *Table { 211 tab := &Table{ 212 TabID: tc.nextStableID(), 213 TabName: stmt.Table, 214 Catalog: tc, 215 IsVirtual: true, 216 } 217 218 // Add the dummy PK column. 219 tab.Columns = []*Column{{ 220 Ordinal: 0, 221 Hidden: true, 222 Nullable: false, 223 Name: "crdb_internal_vtable_pk", 224 Type: types.Int, 225 }} 226 227 for _, def := range stmt.Defs { 228 switch def := def.(type) { 229 case *tree.ColumnTableDef: 230 tab.addColumn(def) 231 } 232 } 233 234 tab.Families = []*Family{{FamName: "primary", Ordinal: 0, table: tab}} 235 for colOrd, col := range tab.Columns { 236 tab.Families[0].Columns = append(tab.Families[0].Columns, 237 cat.FamilyColumn{Column: col, Ordinal: colOrd}) 238 } 239 240 tab.addPrimaryColumnIndex(tab.Columns[0].Name) 241 return tab 242 } 243 244 // CreateTableAs creates a table in the catalog with the given name and 245 // columns. It should be used for creating a table from the CREATE TABLE <name> 246 // AS <query> syntax. In addition to the provided columns, CreateTableAs adds a 247 // unique rowid column as the primary key. It returns a pointer to the new 248 // table. 249 func (tc *Catalog) CreateTableAs(name tree.TableName, columns []*Column) *Table { 250 // Update the table name to include catalog and schema if not provided. 251 tc.qualifyTableName(&name) 252 253 tab := &Table{TabID: tc.nextStableID(), TabName: name, Catalog: tc, Columns: columns} 254 255 rowid := &Column{ 256 Ordinal: tab.ColumnCount(), 257 Name: "rowid", 258 Type: types.Int, 259 Hidden: true, 260 DefaultExpr: &uniqueRowIDString, 261 } 262 tab.Columns = append(tab.Columns, rowid) 263 tab.addPrimaryColumnIndex("rowid") 264 265 // Add the new table to the catalog. 266 tc.AddTable(tab) 267 268 return tab 269 } 270 271 // resolveFK processes a foreign key constraint. 272 func (tc *Catalog) resolveFK(tab *Table, d *tree.ForeignKeyConstraintTableDef) { 273 fromCols := make([]int, len(d.FromCols)) 274 for i, c := range d.FromCols { 275 fromCols[i] = tab.FindOrdinal(string(c)) 276 } 277 278 var targetTable *Table 279 if d.Table.ObjectName == tab.Name() { 280 targetTable = tab 281 } else { 282 targetTable = tc.Table(&d.Table) 283 } 284 285 toCols := make([]int, len(d.ToCols)) 286 for i, c := range d.ToCols { 287 toCols[i] = targetTable.FindOrdinal(string(c)) 288 } 289 290 constraintName := string(d.Name) 291 if constraintName == "" { 292 constraintName = fmt.Sprintf( 293 "fk_%s_ref_%s", string(d.FromCols[0]), targetTable.TabName.Table(), 294 ) 295 } 296 297 // Foreign keys require indexes in both tables: 298 // 299 // 1. In the target table, we need an index because adding a new row to the 300 // source table requires looking up whether there is a matching value in 301 // the target table. This index should already exist because a unique 302 // constraint is required on the target table (it's a foreign *key*). 303 // 304 // 2. In the source table, we need an index because removing a row from the 305 // target table requires looking up whether there would be orphan values 306 // left in the source table. This index does not need to be unique; in 307 // fact, if an existing index has the relevant columns as a prefix, that 308 // is good enough. 309 310 // matches returns true if the key columns in the given index match the given 311 // columns. If strict is false, it is acceptable if the given columns are a 312 // prefix of the index key columns. 313 matches := func(idx *Index, cols []int, strict bool) bool { 314 if idx.LaxKeyColumnCount() < len(cols) { 315 return false 316 } 317 if strict && idx.LaxKeyColumnCount() > len(cols) { 318 return false 319 } 320 for i := range cols { 321 if idx.Column(i).Ordinal != cols[i] { 322 return false 323 } 324 } 325 return true 326 } 327 328 // 1. Verify that the target table has a unique index. 329 var targetIndex *Index 330 for _, idx := range targetTable.Indexes { 331 if matches(idx, toCols, true /* strict */) { 332 targetIndex = idx 333 break 334 } 335 } 336 if targetIndex == nil { 337 panic(fmt.Errorf( 338 "there is no unique constraint matching given keys for referenced table %s", 339 targetTable.Name(), 340 )) 341 } 342 343 // 2. Search for an existing index in the source table; add it if necessary. 344 found := false 345 for _, idx := range tab.Indexes { 346 if matches(idx, fromCols, false /* strict */) { 347 found = true 348 break 349 } 350 } 351 if !found { 352 // Add a non-unique index on fromCols. 353 idx := tree.IndexTableDef{ 354 Name: tree.Name(fmt.Sprintf("%s_auto_index_%s", tab.TabName.Table(), constraintName)), 355 Columns: make(tree.IndexElemList, len(fromCols)), 356 } 357 for i, c := range fromCols { 358 idx.Columns[i].Column = tab.Columns[c].ColName() 359 idx.Columns[i].Direction = tree.Ascending 360 } 361 tab.addIndex(&idx, nonUniqueIndex) 362 } 363 364 fk := ForeignKeyConstraint{ 365 name: constraintName, 366 originTableID: tab.ID(), 367 referencedTableID: targetTable.ID(), 368 originColumnOrdinals: fromCols, 369 referencedColumnOrdinals: toCols, 370 validated: true, 371 matchMethod: d.Match, 372 deleteAction: d.Actions.Delete, 373 updateAction: d.Actions.Update, 374 } 375 tab.outboundFKs = append(tab.outboundFKs, fk) 376 targetTable.inboundFKs = append(targetTable.inboundFKs, fk) 377 } 378 379 func (tt *Table) addColumn(def *tree.ColumnTableDef) { 380 nullable := !def.PrimaryKey.IsPrimaryKey && def.Nullable.Nullability != tree.NotNull 381 col := &Column{ 382 Ordinal: tt.ColumnCount(), 383 Name: string(def.Name), 384 Type: tree.MustBeStaticallyKnownType(def.Type), 385 Nullable: nullable, 386 } 387 388 // Look for name suffixes indicating this is a mutation column. 389 if name, ok := extractWriteOnlyColumn(def); ok { 390 col.Name = name 391 tt.writeOnlyColCount++ 392 } else if name, ok := extractDeleteOnlyColumn(def); ok { 393 col.Name = name 394 tt.deleteOnlyColCount++ 395 } 396 397 if def.DefaultExpr.Expr != nil { 398 s := serializeTableDefExpr(def.DefaultExpr.Expr) 399 col.DefaultExpr = &s 400 } 401 402 if def.Computed.Expr != nil { 403 s := serializeTableDefExpr(def.Computed.Expr) 404 col.ComputedExpr = &s 405 } 406 407 tt.Columns = append(tt.Columns, col) 408 } 409 410 func (tt *Table) addIndex(def *tree.IndexTableDef, typ indexType) *Index { 411 idx := &Index{ 412 IdxName: tt.makeIndexName(def.Name, typ), 413 Unique: typ != nonUniqueIndex, 414 Inverted: def.Inverted, 415 IdxZone: &zonepb.ZoneConfig{}, 416 table: tt, 417 partitionBy: def.PartitionBy, 418 } 419 420 // Look for name suffixes indicating this is a mutation index. 421 if name, ok := extractWriteOnlyIndex(def); ok { 422 idx.IdxName = name 423 tt.writeOnlyIdxCount++ 424 } else if name, ok := extractDeleteOnlyIndex(def); ok { 425 idx.IdxName = name 426 tt.deleteOnlyIdxCount++ 427 } 428 429 // Add explicit columns and mark primary key columns as not null. 430 notNullIndex := true 431 for _, colDef := range def.Columns { 432 col := idx.addColumn(tt, string(colDef.Column), colDef.Direction, keyCol) 433 434 if typ == primaryIndex { 435 col.Nullable = false 436 } 437 438 if col.Nullable { 439 notNullIndex = false 440 } 441 } 442 443 if typ == primaryIndex { 444 var pkOrdinals util.FastIntSet 445 for _, c := range idx.Columns { 446 pkOrdinals.Add(c.Ordinal) 447 } 448 // Add the rest of the columns in the table. 449 for i, n := 0, tt.DeletableColumnCount(); i < n; i++ { 450 if !pkOrdinals.Contains(i) { 451 idx.addColumnByOrdinal(tt, i, tree.Ascending, nonKeyCol) 452 } 453 } 454 if len(tt.Indexes) != 0 { 455 panic("primary index should always be 0th index") 456 } 457 idx.ordinal = len(tt.Indexes) 458 tt.Indexes = append(tt.Indexes, idx) 459 return idx 460 } 461 462 // Add implicit key columns from primary index. 463 pkCols := tt.Indexes[cat.PrimaryIndex].Columns[:tt.Indexes[cat.PrimaryIndex].KeyCount] 464 for _, pkCol := range pkCols { 465 // Only add columns that aren't already part of index. 466 found := false 467 for _, colDef := range def.Columns { 468 if pkCol.ColName() == colDef.Column { 469 found = true 470 } 471 } 472 473 if !found { 474 name := string(pkCol.ColName()) 475 476 if typ == uniqueIndex { 477 // If unique index has no NULL columns, then the implicit columns 478 // are added as storing columns. Otherwise, they become part of the 479 // strict key, since they're needed to ensure uniqueness (but they 480 // are not part of the lax key). 481 if notNullIndex { 482 idx.addColumn(tt, name, tree.Ascending, nonKeyCol) 483 } else { 484 idx.addColumn(tt, name, tree.Ascending, strictKeyCol) 485 } 486 } else { 487 // Implicit columns are always added to the key for a non-unique 488 // index. In addition, there is no separate lax key, so the lax 489 // key column count = key column count. 490 idx.addColumn(tt, name, tree.Ascending, keyCol) 491 } 492 } 493 } 494 495 // Add storing columns. 496 for _, name := range def.Storing { 497 // Only add storing columns that weren't added as part of adding implicit 498 // key columns. 499 found := false 500 for _, pkCol := range pkCols { 501 if name == pkCol.ColName() { 502 found = true 503 } 504 } 505 if !found { 506 idx.addColumn(tt, string(name), tree.Ascending, nonKeyCol) 507 } 508 } 509 510 // Add partial index predicate. 511 if def.Predicate != nil { 512 idx.predicate = tree.Serialize(def.Predicate) 513 } 514 515 idx.ordinal = len(tt.Indexes) 516 tt.Indexes = append(tt.Indexes, idx) 517 518 return idx 519 } 520 521 func (tt *Table) makeIndexName(defName tree.Name, typ indexType) string { 522 name := string(defName) 523 if name == "" { 524 if typ == primaryIndex { 525 name = "primary" 526 } else { 527 name = "secondary" 528 } 529 } 530 return name 531 } 532 533 func (tt *Table) addFamily(def *tree.FamilyTableDef) { 534 // Synthesize name if one was not provided. 535 name := string(def.Name) 536 if name == "" { 537 name = fmt.Sprintf("family%d", len(tt.Families)+1) 538 } 539 540 family := &Family{ 541 FamName: name, 542 Ordinal: tt.FamilyCount(), 543 table: tt, 544 } 545 546 // Add columns to family. 547 for _, defCol := range def.Columns { 548 ord := tt.FindOrdinal(string(defCol)) 549 col := tt.Column(ord) 550 family.Columns = append(family.Columns, cat.FamilyColumn{Column: col, Ordinal: ord}) 551 } 552 553 tt.Families = append(tt.Families, family) 554 } 555 556 func (ti *Index) addColumn( 557 tt *Table, name string, direction tree.Direction, colType colType, 558 ) *Column { 559 return ti.addColumnByOrdinal(tt, tt.FindOrdinal(name), direction, colType) 560 } 561 562 func (ti *Index) addColumnByOrdinal( 563 tt *Table, ord int, direction tree.Direction, colType colType, 564 ) *Column { 565 col := tt.Column(ord) 566 idxCol := cat.IndexColumn{ 567 Column: col, 568 Ordinal: ord, 569 Descending: direction == tree.Descending, 570 } 571 ti.Columns = append(ti.Columns, idxCol) 572 573 // Update key column counts. 574 switch colType { 575 case keyCol: 576 // Column is part of both any lax key, as well as the strict key. 577 ti.LaxKeyCount++ 578 ti.KeyCount++ 579 580 case strictKeyCol: 581 // Column is only part of the strict key. 582 ti.KeyCount++ 583 } 584 585 return col.(*Column) 586 } 587 588 func (tt *Table) addPrimaryColumnIndex(colName string) { 589 def := tree.IndexTableDef{ 590 Columns: tree.IndexElemList{{Column: tree.Name(colName), Direction: tree.Ascending}}, 591 } 592 tt.addIndex(&def, primaryIndex) 593 } 594 595 func extractWriteOnlyColumn(def *tree.ColumnTableDef) (name string, ok bool) { 596 if !strings.HasSuffix(string(def.Name), ":write-only") { 597 return "", false 598 } 599 return strings.TrimSuffix(string(def.Name), ":write-only"), true 600 } 601 602 func extractDeleteOnlyColumn(def *tree.ColumnTableDef) (name string, ok bool) { 603 if !strings.HasSuffix(string(def.Name), ":delete-only") { 604 return "", false 605 } 606 return strings.TrimSuffix(string(def.Name), ":delete-only"), true 607 } 608 609 func isMutationColumn(def *tree.ColumnTableDef) bool { 610 if _, ok := extractWriteOnlyColumn(def); ok { 611 return true 612 } 613 if _, ok := extractDeleteOnlyColumn(def); ok { 614 return true 615 } 616 return false 617 } 618 619 func extractWriteOnlyIndex(def *tree.IndexTableDef) (name string, ok bool) { 620 if !strings.HasSuffix(string(def.Name), ":write-only") { 621 return "", false 622 } 623 return strings.TrimSuffix(string(def.Name), ":write-only"), true 624 } 625 626 func extractDeleteOnlyIndex(def *tree.IndexTableDef) (name string, ok bool) { 627 if !strings.HasSuffix(string(def.Name), ":delete-only") { 628 return "", false 629 } 630 return strings.TrimSuffix(string(def.Name), ":delete-only"), true 631 } 632 633 func validatedCheckConstraint(def *tree.CheckConstraintTableDef) bool { 634 return !strings.HasSuffix(string(def.Name), ":unvalidated") 635 } 636 637 func serializeTableDefExpr(expr tree.Expr) string { 638 // Disallow any column references that are qualified with the table. The 639 // production table creation code verifies them and strips them away, so the 640 // stored expressions contain only unqualified column references. 641 preFn := func(expr tree.Expr) (recurse bool, newExpr tree.Expr, err error) { 642 if vBase, ok := expr.(tree.VarName); ok { 643 v, err := vBase.NormalizeVarName() 644 if err != nil { 645 return false, nil, err 646 } 647 if c, ok := v.(*tree.ColumnItem); ok && c.TableName != nil { 648 return false, nil, fmt.Errorf( 649 "expressions in table definitions must not contain qualified column references: %s", c, 650 ) 651 } 652 } 653 return true, expr, nil 654 } 655 _, err := tree.SimpleVisit(expr, preFn) 656 if err != nil { 657 panic(err) 658 } 659 return tree.Serialize(expr) 660 }