github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/doltcore/sqle/indexed_dolt_table.go (about) 1 // Copyright 2020 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 sqle 16 17 import ( 18 "encoding/binary" 19 "errors" 20 "io" 21 "sync" 22 23 "github.com/dolthub/go-mysql-server/sql" 24 25 "github.com/dolthub/dolt/go/libraries/doltcore/sqle/lookup" 26 "github.com/dolthub/dolt/go/libraries/doltcore/sqle/sqlutil" 27 "github.com/dolthub/dolt/go/store/types" 28 ) 29 30 // IndexedDoltTable is a wrapper for a DoltTable and a doltIndexLookup. It implements the sql.Table interface like 31 // DoltTable, but its RowIter function returns values that match the indexLookup, instead of all rows. It's returned by 32 // the DoltTable WithIndexLookup function. 33 type IndexedDoltTable struct { 34 table *DoltTable 35 indexLookup *doltIndexLookup 36 } 37 38 var _ sql.IndexedTable = (*IndexedDoltTable)(nil) 39 40 func (idt *IndexedDoltTable) GetIndexes(ctx *sql.Context) ([]sql.Index, error) { 41 return idt.table.GetIndexes(ctx) 42 } 43 44 func (idt *IndexedDoltTable) WithIndexLookup(lookup sql.IndexLookup) sql.Table { 45 // TODO: this should probably be an error (there should be at most one indexed lookup on a given table) 46 return idt.table.WithIndexLookup(lookup) 47 } 48 49 func (idt *IndexedDoltTable) Name() string { 50 return idt.table.Name() 51 } 52 53 func (idt *IndexedDoltTable) String() string { 54 return idt.table.String() 55 } 56 57 func (idt *IndexedDoltTable) Schema() sql.Schema { 58 return idt.table.Schema() 59 } 60 61 func (idt *IndexedDoltTable) Partitions(ctx *sql.Context) (sql.PartitionIter, error) { 62 return sqlutil.NewSinglePartitionIter(idt.indexLookup.IndexRowData()), nil 63 } 64 65 func (idt *IndexedDoltTable) PartitionRows(ctx *sql.Context, part sql.Partition) (sql.RowIter, error) { 66 if singlePart, ok := part.(sqlutil.SinglePartition); ok { 67 return idt.indexLookup.RowIter(ctx, singlePart.RowData, nil) 68 } 69 70 return nil, errors.New("unexpected partition type") 71 } 72 73 func (idt *IndexedDoltTable) IsTemporary() bool { 74 return idt.table.IsTemporary() 75 } 76 77 type rangePartition struct { 78 partitionRange lookup.Range 79 keyBytes []byte 80 rowData types.Map 81 } 82 83 func (rp rangePartition) Key() []byte { 84 return rp.keyBytes 85 } 86 87 type rangePartitionIter struct { 88 ranges []lookup.Range 89 curr int 90 mu *sync.Mutex 91 rowData types.Map 92 } 93 94 func NewRangePartitionIter(ranges []lookup.Range, rowData types.Map) *rangePartitionIter { 95 return &rangePartitionIter{ 96 ranges: ranges, 97 curr: 0, 98 mu: &sync.Mutex{}, 99 rowData: rowData, 100 } 101 } 102 103 // Close is required by the sql.PartitionIter interface. Does nothing. 104 func (itr *rangePartitionIter) Close(*sql.Context) error { 105 return nil 106 } 107 108 // Next returns the next partition if there is one, or io.EOF if there isn't. 109 func (itr *rangePartitionIter) Next() (sql.Partition, error) { 110 itr.mu.Lock() 111 defer itr.mu.Unlock() 112 113 if itr.curr >= len(itr.ranges) { 114 return nil, io.EOF 115 } 116 117 var bytes [4]byte 118 binary.BigEndian.PutUint32(bytes[:], uint32(itr.curr)) 119 part := rangePartition{itr.ranges[itr.curr], bytes[:], itr.rowData} 120 itr.curr += 1 121 122 return part, nil 123 } 124 125 var _ sql.IndexedTable = (*WritableIndexedDoltTable)(nil) 126 var _ sql.UpdatableTable = (*WritableIndexedDoltTable)(nil) 127 var _ sql.DeletableTable = (*WritableIndexedDoltTable)(nil) 128 var _ sql.ReplaceableTable = (*WritableIndexedDoltTable)(nil) 129 var _ sql.StatisticsTable = (*WritableIndexedDoltTable)(nil) 130 131 type WritableIndexedDoltTable struct { 132 *WritableDoltTable 133 indexLookup *doltIndexLookup 134 } 135 136 func (t *WritableIndexedDoltTable) Partitions(ctx *sql.Context) (sql.PartitionIter, error) { 137 if len(t.indexLookup.ranges) > 1 { 138 return NewRangePartitionIter(t.indexLookup.ranges, t.indexLookup.IndexRowData()), nil 139 } 140 141 return sqlutil.NewSinglePartitionIter(t.indexLookup.IndexRowData()), nil 142 } 143 144 func (t *WritableIndexedDoltTable) PartitionRows(ctx *sql.Context, part sql.Partition) (sql.RowIter, error) { 145 return partitionIndexedTableRows(ctx, t, t.projectedCols, part) 146 } 147 148 func partitionIndexedTableRows(ctx *sql.Context, t *WritableIndexedDoltTable, projectedCols []string, part sql.Partition) (sql.RowIter, error) { 149 switch typed := part.(type) { 150 case rangePartition: 151 return t.indexLookup.RowIterForRanges(ctx, typed.rowData, []lookup.Range{typed.partitionRange}, projectedCols) 152 case sqlutil.SinglePartition: 153 return t.indexLookup.RowIter(ctx, typed.RowData, projectedCols) 154 } 155 156 return nil, errors.New("unknown partition type") 157 } 158 159 func (t *WritableIndexedDoltTable) WithProjection(colNames []string) sql.Table { 160 return &WritableIndexedDoltTable{ 161 WritableDoltTable: t.WithProjection(colNames).(*WritableDoltTable), 162 indexLookup: t.indexLookup, 163 } 164 }