Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions memory/stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,11 @@ func (s *StatsProv) AnalyzeTable(ctx *sql.Context, table sql.Table, db string) e
}

newStats := make(map[statsKey][]int)
tablePrefix := fmt.Sprintf("%s.", strings.ToLower(table.Name()))
tablePrefix := strings.ToLower(table.Name()) + "."
for _, idx := range indexes {
cols := make([]string, len(idx.Expressions()))
for i, c := range idx.Expressions() {
exprs := idx.Expressions()
cols := make([]string, len(exprs))
for i, c := range exprs {
cols[i] = strings.TrimPrefix(strings.ToLower(c), tablePrefix)
}
for i := 1; i < len(cols)+1; i++ {
Expand Down Expand Up @@ -244,7 +245,7 @@ func (s *StatsProv) reservoirSample(ctx *sql.Context, table sql.Table) ([]sql.Ro
}

func (s *StatsProv) GetTableStats(ctx *sql.Context, db string, table sql.Table) ([]sql.Statistic, error) {
pref := fmt.Sprintf("%s.%s", strings.ToLower(db), strings.ToLower(table.Name()))
pref := strings.ToLower(db) + "." + strings.ToLower(table.Name())
var ret []sql.Statistic
for key, stats := range s.colStats {
if strings.HasPrefix(string(key), pref) {
Expand Down Expand Up @@ -279,7 +280,7 @@ func (s *StatsProv) DropStats(ctx *sql.Context, qual sql.StatQualifier, cols []s
}

func (s *StatsProv) RowCount(ctx *sql.Context, db string, table sql.Table) (uint64, error) {
pref := fmt.Sprintf("%s.%s", strings.ToLower(db), strings.ToLower(table.Name()))
pref := strings.ToLower(db) + "." + strings.ToLower(table.Name())
var cnt uint64
for key, stats := range s.colStats {
if strings.HasPrefix(string(key), pref) {
Expand All @@ -292,7 +293,7 @@ func (s *StatsProv) RowCount(ctx *sql.Context, db string, table sql.Table) (uint
}

func (s *StatsProv) DataLength(ctx *sql.Context, db string, table sql.Table) (uint64, error) {
pref := fmt.Sprintf("%s.%s", db, table)
pref := strings.ToLower(db) + "." + strings.ToLower(table.Name())
var size uint64
for key, stats := range s.colStats {
if strings.HasPrefix(string(key), pref) {
Expand Down
102 changes: 54 additions & 48 deletions sql/analyzer/costed_index_scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ func costedIndexLookup(ctx *sql.Context, n sql.Node, a *Analyzer, iat sql.IndexA
}

func getCostedIndexScan(ctx *sql.Context, statsProv sql.StatsProvider, rt sql.TableNode, indexes []sql.Index, filters []sql.Expression, qFlags *sql.QueryFlags) (*plan.IndexedTableAccess, sql.Statistic, []sql.Expression, error) {
statistics, err := statsProv.GetTableStats(ctx, strings.ToLower(rt.Database().Name()), rt.UnderlyingTable())
statistics, err := statsProv.GetTableStats(ctx, rt.Database().Name(), rt.UnderlyingTable())
if err != nil {
return nil, nil, nil, err
}
Expand All @@ -182,19 +182,19 @@ func getCostedIndexScan(ctx *sql.Context, statsProv sql.StatsProvider, rt sql.Ta
// run each index through coster, save the cheapest
var dbName string
if dbTab, ok := rt.UnderlyingTable().(sql.Databaseable); ok {
dbName = strings.ToLower(dbTab.Database())
dbName = dbTab.Database()
}
table := rt.UnderlyingTable()
var schemaName string
if schTab, ok := table.(sql.DatabaseSchemaTable); ok {
schemaName = strings.ToLower(schTab.DatabaseSchema().SchemaName())
schemaName = schTab.DatabaseSchema().SchemaName()
}
tableName := strings.ToLower(table.Name())
tableName := table.Name()

if len(qualToStat) > 0 {
// don't mix and match real and default stats
for _, idx := range indexes {
qual := sql.NewStatQualifier(dbName, schemaName, tableName, strings.ToLower(idx.ID()))
qual := sql.NewStatQualifier(dbName, schemaName, tableName, idx.ID())
_, ok := qualToStat[qual]
if !ok {
qualToStat = nil
Expand All @@ -204,15 +204,15 @@ func getCostedIndexScan(ctx *sql.Context, statsProv sql.StatsProvider, rt sql.Ta
}

for _, idx := range indexes {
qual := sql.NewStatQualifier(dbName, schemaName, tableName, strings.ToLower(idx.ID()))
qual := sql.NewStatQualifier(dbName, schemaName, tableName, idx.ID())
stat, ok := qualToStat[qual]
if !ok {
stat, err = uniformDistStatisticsForIndex(ctx, statsProv, iat, idx)
if err != nil {
return nil, nil, nil, err
}
}
if err != nil {
return nil, nil, nil, err
}
err := c.cost(root, stat, idx)
err = c.cost(root, stat, idx)
if err != nil {
return nil, nil, nil, err
}
Expand Down Expand Up @@ -492,6 +492,7 @@ func (c *indexCoster) cost(f indexFilter, stat sql.Statistic, idx sql.Index) err
if ok {
filters.Add(int(f.id))
}

case *iScanLeaf:
newHist, newFds, ok, prefix, err = c.costIndexScanLeaf(f, stat, stat.Histogram(), ordinals, idx)
if err != nil {
Expand All @@ -500,6 +501,7 @@ func (c *indexCoster) cost(f indexFilter, stat sql.Statistic, idx sql.Index) err
if ok {
filters.Add(int(f.id))
}

default:
panic("unreachable")
}
Expand All @@ -517,7 +519,7 @@ func (c *indexCoster) updateBest(s sql.Statistic, hist []sql.HistogramBucket, fd
if s == nil || filters.Len() == 0 {
return
}
rowCnt, _, _ := stats.GetNewCounts(hist)
rowCnt := stats.GetNewRowCounts(hist)

var update bool
defer func() {
Expand All @@ -534,16 +536,24 @@ func (c *indexCoster) updateBest(s sql.Statistic, hist []sql.HistogramBucket, fd
if c.bestStat == nil {
update = true
return
} else if c.bestStat.FuncDeps().HasMax1Row() {
}

if c.bestStat.FuncDeps().HasMax1Row() {
return
} else if rowCnt < c.bestCnt {
}

if rowCnt < c.bestCnt {
update = true
return
} else if c.bestPrefix == 0 || prefix == 0 && c.bestPrefix != prefix {
}

if c.bestPrefix == 0 || prefix == 0 && c.bestPrefix != prefix {
// any prefix is better than no prefix
update = prefix > c.bestPrefix
return
} else if rowCnt == c.bestCnt {
}

if rowCnt == c.bestCnt {
// hand rules when stats don't exist or match exactly
cmp := fds
best := c.bestStat.FuncDeps()
Expand All @@ -554,21 +564,20 @@ func (c *indexCoster) updateBest(s sql.Statistic, hist []sql.HistogramBucket, fd

// If one index uses a strict superset of the filters of the other, we should always pick the superset.
// This is true even if the index with more filters isn't unique.
if prefix > c.bestPrefix && slices.Equal(c.bestStat.Columns()[:c.bestPrefix], s.Columns()[:c.bestPrefix]) {
bestCols := c.bestStat.Columns()
newCols := s.Columns()
if prefix > c.bestPrefix && slices.Equal(bestCols[:c.bestPrefix], newCols[:c.bestPrefix]) {
update = true
return
}

if prefix == c.bestPrefix && slices.Equal(c.bestStat.Columns()[:c.bestPrefix], s.Columns()[:c.bestPrefix]) && hasRange && !c.hasRange {
if prefix == c.bestPrefix && slices.Equal(bestCols[:c.bestPrefix], newCols[:c.bestPrefix]) && hasRange && !c.hasRange {
update = true
return
}

if c.bestPrefix > prefix && slices.Equal(c.bestStat.Columns()[:prefix], s.Columns()[:prefix]) {
if c.bestPrefix > prefix && slices.Equal(bestCols[:prefix], newCols[:prefix]) {
return
}

if c.bestPrefix == prefix && slices.Equal(c.bestStat.Columns()[:prefix], s.Columns()[:prefix]) && !hasRange && c.hasRange {
if c.bestPrefix == prefix && slices.Equal(bestCols[:prefix], newCols[:prefix]) && !hasRange && c.hasRange {
return
}

Expand Down Expand Up @@ -600,7 +609,8 @@ func (c *indexCoster) updateBest(s sql.Statistic, hist []sql.HistogramBucket, fd
}
update = true
return
} else if cmp.Constants().Len() < best.Constants().Len() {
}
if cmp.Constants().Len() < best.Constants().Len() {
if cmpHasLax && !bestHasLax {
// keep unique key
update = true
Expand All @@ -612,7 +622,6 @@ func (c *indexCoster) updateBest(s sql.Statistic, hist []sql.HistogramBucket, fd
update = true
return
}

if filters.Len() < c.bestFilters.Len() {
return
}
Expand All @@ -624,32 +633,29 @@ func (c *indexCoster) updateBest(s sql.Statistic, hist []sql.HistogramBucket, fd
return
}

{
// if no unique keys, prefer equality over ranges
bestConst, bestIsNull := c.getConstAndNullFilters(c.bestFilters)
cmpConst, cmpIsNull := c.getConstAndNullFilters(filters)
if cmpConst.Len() > bestConst.Len() {
update = true
return
}
if cmpIsNull.Len() > bestIsNull.Len() {
update = true
return
}
// if no unique keys, prefer equality over ranges
bestConst, bestIsNull := c.getConstAndNullFilters(c.bestFilters)
cmpConst, cmpIsNull := c.getConstAndNullFilters(filters)
if cmpConst.Len() > bestConst.Len() {
update = true
return
}
if cmpIsNull.Len() > bestIsNull.Len() {
update = true
return
}

{
if strings.EqualFold(s.Qualifier().Index(), "primary") {
update = true
return
} else if strings.EqualFold(c.bestStat.Qualifier().Index(), "primary") {
return
}
if strings.Compare(s.Qualifier().Index(), c.bestStat.Qualifier().Index()) < 0 {
// if they are still equal, use index name to make deterministic
update = true
return
}
if strings.EqualFold(s.Qualifier().Index(), "primary") {
update = true
return
}
if strings.EqualFold(c.bestStat.Qualifier().Index(), "primary") {
return
}
if strings.Compare(s.Qualifier().Index(), c.bestStat.Qualifier().Index()) < 0 {
// if they are still equal, use index name to make deterministic
update = true
return
}
}
}
Expand Down
36 changes: 17 additions & 19 deletions sql/convert_value.go
Original file line number Diff line number Diff line change
@@ -1,92 +1,90 @@
package sql

import (
"fmt"

"github.com/dolthub/go-mysql-server/sql/values"

"github.com/dolthub/vitess/go/vt/proto/query"
)

// ConvertToValue converts the interface to a sql value.
func ConvertToValue(v interface{}) (Value, error) {
func ConvertToValue(v interface{}) Value {
switch v := v.(type) {
case nil:
return Value{
Typ: query.Type_NULL_TYPE,
Val: nil,
}, nil
}
case int:
return Value{
Typ: query.Type_INT64,
Val: values.WriteInt64(make([]byte, values.Int64Size), int64(v)),
}, nil
}
case int8:
return Value{
Typ: query.Type_INT8,
Val: values.WriteInt8(make([]byte, values.Int8Size), v),
}, nil
}
case int16:
return Value{
Typ: query.Type_INT16,
Val: values.WriteInt16(make([]byte, values.Int16Size), v),
}, nil
}
case int32:
return Value{
Typ: query.Type_INT32,
Val: values.WriteInt32(make([]byte, values.Int32Size), v),
}, nil
}
case int64:
return Value{
Typ: query.Type_INT64,
Val: values.WriteInt64(make([]byte, values.Int64Size), v),
}, nil
}
case uint:
return Value{
Typ: query.Type_UINT64,
Val: values.WriteUint64(make([]byte, values.Uint64Size), uint64(v)),
}, nil
}
case uint8:
return Value{
Typ: query.Type_UINT8,
Val: values.WriteUint8(make([]byte, values.Uint8Size), v),
}, nil
}
case uint16:
return Value{
Typ: query.Type_UINT16,
Val: values.WriteUint16(make([]byte, values.Uint16Size), v),
}, nil
}
case uint32:
return Value{
Typ: query.Type_UINT32,
Val: values.WriteUint32(make([]byte, values.Uint32Size), v),
}, nil
}
case uint64:
return Value{
Typ: query.Type_UINT64,
Val: values.WriteUint64(make([]byte, values.Uint64Size), v),
}, nil
}
case float32:
return Value{
Typ: query.Type_FLOAT32,
Val: values.WriteFloat32(make([]byte, values.Float32Size), v),
}, nil
}
case float64:
return Value{
Typ: query.Type_FLOAT64,
Val: values.WriteFloat64(make([]byte, values.Float64Size), v),
}, nil
}
case string:
return Value{
Typ: query.Type_VARCHAR,
Val: values.WriteString(make([]byte, len(v)), v, values.ByteOrderCollation),
}, nil
}
case []byte:
return Value{
Typ: query.Type_BLOB,
Val: values.WriteBytes(make([]byte, len(v)), v, values.ByteOrderCollation),
}, nil
}
default:
return Value{}, fmt.Errorf("type %T not implemented", v)
return Value{}
}
}
2 changes: 1 addition & 1 deletion sql/expression/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ func (e *Alias) Describe(options sql.DescribeOptions) string {
return fmt.Sprintf("%s->%s:%d", sql.Describe(e.Child, options), e.name, e.id)
}
}
return fmt.Sprintf("%s as %s", sql.Describe(e.Child, options), e.name)
return sql.Describe(e.Child, options) + " as " + e.name
}

func (e *Alias) String() string {
Expand Down
2 changes: 1 addition & 1 deletion sql/expression/arithmetic.go
Original file line number Diff line number Diff line change
Expand Up @@ -798,7 +798,7 @@ func (*UnaryMinus) CollationCoercibility(ctx *sql.Context) (collation sql.Collat
}

func (e *UnaryMinus) String() string {
return fmt.Sprintf("-%s", e.Child)
return "-" + e.Child.String()
}

// WithChildren implements the Expression interface.
Expand Down
2 changes: 1 addition & 1 deletion sql/expression/function/aggregation/unary_aggs.og.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading