diff --git a/bats/index.bats b/bats/index.bats index c147098c6a..c51aa22742 100644 --- a/bats/index.bats +++ b/bats/index.bats @@ -713,7 +713,57 @@ SQL [[ "${#lines[@]}" = "1" ]] || false } -@test "index: SELECT = Full Match" { +@test "index: SELECT = Primary Key" { + dolt sql < Full Match" { +@test "index: SELECT > Primary Key" { + dolt sql < 2" -r=csv + [ "$status" -eq "0" ] + [[ "$output" =~ "pk1,v1,v2" ]] || false + [[ "$output" =~ "3,88,52" ]] || false + [[ "$output" =~ "4,22,54" ]] || false + [[ "$output" =~ "5,77,53" ]] || false + [[ "${#lines[@]}" = "4" ]] || false + # not found + run dolt sql -q "SELECT * FROM onepk WHERE pk1 > 999" -r=csv + [ "$status" -eq "0" ] + [[ "$output" =~ "pk1,v1,v2" ]] || false + [[ "${#lines[@]}" = "1" ]] || false + # found partial pk + run dolt sql -q "SELECT * FROM twopk WHERE pk1 > 2" -r=csv + [ "$status" -eq "0" ] + [[ "$output" =~ "pk1,pk2,v1,v2" ]] || false + [[ "$output" =~ "3,88,52,61" ]] || false + [[ "$output" =~ "4,22,54,65" ]] || false + [[ "$output" =~ "5,77,53,61" ]] || false + [[ "${#lines[@]}" = "4" ]] || false + # not found partial pk + run dolt sql -q "SELECT * FROM twopk WHERE pk1 > 999" -r=csv + [ "$status" -eq "0" ] + [[ "$output" =~ "pk1,pk2,v1,v2" ]] || false + [[ "${#lines[@]}" = "1" ]] || false + # found + run dolt sql -q "SELECT * FROM twopk WHERE pk1 > 4 AND pk2 > 22" -r=csv + [ "$status" -eq "0" ] + [[ "$output" =~ "pk1,pk2,v1,v2" ]] || false + [[ "$output" =~ "5,77,53,61" ]] || false + [[ "${#lines[@]}" = "2" ]] || false + # not found key 1 + run dolt sql -q "SELECT * FROM twopk WHERE pk1 > 999 AND pk2 > 11" -r=csv + [ "$status" -eq "0" ] + [[ "$output" =~ "pk1,pk2,v1,v2" ]] || false + [[ "${#lines[@]}" = "1" ]] || false + # not found key 2 + run dolt sql -q "SELECT * FROM twopk WHERE pk1 > 2 AND pk2 > 999" -r=csv + [ "$status" -eq "0" ] + [[ "$output" =~ "pk1,pk2,v1,v2" ]] || false + [[ "${#lines[@]}" = "1" ]] || false + # not found key mismatch + run dolt sql -q "SELECT * FROM twopk WHERE pk1 > 3 AND pk2 > 99" -r=csv + [ "$status" -eq "0" ] + [[ "$output" =~ "pk1,pk2,v1,v2" ]] || false + [[ "${#lines[@]}" = "1" ]] || false +} + +@test "index: SELECT > Secondary Index" { dolt sql < 63" -r=csv + [ "$status" -eq "0" ] + [[ "$output" =~ "pk1,pk2,v1,v2" ]] || false + [[ "$output" =~ "2,11,55,64" ]] || false + [[ "$output" =~ "4,22,54,65" ]] || false + [[ "${#lines[@]}" = "3" ]] || false + # not found partial index + run dolt sql -q "SELECT * FROM twopk WHERE v2 > 111" -r=csv + [ "$status" -eq "0" ] + [[ "$output" =~ "pk1,pk2,v1,v2" ]] || false + [[ "${#lines[@]}" = "1" ]] || false # found run dolt sql -q "SELECT * FROM twopk WHERE v2 > 61 AND v1 > 53" -r=csv [ "$status" -eq "0" ] @@ -844,7 +971,60 @@ SQL [[ "${#lines[@]}" = "1" ]] || false } -@test "index: SELECT < Full Match" { +@test "index: SELECT < Primary Key" { + dolt sql <= Full Match" { +@test "index: SELECT >= Primary Key" { + dolt sql <= 2" -r=csv + [ "$status" -eq "0" ] + [[ "$output" =~ "pk1,v1,v2" ]] || false + [[ "$output" =~ "2,11,55" ]] || false + [[ "$output" =~ "3,88,52" ]] || false + [[ "$output" =~ "4,22,54" ]] || false + [[ "$output" =~ "5,77,53" ]] || false + [[ "${#lines[@]}" = "5" ]] || false + # not found + run dolt sql -q "SELECT * FROM onepk WHERE pk1 >= 999" -r=csv + [ "$status" -eq "0" ] + [[ "$output" =~ "pk1,v1,v2" ]] || false + [[ "${#lines[@]}" = "1" ]] || false + # found partial pk + run dolt sql -q "SELECT * FROM twopk WHERE pk1 >= 2" -r=csv + [ "$status" -eq "0" ] + [[ "$output" =~ "pk1,pk2,v1,v2" ]] || false + [[ "$output" =~ "2,11,55,64" ]] || false + [[ "$output" =~ "3,88,52,61" ]] || false + [[ "$output" =~ "4,22,54,65" ]] || false + [[ "$output" =~ "5,77,53,61" ]] || false + [[ "${#lines[@]}" = "5" ]] || false + # not found partial pk + run dolt sql -q "SELECT * FROM twopk WHERE pk1 >= 999" -r=csv + [ "$status" -eq "0" ] + [[ "$output" =~ "pk1,pk2,v1,v2" ]] || false + [[ "${#lines[@]}" = "1" ]] || false + # found + run dolt sql -q "SELECT * FROM twopk WHERE pk1 >= 4 AND pk2 >= 22" -r=csv + [ "$status" -eq "0" ] + [[ "$output" =~ "pk1,pk2,v1,v2" ]] || false + [[ "$output" =~ "4,22,54,65" ]] || false + [[ "$output" =~ "5,77,53,61" ]] || false + [[ "${#lines[@]}" = "3" ]] || false + # not found key 1 + run dolt sql -q "SELECT * FROM twopk WHERE pk1 >= 999 AND pk2 >= 11" -r=csv + [ "$status" -eq "0" ] + [[ "$output" =~ "pk1,pk2,v1,v2" ]] || false + [[ "${#lines[@]}" = "1" ]] || false + # not found key 2 + run dolt sql -q "SELECT * FROM twopk WHERE pk1 >= 2 AND pk2 >= 999" -r=csv + [ "$status" -eq "0" ] + [[ "$output" =~ "pk1,pk2,v1,v2" ]] || false + [[ "${#lines[@]}" = "1" ]] || false + # not found key mismatch + run dolt sql -q "SELECT * FROM twopk WHERE pk1 >= 4 AND pk2 >= 88" -r=csv + [ "$status" -eq "0" ] + [[ "$output" =~ "pk1,pk2,v1,v2" ]] || false + [[ "${#lines[@]}" = "1" ]] || false +} + +@test "index: SELECT >= Secondary Index" { dolt sql <= 63" -r=csv + [ "$status" -eq "0" ] + [[ "$output" =~ "pk1,pk2,v1,v2" ]] || false + [[ "$output" =~ "1,99,51,63" ]] || false + [[ "$output" =~ "2,11,55,64" ]] || false + [[ "$output" =~ "4,22,54,65" ]] || false + [[ "${#lines[@]}" = "4" ]] || false + # not found partial index + run dolt sql -q "SELECT * FROM twopk WHERE v2 >= 111" -r=csv + [ "$status" -eq "0" ] + [[ "$output" =~ "pk1,pk2,v1,v2" ]] || false + [[ "${#lines[@]}" = "1" ]] || false # found run dolt sql -q "SELECT * FROM twopk WHERE v2 >= 61 AND v1 >= 53" -r=csv [ "$status" -eq "0" ] @@ -984,7 +1247,64 @@ SQL [[ "${#lines[@]}" = "1" ]] || false } -@test "index: SELECT <= Full Match" { +@test "index: SELECT <= Primary Key" { + dolt sql <= len(key) { - break - } - col, _ := di.index.GetColumn(tag) - val, err := col.TypeInfo.ConvertValueToNomsValue(key[i]) - if err != nil { - return nil, err - } - taggedVals[tag] = val + equals := make([]*expression.Equals, len(key)) + for i := 0; i < len(key); i++ { + equals[i] = expression.NewEquals( + expression.NewGetField(i, di.cols[i].TypeInfo.ToSqlType(), di.cols[i].Name, di.cols[i].IsNullable()), + expression.NewLiteral(key[i], di.cols[i].TypeInfo.ToSqlType()), + ) + } + var lastExpr sql.Expression = equals[len(equals)-1] + for i := len(equals) - 2; i >= 0; i-- { + lastExpr = expression.NewAnd(equals[i], lastExpr) } - rowData, err := di.table.GetIndexRowData(di.ctx, di.index.Name()) + crf, err := CreateReaderFuncLimitedByExpressions(di.rowData.Format(), di.mapSch, []sql.Expression{lastExpr}) if err != nil { return nil, err } - rowDataIter, err := rowData.Iterator(di.ctx) + mapIter, err := crf(di.ctx, di.rowData) if err != nil { return nil, err } + return &doltIndexLookup{ di, &doltIndexKeyIter{ - index: di.index, - indexMapIter: rowDataIter, - val: taggedVals, + indexMapIter: mapIter, }, }, nil } @@ -215,7 +122,7 @@ func (*doltIndex) Has(partition sql.Partition, key ...interface{}) (bool, error) } func (di *doltIndex) ID() string { - return fmt.Sprintf("%s:%s%v", di.tableName, di.index.Name(), len(di.index.IndexedColumnTags())) + return di.id } func (di *doltIndex) Schema() schema.Schema { diff --git a/go/libraries/doltcore/sqle/index_driver.go b/go/libraries/doltcore/sqle/index_driver.go index 17bedc56eb..a7f7f78ddd 100644 --- a/go/libraries/doltcore/sqle/index_driver.go +++ b/go/libraries/doltcore/sqle/index_driver.go @@ -15,7 +15,11 @@ package sqle import ( + "fmt" + "github.com/liquidata-inc/go-mysql-server/sql" + + "github.com/liquidata-inc/dolt/go/libraries/doltcore/schema" ) type DoltIndexDriver struct { @@ -69,26 +73,46 @@ func (driver *DoltIndexDriver) LoadAll(ctx *sql.Context, db, table string) ([]sq return nil, err } + rowData, err := tbl.GetRowData(ctx) + if err != nil { + return nil, err + } + + cols := sch.GetPKCols().GetColumns() sqlIndexes := []sql.Index{ - &doltIndexPk{ - db: database, - sch: sch, - tableName: table, - table: tbl, - driver: driver, - cols: sch.GetPKCols().GetColumns(), + &doltIndex{ + cols: cols, ctx: ctx, + db: database, + driver: driver, + id: fmt.Sprintf("%s:primaryKey%v", table, len(cols)), + mapSch: sch, + rowData: rowData, + table: tbl, + tableName: table, + tableSch: sch, }, } for _, index := range sch.Indexes().AllIndexes() { + rowData, err := tbl.GetIndexRowData(ctx, index.Name()) + if err != nil { + return nil, err + } + cols := make([]schema.Column, index.Count()) + for i, tag := range index.IndexedColumnTags() { + cols[i], _ = index.GetColumn(tag) + } sqlIndexes = append(sqlIndexes, &doltIndex{ + cols: cols, + ctx: ctx, db: database, driver: driver, - tableSch: sch, - tableName: table, + id: table + index.Name(), + mapSch: index.Schema(), + rowData: rowData, table: tbl, - index: index, - ctx: ctx, + tableName: table, + tableSch: sch, }) } diff --git a/go/libraries/doltcore/sqle/index_lookup.go b/go/libraries/doltcore/sqle/index_lookup.go index 88af5bcc04..23b325645d 100644 --- a/go/libraries/doltcore/sqle/index_lookup.go +++ b/go/libraries/doltcore/sqle/index_lookup.go @@ -15,14 +15,10 @@ package sqle import ( - "fmt" - "io" - "github.com/liquidata-inc/go-mysql-server/sql" "github.com/liquidata-inc/dolt/go/libraries/doltcore/row" - "github.com/liquidata-inc/dolt/go/libraries/doltcore/schema" - "github.com/liquidata-inc/dolt/go/store/types" + "github.com/liquidata-inc/dolt/go/libraries/doltcore/table" ) type IndexLookupKeyIterator interface { @@ -48,89 +44,16 @@ func (il *doltIndexLookup) RowIter(ctx *sql.Context) (sql.RowIter, error) { return &indexLookupRowIterAdapter{indexLookup: il, ctx: ctx}, nil } -type doltIndexSinglePkKeyIter struct { - hasReturned bool - val row.TaggedValues -} - -var _ IndexLookupKeyIterator = (*doltIndexSinglePkKeyIter)(nil) - -func (iter *doltIndexSinglePkKeyIter) NextKey(*sql.Context) (row.TaggedValues, error) { - if iter.hasReturned { - return nil, io.EOF - } - iter.hasReturned = true - return iter.val, nil -} - -type doltIndexMultiPkKeyIter struct { - tableName string - tableMapIter types.MapIterator - val row.TaggedValues -} - -var _ IndexLookupKeyIterator = (*doltIndexMultiPkKeyIter)(nil) - -func (iter *doltIndexMultiPkKeyIter) NextKey(ctx *sql.Context) (row.TaggedValues, error) { - var k types.Value - var err error -IterateOverMap: - for k, _, err = iter.tableMapIter.Next(ctx); k != nil && err == nil; k, _, err = iter.tableMapIter.Next(ctx) { - key, err := row.ParseTaggedValues(k.(types.Tuple)) - if err != nil { - return nil, err - } - for tag, val := range iter.val { - indexVal, ok := key[tag] - if !ok { - return nil, fmt.Errorf("on table `%s`, attempted to gather value for tag `%v`", iter.tableName, tag) - } - if !val.Equals(indexVal) { - continue IterateOverMap - } - } - return key, nil - } - if err != nil { - return nil, err - } - return nil, io.EOF -} - type doltIndexKeyIter struct { - index schema.Index - indexMapIter types.MapIterator - val row.TaggedValues + indexMapIter table.TableReadCloser } var _ IndexLookupKeyIterator = (*doltIndexKeyIter)(nil) func (iter *doltIndexKeyIter) NextKey(ctx *sql.Context) (row.TaggedValues, error) { - var k types.Value - var err error -IterateOverMap: - for k, _, err = iter.indexMapIter.Next(ctx); k != nil && err == nil; k, _, err = iter.indexMapIter.Next(ctx) { - indexKeyTaggedValues, err := row.ParseTaggedValues(k.(types.Tuple)) - if err != nil { - return nil, err - } - for tag, val := range iter.val { - indexVal, ok := indexKeyTaggedValues[tag] - if !ok { - return nil, fmt.Errorf("on index `%s`, attempted to gather value for tag `%v`", iter.index.Name(), tag) - } - if !val.Equals(indexVal) { - continue IterateOverMap - } - } - primaryKeys := make(row.TaggedValues) - for _, tag := range iter.index.PrimaryKeyTags() { - primaryKeys[tag] = indexKeyTaggedValues[tag] - } - return primaryKeys, nil - } + indexRow, err := iter.indexMapIter.ReadRow(ctx) if err != nil { return nil, err } - return nil, io.EOF + return row.GetTaggedVals(indexRow) }