github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/doltcore/sqle/rows.go (about) 1 // Copyright 2019 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 "context" 19 20 "github.com/dolthub/go-mysql-server/sql" 21 22 "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" 23 "github.com/dolthub/dolt/go/libraries/doltcore/doltdb/durable" 24 "github.com/dolthub/dolt/go/libraries/doltcore/schema" 25 "github.com/dolthub/dolt/go/libraries/doltcore/sqle/index" 26 "github.com/dolthub/dolt/go/libraries/doltcore/sqle/sqlutil" 27 "github.com/dolthub/dolt/go/libraries/doltcore/table" 28 "github.com/dolthub/dolt/go/store/types" 29 ) 30 31 var _ sql.RowIter = (*keylessRowIter)(nil) 32 33 type keylessRowIter struct { 34 keyedIter *index.DoltMapIter 35 36 cardIdx int 37 nonCardCols int 38 39 lastRead sql.Row 40 lastCard uint64 41 } 42 43 func (k *keylessRowIter) Next(ctx *sql.Context) (sql.Row, error) { 44 if k.lastCard == 0 { 45 r, err := k.keyedIter.Next(ctx) 46 47 if err != nil { 48 return nil, err 49 } 50 51 k.lastCard = r[k.cardIdx].(uint64) 52 k.lastRead = r[:k.nonCardCols] 53 } 54 55 k.lastCard-- 56 return k.lastRead, nil 57 } 58 59 func (k keylessRowIter) Close(ctx *sql.Context) error { 60 return k.keyedIter.Close(ctx) 61 } 62 63 // An iterator over the rows of a table. 64 type doltTableRowIter struct { 65 sql.RowIter 66 ctx context.Context 67 reader table.SqlTableReader 68 } 69 70 // Returns a new row iterator for the table given 71 func newRowIterator(ctx context.Context, tbl *doltdb.Table, projCols []uint64, partition doltTablePartition) (sql.RowIter, error) { 72 sch, err := tbl.GetSchema(ctx) 73 74 if err != nil { 75 return nil, err 76 } 77 78 if types.IsFormat_DOLT(tbl.Format()) { 79 return ProllyRowIterFromPartition(ctx, sch, projCols, partition) 80 } 81 82 mapIter, err := iterForPartition(ctx, partition) 83 if err != nil { 84 return nil, err 85 } 86 87 if schema.IsKeyless(sch) { 88 // would be more optimal to project columns into keyless tables also 89 return newKeylessRowIterator(ctx, tbl, projCols, mapIter) 90 } else { 91 return newKeyedRowIter(ctx, tbl, projCols, mapIter) 92 } 93 } 94 95 func newKeylessRowIterator(ctx context.Context, tbl *doltdb.Table, projectedCols []uint64, mapIter types.MapTupleIterator) (sql.RowIter, error) { 96 97 cols, tagToSqlColIdx, err := getTagToResColIdx(ctx, tbl, projectedCols) 98 if err != nil { 99 return nil, err 100 } 101 102 idxOfCardinality := len(cols) 103 tagToSqlColIdx[schema.KeylessRowCardinalityTag] = idxOfCardinality 104 105 colsCopy := make([]schema.Column, len(cols), len(cols)+1) 106 copy(colsCopy, cols) 107 colsCopy = append(colsCopy, schema.NewColumn("__cardinality__", schema.KeylessRowCardinalityTag, types.UintKind, false)) 108 109 conv := index.NewKVToSqlRowConverter(tbl.Format(), tagToSqlColIdx, colsCopy, len(colsCopy)) 110 keyedItr, err := index.NewDoltMapIter(mapIter.NextTuple, nil, conv), nil 111 if err != nil { 112 return nil, err 113 } 114 115 return &keylessRowIter{ 116 keyedIter: keyedItr, 117 cardIdx: idxOfCardinality, 118 nonCardCols: len(cols), 119 }, nil 120 } 121 122 func newKeyedRowIter(ctx context.Context, tbl *doltdb.Table, projectedCols []uint64, mapIter types.MapTupleIterator) (sql.RowIter, error) { 123 124 cols, tagToSqlColIdx, err := getTagToResColIdx(ctx, tbl, projectedCols) 125 if err != nil { 126 return nil, err 127 } 128 129 conv := index.NewKVToSqlRowConverter(tbl.Format(), tagToSqlColIdx, cols, len(cols)) 130 return index.NewDoltMapIter(mapIter.NextTuple, nil, conv), nil 131 } 132 133 func iterForPartition(ctx context.Context, partition doltTablePartition) (types.MapTupleIterator, error) { 134 if partition.end == NoUpperBound { 135 c, err := partition.rowData.Count() 136 if err != nil { 137 return nil, err 138 } 139 partition.end = c 140 } 141 return partition.IteratorForPartition(ctx, partition.rowData) 142 } 143 144 func getTagToResColIdx(ctx context.Context, tbl *doltdb.Table, projectedCols []uint64) ([]schema.Column, map[uint64]int, error) { 145 sch, err := tbl.GetSchema(ctx) 146 if err != nil { 147 return nil, nil, err 148 } 149 150 allCols := sch.GetAllCols().GetColumns() 151 tagToSqlColIdx := make(map[uint64]int) 152 153 if projectedCols != nil { 154 outCols := make([]schema.Column, len(projectedCols)) 155 for i := range projectedCols { 156 t := projectedCols[i] 157 idx := sch.GetAllCols().TagToIdx[t] 158 tagToSqlColIdx[t] = i 159 outCols[i] = allCols[idx] 160 } 161 return outCols, tagToSqlColIdx, nil 162 } 163 164 for i, col := range allCols { 165 tagToSqlColIdx[col.Tag] = i 166 } 167 return allCols, tagToSqlColIdx, nil 168 } 169 170 // Next returns the next row in this row iterator, or an io.EOF error if there aren't any more. 171 func (itr *doltTableRowIter) Next() (sql.Row, error) { 172 return itr.reader.ReadSqlRow(itr.ctx) 173 } 174 175 // Close required by sql.RowIter interface 176 func (itr *doltTableRowIter) Close(*sql.Context) error { 177 return nil 178 } 179 180 func ProllyRowIterFromPartition( 181 ctx context.Context, 182 sch schema.Schema, 183 projections []uint64, 184 partition doltTablePartition, 185 ) (sql.RowIter, error) { 186 rows := durable.ProllyMapFromIndex(partition.rowData) 187 c, err := rows.Count() 188 if err != nil { 189 return nil, err 190 } 191 if partition.end > uint64(c) { 192 partition.end = uint64(c) 193 } 194 195 iter, err := rows.FetchOrdinalRange(ctx, partition.start, partition.end) 196 if err != nil { 197 return nil, err 198 } 199 200 return index.NewProllyRowIterForMap(sch, rows, iter, projections), nil 201 } 202 203 // SqlTableToRowIter returns a |sql.RowIter| for a full table scan for the given |table|. If 204 // |columns| is not empty, only columns with names appearing in |columns| will 205 // have non-|nil| values in the resulting |sql.Row|s. If |columns| is empty, 206 // values for all columns in the table are populated in each returned Row. The 207 // returned rows always have the schema of the table, regardless of the value 208 // of |columns|. Providing a column name which does not appear in the schema 209 // is not an error, but no corresponding column will appear in the results. 210 func SqlTableToRowIter(ctx *sql.Context, table *DoltTable, columns []uint64) (sql.RowIter, error) { 211 t, err := table.DoltTable(ctx) 212 if err != nil { 213 return nil, err 214 } 215 216 data, err := t.GetRowData(ctx) 217 if err != nil { 218 return nil, err 219 } 220 221 p := doltTablePartition{ 222 end: NoUpperBound, 223 rowData: data, 224 } 225 226 return newRowIterator(ctx, t, columns, p) 227 } 228 229 // DoltTablePartitionToRowIter returns a sql.RowIter for a partition of the clustered index of |table|. 230 func DoltTablePartitionToRowIter(ctx *sql.Context, name string, table *doltdb.Table, start uint64, end uint64) (sql.Schema, sql.RowIter, error) { 231 sch, err := table.GetSchema(ctx) 232 if err != nil { 233 return nil, nil, err 234 } 235 pkSch, err := sqlutil.FromDoltSchema("", name, sch) 236 if err != nil { 237 return nil, nil, err 238 } 239 240 data, err := table.GetRowData(ctx) 241 if err != nil { 242 return nil, nil, err 243 } 244 245 if types.IsFormat_DOLT(data.Format()) { 246 idx := durable.ProllyMapFromIndex(data) 247 c, err := idx.Count() 248 if err != nil { 249 return nil, nil, err 250 } 251 if end > uint64(c) { 252 end = uint64(c) 253 } 254 iter, err := idx.IterOrdinalRange(ctx, start, end) 255 if err != nil { 256 return nil, nil, err 257 } 258 rowIter := index.NewProllyRowIterForMap(sch, idx, iter, nil) 259 if err != nil { 260 return nil, nil, err 261 } 262 return pkSch.Schema, rowIter, nil 263 } 264 265 idx := durable.NomsMapFromIndex(data) 266 iterAt, err := idx.IteratorAt(ctx, start) 267 if err != nil { 268 return nil, nil, err 269 } 270 271 iter := types.NewLimitingMapIterator(iterAt, end-start) 272 273 var rowIter sql.RowIter 274 if schema.IsKeyless(sch) { 275 rowIter, err = newKeylessRowIterator(ctx, table, nil, iter) 276 if err != nil { 277 return nil, nil, err 278 } 279 } else { 280 rowIter, err = newKeyedRowIter(ctx, table, nil, iter) 281 if err != nil { 282 return nil, nil, err 283 } 284 } 285 286 return pkSch.Schema, rowIter, nil 287 }