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 }