github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/store/prolly/tuple_range.go (about)

     1  // Copyright 2022 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package prolly
    16  
    17  import (
    18  	"sort"
    19  
    20  	"github.com/dolthub/dolt/go/store/prolly/tree"
    21  	"github.com/dolthub/dolt/go/store/val"
    22  )
    23  
    24  // OpenStopRange defines a half-open Range of Tuples [start, stop).
    25  func OpenStopRange(start, stop val.Tuple, desc val.TupleDesc) Range {
    26  	return openStopRange(start, stop, desc)
    27  }
    28  
    29  // GreaterOrEqualRange defines a Range of Tuples greater than or equal to |start|.
    30  func GreaterOrEqualRange(start val.Tuple, desc val.TupleDesc) Range {
    31  	return greaterOrEqualRange(start, desc)
    32  }
    33  
    34  // LesserRange defines a Range of Tuples less than |stop|.
    35  func LesserRange(stop val.Tuple, desc val.TupleDesc) Range {
    36  	return lesserRange(stop, desc)
    37  }
    38  
    39  // PrefixRange constructs a Range for Tuples with a prefix of |prefix|.
    40  func PrefixRange(prefix val.Tuple, desc val.TupleDesc) Range {
    41  	return closedRange(prefix, prefix, desc)
    42  }
    43  
    44  // Range defines a subset of a prolly Tree Tuple index.
    45  //
    46  // Range can be used either to physically partition an index or
    47  // to logically filter an index.
    48  // A Range's physical partition is a contiguous set of Tuples
    49  // containing every Tuple matching the Range's predicates, but
    50  // possibly containing non-matching Tuples.
    51  // Non-matching Tuples can be filtered from physical partitions
    52  // by using RangeFields as logical predicates (see filteredIter).
    53  type Range struct {
    54  	Fields []RangeField
    55  	Desc   val.TupleDesc
    56  	Tup    val.Tuple
    57  }
    58  
    59  // RangeField bounds one dimension of a Range.
    60  type RangeField struct {
    61  	Lo, Hi Bound
    62  	Exact  bool // Lo.Value == Hi.Value
    63  }
    64  
    65  type Bound struct {
    66  	Binding   bool
    67  	Inclusive bool
    68  	Value     []byte
    69  }
    70  
    71  // aboveStart is used to find the start of the
    72  // physical partition defined by a Range.
    73  func (r Range) aboveStart(t val.Tuple) bool {
    74  	order := r.Desc.Comparator()
    75  	for i := range r.Fields {
    76  		bound := r.Fields[i].Lo
    77  		if !bound.Binding {
    78  			return true
    79  		}
    80  
    81  		field := r.Desc.GetField(i, t)
    82  		typ := r.Desc.Types[i]
    83  
    84  		cmp := order.CompareValues(i, field, bound.Value, typ)
    85  		if cmp < 0 {
    86  			// |field| is outside Range
    87  			return false
    88  		}
    89  
    90  		if r.Fields[i].Exact && cmp == 0 {
    91  			// for exact bounds (operators '=' and 'IS')
    92  			// we can use subsequent columns to narrow
    93  			// physical index scans.
    94  			// this is not possible for interval bounds.
    95  			continue
    96  		}
    97  
    98  		return cmp > 0 || bound.Inclusive
    99  	}
   100  	return true
   101  }
   102  
   103  // belowStop is used to find the end of the
   104  // physical partition defined by a Range.
   105  func (r Range) belowStop(t val.Tuple) bool {
   106  	order := r.Desc.Comparator()
   107  	for i := range r.Fields {
   108  		bound := r.Fields[i].Hi
   109  		if !bound.Binding {
   110  			return true
   111  		}
   112  
   113  		field := r.Desc.GetField(i, t)
   114  		typ := r.Desc.Types[i]
   115  
   116  		cmp := order.CompareValues(i, field, bound.Value, typ)
   117  		if cmp > 0 {
   118  			// |field| is outside Range
   119  			return false
   120  		}
   121  
   122  		if r.Fields[i].Exact && cmp == 0 {
   123  			// for exact bounds (operators '=' and 'IS')
   124  			// we can use subsequent columns to narrow
   125  			// physical index scans.
   126  			// this is not possible for interval bounds.
   127  			continue
   128  		}
   129  
   130  		return cmp < 0 || bound.Inclusive
   131  	}
   132  	return true
   133  }
   134  
   135  // Matches returns true if all the filter predicates
   136  // for Range |r| are true for Tuple |t|.
   137  func (r Range) Matches(t val.Tuple) bool {
   138  	order := r.Desc.Comparator()
   139  	for i := range r.Fields {
   140  		field := r.Desc.GetField(i, t)
   141  		typ := r.Desc.Types[i]
   142  
   143  		if r.Fields[i].Exact {
   144  			v := r.Fields[i].Lo.Value
   145  			if order.CompareValues(i, field, v, typ) == 0 {
   146  				continue
   147  			}
   148  			return false
   149  		}
   150  
   151  		lo := r.Fields[i].Lo
   152  		if lo.Binding {
   153  			cmp := order.CompareValues(i, field, lo.Value, typ)
   154  			if cmp < 0 || (cmp == 0 && !lo.Inclusive) {
   155  				return false
   156  			}
   157  		}
   158  
   159  		hi := r.Fields[i].Hi
   160  		if hi.Binding {
   161  			cmp := order.CompareValues(i, field, hi.Value, typ)
   162  			if cmp > 0 || (cmp == 0 && !hi.Inclusive) {
   163  				return false
   164  			}
   165  		}
   166  	}
   167  	return true
   168  }
   169  
   170  func (r Range) IsPointLookup(desc val.TupleDesc) bool {
   171  	if len(r.Fields) < len(desc.Types) {
   172  		return false
   173  	}
   174  	for i := range r.Fields {
   175  		if !r.Fields[i].Exact {
   176  			return false
   177  		}
   178  	}
   179  	return true
   180  }
   181  
   182  func rangeStartSearchFn(rng Range) tree.SearchFn {
   183  	return func(nd tree.Node) int {
   184  		// todo(andy): inline sort.Search()
   185  		return sort.Search(nd.Count(), func(i int) (in bool) {
   186  			// if |tup| ∈ |rng|, set |in| to true
   187  			tup := val.Tuple(nd.GetKey(i))
   188  			in = rng.aboveStart(tup)
   189  			return
   190  		})
   191  	}
   192  }
   193  
   194  func rangeStopSearchFn(rng Range) tree.SearchFn {
   195  	return func(nd tree.Node) (idx int) {
   196  		// todo(andy): inline sort.Search()
   197  		return sort.Search(nd.Count(), func(i int) (out bool) {
   198  			// if |tup| ∈ |rng|, set |out| to false
   199  			tup := val.Tuple(nd.GetKey(i))
   200  			out = !rng.belowStop(tup)
   201  			return
   202  		})
   203  	}
   204  }
   205  
   206  // closedRange defines an inclusive Range of Tuples from [start, stop].
   207  func closedRange(start, stop val.Tuple, desc val.TupleDesc) (rng Range) {
   208  	rng = Range{
   209  		Fields: make([]RangeField, len(desc.Types)),
   210  		Desc:   desc,
   211  	}
   212  	order := desc.Comparator()
   213  
   214  	for i := range rng.Fields {
   215  		lo := desc.GetField(i, start)
   216  		hi := desc.GetField(i, stop)
   217  		rng.Fields[i] = RangeField{
   218  			Lo:    Bound{Binding: true, Inclusive: true, Value: lo},
   219  			Hi:    Bound{Binding: true, Inclusive: true, Value: hi},
   220  			Exact: order.CompareValues(i, lo, hi, desc.Types[i]) == 0,
   221  		}
   222  	}
   223  	return
   224  }
   225  
   226  // OpenStartRange defines a half-open Range of Tuples (start, stop].
   227  func openStartRange(start, stop val.Tuple, desc val.TupleDesc) (rng Range) {
   228  	rng = closedRange(start, stop, desc)
   229  	last := len(rng.Fields) - 1
   230  	rng.Fields[last].Lo.Inclusive = false
   231  	rng.Fields[last].Exact = false
   232  	return rng
   233  }
   234  
   235  // OpenStopRange defines a half-open Range of Tuples [start, stop).
   236  func openStopRange(start, stop val.Tuple, desc val.TupleDesc) (rng Range) {
   237  	rng = closedRange(start, stop, desc)
   238  	last := len(rng.Fields) - 1
   239  	rng.Fields[last].Hi.Inclusive = false
   240  	rng.Fields[last].Exact = false
   241  	return
   242  }
   243  
   244  // OpenRange defines a non-inclusive Range of Tuples from (start, stop).
   245  func openRange(start, stop val.Tuple, desc val.TupleDesc) (rng Range) {
   246  	rng = closedRange(start, stop, desc)
   247  	last := len(rng.Fields) - 1
   248  	rng.Fields[last].Lo.Inclusive = false
   249  	rng.Fields[last].Hi.Inclusive = false
   250  	rng.Fields[last].Exact = false
   251  	return
   252  }
   253  
   254  // GreaterRange defines a Range of Tuples greater than |start|.
   255  func greaterRange(start val.Tuple, desc val.TupleDesc) (rng Range) {
   256  	rng = greaterOrEqualRange(start, desc)
   257  	last := len(rng.Fields) - 1
   258  	rng.Fields[last].Lo.Inclusive = false
   259  	return
   260  }
   261  
   262  // GreaterOrEqualRange defines a Range of Tuples greater than or equal to |start|.
   263  func greaterOrEqualRange(start val.Tuple, desc val.TupleDesc) (rng Range) {
   264  	rng = Range{
   265  		Fields: make([]RangeField, len(desc.Types)),
   266  		Desc:   desc,
   267  	}
   268  	for i := range rng.Fields {
   269  		lo := desc.GetField(i, start)
   270  		rng.Fields[i] = RangeField{
   271  			Lo: Bound{Binding: true, Inclusive: true, Value: lo},
   272  		}
   273  	}
   274  	return
   275  }
   276  
   277  // LesserRange defines a Range of Tuples less than |stop|.
   278  func lesserRange(stop val.Tuple, desc val.TupleDesc) (rng Range) {
   279  	rng = lesserOrEqualRange(stop, desc)
   280  	last := len(rng.Fields) - 1
   281  	rng.Fields[last].Hi.Inclusive = false
   282  	return
   283  }
   284  
   285  // LesserOrEqualRange defines a Range of Tuples less than or equal to |stop|.
   286  func lesserOrEqualRange(stop val.Tuple, desc val.TupleDesc) (rng Range) {
   287  	rng = Range{
   288  		Fields: make([]RangeField, len(desc.Types)),
   289  		Desc:   desc,
   290  	}
   291  	for i := range rng.Fields {
   292  		hi := desc.GetField(i, stop)
   293  		rng.Fields[i] = RangeField{
   294  			Hi: Bound{Binding: true, Inclusive: true, Value: hi},
   295  		}
   296  	}
   297  	return
   298  }