github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/table_meta.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 opt
    12  
    13  import (
    14  	"github.com/cockroachdb/cockroach/pkg/sql/opt/cat"
    15  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    16  	"github.com/cockroachdb/cockroach/pkg/util"
    17  	"github.com/cockroachdb/errors"
    18  )
    19  
    20  // TableID uniquely identifies the usage of a table within the scope of a
    21  // query. TableID 0 is reserved to mean "unknown table".
    22  //
    23  // Internally, the TableID consists of an index into the Metadata.tables slice,
    24  // as well as the ColumnID of the first column in the table. Subsequent columns
    25  // have sequential ids, relative to their ordinal position in the table.
    26  //
    27  // See the comment for Metadata for more details on identifiers.
    28  type TableID uint64
    29  
    30  const (
    31  	tableIDMask = 0xffffffff
    32  )
    33  
    34  // ColumnID returns the metadata id of the column at the given ordinal position
    35  // in the table. This is equivalent to calling:
    36  //
    37  //   md.TableMeta(t).ColumnMeta(ord).MetaID
    38  //
    39  // NOTE: This method cannot do bounds checking, so it's up to the caller to
    40  //       ensure that a column really does exist at this ordinal position.
    41  func (t TableID) ColumnID(ord int) ColumnID {
    42  	return t.firstColID() + ColumnID(ord)
    43  }
    44  
    45  // ColumnOrdinal returns the ordinal position of the given column in its base
    46  // table. This is equivalent to calling:
    47  //
    48  //   md.ColumnMeta(id).Ordinal()
    49  //
    50  // NOTE: This method cannot do complete bounds checking, so it's up to the
    51  //       caller to ensure that this column is really in the given base table.
    52  func (t TableID) ColumnOrdinal(id ColumnID) int {
    53  	if util.RaceEnabled {
    54  		if id < t.firstColID() {
    55  			panic(errors.AssertionFailedf("ordinal cannot be negative"))
    56  		}
    57  	}
    58  	return int(id - t.firstColID())
    59  }
    60  
    61  // makeTableID constructs a new TableID from its component parts.
    62  func makeTableID(index int, firstColID ColumnID) TableID {
    63  	// Bias the table index by 1.
    64  	return TableID((uint64(index+1) << 32) | uint64(firstColID))
    65  }
    66  
    67  // firstColID returns the ColumnID of the first column in the table.
    68  func (t TableID) firstColID() ColumnID {
    69  	return ColumnID(t & tableIDMask)
    70  }
    71  
    72  // index returns the index of the table in Metadata.tables. It's biased by 1, so
    73  // that TableID 0 can be be reserved to mean "unknown table".
    74  func (t TableID) index() int {
    75  	return int((t>>32)&tableIDMask) - 1
    76  }
    77  
    78  // TableAnnID uniquely identifies an annotation on an instance of table
    79  // metadata. A table annotation allows arbitrary values to be cached with table
    80  // metadata, which can be used to avoid recalculating base table properties or
    81  // other information each time it's needed.
    82  //
    83  // WARNING! When copying memo metadata (which happens when we use a cached
    84  // memo), the annotations are cleared. Any code using a annotation must treat
    85  // this as a best-effort cache and be prepared to repopulate the annotation as
    86  // necessary.
    87  //
    88  // To create a TableAnnID, call NewTableAnnID during Go's program initialization
    89  // phase. The returned TableAnnID never clashes with other annotations on the
    90  // same table. Here is a usage example:
    91  //
    92  //   var myAnnID = NewTableAnnID()
    93  //
    94  //   md.SetTableAnnotation(TableID(1), myAnnID, "foo")
    95  //   ann := md.TableAnnotation(TableID(1), myAnnID)
    96  //
    97  // Currently, the following annotations are in use:
    98  //   - WeakKeys: weak keys derived from the base table
    99  //   - Stats: statistics derived from the base table
   100  //
   101  // To add an additional annotation, increase the value of maxTableAnnIDCount and
   102  // add a call to NewTableAnnID.
   103  type TableAnnID int
   104  
   105  // tableAnnIDCount counts the number of times NewTableAnnID is called.
   106  var tableAnnIDCount TableAnnID
   107  
   108  // maxTableAnnIDCount is the maximum number of times that NewTableAnnID can be
   109  // called. Calling more than this number of times results in a panic. Having
   110  // a maximum enables a static annotation array to be inlined into the metadata
   111  // table struct.
   112  const maxTableAnnIDCount = 2
   113  
   114  // TableMeta stores information about one of the tables stored in the metadata.
   115  type TableMeta struct {
   116  	// MetaID is the identifier for this table that is unique within the query
   117  	// metadata.
   118  	MetaID TableID
   119  
   120  	// Table is a reference to the table in the catalog.
   121  	Table cat.Table
   122  
   123  	// Alias stores the identifier used in the query to identify the table. This
   124  	// might be explicitly qualified (e.g. <catalog>.<schema>.<table>), or not
   125  	// (e.g. <table>). Or, it may be an alias used in the query, in which case it
   126  	// is always an unqualified name.
   127  	Alias tree.TableName
   128  
   129  	// IgnoreForeignKeys is true if we should disable any rules that depend on the
   130  	// consistency of outgoing foreign key references. Set by the
   131  	// IGNORE_FOREIGN_KEYS table hint; useful for scrub queries meant to verify
   132  	// the consistency of foreign keys.
   133  	IgnoreForeignKeys bool
   134  
   135  	// Constraints stores a *FiltersExpr containing filters that are known to
   136  	// evaluate to true on the table data. This list is extracted from validated
   137  	// check constraints; specifically, those check constraints that we can prove
   138  	// never evaluate to NULL (as NULL is treated differently in check constraints
   139  	// and filters).
   140  	//
   141  	// If nil, there are no check constraints.
   142  	//
   143  	// See comment above GenerateConstrainedScans for more detail.
   144  	Constraints ScalarExpr
   145  
   146  	// ComputedCols stores ScalarExprs for each computed column on the table,
   147  	// indexed by ColumnID. These will be used when building mutation statements
   148  	// and constraining indexes. See comment above GenerateConstrainedScans for
   149  	// more detail.
   150  	ComputedCols map[ColumnID]ScalarExpr
   151  
   152  	// anns annotates the table metadata with arbitrary data.
   153  	anns [maxTableAnnIDCount]interface{}
   154  }
   155  
   156  // clearAnnotations resets all the table annotations; used when copying a
   157  // Metadata.
   158  func (tm *TableMeta) clearAnnotations() {
   159  	for i := range tm.anns {
   160  		tm.anns[i] = nil
   161  	}
   162  }
   163  
   164  // IndexColumns returns the metadata IDs for the set of columns in the given
   165  // index.
   166  // TODO(justin): cache this value in the table metadata.
   167  func (tm *TableMeta) IndexColumns(indexOrd int) ColSet {
   168  	index := tm.Table.Index(indexOrd)
   169  
   170  	var indexCols ColSet
   171  	for i, n := 0, index.ColumnCount(); i < n; i++ {
   172  		ord := index.Column(i).Ordinal
   173  		indexCols.Add(tm.MetaID.ColumnID(ord))
   174  	}
   175  	return indexCols
   176  }
   177  
   178  // IndexKeyColumns returns the metadata IDs for the set of strict key columns in
   179  // the given index.
   180  func (tm *TableMeta) IndexKeyColumns(indexOrd int) ColSet {
   181  	index := tm.Table.Index(indexOrd)
   182  
   183  	var indexCols ColSet
   184  	for i, n := 0, index.KeyColumnCount(); i < n; i++ {
   185  		ord := index.Column(i).Ordinal
   186  		indexCols.Add(tm.MetaID.ColumnID(ord))
   187  	}
   188  	return indexCols
   189  }
   190  
   191  // SetConstraints sets the filters derived from check constraints; see
   192  // TableMeta.Constraint. The argument must be a *FiltersExpr.
   193  func (tm *TableMeta) SetConstraints(constraints ScalarExpr) {
   194  	tm.Constraints = constraints
   195  }
   196  
   197  // AddComputedCol adds a computed column expression to the table's metadata.
   198  func (tm *TableMeta) AddComputedCol(colID ColumnID, computedCol ScalarExpr) {
   199  	if tm.ComputedCols == nil {
   200  		tm.ComputedCols = make(map[ColumnID]ScalarExpr)
   201  	}
   202  	tm.ComputedCols[colID] = computedCol
   203  }
   204  
   205  // TableAnnotation returns the given annotation that is associated with the
   206  // given table. If the table has no such annotation, TableAnnotation returns
   207  // nil.
   208  func (md *Metadata) TableAnnotation(tabID TableID, annID TableAnnID) interface{} {
   209  	return md.tables[tabID.index()].anns[annID]
   210  }
   211  
   212  // SetTableAnnotation associates the given annotation with the given table. The
   213  // annotation is associated by the given ID, which was allocated by calling
   214  // NewTableAnnID. If an annotation with the ID already exists on the table, then
   215  // it is overwritten.
   216  //
   217  // See the TableAnnID comment for more details and a usage example.
   218  func (md *Metadata) SetTableAnnotation(tabID TableID, tabAnnID TableAnnID, ann interface{}) {
   219  	md.tables[tabID.index()].anns[tabAnnID] = ann
   220  }
   221  
   222  // NewTableAnnID allocates a unique annotation identifier that is used to
   223  // associate arbitrary data with table metadata. Only maxTableAnnIDCount total
   224  // annotation ID's can exist in the system. Attempting to exceed the maximum
   225  // results in a panic.
   226  //
   227  // This method is not thread-safe, and therefore should only be called during
   228  // Go's program initialization phase (which uses a single goroutine to init
   229  // variables).
   230  //
   231  // See the TableAnnID comment for more details and a usage example.
   232  func NewTableAnnID() TableAnnID {
   233  	if tableAnnIDCount == maxTableAnnIDCount {
   234  		panic(errors.AssertionFailedf(
   235  			"can't allocate table annotation id; increase maxTableAnnIDCount to allow"))
   236  	}
   237  	cnt := tableAnnIDCount
   238  	tableAnnIDCount++
   239  	return cnt
   240  }