github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/span/span_builder.go (about) 1 // Copyright 2019 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 span 12 13 import ( 14 "github.com/cockroachdb/cockroach/pkg/keys" 15 "github.com/cockroachdb/cockroach/pkg/roachpb" 16 "github.com/cockroachdb/cockroach/pkg/sql/opt/constraint" 17 "github.com/cockroachdb/cockroach/pkg/sql/opt/exec" 18 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 19 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 20 "github.com/cockroachdb/cockroach/pkg/sql/types" 21 "github.com/cockroachdb/cockroach/pkg/util" 22 "github.com/cockroachdb/cockroach/pkg/util/encoding" 23 "github.com/cockroachdb/errors" 24 ) 25 26 // Builder is a single struct for generating key spans from Constraints, Datums and encDatums. 27 type Builder struct { 28 codec keys.SQLCodec 29 table *sqlbase.TableDescriptor 30 index *sqlbase.IndexDescriptor 31 indexColTypes []*types.T 32 indexColDirs []sqlbase.IndexDescriptor_Direction 33 34 // KeyPrefix is the prefix of keys generated by the builder. 35 KeyPrefix []byte 36 alloc sqlbase.DatumAlloc 37 38 // TODO (rohany): The interstices are used to convert opt constraints into spans. In future work, 39 // we should unify the codepaths and use the allocation free method used on datums. 40 // This work is tracked in #42738. 41 interstices [][]byte 42 43 neededFamilies []sqlbase.FamilyID 44 } 45 46 // Use some functions that aren't needed right now to make the linter happy. 47 var _ = (*Builder).UnsetNeededColumns 48 var _ = (*Builder).SetNeededFamilies 49 var _ = (*Builder).UnsetNeededFamilies 50 51 // MakeBuilder creates a Builder for a table and index. 52 func MakeBuilder( 53 codec keys.SQLCodec, table *sqlbase.TableDescriptor, index *sqlbase.IndexDescriptor, 54 ) *Builder { 55 s := &Builder{ 56 codec: codec, 57 table: table, 58 index: index, 59 KeyPrefix: sqlbase.MakeIndexKeyPrefix(codec, table, index.ID), 60 interstices: make([][]byte, len(index.ColumnDirections)+len(index.ExtraColumnIDs)+1), 61 neededFamilies: nil, 62 } 63 64 var columnIDs sqlbase.ColumnIDs 65 columnIDs, s.indexColDirs = index.FullColumnIDs() 66 s.indexColTypes = make([]*types.T, len(columnIDs)) 67 for i, colID := range columnIDs { 68 // TODO (rohany): do I need to look at table columns with mutations here as well? 69 for _, col := range table.Columns { 70 if col.ID == colID { 71 s.indexColTypes[i] = col.Type 72 break 73 } 74 } 75 } 76 77 // Set up the interstices for encoding interleaved tables later. 78 s.interstices[0] = s.KeyPrefix 79 if len(index.Interleave.Ancestors) > 0 { 80 // TODO(rohany): too much of this code is copied from EncodePartialIndexKey. 81 sharedPrefixLen := 0 82 for i, ancestor := range index.Interleave.Ancestors { 83 // The first ancestor is already encoded in interstices[0]. 84 if i != 0 { 85 s.interstices[sharedPrefixLen] = sqlbase.EncodePartialTableIDIndexID( 86 s.interstices[sharedPrefixLen], ancestor.TableID, ancestor.IndexID) 87 } 88 sharedPrefixLen += int(ancestor.SharedPrefixLen) 89 s.interstices[sharedPrefixLen] = encoding.EncodeInterleavedSentinel( 90 s.interstices[sharedPrefixLen]) 91 } 92 s.interstices[sharedPrefixLen] = sqlbase.EncodePartialTableIDIndexID( 93 s.interstices[sharedPrefixLen], table.ID, index.ID) 94 } 95 96 return s 97 } 98 99 // N.B. [Un]SetNeeded{Columns,Families} interact / overwrite each other. 100 101 // SetNeededColumns sets the needed columns on the Builder. This information 102 // is used by MaybeSplitSpanIntoSeparateFamilies. 103 func (s *Builder) SetNeededColumns(neededCols util.FastIntSet) { 104 s.neededFamilies = sqlbase.NeededColumnFamilyIDs(neededCols, s.table, s.index) 105 } 106 107 // UnsetNeededColumns resets the needed columns for column family specific optimizations 108 // that the Builder performs. 109 func (s *Builder) UnsetNeededColumns() { 110 s.neededFamilies = nil 111 } 112 113 // SetNeededFamilies sets the needed families of the span builder directly. This information 114 // is used by MaybeSplitSpanIntoSeparateFamilies. 115 func (s *Builder) SetNeededFamilies(neededFamilies []sqlbase.FamilyID) { 116 s.neededFamilies = neededFamilies 117 } 118 119 // UnsetNeededFamilies resets the needed families for column family specific optimizations 120 // that the Builder performs. 121 func (s *Builder) UnsetNeededFamilies() { 122 s.neededFamilies = nil 123 } 124 125 // SpanFromEncDatums encodes a span with prefixLen constraint columns from the index. 126 // SpanFromEncDatums assumes that the EncDatums in values are in the order of the index columns. 127 // It also returns whether or not the input values contain a null value or not, which can be 128 // used as input for CanSplitSpanIntoSeparateFamilies. 129 func (s *Builder) SpanFromEncDatums( 130 values sqlbase.EncDatumRow, prefixLen int, 131 ) (_ roachpb.Span, containsNull bool, _ error) { 132 return sqlbase.MakeSpanFromEncDatums( 133 values[:prefixLen], s.indexColTypes[:prefixLen], s.indexColDirs[:prefixLen], s.table, s.index, &s.alloc, s.KeyPrefix) 134 } 135 136 // SpanFromDatumRow generates an index span with prefixLen constraint columns from the index. 137 // SpanFromDatumRow assumes that values is a valid table row for the Builder's table. 138 // It also returns whether or not the input values contain a null value or not, which can be 139 // used as input for CanSplitSpanIntoSeparateFamilies. 140 func (s *Builder) SpanFromDatumRow( 141 values tree.Datums, prefixLen int, colMap map[sqlbase.ColumnID]int, 142 ) (_ roachpb.Span, containsNull bool, _ error) { 143 return sqlbase.EncodePartialIndexSpan(s.table, s.index, prefixLen, colMap, values, s.KeyPrefix) 144 } 145 146 // SpanToPointSpan converts a span into a span that represents a point lookup on a 147 // specific family. It is up to the caller to ensure that this is a safe operation, 148 // by calling CanSplitSpanIntoSeparateFamilies before using it. 149 func (s *Builder) SpanToPointSpan(span roachpb.Span, family sqlbase.FamilyID) roachpb.Span { 150 key := keys.MakeFamilyKey(span.Key, uint32(family)) 151 return roachpb.Span{Key: key, EndKey: roachpb.Key(key).PrefixEnd()} 152 } 153 154 // MaybeSplitSpanIntoSeparateFamilies uses the needed columns configured by 155 // SetNeededColumns to conditionally split the input span into multiple family 156 // specific spans. prefixLen is the number of index columns encoded in the span. 157 // 158 // The function accepts a slice of spans to append to. 159 func (s *Builder) MaybeSplitSpanIntoSeparateFamilies( 160 appendTo roachpb.Spans, span roachpb.Span, prefixLen int, containsNull bool, 161 ) roachpb.Spans { 162 if s.neededFamilies != nil && s.CanSplitSpanIntoSeparateFamilies(len(s.neededFamilies), prefixLen, containsNull) { 163 return sqlbase.SplitSpanIntoSeparateFamilies(appendTo, span, s.neededFamilies) 164 } 165 return append(appendTo, span) 166 } 167 168 // CanSplitSpanIntoSeparateFamilies returns whether a span encoded with prefixLen keys and numNeededFamilies 169 // needed families can be safely split into multiple family specific spans. 170 func (s *Builder) CanSplitSpanIntoSeparateFamilies( 171 numNeededFamilies, prefixLen int, containsNull bool, 172 ) bool { 173 // We can only split a span into separate family specific point lookups if: 174 // * We have a unique index. 175 // * The index we are generating spans for actually has multiple families: 176 // - In the case of the primary index, that means the table itself has 177 // multiple families. 178 // - In the case of a secondary index, the table must have multiple families 179 // and the index must store some columns. 180 // * If we have a secondary index, then containsNull must be false 181 // and it cannot be an inverted index. 182 // * We have all of the lookup columns of the index. 183 // * We don't need all of the families. 184 return s.index.Unique && len(s.table.Families) > 1 && 185 (s.index.ID == s.table.PrimaryIndex.ID || 186 // Secondary index specific checks. 187 (s.index.Version == sqlbase.SecondaryIndexFamilyFormatVersion && 188 !containsNull && 189 len(s.index.StoreColumnIDs) > 0 && 190 s.index.Type == sqlbase.IndexDescriptor_FORWARD)) && 191 prefixLen == len(s.index.ColumnIDs) && 192 numNeededFamilies < len(s.table.Families) 193 } 194 195 // Functions for optimizer related span generation are below. 196 197 // SpansFromConstraint generates spans from an optimizer constraint. 198 // TODO (rohany): In future work, there should be a single API to generate spans 199 // from constraints, datums and encdatums. 200 func (s *Builder) SpansFromConstraint( 201 c *constraint.Constraint, needed exec.TableColumnOrdinalSet, forDelete bool, 202 ) (roachpb.Spans, error) { 203 var spans roachpb.Spans 204 var err error 205 if c == nil || c.IsUnconstrained() { 206 // Encode a full span. 207 spans, err = s.appendSpansFromConstraintSpan(spans, &constraint.UnconstrainedSpan, needed, forDelete) 208 if err != nil { 209 return nil, err 210 } 211 return spans, nil 212 } 213 214 spans = make(roachpb.Spans, 0, c.Spans.Count()) 215 for i := 0; i < c.Spans.Count(); i++ { 216 spans, err = s.appendSpansFromConstraintSpan(spans, c.Spans.Get(i), needed, forDelete) 217 if err != nil { 218 return nil, err 219 } 220 } 221 return spans, nil 222 } 223 224 // UnconstrainedSpans returns the full span corresponding to the Builder's 225 // table and index. 226 func (s *Builder) UnconstrainedSpans() (roachpb.Spans, error) { 227 return s.SpansFromConstraint(nil, exec.TableColumnOrdinalSet{}, false /* forDelete */) 228 } 229 230 // appendSpansFromConstraintSpan converts a constraint.Span to one or more 231 // roachpb.Spans and appends them to the provided spans. It appends multiple 232 // spans in the case that multiple, non-adjacent column families should be 233 // scanned. The forDelete parameter indicates whether these spans will be used 234 // for row deletion. 235 func (s *Builder) appendSpansFromConstraintSpan( 236 appendTo roachpb.Spans, cs *constraint.Span, needed exec.TableColumnOrdinalSet, forDelete bool, 237 ) (roachpb.Spans, error) { 238 var span roachpb.Span 239 var err error 240 var containsNull bool 241 // Encode each logical part of the start key. 242 span.Key, containsNull, err = s.encodeConstraintKey(cs.StartKey()) 243 if err != nil { 244 return nil, err 245 } 246 if cs.StartBoundary() == constraint.IncludeBoundary { 247 span.Key = append(span.Key, s.interstices[cs.StartKey().Length()]...) 248 } else { 249 // We need to exclude the value this logical part refers to. 250 span.Key = span.Key.PrefixEnd() 251 } 252 // Encode each logical part of the end key. 253 span.EndKey, _, err = s.encodeConstraintKey(cs.EndKey()) 254 if err != nil { 255 return nil, err 256 } 257 span.EndKey = append(span.EndKey, s.interstices[cs.EndKey().Length()]...) 258 259 // Optimization: for single row lookups on a table with multiple column 260 // families, only scan the relevant column families. This is disabled for 261 // deletions to ensure that the entire row is deleted. 262 if !forDelete && needed.Len() > 0 && span.Key.Equal(span.EndKey) { 263 neededFamilyIDs := sqlbase.NeededColumnFamilyIDs(needed, s.table, s.index) 264 if s.CanSplitSpanIntoSeparateFamilies(len(neededFamilyIDs), cs.StartKey().Length(), containsNull) { 265 return sqlbase.SplitSpanIntoSeparateFamilies(appendTo, span, neededFamilyIDs), nil 266 } 267 } 268 269 // We tighten the end key to prevent reading interleaved children after the 270 // last parent key. If cs.End.Inclusive is true, we also advance the key as 271 // necessary. 272 endInclusive := cs.EndBoundary() == constraint.IncludeBoundary 273 span.EndKey, err = sqlbase.AdjustEndKeyForInterleave(s.codec, s.table, s.index, span.EndKey, endInclusive) 274 if err != nil { 275 return nil, err 276 } 277 return append(appendTo, span), nil 278 } 279 280 // encodeConstraintKey encodes each logical part of a constraint.Key into a 281 // roachpb.Key; interstices[i] is inserted before the i-th value. 282 func (s *Builder) encodeConstraintKey( 283 ck constraint.Key, 284 ) (_ roachpb.Key, containsNull bool, _ error) { 285 var key []byte 286 for i := 0; i < ck.Length(); i++ { 287 val := ck.Value(i) 288 if val == tree.DNull { 289 containsNull = true 290 } 291 key = append(key, s.interstices[i]...) 292 293 var err error 294 // For extra columns (like implicit columns), the direction 295 // is ascending. 296 dir := encoding.Ascending 297 if i < len(s.index.ColumnDirections) { 298 dir, err = s.index.ColumnDirections[i].ToEncodingDirection() 299 if err != nil { 300 return nil, false, err 301 } 302 } 303 304 if s.index.Type == sqlbase.IndexDescriptor_INVERTED { 305 keys, err := sqlbase.EncodeInvertedIndexTableKeys(val, key) 306 if err != nil { 307 return nil, false, err 308 } 309 if len(keys) == 0 { 310 err := errors.AssertionFailedf("trying to use null key in index lookup") 311 return nil, false, err 312 } 313 if len(keys) > 1 { 314 err := errors.AssertionFailedf("trying to use multiple keys in index lookup") 315 return nil, false, err 316 } 317 key = keys[0] 318 } else { 319 key, err = sqlbase.EncodeTableKey(key, val, dir) 320 if err != nil { 321 return nil, false, err 322 } 323 } 324 } 325 return key, containsNull, nil 326 }