diff --git a/go/libraries/doltcore/env/actions/branch.go b/go/libraries/doltcore/env/actions/branch.go index 52f461ff0e4..68897cb15a6 100644 --- a/go/libraries/doltcore/env/actions/branch.go +++ b/go/libraries/doltcore/env/actions/branch.go @@ -63,6 +63,8 @@ func RenameBranch(ctx context.Context, dbData env.DbData, oldBranch, newBranch s } } + // todo: update default branch variable + return DeleteBranch(ctx, dbData, oldBranch, DeleteOptions{Force: true, AllowDeletingCurrentBranch: true}, remoteDbPro, rsc) } diff --git a/go/libraries/doltcore/sqle/dsess/variables.go b/go/libraries/doltcore/sqle/dsess/variables.go index 74e6db00b1c..848ed2218ec 100644 --- a/go/libraries/doltcore/sqle/dsess/variables.go +++ b/go/libraries/doltcore/sqle/dsess/variables.go @@ -60,6 +60,7 @@ const ( DoltClusterAckWritesTimeoutSecs = "dolt_cluster_ack_writes_timeout_secs" DoltStatsAutoRefreshEnabled = "dolt_stats_auto_refresh_enabled" + DoltStatsBootstrapEnabled = "dolt_stats_bootstrap_enabled" DoltStatsAutoRefreshThreshold = "dolt_stats_auto_refresh_threshold" DoltStatsAutoRefreshInterval = "dolt_stats_auto_refresh_interval" DoltStatsMemoryOnly = "dolt_stats_memory_only" diff --git a/go/libraries/doltcore/sqle/enginetest/dolt_engine_tests.go b/go/libraries/doltcore/sqle/enginetest/dolt_engine_tests.go index 1d6cfeba360..b05a000115a 100755 --- a/go/libraries/doltcore/sqle/enginetest/dolt_engine_tests.go +++ b/go/libraries/doltcore/sqle/enginetest/dolt_engine_tests.go @@ -266,6 +266,7 @@ func RunQueryTestPlans(t *testing.T, harness DoltEnginetestHarness) { } defer harness.Close() + sql.SystemVariables.SetGlobal(dsess.DoltStatsBootstrapEnabled, 0) enginetest.TestQueryPlans(t, harness, queries.PlanTests) } diff --git a/go/libraries/doltcore/sqle/statsnoms/iter.go b/go/libraries/doltcore/sqle/statsnoms/iter.go index 08074a3b124..8dc9b8161da 100644 --- a/go/libraries/doltcore/sqle/statsnoms/iter.go +++ b/go/libraries/doltcore/sqle/statsnoms/iter.go @@ -21,7 +21,6 @@ import ( "github.com/dolthub/go-mysql-server/sql" "github.com/dolthub/go-mysql-server/sql/planbuilder" - "github.com/dolthub/go-mysql-server/sql/stats" "gopkg.in/errgo.v2/errors" "github.com/dolthub/dolt/go/libraries/doltcore/schema" @@ -114,7 +113,7 @@ func (s *statsIter) Next(ctx *sql.Context) (sql.Row, error) { upperBoundCnt := row[schema.StatsUpperBoundCntTag].(int64) createdAt := row[schema.StatsCreatedAtTag].(time.Time) - typs := strings.Split(typesStr, ",") + typs := strings.Split(typesStr, "\n") for i, t := range typs { typs[i] = strings.TrimSpace(t) } @@ -122,7 +121,7 @@ func (s *statsIter) Next(ctx *sql.Context) (sql.Row, error) { qual := sql.NewStatQualifier(dbName, tableName, indexName) if curQual := qual.String(); !strings.EqualFold(curQual, s.currentQual) { s.currentQual = curQual - s.currentTypes, err = stats.ParseTypeStrings(typs) + s.currentTypes, err = parseTypeStrings(typs) if err != nil { return nil, err } diff --git a/go/libraries/doltcore/sqle/statsnoms/load.go b/go/libraries/doltcore/sqle/statsnoms/load.go index b2ec5d9606d..ea8e6b10698 100644 --- a/go/libraries/doltcore/sqle/statsnoms/load.go +++ b/go/libraries/doltcore/sqle/statsnoms/load.go @@ -23,6 +23,7 @@ import ( "time" "github.com/dolthub/go-mysql-server/sql" + "github.com/dolthub/go-mysql-server/sql/planbuilder" "github.com/dolthub/go-mysql-server/sql/stats" "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" @@ -68,7 +69,7 @@ func loadStats(ctx *sql.Context, db dsess.SqlDatabase, m prolly.Map) (map[sql.St upperBoundCnt := row[schema.StatsUpperBoundCntTag].(uint64) createdAt := row[schema.StatsCreatedAtTag].(time.Time) - typs := strings.Split(typesStr, ",") + typs := strings.Split(typesStr, "\n") for i, t := range typs { typs[i] = strings.TrimSpace(t) } @@ -90,7 +91,7 @@ func loadStats(ctx *sql.Context, db dsess.SqlDatabase, m prolly.Map) (map[sql.St mcvs := make([]sql.Row, numMcvs) for i, v := range row[schema.StatsMcv1Tag:schema.StatsMcvCountsTag] { - if v != nil { + if v != nil && v != "" { row, err := iter.ParseRow(v.(string)) if err != nil { return nil, err @@ -136,7 +137,7 @@ func loadStats(ctx *sql.Context, db dsess.SqlDatabase, m prolly.Map) (map[sql.St } if currentStat.Statistic.Hist == nil { - currentStat.Statistic.Typs, err = stats.ParseTypeStrings(typs) + currentStat.Statistic.Typs, err = parseTypeStrings(typs) if err != nil { return nil, err } @@ -180,6 +181,18 @@ func loadStats(ctx *sql.Context, db dsess.SqlDatabase, m prolly.Map) (map[sql.St return qualToStats, nil } +func parseTypeStrings(typs []string) ([]sql.Type, error) { + var ret []sql.Type + for _, typ := range typs { + ct, err := planbuilder.ParseColumnTypeString(typ) + if err != nil { + return nil, err + } + ret = append(ret, ct) + } + return ret, nil +} + func loadLowerBound(ctx *sql.Context, qual sql.StatQualifier) (sql.Row, error) { dSess := dsess.DSessFromSess(ctx.Session) roots, ok := dSess.GetRoots(ctx, qual.Db()) @@ -216,7 +229,7 @@ func loadLowerBound(ctx *sql.Context, qual sql.StatQualifier) (sql.Row, error) { } firstKey := keyBuilder.Build(buffPool) - var firstRow sql.Row + firstRow := make(sql.Row, keyBuilder.Desc.Count()) for i := 0; i < keyBuilder.Desc.Count(); i++ { firstRow[i], err = tree.GetField(ctx, prollyMap.KeyDesc(), i, firstKey, prollyMap.NodeStore()) if err != nil { diff --git a/go/libraries/doltcore/sqle/statsnoms/write.go b/go/libraries/doltcore/sqle/statsnoms/write.go index 3e87ed0104d..e5719002be8 100644 --- a/go/libraries/doltcore/sqle/statsnoms/write.go +++ b/go/libraries/doltcore/sqle/statsnoms/write.go @@ -100,7 +100,7 @@ func putIndexRows(ctx context.Context, statsMap *prolly.MutableMap, dStats *stat sep := "" for _, t := range dStats.Statistic.Typs { typesB.WriteString(sep + t.String()) - sep = "," + sep = "\n" } typesStr := typesB.String() diff --git a/go/libraries/doltcore/sqle/statspro/analyze.go b/go/libraries/doltcore/sqle/statspro/analyze.go index ccbf60bc0c8..1c8f2969010 100644 --- a/go/libraries/doltcore/sqle/statspro/analyze.go +++ b/go/libraries/doltcore/sqle/statspro/analyze.go @@ -29,12 +29,62 @@ import ( "github.com/dolthub/dolt/go/store/prolly/tree" ) +const ( + boostrapRowLimit = 2e6 +) + func (p *Provider) RefreshTableStats(ctx *sql.Context, table sql.Table, db string) error { dSess := dsess.DSessFromSess(ctx.Session) branch, err := dSess.GetBranch() if err != nil { return err } + return p.RefreshTableStatsWithBranch(ctx, table, db, branch) +} + +func (p *Provider) BootstrapDatabaseStats(ctx *sql.Context, db string) error { + dSess := dsess.DSessFromSess(ctx.Session) + branches := p.getStatsBranches(ctx) + var rows uint64 + for _, branch := range branches { + sqlDb, err := dSess.Provider().Database(ctx, p.branchQualifiedDatabase(db, branch)) + if err != nil { + if sql.ErrDatabaseNotFound.Is(err) { + // default branch is not valid + continue + } + return err + } + tables, err := sqlDb.GetTableNames(ctx) + if err != nil { + return err + } + for _, table := range tables { + sqlTable, _, err := GetLatestTable(ctx, table, sqlDb) + if err != nil { + return err + } + + if st, ok := sqlTable.(sql.StatisticsTable); ok { + cnt, ok, err := st.RowCount(ctx) + if ok && err == nil { + rows += cnt + } + } + if rows >= boostrapRowLimit { + return fmt.Errorf("stats bootstrap aborted because %s exceeds the default row limit; manually run \"ANALYZE