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  }