github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/testutils/testcat/test_catalog.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 "context" 15 "fmt" 16 "sort" 17 "time" 18 19 "github.com/cockroachdb/cockroach/pkg/config/zonepb" 20 "github.com/cockroachdb/cockroach/pkg/roachpb" 21 "github.com/cockroachdb/cockroach/pkg/settings/cluster" 22 "github.com/cockroachdb/cockroach/pkg/sql/opt/cat" 23 "github.com/cockroachdb/cockroach/pkg/sql/parser" 24 "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode" 25 "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror" 26 "github.com/cockroachdb/cockroach/pkg/sql/privilege" 27 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 28 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 29 "github.com/cockroachdb/cockroach/pkg/sql/stats" 30 "github.com/cockroachdb/cockroach/pkg/sql/types" 31 "github.com/cockroachdb/cockroach/pkg/util/treeprinter" 32 "github.com/cockroachdb/errors" 33 ) 34 35 const ( 36 // testDB is the default current database for testing purposes. 37 testDB = "t" 38 ) 39 40 // Catalog implements the cat.Catalog interface for testing purposes. 41 type Catalog struct { 42 tree.TypeReferenceResolver 43 testSchema Schema 44 counter int 45 } 46 47 type dataSource interface { 48 cat.DataSource 49 fqName() cat.DataSourceName 50 } 51 52 var _ cat.Catalog = &Catalog{} 53 54 // New creates a new empty instance of the test catalog. 55 func New() *Catalog { 56 return &Catalog{ 57 testSchema: Schema{ 58 SchemaID: 1, 59 SchemaName: cat.SchemaName{ 60 CatalogName: testDB, 61 SchemaName: tree.PublicSchemaName, 62 ExplicitSchema: true, 63 ExplicitCatalog: true, 64 }, 65 dataSources: make(map[string]dataSource), 66 }, 67 } 68 } 69 70 // ResolveSchema is part of the cat.Catalog interface. 71 func (tc *Catalog) ResolveSchema( 72 _ context.Context, _ cat.Flags, name *cat.SchemaName, 73 ) (cat.Schema, cat.SchemaName, error) { 74 // This is a simplified version of tree.TableName.ResolveTarget() from 75 // sql/tree/name_resolution.go. 76 toResolve := *name 77 if name.ExplicitSchema { 78 if name.ExplicitCatalog { 79 // Already 2 parts: nothing to do. 80 return tc.resolveSchema(&toResolve) 81 } 82 83 // Only one part specified; assume it's a schema name and determine 84 // whether the current database has that schema. 85 toResolve.CatalogName = testDB 86 if sch, resName, err := tc.resolveSchema(&toResolve); err == nil { 87 return sch, resName, nil 88 } 89 90 // No luck so far. Compatibility with CockroachDB v1.1: use D.public 91 // instead. 92 toResolve.CatalogName = name.SchemaName 93 toResolve.SchemaName = tree.PublicSchemaName 94 toResolve.ExplicitCatalog = true 95 return tc.resolveSchema(&toResolve) 96 } 97 98 // Neither schema or catalog was specified, so use t.public. 99 toResolve.CatalogName = tree.Name(testDB) 100 toResolve.SchemaName = tree.PublicSchemaName 101 return tc.resolveSchema(&toResolve) 102 } 103 104 // ResolveDataSource is part of the cat.Catalog interface. 105 func (tc *Catalog) ResolveDataSource( 106 _ context.Context, _ cat.Flags, name *cat.DataSourceName, 107 ) (cat.DataSource, cat.DataSourceName, error) { 108 // This is a simplified version of tree.TableName.ResolveExisting() from 109 // sql/tree/name_resolution.go. 110 var ds cat.DataSource 111 var err error 112 toResolve := *name 113 if name.ExplicitSchema && name.ExplicitCatalog { 114 // Already 3 parts. 115 ds, err = tc.resolveDataSource(&toResolve) 116 if err == nil { 117 return ds, toResolve, nil 118 } 119 } else if name.ExplicitSchema { 120 // Two parts: Try to use the current database, and be satisfied if it's 121 // sufficient to find the object. 122 toResolve.CatalogName = testDB 123 if tab, err := tc.resolveDataSource(&toResolve); err == nil { 124 return tab, toResolve, nil 125 } 126 127 // No luck so far. Compatibility with CockroachDB v1.1: try D.public.T 128 // instead. 129 toResolve.CatalogName = name.SchemaName 130 toResolve.SchemaName = tree.PublicSchemaName 131 toResolve.ExplicitCatalog = true 132 ds, err = tc.resolveDataSource(&toResolve) 133 if err == nil { 134 return ds, toResolve, nil 135 } 136 } else { 137 // This is a naked data source name. Use the current database. 138 toResolve.CatalogName = tree.Name(testDB) 139 toResolve.SchemaName = tree.PublicSchemaName 140 ds, err = tc.resolveDataSource(&toResolve) 141 if err == nil { 142 return ds, toResolve, nil 143 } 144 } 145 146 // If we didn't find the table in the catalog, try to lazily resolve it as 147 // a virtual table. 148 if table, ok := resolveVTable(name); ok { 149 // We rely on the check in CreateTable against this table's schema to infer 150 // that this is a virtual table. 151 return tc.CreateTable(table), *name, nil 152 } 153 154 // If this didn't end up being a virtual table, then return the original 155 // error returned by resolveDataSource. 156 return nil, cat.DataSourceName{}, err 157 } 158 159 // ResolveDataSourceByID is part of the cat.Catalog interface. 160 func (tc *Catalog) ResolveDataSourceByID( 161 ctx context.Context, flags cat.Flags, id cat.StableID, 162 ) (_ cat.DataSource, isAdding bool, _ error) { 163 for _, ds := range tc.testSchema.dataSources { 164 if ds.ID() == id { 165 return ds, false, nil 166 } 167 } 168 return nil, false, pgerror.Newf(pgcode.UndefinedTable, 169 "relation [%d] does not exist", id) 170 } 171 172 // CheckPrivilege is part of the cat.Catalog interface. 173 func (tc *Catalog) CheckPrivilege(ctx context.Context, o cat.Object, priv privilege.Kind) error { 174 return tc.CheckAnyPrivilege(ctx, o) 175 } 176 177 // CheckAnyPrivilege is part of the cat.Catalog interface. 178 func (tc *Catalog) CheckAnyPrivilege(ctx context.Context, o cat.Object) error { 179 switch t := o.(type) { 180 case *Schema: 181 if t.Revoked { 182 return pgerror.Newf(pgcode.InsufficientPrivilege, "user does not have privilege to access %v", t.SchemaName) 183 } 184 case *Table: 185 if t.Revoked { 186 return pgerror.Newf(pgcode.InsufficientPrivilege, "user does not have privilege to access %v", t.TabName) 187 } 188 case *View: 189 if t.Revoked { 190 return pgerror.Newf(pgcode.InsufficientPrivilege, "user does not have privilege to access %v", t.ViewName) 191 } 192 case *Sequence: 193 if t.Revoked { 194 return pgerror.Newf(pgcode.InsufficientPrivilege, "user does not have privilege to access %v", t.SeqName) 195 } 196 default: 197 panic("invalid Object") 198 } 199 return nil 200 } 201 202 // HasAdminRole is part of the cat.Catalog interface. 203 func (tc *Catalog) HasAdminRole(ctx context.Context) (bool, error) { 204 return true, nil 205 } 206 207 // RequireAdminRole is part of the cat.Catalog interface. 208 func (tc *Catalog) RequireAdminRole(ctx context.Context, action string) error { 209 return nil 210 } 211 212 // FullyQualifiedName is part of the cat.Catalog interface. 213 func (tc *Catalog) FullyQualifiedName( 214 ctx context.Context, ds cat.DataSource, 215 ) (cat.DataSourceName, error) { 216 return ds.(dataSource).fqName(), nil 217 } 218 219 func (tc *Catalog) resolveSchema(toResolve *cat.SchemaName) (cat.Schema, cat.SchemaName, error) { 220 if string(toResolve.CatalogName) != testDB { 221 return nil, cat.SchemaName{}, pgerror.Newf(pgcode.InvalidSchemaName, 222 "target database or schema does not exist") 223 } 224 225 if string(toResolve.SchemaName) != tree.PublicSchema { 226 return nil, cat.SchemaName{}, pgerror.Newf(pgcode.InvalidName, 227 "schema cannot be modified: %q", tree.ErrString(toResolve)) 228 } 229 230 return &tc.testSchema, *toResolve, nil 231 } 232 233 // resolveDataSource checks if `toResolve` exists among the data sources in this 234 // Catalog. If it does, returns the corresponding data source. Otherwise, it 235 // returns an error. 236 func (tc *Catalog) resolveDataSource(toResolve *cat.DataSourceName) (cat.DataSource, error) { 237 if table, ok := tc.testSchema.dataSources[toResolve.FQString()]; ok { 238 return table, nil 239 } 240 return nil, pgerror.Newf(pgcode.UndefinedTable, 241 "no data source matches prefix: %q", tree.ErrString(toResolve)) 242 } 243 244 // Schema returns the singleton test schema. 245 func (tc *Catalog) Schema() *Schema { 246 return &tc.testSchema 247 } 248 249 // Table returns the test table that was previously added with the given name. 250 func (tc *Catalog) Table(name *tree.TableName) *Table { 251 ds, _, err := tc.ResolveDataSource(context.TODO(), cat.Flags{}, name) 252 if err != nil { 253 panic(err) 254 } 255 if tab, ok := ds.(*Table); ok { 256 return tab 257 } 258 panic(pgerror.Newf(pgcode.WrongObjectType, 259 "\"%q\" is not a table", tree.ErrString(name))) 260 } 261 262 // AddTable adds the given test table to the catalog. 263 func (tc *Catalog) AddTable(tab *Table) { 264 fq := tab.TabName.FQString() 265 if _, ok := tc.testSchema.dataSources[fq]; ok { 266 panic(pgerror.Newf(pgcode.DuplicateObject, 267 "table %q already exists", tree.ErrString(&tab.TabName))) 268 } 269 tc.testSchema.dataSources[fq] = tab 270 } 271 272 // View returns the test view that was previously added with the given name. 273 func (tc *Catalog) View(name *cat.DataSourceName) *View { 274 ds, _, err := tc.ResolveDataSource(context.TODO(), cat.Flags{}, name) 275 if err != nil { 276 panic(err) 277 } 278 if vw, ok := ds.(*View); ok { 279 return vw 280 } 281 panic(pgerror.Newf(pgcode.WrongObjectType, 282 "\"%q\" is not a view", tree.ErrString(name))) 283 } 284 285 // AddView adds the given test view to the catalog. 286 func (tc *Catalog) AddView(view *View) { 287 fq := view.ViewName.FQString() 288 if _, ok := tc.testSchema.dataSources[fq]; ok { 289 panic(pgerror.Newf(pgcode.DuplicateObject, 290 "view %q already exists", tree.ErrString(&view.ViewName))) 291 } 292 tc.testSchema.dataSources[fq] = view 293 } 294 295 // AddSequence adds the given test sequence to the catalog. 296 func (tc *Catalog) AddSequence(seq *Sequence) { 297 fq := seq.SeqName.FQString() 298 if _, ok := tc.testSchema.dataSources[fq]; ok { 299 panic(pgerror.Newf(pgcode.DuplicateObject, 300 "sequence %q already exists", tree.ErrString(&seq.SeqName))) 301 } 302 tc.testSchema.dataSources[fq] = seq 303 } 304 305 // ExecuteMultipleDDL parses the given semicolon-separated DDL SQL statements 306 // and applies each of them to the test catalog. 307 func (tc *Catalog) ExecuteMultipleDDL(sql string) error { 308 stmts, err := parser.Parse(sql) 309 if err != nil { 310 return err 311 } 312 313 for _, stmt := range stmts { 314 _, err := tc.ExecuteDDL(stmt.SQL) 315 if err != nil { 316 return err 317 } 318 } 319 320 return nil 321 } 322 323 // ExecuteDDL parses the given DDL SQL statement and creates objects in the test 324 // catalog. This is used to test without spinning up a cluster. 325 func (tc *Catalog) ExecuteDDL(sql string) (string, error) { 326 stmt, err := parser.ParseOne(sql) 327 if err != nil { 328 return "", err 329 } 330 331 switch stmt := stmt.AST.(type) { 332 case *tree.CreateTable: 333 tc.CreateTable(stmt) 334 return "", nil 335 336 case *tree.CreateView: 337 tc.CreateView(stmt) 338 return "", nil 339 340 case *tree.AlterTable: 341 tc.AlterTable(stmt) 342 return "", nil 343 344 case *tree.DropTable: 345 tc.DropTable(stmt) 346 return "", nil 347 348 case *tree.CreateSequence: 349 tc.CreateSequence(stmt) 350 return "", nil 351 352 case *tree.SetZoneConfig: 353 tc.SetZoneConfig(stmt) 354 return "", nil 355 356 case *tree.ShowCreate: 357 tn := stmt.Name.ToTableName() 358 ds, _, err := tc.ResolveDataSource(context.Background(), cat.Flags{}, &tn) 359 if err != nil { 360 return "", err 361 } 362 return ds.(fmt.Stringer).String(), nil 363 364 default: 365 return "", errors.AssertionFailedf("unsupported statement: %v", stmt) 366 } 367 } 368 369 // nextStableID returns a new unique StableID for a data source. 370 func (tc *Catalog) nextStableID() cat.StableID { 371 tc.counter++ 372 373 // 53 is a magic number derived from how CRDB internally stores tables. The 374 // first user table is 53. Use this to have the test catalog look more 375 // consistent with the real catalog. 376 return cat.StableID(53 + tc.counter - 1) 377 } 378 379 // qualifyTableName updates the given table name to include catalog and schema 380 // if not already included. 381 func (tc *Catalog) qualifyTableName(name *tree.TableName) { 382 hadExplicitSchema := name.ExplicitSchema 383 hadExplicitCatalog := name.ExplicitCatalog 384 name.ExplicitSchema = true 385 name.ExplicitCatalog = true 386 387 if hadExplicitSchema { 388 if hadExplicitCatalog { 389 // Already 3 parts: nothing to do. 390 return 391 } 392 393 if name.SchemaName == tree.PublicSchemaName { 394 // Use the current database. 395 name.CatalogName = testDB 396 return 397 } 398 399 // Compatibility with CockroachDB v1.1: use D.public.T. 400 name.CatalogName = name.SchemaName 401 name.SchemaName = tree.PublicSchemaName 402 return 403 } 404 405 // Use the current database. 406 name.CatalogName = testDB 407 name.SchemaName = tree.PublicSchemaName 408 } 409 410 // Schema implements the cat.Schema interface for testing purposes. 411 type Schema struct { 412 SchemaID cat.StableID 413 SchemaName cat.SchemaName 414 415 // If Revoked is true, then the user has had privileges on the schema revoked. 416 Revoked bool 417 418 dataSources map[string]dataSource 419 } 420 421 var _ cat.Schema = &Schema{} 422 423 // ID is part of the cat.Object interface. 424 func (s *Schema) ID() cat.StableID { 425 return s.SchemaID 426 } 427 428 // PostgresDescriptorID is part of the cat.Object interface. 429 func (s *Schema) PostgresDescriptorID() cat.StableID { 430 return s.SchemaID 431 } 432 433 // Equals is part of the cat.Object interface. 434 func (s *Schema) Equals(other cat.Object) bool { 435 otherSchema, ok := other.(*Schema) 436 return ok && s.SchemaID == otherSchema.SchemaID 437 } 438 439 // Name is part of the cat.Schema interface. 440 func (s *Schema) Name() *cat.SchemaName { 441 return &s.SchemaName 442 } 443 444 // GetDataSourceNames is part of the cat.Schema interface. 445 func (s *Schema) GetDataSourceNames(ctx context.Context) ([]cat.DataSourceName, error) { 446 var keys []string 447 for k := range s.dataSources { 448 keys = append(keys, k) 449 } 450 sort.Strings(keys) 451 var res []cat.DataSourceName 452 for _, k := range keys { 453 res = append(res, s.dataSources[k].fqName()) 454 } 455 return res, nil 456 } 457 458 // View implements the cat.View interface for testing purposes. 459 type View struct { 460 ViewID cat.StableID 461 ViewVersion int 462 ViewName cat.DataSourceName 463 QueryText string 464 ColumnNames tree.NameList 465 466 // If Revoked is true, then the user has had privileges on the view revoked. 467 Revoked bool 468 } 469 470 var _ cat.View = &View{} 471 472 func (tv *View) String() string { 473 tp := treeprinter.New() 474 cat.FormatView(tv, tp) 475 return tp.String() 476 } 477 478 // ID is part of the cat.DataSource interface. 479 func (tv *View) ID() cat.StableID { 480 return tv.ViewID 481 } 482 483 // PostgresDescriptorID is part of the cat.Object interface. 484 func (tv *View) PostgresDescriptorID() cat.StableID { 485 return tv.ViewID 486 } 487 488 // Equals is part of the cat.Object interface. 489 func (tv *View) Equals(other cat.Object) bool { 490 otherView, ok := other.(*View) 491 if !ok { 492 return false 493 } 494 return tv.ViewID == otherView.ViewID && tv.ViewVersion == otherView.ViewVersion 495 } 496 497 // Name is part of the cat.DataSource interface. 498 func (tv *View) Name() tree.Name { 499 return tv.ViewName.ObjectName 500 } 501 502 // fqName is part of the dataSource interface. 503 func (tv *View) fqName() cat.DataSourceName { 504 return tv.ViewName 505 } 506 507 // IsSystemView is part of the cat.View interface. 508 func (tv *View) IsSystemView() bool { 509 return false 510 } 511 512 // Query is part of the cat.View interface. 513 func (tv *View) Query() string { 514 return tv.QueryText 515 } 516 517 // ColumnNameCount is part of the cat.View interface. 518 func (tv *View) ColumnNameCount() int { 519 return len(tv.ColumnNames) 520 } 521 522 // ColumnName is part of the cat.View interface. 523 func (tv *View) ColumnName(i int) tree.Name { 524 return tv.ColumnNames[i] 525 } 526 527 // Table implements the cat.Table interface for testing purposes. 528 type Table struct { 529 TabID cat.StableID 530 TabVersion int 531 TabName tree.TableName 532 Columns []*Column 533 Indexes []*Index 534 Stats TableStats 535 Checks []cat.CheckConstraint 536 Families []*Family 537 IsVirtual bool 538 Catalog cat.Catalog 539 540 // If Revoked is true, then the user has had privileges on the table revoked. 541 Revoked bool 542 543 writeOnlyColCount int 544 deleteOnlyColCount int 545 writeOnlyIdxCount int 546 deleteOnlyIdxCount int 547 548 // interleaved is true if the table's rows are interleaved with rows from 549 // other table(s). 550 interleaved bool 551 552 outboundFKs []ForeignKeyConstraint 553 inboundFKs []ForeignKeyConstraint 554 } 555 556 var _ cat.Table = &Table{} 557 558 func (tt *Table) String() string { 559 tp := treeprinter.New() 560 cat.FormatTable(tt.Catalog, tt, tp) 561 return tp.String() 562 } 563 564 // ID is part of the cat.DataSource interface. 565 func (tt *Table) ID() cat.StableID { 566 return tt.TabID 567 } 568 569 // PostgresDescriptorID is part of the cat.Object interface. 570 func (tt *Table) PostgresDescriptorID() cat.StableID { 571 return tt.TabID 572 } 573 574 // Equals is part of the cat.Object interface. 575 func (tt *Table) Equals(other cat.Object) bool { 576 otherTable, ok := other.(*Table) 577 if !ok { 578 return false 579 } 580 return tt.TabID == otherTable.TabID && tt.TabVersion == otherTable.TabVersion 581 } 582 583 // Name is part of the cat.DataSource interface. 584 func (tt *Table) Name() tree.Name { 585 return tt.TabName.ObjectName 586 } 587 588 // fqName is part of the dataSource interface. 589 func (tt *Table) fqName() cat.DataSourceName { 590 return tt.TabName 591 } 592 593 // IsVirtualTable is part of the cat.Table interface. 594 func (tt *Table) IsVirtualTable() bool { 595 return tt.IsVirtual 596 } 597 598 // ColumnCount is part of the cat.Table interface. 599 func (tt *Table) ColumnCount() int { 600 return len(tt.Columns) - tt.writeOnlyColCount - tt.deleteOnlyColCount 601 } 602 603 // WritableColumnCount is part of the cat.Table interface. 604 func (tt *Table) WritableColumnCount() int { 605 return len(tt.Columns) - tt.deleteOnlyColCount 606 } 607 608 // DeletableColumnCount is part of the cat.Table interface. 609 func (tt *Table) DeletableColumnCount() int { 610 return len(tt.Columns) 611 } 612 613 // Column is part of the cat.Table interface. 614 func (tt *Table) Column(i int) cat.Column { 615 return tt.Columns[i] 616 } 617 618 // IndexCount is part of the cat.Table interface. 619 func (tt *Table) IndexCount() int { 620 return len(tt.Indexes) - tt.writeOnlyIdxCount - tt.deleteOnlyIdxCount 621 } 622 623 // WritableIndexCount is part of the cat.Table interface. 624 func (tt *Table) WritableIndexCount() int { 625 return len(tt.Indexes) - tt.deleteOnlyIdxCount 626 } 627 628 // DeletableIndexCount is part of the cat.Table interface. 629 func (tt *Table) DeletableIndexCount() int { 630 return len(tt.Indexes) 631 } 632 633 // Index is part of the cat.Table interface. 634 func (tt *Table) Index(i cat.IndexOrdinal) cat.Index { 635 return tt.Indexes[i] 636 } 637 638 // StatisticCount is part of the cat.Table interface. 639 func (tt *Table) StatisticCount() int { 640 return len(tt.Stats) 641 } 642 643 // Statistic is part of the cat.Table interface. 644 func (tt *Table) Statistic(i int) cat.TableStatistic { 645 return tt.Stats[i] 646 } 647 648 // CheckCount is part of the cat.Table interface. 649 func (tt *Table) CheckCount() int { 650 return len(tt.Checks) 651 } 652 653 // Check is part of the cat.Table interface. 654 func (tt *Table) Check(i int) cat.CheckConstraint { 655 return tt.Checks[i] 656 } 657 658 // FamilyCount is part of the cat.Table interface. 659 func (tt *Table) FamilyCount() int { 660 return len(tt.Families) 661 } 662 663 // Family is part of the cat.Table interface. 664 func (tt *Table) Family(i int) cat.Family { 665 return tt.Families[i] 666 } 667 668 // OutboundForeignKeyCount is part of the cat.Table interface. 669 func (tt *Table) OutboundForeignKeyCount() int { 670 return len(tt.outboundFKs) 671 } 672 673 // OutboundForeignKey is part of the cat.Table interface. 674 func (tt *Table) OutboundForeignKey(i int) cat.ForeignKeyConstraint { 675 return &tt.outboundFKs[i] 676 } 677 678 // InboundForeignKeyCount is part of the cat.Table interface. 679 func (tt *Table) InboundForeignKeyCount() int { 680 return len(tt.inboundFKs) 681 } 682 683 // InboundForeignKey is part of the cat.Table interface. 684 func (tt *Table) InboundForeignKey(i int) cat.ForeignKeyConstraint { 685 return &tt.inboundFKs[i] 686 } 687 688 // FindOrdinal returns the ordinal of the column with the given name. 689 func (tt *Table) FindOrdinal(name string) int { 690 for i, col := range tt.Columns { 691 if col.Name == name { 692 return i 693 } 694 } 695 panic(pgerror.Newf(pgcode.UndefinedColumn, 696 "cannot find column %q in table %q", 697 tree.ErrString((*tree.Name)(&name)), 698 tree.ErrString(&tt.TabName), 699 )) 700 } 701 702 // Index implements the cat.Index interface for testing purposes. 703 type Index struct { 704 IdxName string 705 706 // KeyCount is the number of columns that make up the unique key for the 707 // index. See the cat.Index.KeyColumnCount for more details. 708 KeyCount int 709 710 // LaxKeyCount is the number of columns that make up a lax key for the 711 // index, which allows duplicate rows when at least one of the values is 712 // NULL. See the cat.Index.LaxKeyColumnCount for more details. 713 LaxKeyCount int 714 715 // Unique is true if this index is declared as UNIQUE in the schema. 716 Unique bool 717 718 // Inverted is true when this index is an inverted index. 719 Inverted bool 720 721 Columns []cat.IndexColumn 722 723 // IdxZone is the zone associated with the index. This may be inherited from 724 // the parent table, database, or even the default zone. 725 IdxZone *zonepb.ZoneConfig 726 727 // Ordinal is the ordinal of this index in the table. 728 ordinal int 729 730 // table is a back reference to the table this index is on. 731 table *Table 732 733 // partitionBy is the partitioning clause that corresponds to this index. Used 734 // to implement PartitionByListPrefixes. 735 partitionBy *tree.PartitionBy 736 737 // predicate is the partial index predicate expression, if it exists. 738 predicate string 739 } 740 741 // ID is part of the cat.Index interface. 742 func (ti *Index) ID() cat.StableID { 743 return 1 + cat.StableID(ti.ordinal) 744 } 745 746 // Name is part of the cat.Index interface. 747 func (ti *Index) Name() tree.Name { 748 return tree.Name(ti.IdxName) 749 } 750 751 // Table is part of the cat.Index interface. 752 func (ti *Index) Table() cat.Table { 753 return ti.table 754 } 755 756 // Ordinal is part of the cat.Index interface. 757 func (ti *Index) Ordinal() int { 758 return ti.ordinal 759 } 760 761 // IsUnique is part of the cat.Index interface. 762 func (ti *Index) IsUnique() bool { 763 return ti.Unique 764 } 765 766 // IsInverted is part of the cat.Index interface. 767 func (ti *Index) IsInverted() bool { 768 return ti.Inverted 769 } 770 771 // ColumnCount is part of the cat.Index interface. 772 func (ti *Index) ColumnCount() int { 773 return len(ti.Columns) 774 } 775 776 // KeyColumnCount is part of the cat.Index interface. 777 func (ti *Index) KeyColumnCount() int { 778 return ti.KeyCount 779 } 780 781 // LaxKeyColumnCount is part of the cat.Index interface. 782 func (ti *Index) LaxKeyColumnCount() int { 783 return ti.LaxKeyCount 784 } 785 786 // Column is part of the cat.Index interface. 787 func (ti *Index) Column(i int) cat.IndexColumn { 788 return ti.Columns[i] 789 } 790 791 // Zone is part of the cat.Index interface. 792 func (ti *Index) Zone() cat.Zone { 793 return ti.IdxZone 794 } 795 796 // Span is part of the cat.Index interface. 797 func (ti *Index) Span() roachpb.Span { 798 panic("not implemented") 799 } 800 801 // Predicate is part of the cat.Index interface. It returns the predicate 802 // expression and true if the index is a partial index. If the index is not 803 // partial, the empty string and false is returned. 804 func (ti *Index) Predicate() (string, bool) { 805 return ti.predicate, ti.predicate != "" 806 } 807 808 // PartitionByListPrefixes is part of the cat.Index interface. 809 func (ti *Index) PartitionByListPrefixes() []tree.Datums { 810 ctx := context.Background() 811 p := ti.partitionBy 812 if p == nil { 813 return nil 814 } 815 if len(p.List) == 0 { 816 return nil 817 } 818 var res []tree.Datums 819 semaCtx := tree.MakeSemaContext() 820 evalCtx := tree.MakeTestingEvalContext(cluster.MakeTestingClusterSettings()) 821 for i := range p.Fields { 822 if i >= len(ti.Columns) || p.Fields[i] != ti.Columns[i].ColName() { 823 panic("partition by columns must be a prefix of the index columns") 824 } 825 } 826 for i := range p.List { 827 // Exprs contains a list of values. 828 for _, e := range p.List[i].Exprs { 829 var vals []tree.Expr 830 switch t := e.(type) { 831 case *tree.Tuple: 832 vals = t.Exprs 833 default: 834 vals = []tree.Expr{e} 835 } 836 837 // Cut off at DEFAULT, if present. 838 for i := range vals { 839 if _, ok := vals[i].(tree.DefaultVal); ok { 840 vals = vals[:i] 841 } 842 } 843 if len(vals) == 0 { 844 continue 845 } 846 d := make(tree.Datums, len(vals)) 847 for i := range vals { 848 c := tree.CastExpr{Expr: vals[i], Type: ti.Columns[i].DatumType()} 849 cTyped, err := c.TypeCheck(ctx, &semaCtx, nil) 850 if err != nil { 851 panic(err) 852 } 853 d[i], err = cTyped.Eval(&evalCtx) 854 if err != nil { 855 panic(err) 856 } 857 } 858 859 // TODO(radu): split into multiple prefixes if Subpartition is also by list. 860 // Note that this functionality should be kept in sync with the real catalog 861 // implementation (opt_catalog.go). 862 863 res = append(res, d) 864 } 865 } 866 return res 867 } 868 869 // InterleaveAncestorCount is part of the cat.Index interface. 870 func (ti *Index) InterleaveAncestorCount() int { 871 return 0 872 } 873 874 // InterleaveAncestor is part of the cat.Index interface. 875 func (ti *Index) InterleaveAncestor(i int) (table, index cat.StableID, numKeyCols int) { 876 panic("no interleavings") 877 } 878 879 // InterleavedByCount is part of the cat.Index interface. 880 func (ti *Index) InterleavedByCount() int { 881 return 0 882 } 883 884 // InterleavedBy is part of the cat.Index interface. 885 func (ti *Index) InterleavedBy(i int) (table, index cat.StableID) { 886 panic("no interleavings") 887 } 888 889 // Column implements the cat.Column interface for testing purposes. 890 type Column struct { 891 Ordinal int 892 Hidden bool 893 Nullable bool 894 Name string 895 Type *types.T 896 DefaultExpr *string 897 ComputedExpr *string 898 } 899 900 var _ cat.Column = &Column{} 901 902 // ColID is part of the cat.Index interface. 903 func (tc *Column) ColID() cat.StableID { 904 return 1 + cat.StableID(tc.Ordinal) 905 } 906 907 // IsNullable is part of the cat.Column interface. 908 func (tc *Column) IsNullable() bool { 909 return tc.Nullable 910 } 911 912 // ColName is part of the cat.Column interface. 913 func (tc *Column) ColName() tree.Name { 914 return tree.Name(tc.Name) 915 } 916 917 // DatumType is part of the cat.Column interface. 918 func (tc *Column) DatumType() *types.T { 919 return tc.Type 920 } 921 922 // ColTypePrecision is part of the cat.Column interface. 923 func (tc *Column) ColTypePrecision() int { 924 if tc.Type.Family() == types.ArrayFamily { 925 if tc.Type.ArrayContents().Family() == types.ArrayFamily { 926 panic(errors.AssertionFailedf("column type should never be a nested array")) 927 } 928 return int(tc.Type.ArrayContents().Precision()) 929 } 930 return int(tc.Type.Precision()) 931 } 932 933 // ColTypeWidth is part of the cat.Column interface. 934 func (tc *Column) ColTypeWidth() int { 935 if tc.Type.Family() == types.ArrayFamily { 936 if tc.Type.ArrayContents().Family() == types.ArrayFamily { 937 panic(errors.AssertionFailedf("column type should never be a nested array")) 938 } 939 return int(tc.Type.ArrayContents().Width()) 940 } 941 return int(tc.Type.Width()) 942 } 943 944 // ColTypeStr is part of the cat.Column interface. 945 func (tc *Column) ColTypeStr() string { 946 return tc.Type.SQLString() 947 } 948 949 // IsHidden is part of the cat.Column interface. 950 func (tc *Column) IsHidden() bool { 951 return tc.Hidden 952 } 953 954 // HasDefault is part of the cat.Column interface. 955 func (tc *Column) HasDefault() bool { 956 return tc.DefaultExpr != nil 957 } 958 959 // IsComputed is part of the cat.Column interface. 960 func (tc *Column) IsComputed() bool { 961 return tc.ComputedExpr != nil 962 } 963 964 // DefaultExprStr is part of the cat.Column interface. 965 func (tc *Column) DefaultExprStr() string { 966 return *tc.DefaultExpr 967 } 968 969 // ComputedExprStr is part of the cat.Column interface. 970 func (tc *Column) ComputedExprStr() string { 971 return *tc.ComputedExpr 972 } 973 974 // TableStat implements the cat.TableStatistic interface for testing purposes. 975 type TableStat struct { 976 js stats.JSONStatistic 977 tt *Table 978 } 979 980 var _ cat.TableStatistic = &TableStat{} 981 982 // CreatedAt is part of the cat.TableStatistic interface. 983 func (ts *TableStat) CreatedAt() time.Time { 984 d, err := tree.ParseDTimestamp(nil, ts.js.CreatedAt, time.Microsecond) 985 if err != nil { 986 panic(err) 987 } 988 return d.Time 989 } 990 991 // ColumnCount is part of the cat.TableStatistic interface. 992 func (ts *TableStat) ColumnCount() int { 993 return len(ts.js.Columns) 994 } 995 996 // ColumnOrdinal is part of the cat.TableStatistic interface. 997 func (ts *TableStat) ColumnOrdinal(i int) int { 998 return ts.tt.FindOrdinal(ts.js.Columns[i]) 999 } 1000 1001 // RowCount is part of the cat.TableStatistic interface. 1002 func (ts *TableStat) RowCount() uint64 { 1003 return ts.js.RowCount 1004 } 1005 1006 // DistinctCount is part of the cat.TableStatistic interface. 1007 func (ts *TableStat) DistinctCount() uint64 { 1008 return ts.js.DistinctCount 1009 } 1010 1011 // NullCount is part of the cat.TableStatistic interface. 1012 func (ts *TableStat) NullCount() uint64 { 1013 return ts.js.NullCount 1014 } 1015 1016 // Histogram is part of the cat.TableStatistic interface. 1017 func (ts *TableStat) Histogram() []cat.HistogramBucket { 1018 evalCtx := tree.MakeTestingEvalContext(cluster.MakeTestingClusterSettings()) 1019 if ts.js.HistogramColumnType == "" || ts.js.HistogramBuckets == nil { 1020 return nil 1021 } 1022 colTypeRef, err := parser.ParseType(ts.js.HistogramColumnType) 1023 if err != nil { 1024 panic(err) 1025 } 1026 colType := tree.MustBeStaticallyKnownType(colTypeRef) 1027 histogram := make([]cat.HistogramBucket, len(ts.js.HistogramBuckets)) 1028 for i := range histogram { 1029 bucket := &ts.js.HistogramBuckets[i] 1030 datum, err := sqlbase.ParseDatumStringAs(colType, bucket.UpperBound, &evalCtx) 1031 if err != nil { 1032 panic(err) 1033 } 1034 histogram[i] = cat.HistogramBucket{ 1035 NumEq: float64(bucket.NumEq), 1036 NumRange: float64(bucket.NumRange), 1037 DistinctRange: bucket.DistinctRange, 1038 UpperBound: datum, 1039 } 1040 } 1041 return histogram 1042 } 1043 1044 // TableStats is a slice of TableStat pointers. 1045 type TableStats []*TableStat 1046 1047 // Len is part of the Sorter interface. 1048 func (ts TableStats) Len() int { return len(ts) } 1049 1050 // Less is part of the Sorter interface. 1051 func (ts TableStats) Less(i, j int) bool { 1052 // Sort with most recent first. 1053 return ts[i].CreatedAt().Unix() > ts[j].CreatedAt().Unix() 1054 } 1055 1056 // Swap is part of the Sorter interface. 1057 func (ts TableStats) Swap(i, j int) { 1058 ts[i], ts[j] = ts[j], ts[i] 1059 } 1060 1061 // ForeignKeyConstraint implements cat.ForeignKeyConstraint. See that interface 1062 // for more information on the fields. 1063 type ForeignKeyConstraint struct { 1064 name string 1065 originTableID cat.StableID 1066 referencedTableID cat.StableID 1067 1068 originColumnOrdinals []int 1069 referencedColumnOrdinals []int 1070 1071 validated bool 1072 matchMethod tree.CompositeKeyMatchMethod 1073 deleteAction tree.ReferenceAction 1074 updateAction tree.ReferenceAction 1075 } 1076 1077 var _ cat.ForeignKeyConstraint = &ForeignKeyConstraint{} 1078 1079 // Name is part of the cat.ForeignKeyConstraint interface. 1080 func (fk *ForeignKeyConstraint) Name() string { 1081 return fk.name 1082 } 1083 1084 // OriginTableID is part of the cat.ForeignKeyConstraint interface. 1085 func (fk *ForeignKeyConstraint) OriginTableID() cat.StableID { 1086 return fk.originTableID 1087 } 1088 1089 // ReferencedTableID is part of the cat.ForeignKeyConstraint interface. 1090 func (fk *ForeignKeyConstraint) ReferencedTableID() cat.StableID { 1091 return fk.referencedTableID 1092 } 1093 1094 // ColumnCount is part of the cat.ForeignKeyConstraint interface. 1095 func (fk *ForeignKeyConstraint) ColumnCount() int { 1096 return len(fk.originColumnOrdinals) 1097 } 1098 1099 // OriginColumnOrdinal is part of the cat.ForeignKeyConstraint interface. 1100 func (fk *ForeignKeyConstraint) OriginColumnOrdinal(originTable cat.Table, i int) int { 1101 if originTable.ID() != fk.originTableID { 1102 panic(errors.AssertionFailedf( 1103 "invalid table %d passed to OriginColumnOrdinal (expected %d)", 1104 originTable.ID(), fk.originTableID, 1105 )) 1106 } 1107 1108 return fk.originColumnOrdinals[i] 1109 } 1110 1111 // ReferencedColumnOrdinal is part of the cat.ForeignKeyConstraint interface. 1112 func (fk *ForeignKeyConstraint) ReferencedColumnOrdinal(referencedTable cat.Table, i int) int { 1113 if referencedTable.ID() != fk.referencedTableID { 1114 panic(errors.AssertionFailedf( 1115 "invalid table %d passed to ReferencedColumnOrdinal (expected %d)", 1116 referencedTable.ID(), fk.referencedTableID, 1117 )) 1118 } 1119 return fk.referencedColumnOrdinals[i] 1120 } 1121 1122 // Validated is part of the cat.ForeignKeyConstraint interface. 1123 func (fk *ForeignKeyConstraint) Validated() bool { 1124 return fk.validated 1125 } 1126 1127 // MatchMethod is part of the cat.ForeignKeyConstraint interface. 1128 func (fk *ForeignKeyConstraint) MatchMethod() tree.CompositeKeyMatchMethod { 1129 return fk.matchMethod 1130 } 1131 1132 // DeleteReferenceAction is part of the cat.ForeignKeyConstraint interface. 1133 func (fk *ForeignKeyConstraint) DeleteReferenceAction() tree.ReferenceAction { 1134 return fk.deleteAction 1135 } 1136 1137 // UpdateReferenceAction is part of the cat.ForeignKeyConstraint interface. 1138 func (fk *ForeignKeyConstraint) UpdateReferenceAction() tree.ReferenceAction { 1139 return fk.updateAction 1140 } 1141 1142 // Sequence implements the cat.Sequence interface for testing purposes. 1143 type Sequence struct { 1144 SeqID cat.StableID 1145 SeqVersion int 1146 SeqName tree.TableName 1147 Catalog cat.Catalog 1148 1149 // If Revoked is true, then the user has had privileges on the sequence revoked. 1150 Revoked bool 1151 } 1152 1153 var _ cat.Sequence = &Sequence{} 1154 1155 // ID is part of the cat.DataSource interface. 1156 func (ts *Sequence) ID() cat.StableID { 1157 return ts.SeqID 1158 } 1159 1160 // PostgresDescriptorID is part of the cat.Object interface. 1161 func (ts *Sequence) PostgresDescriptorID() cat.StableID { 1162 return ts.SeqID 1163 } 1164 1165 // Equals is part of the cat.Object interface. 1166 func (ts *Sequence) Equals(other cat.Object) bool { 1167 otherSequence, ok := other.(*Sequence) 1168 if !ok { 1169 return false 1170 } 1171 return ts.SeqID == otherSequence.SeqID && ts.SeqVersion == otherSequence.SeqVersion 1172 } 1173 1174 // Name is part of the cat.DataSource interface. 1175 func (ts *Sequence) Name() tree.Name { 1176 return ts.SeqName.ObjectName 1177 } 1178 1179 // fqName is part of the dataSource interface. 1180 func (ts *Sequence) fqName() cat.DataSourceName { 1181 return ts.SeqName 1182 } 1183 1184 // SequenceMarker is part of the cat.Sequence interface. 1185 func (ts *Sequence) SequenceMarker() {} 1186 1187 func (ts *Sequence) String() string { 1188 tp := treeprinter.New() 1189 cat.FormatSequence(ts.Catalog, ts, tp) 1190 return tp.String() 1191 } 1192 1193 // Family implements the cat.Family interface for testing purposes. 1194 type Family struct { 1195 FamName string 1196 1197 // Ordinal is the ordinal of this family in the table. 1198 Ordinal int 1199 1200 Columns []cat.FamilyColumn 1201 1202 // table is a back reference to the table this index is on. 1203 table *Table 1204 } 1205 1206 // ID is part of the cat.Family interface. 1207 func (tf *Family) ID() cat.StableID { 1208 return 1 + cat.StableID(tf.Ordinal) 1209 } 1210 1211 // Name is part of the cat.Family interface. 1212 func (tf *Family) Name() tree.Name { 1213 return tree.Name(tf.FamName) 1214 } 1215 1216 // Table is part of the cat.Family interface. 1217 func (tf *Family) Table() cat.Table { 1218 return tf.table 1219 } 1220 1221 // ColumnCount is part of the cat.Family interface. 1222 func (tf *Family) ColumnCount() int { 1223 return len(tf.Columns) 1224 } 1225 1226 // Column is part of the cat.Family interface. 1227 func (tf *Family) Column(i int) cat.FamilyColumn { 1228 return tf.Columns[i] 1229 }