github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/virtual_schema.go (about)

     1  // Copyright 2016 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
    12  
    13  import (
    14  	"context"
    15  	"math"
    16  	"sort"
    17  
    18  	"github.com/cockroachdb/cockroach/pkg/settings/cluster"
    19  	"github.com/cockroachdb/cockroach/pkg/sql/catalog"
    20  	"github.com/cockroachdb/cockroach/pkg/sql/opt/constraint"
    21  	"github.com/cockroachdb/cockroach/pkg/sql/parser"
    22  	"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode"
    23  	"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror"
    24  	"github.com/cockroachdb/cockroach/pkg/sql/privilege"
    25  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    26  	"github.com/cockroachdb/cockroach/pkg/sql/sessiondata"
    27  	"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
    28  	"github.com/cockroachdb/cockroach/pkg/util/errorutil/unimplemented"
    29  	"github.com/cockroachdb/cockroach/pkg/util/hlc"
    30  	"github.com/cockroachdb/errors"
    31  )
    32  
    33  //
    34  // Programmer interface to define virtual schemas.
    35  //
    36  
    37  // virtualSchema represents a database with a set of virtual tables. Virtual
    38  // tables differ from standard tables in that they are not persisted to storage,
    39  // and instead their contents are populated whenever they are queried.
    40  //
    41  // The virtual database and its virtual tables also differ from standard databases
    42  // and tables in that their descriptors are not distributed, but instead live statically
    43  // in code. This means that they are accessed separately from standard descriptors.
    44  type virtualSchema struct {
    45  	name           string
    46  	allTableNames  map[string]struct{}
    47  	tableDefs      map[sqlbase.ID]virtualSchemaDef
    48  	tableValidator func(*sqlbase.TableDescriptor) error // optional
    49  	// Some virtual tables can be used if there is no current database set; others can't.
    50  	validWithNoDatabaseContext bool
    51  	// Some virtual schemas (like pg_catalog) contain types that we can resolve.
    52  	containsTypes bool
    53  }
    54  
    55  // virtualSchemaDef represents the interface of a table definition within a virtualSchema.
    56  type virtualSchemaDef interface {
    57  	getSchema() string
    58  	initVirtualTableDesc(
    59  		ctx context.Context, st *cluster.Settings, parentSchemaID, id sqlbase.ID,
    60  	) (sqlbase.TableDescriptor, error)
    61  	getComment() string
    62  }
    63  
    64  type virtualIndex struct {
    65  	// populate populates the table given the constraint. matched is true if any
    66  	// rows were generated.
    67  	populate func(ctx context.Context, constraint tree.Datum, p *planner, db *DatabaseDescriptor,
    68  		addRow func(...tree.Datum) error,
    69  	) (matched bool, err error)
    70  
    71  	// partial is true if the virtual index isn't able to satisfy all constraints.
    72  	// For example, the pg_class table contains both indexes and tables. Tables
    73  	// can be looked up via a virtual index, since we can look up their descriptor
    74  	// by their ID directly. But indexes can't - they're hashed identifiers with
    75  	// no actual index. So we mark this index as partial, and if we get no match
    76  	// during populate, we'll fall back on populating the entire table.
    77  	partial bool
    78  }
    79  
    80  // virtualSchemaTable represents a table within a virtualSchema.
    81  type virtualSchemaTable struct {
    82  	// Exactly one of the populate and generator fields should be defined for
    83  	// each virtualSchemaTable.
    84  	schema string
    85  
    86  	// comment represents comment of virtual schema table.
    87  	comment string
    88  
    89  	// populate, if non-nil, is a function that is used when creating a
    90  	// valuesNode. This function eagerly loads every row of the virtual table
    91  	// during initialization of the valuesNode.
    92  	populate func(ctx context.Context, p *planner, db *DatabaseDescriptor, addRow func(...tree.Datum) error) error
    93  
    94  	// indexes, if non empty, is a slice of populate methods that also take a
    95  	// constraint, only generating rows that match the constraint. The order of
    96  	// indexes must match the order of the index definitions in the virtual table's
    97  	// schema.
    98  	indexes []virtualIndex
    99  
   100  	// generator, if non-nil, is a function that is used when creating a
   101  	// virtualTableNode. This function returns a virtualTableGenerator function
   102  	// which generates the next row of the virtual table when called.
   103  	generator func(ctx context.Context, p *planner, db *DatabaseDescriptor) (virtualTableGenerator, cleanupFunc, error)
   104  }
   105  
   106  // virtualSchemaView represents a view within a virtualSchema
   107  type virtualSchemaView struct {
   108  	schema        string
   109  	resultColumns sqlbase.ResultColumns
   110  }
   111  
   112  // getSchema is part of the virtualSchemaDef interface.
   113  func (t virtualSchemaTable) getSchema() string {
   114  	return t.schema
   115  }
   116  
   117  // initVirtualTableDesc is part of the virtualSchemaDef interface.
   118  func (t virtualSchemaTable) initVirtualTableDesc(
   119  	ctx context.Context, st *cluster.Settings, parentSchemaID, id sqlbase.ID,
   120  ) (sqlbase.TableDescriptor, error) {
   121  	stmt, err := parser.ParseOne(t.schema)
   122  	if err != nil {
   123  		return sqlbase.TableDescriptor{}, err
   124  	}
   125  
   126  	create := stmt.AST.(*tree.CreateTable)
   127  	var firstColDef *tree.ColumnTableDef
   128  	for _, def := range create.Defs {
   129  		if d, ok := def.(*tree.ColumnTableDef); ok {
   130  			if d.HasDefaultExpr() {
   131  				return sqlbase.TableDescriptor{},
   132  					errors.Errorf("virtual tables are not allowed to use default exprs "+
   133  						"because bootstrapping: %s:%s", &create.Table, d.Name)
   134  			}
   135  			if firstColDef == nil {
   136  				firstColDef = d
   137  			}
   138  		}
   139  		if _, ok := def.(*tree.UniqueConstraintTableDef); ok {
   140  			return sqlbase.TableDescriptor{},
   141  				errors.Errorf("virtual tables are not allowed to have unique constraints")
   142  		}
   143  	}
   144  	if firstColDef == nil {
   145  		return sqlbase.TableDescriptor{},
   146  			errors.Errorf("can't have empty virtual tables")
   147  	}
   148  
   149  	// Virtual tables never use SERIAL so we need not process SERIAL
   150  	// types here.
   151  	mutDesc, err := MakeTableDesc(
   152  		ctx,
   153  		nil, /* txn */
   154  		nil, /* vs */
   155  		st,
   156  		create,
   157  		0, /* parentID */
   158  		parentSchemaID,
   159  		id,
   160  		hlc.Timestamp{}, /* creationTime */
   161  		publicSelectPrivileges,
   162  		nil,                        /* affected */
   163  		nil,                        /* semaCtx */
   164  		nil,                        /* evalCtx */
   165  		&sessiondata.SessionData{}, /* sessionData */
   166  		false,                      /* temporary */
   167  	)
   168  	if err != nil {
   169  		return mutDesc.TableDescriptor, err
   170  	}
   171  	for i := range mutDesc.Indexes {
   172  		idx := &mutDesc.Indexes[i]
   173  		if len(idx.ColumnIDs) > 1 {
   174  			panic("we don't know how to deal with virtual composite indexes yet")
   175  		}
   176  		// All indexes of virtual tables automatically STORE all other columns in
   177  		// the table.
   178  		idx.StoreColumnIDs = make([]sqlbase.ColumnID, len(mutDesc.Columns)-len(idx.ColumnIDs))
   179  		idx.StoreColumnNames = make([]string, len(mutDesc.Columns)-len(idx.ColumnIDs))
   180  		// Store all columns but the ones in the index.
   181  		outputIdx := 0
   182  	EACHCOLUMN:
   183  		for j := range mutDesc.Columns {
   184  			for _, id := range idx.ColumnIDs {
   185  				if mutDesc.Columns[j].ID == id {
   186  					// Skip columns in the index.
   187  					continue EACHCOLUMN
   188  				}
   189  			}
   190  			idx.StoreColumnIDs[outputIdx] = mutDesc.Columns[j].ID
   191  			idx.StoreColumnNames[outputIdx] = mutDesc.Columns[j].Name
   192  			outputIdx++
   193  		}
   194  	}
   195  	return mutDesc.TableDescriptor, nil
   196  }
   197  
   198  // getComment is part of the virtualSchemaDef interface.
   199  func (t virtualSchemaTable) getComment() string {
   200  	return t.comment
   201  }
   202  
   203  // getIndex returns the virtual index with the input ID.
   204  func (t virtualSchemaTable) getIndex(id sqlbase.IndexID) *virtualIndex {
   205  	// Subtract 2 from the index id to get the ordinal in def.indexes, since
   206  	// the index with ID 1 is the "primary" index defined by def.populate.
   207  	return &t.indexes[id-2]
   208  }
   209  
   210  // getSchema is part of the virtualSchemaDef interface.
   211  func (v virtualSchemaView) getSchema() string {
   212  	return v.schema
   213  }
   214  
   215  // initVirtualTableDesc is part of the virtualSchemaDef interface.
   216  func (v virtualSchemaView) initVirtualTableDesc(
   217  	ctx context.Context, st *cluster.Settings, parentSchemaID sqlbase.ID, id sqlbase.ID,
   218  ) (sqlbase.TableDescriptor, error) {
   219  	stmt, err := parser.ParseOne(v.schema)
   220  	if err != nil {
   221  		return sqlbase.TableDescriptor{}, err
   222  	}
   223  
   224  	create := stmt.AST.(*tree.CreateView)
   225  
   226  	columns := v.resultColumns
   227  	if len(create.ColumnNames) != 0 {
   228  		columns = overrideColumnNames(columns, create.ColumnNames)
   229  	}
   230  	mutDesc, err := makeViewTableDesc(
   231  		ctx,
   232  		create.Name.Table(),
   233  		tree.AsStringWithFlags(create.AsSource, tree.FmtParsable),
   234  		0, /* parentID */
   235  		parentSchemaID,
   236  		id,
   237  		columns,
   238  		hlc.Timestamp{}, /* creationTime */
   239  		publicSelectPrivileges,
   240  		nil,   /* semaCtx */
   241  		nil,   /* evalCtx */
   242  		false, /* temporary */
   243  	)
   244  	return mutDesc.TableDescriptor, err
   245  }
   246  
   247  // getComment is part of the virtualSchemaDef interface.
   248  func (v virtualSchemaView) getComment() string {
   249  	return ""
   250  }
   251  
   252  // virtualSchemas holds a slice of statically registered virtualSchema objects.
   253  //
   254  // When adding a new virtualSchema, define a virtualSchema in a separate file, and
   255  // add that object to this slice.
   256  var virtualSchemas = map[sqlbase.ID]virtualSchema{
   257  	sqlbase.InformationSchemaID: informationSchema,
   258  	sqlbase.PgCatalogID:         pgCatalog,
   259  	sqlbase.CrdbInternalID:      crdbInternal,
   260  	sqlbase.PgExtensionSchemaID: pgExtension,
   261  }
   262  
   263  //
   264  // SQL-layer interface to work with virtual schemas.
   265  //
   266  
   267  // VirtualSchemaHolder is a type used to provide convenient access to virtual
   268  // database and table descriptors. VirtualSchemaHolder, virtualSchemaEntry,
   269  // and virtualDefEntry make up the generated data structure which the
   270  // virtualSchemas slice is mapped to. Because of this, they should not be
   271  // created directly, but instead will be populated in a post-startup hook
   272  // on an Executor.
   273  type VirtualSchemaHolder struct {
   274  	entries      map[string]virtualSchemaEntry
   275  	defsByID     map[sqlbase.ID]*virtualDefEntry
   276  	orderedNames []string
   277  }
   278  
   279  // GetVirtualSchema makes VirtualSchemaHolder implement schema.VirtualSchemas.
   280  func (vs *VirtualSchemaHolder) GetVirtualSchema(schemaName string) (catalog.VirtualSchema, bool) {
   281  	virtualSchema, ok := vs.entries[schemaName]
   282  	return virtualSchema, ok
   283  }
   284  
   285  var _ catalog.VirtualSchemas = (*VirtualSchemaHolder)(nil)
   286  
   287  type virtualSchemaEntry struct {
   288  	// TODO(ajwerner): Use a sqlbase.SchemaDescriptor here as part of the
   289  	// user-defined schema work.
   290  	desc            *sqlbase.DatabaseDescriptor
   291  	defs            map[string]virtualDefEntry
   292  	orderedDefNames []string
   293  	allTableNames   map[string]struct{}
   294  	containsTypes   bool
   295  }
   296  
   297  func (v virtualSchemaEntry) Desc() catalog.Descriptor {
   298  	return v.desc
   299  }
   300  
   301  func (v virtualSchemaEntry) NumTables() int {
   302  	return len(v.defs)
   303  }
   304  
   305  func (v virtualSchemaEntry) VisitTables(f func(object catalog.VirtualObject)) {
   306  	for _, name := range v.orderedDefNames {
   307  		f(v.defs[name])
   308  	}
   309  }
   310  
   311  func (v virtualSchemaEntry) GetObjectByName(
   312  	name string, flags tree.ObjectLookupFlags,
   313  ) (catalog.VirtualObject, error) {
   314  	switch flags.DesiredObjectKind {
   315  	case tree.TableObject:
   316  		if def, ok := v.defs[name]; ok {
   317  			if flags.RequireMutable {
   318  				return mutableVirtualDefEntry{desc: def.desc}, nil
   319  			}
   320  			return &def, nil
   321  		}
   322  		if _, ok := v.allTableNames[name]; ok {
   323  			return nil, unimplemented.Newf(v.desc.Name+"."+name,
   324  				"virtual schema table not implemented: %s.%s", v.desc.Name, name)
   325  		}
   326  		return nil, nil
   327  	case tree.TypeObject:
   328  		if !v.containsTypes {
   329  			return nil, nil
   330  		}
   331  		// Currently, we don't allow creation of types in virtual schemas, so
   332  		// the only types present in the virtual schemas that have types (i.e.
   333  		// pg_catalog) are types that are known at parse time. So, attempt to
   334  		// parse the input object as a statically known type. Note that an
   335  		// invalid input type like "notatype" will be parsed successfully as
   336  		// a ResolvableTypeReference, so the error here does not need to be
   337  		// intercepted and inspected.
   338  		typRef, err := parser.ParseType(name)
   339  		if err != nil {
   340  			return nil, err
   341  		}
   342  		// If the parsed reference is actually a statically known type, then
   343  		// we can return it. We return a simple wrapping of this type as
   344  		// TypeDescriptor that represents an alias of the result type.
   345  		typ, ok := tree.GetStaticallyKnownType(typRef)
   346  		if !ok {
   347  			return nil, nil
   348  		}
   349  		return virtualTypeEntry{
   350  			desc:    sqlbase.MakeSimpleAliasTypeDescriptor(typ),
   351  			mutable: flags.RequireMutable,
   352  		}, nil
   353  	default:
   354  		return nil, errors.AssertionFailedf("unknown desired object kind %d", flags.DesiredObjectKind)
   355  	}
   356  }
   357  
   358  type virtualDefEntry struct {
   359  	virtualDef                 virtualSchemaDef
   360  	desc                       *sqlbase.TableDescriptor
   361  	comment                    string
   362  	validWithNoDatabaseContext bool
   363  }
   364  
   365  func (e virtualDefEntry) Desc() catalog.Descriptor {
   366  	return sqlbase.NewImmutableTableDescriptor(*e.desc)
   367  }
   368  
   369  type mutableVirtualDefEntry struct {
   370  	desc *sqlbase.TableDescriptor
   371  }
   372  
   373  func (e mutableVirtualDefEntry) Desc() catalog.Descriptor {
   374  	return sqlbase.NewMutableExistingTableDescriptor(*e.desc)
   375  }
   376  
   377  type virtualTypeEntry struct {
   378  	desc    *sqlbase.TypeDescriptor
   379  	mutable bool
   380  }
   381  
   382  func (e virtualTypeEntry) Desc() catalog.Descriptor {
   383  	if e.mutable {
   384  		return sqlbase.NewMutableExistingTypeDescriptor(*e.desc)
   385  	}
   386  	return sqlbase.NewImmutableTypeDescriptor(*e.desc)
   387  }
   388  
   389  type virtualTableConstructor func(context.Context, *planner, string) (planNode, error)
   390  
   391  var errInvalidDbPrefix = errors.WithHint(
   392  	pgerror.New(pgcode.UndefinedObject,
   393  		"cannot access virtual schema in anonymous database"),
   394  	"verify that the current database is set")
   395  
   396  func newInvalidVirtualSchemaError() error {
   397  	return errors.AssertionFailedf("virtualSchema cannot have both the populate and generator functions defined")
   398  }
   399  
   400  func newInvalidVirtualDefEntryError() error {
   401  	return errors.AssertionFailedf("virtualDefEntry.virtualDef must be a virtualSchemaTable")
   402  }
   403  
   404  func (e virtualDefEntry) validateRow(datums tree.Datums, columns sqlbase.ResultColumns) error {
   405  	if r, c := len(datums), len(columns); r != c {
   406  		return errors.AssertionFailedf("datum row count and column count differ: %d vs %d", r, c)
   407  	}
   408  	for i := range columns {
   409  		col := &columns[i]
   410  		datum := datums[i]
   411  		if datum == tree.DNull {
   412  			if !e.desc.Columns[i].Nullable {
   413  				return errors.AssertionFailedf("column %s.%s not nullable, but found NULL value",
   414  					e.desc.Name, col.Name)
   415  			}
   416  		} else if !datum.ResolvedType().Equivalent(col.Typ) {
   417  			return errors.AssertionFailedf("datum column %q expected to be type %s; found type %s",
   418  				col.Name, col.Typ, datum.ResolvedType())
   419  		}
   420  	}
   421  	return nil
   422  }
   423  
   424  // getPlanInfo returns the column metadata and a constructor for a new
   425  // valuesNode for the virtual table. We use deferred construction here
   426  // so as to avoid populating a RowContainer during query preparation,
   427  // where we can't guarantee it will be Close()d in case of error.
   428  func (e virtualDefEntry) getPlanInfo(
   429  	table *sqlbase.TableDescriptor,
   430  	index *sqlbase.IndexDescriptor,
   431  	idxConstraint *constraint.Constraint,
   432  ) (sqlbase.ResultColumns, virtualTableConstructor) {
   433  	var columns sqlbase.ResultColumns
   434  	for i := range e.desc.Columns {
   435  		col := &e.desc.Columns[i]
   436  		columns = append(columns, sqlbase.ResultColumn{
   437  			Name:           col.Name,
   438  			Typ:            col.Type,
   439  			TableID:        table.GetID(),
   440  			PGAttributeNum: col.GetLogicalColumnID(),
   441  		})
   442  	}
   443  
   444  	constructor := func(ctx context.Context, p *planner, dbName string) (planNode, error) {
   445  		var dbDesc *DatabaseDescriptor
   446  		if dbName != "" {
   447  			var err error
   448  			dbDesc, err = p.LogicalSchemaAccessor().GetDatabaseDesc(ctx, p.txn, p.ExecCfg().Codec,
   449  				dbName, tree.DatabaseLookupFlags{Required: true, AvoidCached: p.avoidCachedDescriptors})
   450  			if err != nil {
   451  				return nil, err
   452  			}
   453  		} else {
   454  			if !e.validWithNoDatabaseContext {
   455  				return nil, errInvalidDbPrefix
   456  			}
   457  		}
   458  
   459  		switch def := e.virtualDef.(type) {
   460  		case virtualSchemaTable:
   461  			if def.generator != nil && def.populate != nil {
   462  				return nil, newInvalidVirtualSchemaError()
   463  			}
   464  
   465  			if def.generator != nil {
   466  				next, cleanup, err := def.generator(ctx, p, dbDesc)
   467  				if err != nil {
   468  					return nil, err
   469  				}
   470  				return p.newVirtualTableNode(columns, next, cleanup), nil
   471  			}
   472  
   473  			constrainedScan := idxConstraint != nil && !idxConstraint.IsUnconstrained()
   474  			if !constrainedScan {
   475  				generator, cleanup := setupGenerator(ctx, func(pusher rowPusher) error {
   476  					return def.populate(ctx, p, dbDesc, func(row ...tree.Datum) error {
   477  						if err := e.validateRow(row, columns); err != nil {
   478  							return err
   479  						}
   480  						return pusher.pushRow(row...)
   481  					})
   482  				})
   483  				return p.newVirtualTableNode(columns, generator, cleanup), nil
   484  			}
   485  
   486  			// We are now dealing with a constrained virtual index scan.
   487  
   488  			if index.ID == 1 {
   489  				return nil, errors.AssertionFailedf(
   490  					"programming error: can't constrain scan on primary virtual index of table %s", e.desc.Name)
   491  			}
   492  
   493  			// Figure out the ordinal position of the column that we're filtering on.
   494  			columnIdxMap := table.ColumnIdxMap()
   495  			indexKeyDatums := make([]tree.Datum, len(index.ColumnIDs))
   496  
   497  			generator, cleanup := setupGenerator(ctx, e.makeConstrainedRowsGenerator(
   498  				ctx, p, dbDesc, index, indexKeyDatums, columnIdxMap, idxConstraint, columns))
   499  			return p.newVirtualTableNode(columns, generator, cleanup), nil
   500  
   501  		default:
   502  			return nil, newInvalidVirtualDefEntryError()
   503  		}
   504  	}
   505  
   506  	return columns, constructor
   507  }
   508  
   509  // makeConstrainedRowsGenerator returns a generator function that can be invoked
   510  // to push all rows from this virtual table that satisfy the input index
   511  // constraint to a row pusher that's supplied to the generator function.
   512  func (e virtualDefEntry) makeConstrainedRowsGenerator(
   513  	ctx context.Context,
   514  	p *planner,
   515  	dbDesc *DatabaseDescriptor,
   516  	index *sqlbase.IndexDescriptor,
   517  	indexKeyDatums []tree.Datum,
   518  	columnIdxMap map[sqlbase.ColumnID]int,
   519  	idxConstraint *constraint.Constraint,
   520  	columns sqlbase.ResultColumns,
   521  ) func(pusher rowPusher) error {
   522  	def := e.virtualDef.(virtualSchemaTable)
   523  	return func(pusher rowPusher) error {
   524  		var span constraint.Span
   525  		addRowIfPassesFilter := func(datums ...tree.Datum) error {
   526  			for i, id := range index.ColumnIDs {
   527  				indexKeyDatums[i] = datums[columnIdxMap[id]]
   528  			}
   529  			// Construct a single key span out of the current row, so that
   530  			// we can test it for containment within the constraint span of the
   531  			// filter that we're applying. The results of this containment check
   532  			// will tell us whether or not to let the current row pass the filter.
   533  			key := constraint.MakeCompositeKey(indexKeyDatums...)
   534  			span.Init(key, constraint.IncludeBoundary, key, constraint.IncludeBoundary)
   535  			var err error
   536  			if idxConstraint.ContainsSpan(p.EvalContext(), &span) {
   537  				if err := e.validateRow(datums, columns); err != nil {
   538  					return err
   539  				}
   540  				return pusher.pushRow(datums...)
   541  			}
   542  			return err
   543  		}
   544  
   545  		// We have a virtual index with a constraint. Run the constrained
   546  		// populate routine for every span. If for some reason we can't use the
   547  		// index for a given span, we exit the loop early and run a "full scan"
   548  		// over the virtual table, filtering the output using the remaining
   549  		// spans.
   550  		// N.B. we count down in this loop so that, if we have to give up half
   551  		// way through, we can easily truncate the spans we already processed
   552  		// from the end and use them as a filter for the remaining rows of the
   553  		// table.
   554  		currentConstraint := idxConstraint.Spans.Count() - 1
   555  		for ; currentConstraint >= 0; currentConstraint-- {
   556  			span := idxConstraint.Spans.Get(currentConstraint)
   557  			if span.StartKey().Length() > 1 {
   558  				return errors.AssertionFailedf(
   559  					"programming error: can't push down composite constraints into vtables")
   560  			}
   561  			if !span.HasSingleKey(p.EvalContext()) {
   562  				// No hope - we can't deal with range scans on virtual indexes.
   563  				break
   564  			}
   565  			constraintDatum := span.StartKey().Value(0)
   566  			virtualIndex := def.getIndex(index.ID)
   567  
   568  			// For each span, run the index's populate method, constrained to the
   569  			// constraint span's value.
   570  			found, err := virtualIndex.populate(ctx, constraintDatum, p, dbDesc,
   571  				addRowIfPassesFilter)
   572  			if err != nil {
   573  				return err
   574  			}
   575  			if !found && virtualIndex.partial {
   576  				// If we found nothing, and the index was partial, we have no choice
   577  				// but to populate the entire table and search through it.
   578  				break
   579  			}
   580  		}
   581  		if currentConstraint < 0 {
   582  			// We successfully processed all constraints, so we can leave now.
   583  			return nil
   584  		}
   585  
   586  		// Fall back to a full scan of the table, using the remaining filters
   587  		// that weren't able to be used as constraints.
   588  		idxConstraint.Spans.Truncate(currentConstraint + 1)
   589  		return def.populate(ctx, p, dbDesc, addRowIfPassesFilter)
   590  	}
   591  }
   592  
   593  // NewVirtualSchemaHolder creates a new VirtualSchemaHolder.
   594  func NewVirtualSchemaHolder(
   595  	ctx context.Context, st *cluster.Settings,
   596  ) (*VirtualSchemaHolder, error) {
   597  	vs := &VirtualSchemaHolder{
   598  		entries:      make(map[string]virtualSchemaEntry, len(virtualSchemas)),
   599  		orderedNames: make([]string, len(virtualSchemas)),
   600  		defsByID:     make(map[sqlbase.ID]*virtualDefEntry, math.MaxUint32-sqlbase.MinVirtualID),
   601  	}
   602  
   603  	order := 0
   604  	for schemaID, schema := range virtualSchemas {
   605  		dbName := schema.name
   606  		dbDesc := initVirtualDatabaseDesc(schemaID, dbName)
   607  		defs := make(map[string]virtualDefEntry, len(schema.tableDefs))
   608  		orderedDefNames := make([]string, 0, len(schema.tableDefs))
   609  
   610  		for id, def := range schema.tableDefs {
   611  			tableDesc, err := def.initVirtualTableDesc(ctx, st, schemaID, id)
   612  
   613  			if err != nil {
   614  				return nil, errors.NewAssertionErrorWithWrappedErrf(err,
   615  					"failed to initialize %s", errors.Safe(def.getSchema()))
   616  			}
   617  
   618  			if schema.tableValidator != nil {
   619  				if err := schema.tableValidator(&tableDesc); err != nil {
   620  					return nil, errors.NewAssertionErrorWithWrappedErrf(err, "programmer error")
   621  				}
   622  			}
   623  
   624  			entry := virtualDefEntry{
   625  				virtualDef:                 def,
   626  				desc:                       &tableDesc,
   627  				validWithNoDatabaseContext: schema.validWithNoDatabaseContext,
   628  				comment:                    def.getComment(),
   629  			}
   630  			defs[tableDesc.Name] = entry
   631  			vs.defsByID[tableDesc.ID] = &entry
   632  			orderedDefNames = append(orderedDefNames, tableDesc.Name)
   633  		}
   634  
   635  		sort.Strings(orderedDefNames)
   636  
   637  		vs.entries[dbName] = virtualSchemaEntry{
   638  			desc:            dbDesc,
   639  			defs:            defs,
   640  			orderedDefNames: orderedDefNames,
   641  			allTableNames:   schema.allTableNames,
   642  			containsTypes:   schema.containsTypes,
   643  		}
   644  		vs.orderedNames[order] = dbName
   645  		order++
   646  	}
   647  	sort.Strings(vs.orderedNames)
   648  	return vs, nil
   649  }
   650  
   651  // Virtual databases and tables each have SELECT privileges for "public", which includes
   652  // all users. However, virtual schemas have more fine-grained access control.
   653  // For instance, information_schema will only expose rows to a given user which that
   654  // user has access to.
   655  var publicSelectPrivileges = sqlbase.NewPrivilegeDescriptor(sqlbase.PublicRole, privilege.List{privilege.SELECT})
   656  
   657  func initVirtualDatabaseDesc(id sqlbase.ID, name string) *sqlbase.DatabaseDescriptor {
   658  	return &sqlbase.DatabaseDescriptor{
   659  		Name:       name,
   660  		ID:         id,
   661  		Privileges: publicSelectPrivileges,
   662  	}
   663  }
   664  
   665  // getEntries is part of the VirtualTabler interface.
   666  func (vs *VirtualSchemaHolder) getEntries() map[string]virtualSchemaEntry {
   667  	return vs.entries
   668  }
   669  
   670  // getSchemaNames is part of the VirtualTabler interface.
   671  func (vs *VirtualSchemaHolder) getSchemaNames() []string {
   672  	return vs.orderedNames
   673  }
   674  
   675  // getVirtualSchemaEntry retrieves a virtual schema entry given a database name.
   676  // getVirtualSchemaEntry is part of the VirtualTabler interface.
   677  func (vs *VirtualSchemaHolder) getVirtualSchemaEntry(name string) (virtualSchemaEntry, bool) {
   678  	e, ok := vs.entries[name]
   679  	return e, ok
   680  }
   681  
   682  // getVirtualTableEntry checks if the provided name matches a virtual database/table
   683  // pair. The function will return the table's virtual table entry if the name matches
   684  // a specific table. It will return an error if the name references a virtual database
   685  // but the table is non-existent.
   686  // getVirtualTableEntry is part of the VirtualTabler interface.
   687  func (vs *VirtualSchemaHolder) getVirtualTableEntry(tn *tree.TableName) (virtualDefEntry, error) {
   688  	if db, ok := vs.getVirtualSchemaEntry(tn.Schema()); ok {
   689  		tableName := tn.Table()
   690  		if t, ok := db.defs[tableName]; ok {
   691  			return t, nil
   692  		}
   693  		if _, ok := db.allTableNames[tableName]; ok {
   694  			return virtualDefEntry{}, unimplemented.NewWithIssueDetailf(8675,
   695  				tn.Schema()+"."+tableName,
   696  				"virtual schema table not implemented: %s.%s", tn.Schema(), tableName)
   697  		}
   698  		return virtualDefEntry{}, sqlbase.NewUndefinedRelationError(tn)
   699  	}
   700  	return virtualDefEntry{}, nil
   701  }
   702  
   703  func (vs *VirtualSchemaHolder) getVirtualTableEntryByID(id sqlbase.ID) (virtualDefEntry, error) {
   704  	entry, ok := vs.defsByID[id]
   705  	if !ok {
   706  		return virtualDefEntry{}, sqlbase.ErrDescriptorNotFound
   707  	}
   708  	return *entry, nil
   709  }
   710  
   711  // VirtualTabler is used to fetch descriptors for virtual tables and databases.
   712  type VirtualTabler interface {
   713  	getVirtualTableDesc(tn *tree.TableName) (*sqlbase.TableDescriptor, error)
   714  	getVirtualSchemaEntry(name string) (virtualSchemaEntry, bool)
   715  	getVirtualTableEntry(tn *tree.TableName) (virtualDefEntry, error)
   716  	getVirtualTableEntryByID(id sqlbase.ID) (virtualDefEntry, error)
   717  	getEntries() map[string]virtualSchemaEntry
   718  	getSchemaNames() []string
   719  }
   720  
   721  // getVirtualTableDesc checks if the provided name matches a virtual database/table
   722  // pair, and returns its descriptor if it does.
   723  // getVirtualTableDesc is part of the VirtualTabler interface.
   724  func (vs *VirtualSchemaHolder) getVirtualTableDesc(
   725  	tn *tree.TableName,
   726  ) (*sqlbase.TableDescriptor, error) {
   727  	t, err := vs.getVirtualTableEntry(tn)
   728  	if err != nil {
   729  		return nil, err
   730  	}
   731  	return t.desc, nil
   732  }