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  }