From 03a21be1ec2b6defe5c54e7dfd49aa85503224ff Mon Sep 17 00:00:00 2001 From: James Cor Date: Tue, 15 Apr 2025 12:50:35 -0700 Subject: [PATCH 01/22] small refactor for dolt merge --- .../sqle/dfunctions/dolt_merge_base.go | 72 ++++++++----------- 1 file changed, 29 insertions(+), 43 deletions(-) diff --git a/go/libraries/doltcore/sqle/dfunctions/dolt_merge_base.go b/go/libraries/doltcore/sqle/dfunctions/dolt_merge_base.go index 3d7dcec8f00..654ad985824 100644 --- a/go/libraries/doltcore/sqle/dfunctions/dolt_merge_base.go +++ b/go/libraries/doltcore/sqle/dfunctions/dolt_merge_base.go @@ -17,6 +17,7 @@ package dfunctions import ( "errors" "fmt" + "github.com/dolthub/dolt/go/libraries/doltcore/ref" "github.com/dolthub/go-mysql-server/sql" "github.com/dolthub/go-mysql-server/sql/expression" @@ -40,6 +41,21 @@ func NewMergeBase(left, right sql.Expression) sql.Expression { // Eval implements the sql.Expression interface. func (d MergeBase) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { + sess := dsess.DSessFromSess(ctx.Session) + dbName := ctx.GetCurrentDatabase() + dbData, ok := sess.GetDbData(ctx, dbName) + if !ok { + return nil, sql.ErrDatabaseNotFound.New(dbName) + } + doltDB, ok := sess.GetDoltDB(ctx, dbName) + if !ok { + return nil, sql.ErrDatabaseNotFound.New(dbName) + } + headRef, err := dbData.Rsr.CWBHeadRef() + if err != nil { + return nil, err + } + leftSpec, err := d.Left().Eval(ctx, row) if err != nil { return nil, err @@ -48,7 +64,6 @@ func (d MergeBase) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { if err != nil { return nil, err } - if leftSpec == nil || rightSpec == nil { return nil, nil } @@ -57,13 +72,16 @@ func (d MergeBase) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { if !ok { return nil, errors.New("left value is not a string") } - rightStr, ok := rightSpec.(string) if !ok { return nil, errors.New("right value is not a string") } - left, right, err := resolveRefSpecs(ctx, leftStr, rightStr) + left, err := resolveRefSpec(ctx, headRef, doltDB, leftStr) + if err != nil { + return nil, err + } + right, err := resolveRefSpec(ctx, headRef, doltDB, rightStr) if err != nil { return nil, err } @@ -76,52 +94,20 @@ func (d MergeBase) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { return mergeBase.String(), nil } -func resolveRefSpecs(ctx *sql.Context, leftSpec, rightSpec string) (left, right *doltdb.Commit, err error) { - lcs, err := doltdb.NewCommitSpec(leftSpec) - if err != nil { - return nil, nil, err - } - rcs, err := doltdb.NewCommitSpec(rightSpec) +func resolveRefSpec(ctx *sql.Context, headRef ref.DoltRef, doltDB *doltdb.DoltDB, spec string) (*doltdb.Commit, error) { + cs, err := doltdb.NewCommitSpec(spec) if err != nil { - return nil, nil, err - } - - sess := dsess.DSessFromSess(ctx.Session) - dbName := ctx.GetCurrentDatabase() - - dbData, ok := sess.GetDbData(ctx, dbName) - if !ok { - return nil, nil, sql.ErrDatabaseNotFound.New(dbName) - } - doltDB, ok := sess.GetDoltDB(ctx, dbName) - if !ok { - return nil, nil, sql.ErrDatabaseNotFound.New(dbName) - } - - headRef, err := dbData.Rsr.CWBHeadRef() - if err != nil { - return nil, nil, err - } - - optCmt, err := doltDB.Resolve(ctx, lcs, headRef) - if err != nil { - return nil, nil, err - } - left, ok = optCmt.ToCommit() - if !ok { - return nil, nil, doltdb.ErrGhostCommitEncountered + return nil, err } - - optCmt, err = doltDB.Resolve(ctx, rcs, headRef) + optCmt, err := doltDB.Resolve(ctx, cs, headRef) if err != nil { - return nil, nil, err + return nil, err } - right, ok = optCmt.ToCommit() + commit, ok := optCmt.ToCommit() if !ok { - return nil, nil, doltdb.ErrGhostCommitEncountered + return nil, doltdb.ErrGhostCommitEncountered } - - return + return commit, err } // String implements the sql.Expression interface. From 2dfe53893238d2d8b96f4a9fd3d5d8942f55b160 Mon Sep 17 00:00:00 2001 From: James Cor Date: Wed, 16 Apr 2025 11:00:09 -0700 Subject: [PATCH 02/22] partial implementation and tests --- .../sqle/dfunctions/dolt_merge_base.go | 1 + .../dolt_diverge_table_function.go | 168 ++++++++++++++++++ .../sqle/enginetest/dolt_engine_test.go | 21 ++- 3 files changed, 188 insertions(+), 2 deletions(-) create mode 100644 go/libraries/doltcore/sqle/dtablefunctions/dolt_diverge_table_function.go diff --git a/go/libraries/doltcore/sqle/dfunctions/dolt_merge_base.go b/go/libraries/doltcore/sqle/dfunctions/dolt_merge_base.go index 654ad985824..a3c86231bf7 100644 --- a/go/libraries/doltcore/sqle/dfunctions/dolt_merge_base.go +++ b/go/libraries/doltcore/sqle/dfunctions/dolt_merge_base.go @@ -94,6 +94,7 @@ func (d MergeBase) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { return mergeBase.String(), nil } +// TODO: move this to resolve package func resolveRefSpec(ctx *sql.Context, headRef ref.DoltRef, doltDB *doltdb.DoltDB, spec string) (*doltdb.Commit, error) { cs, err := doltdb.NewCommitSpec(spec) if err != nil { diff --git a/go/libraries/doltcore/sqle/dtablefunctions/dolt_diverge_table_function.go b/go/libraries/doltcore/sqle/dtablefunctions/dolt_diverge_table_function.go new file mode 100644 index 00000000000..e7efada330f --- /dev/null +++ b/go/libraries/doltcore/sqle/dtablefunctions/dolt_diverge_table_function.go @@ -0,0 +1,168 @@ +// Copyright 2025 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package dtablefunctions + +import ( + "fmt" + "strings" + + "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" + "github.com/dolthub/dolt/go/libraries/doltcore/env/actions/commitwalk" + "github.com/dolthub/dolt/go/libraries/doltcore/sqle/dsess" + "github.com/dolthub/dolt/go/store/hash" + + "github.com/dolthub/go-mysql-server/sql" + "github.com/dolthub/go-mysql-server/sql/types" +) + +var _ sql.TableFunction = (*DivergeTableFunction)(nil) + +type DivergeTableFunction struct { + db sql.Database + exprs []sql.Expression +} + +// NewInstance creates a new instance of TableFunction interface +func (d *DivergeTableFunction) NewInstance(ctx *sql.Context, db sql.Database, args []sql.Expression) (sql.Node, error) { + if len(args) < 2 { + // TODO: should this just return empty set when there's one argument? + return nil, sql.ErrInvalidArgumentNumber.New(d.Name(), "at least 2", len(args)) + } + return &DivergeTableFunction{ + db: db, + exprs: args, + }, nil +} + +// Name implements the sql.Node interface +func (d *DivergeTableFunction) Name() string { + return "DOLT_DIVERGE" +} + +// String implements the Stringer interface +func (d *DivergeTableFunction) String() string { + exprStrs := make([]string, len(d.exprs)) + for i, expr := range d.exprs { + exprStrs[i] = expr.String() + } + return fmt.Sprintf("%s(%s)", d.Name(), strings.Join(exprStrs, ", ")) +} + +// Resolved implements the sql.Resolvable interface +func (d *DivergeTableFunction) Resolved() bool { + for _, expr := range d.exprs { + if !expr.Resolved() { + return false + } + } + return true +} + +// Expressions implements the sql.Expressioner interface +func (d *DivergeTableFunction) Expressions() []sql.Expression { + return d.exprs +} + +// WithExpressions implements the sql.Expressioner interface +func (d *DivergeTableFunction) WithExpressions(exprs ...sql.Expression) (sql.Node, error) { + nd := *d + nd.exprs = exprs + return &nd, nil +} + +// Database implements the sql.Databaser interface +func (d *DivergeTableFunction) Database() sql.Database { + return d.db +} + +// WithDatabase implements the sql.Databaser interface +func (d *DivergeTableFunction) WithDatabase(db sql.Database) (sql.Node, error) { + nd := *d + nd.db = db + return &nd, nil +} + +// IsReadOnly implements the sql.Node interface +func (d *DivergeTableFunction) IsReadOnly() bool { + return true +} + +// Schema implements the sql.Node interface +func (d *DivergeTableFunction) Schema() sql.Schema { + return sql.Schema{ + &sql.Column{Name: "branch", Type: types.Text, Nullable: false}, + &sql.Column{Name: "commits_ahead", Type: types.Uint64, Nullable: false}, + &sql.Column{Name: "commits_behind", Type: types.Uint64, Nullable: false}, + } +} + +// Children implements the sql.Node interface +func (d *DivergeTableFunction) Children() []sql.Node { + return nil +} + +// WithChildren implements the sql.Node interface +func (d *DivergeTableFunction) WithChildren(children ...sql.Node) (sql.Node, error) { + return d, nil +} + +// RowIter implements the sql.Node interface +func (d *DivergeTableFunction) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIter, error) { + sqlDb, ok := d.db.(dsess.SqlDatabase) + if !ok { + return nil, fmt.Errorf("unable to get dolt database") + } + ddb := sqlDb.DbData().Ddb + + sess := dsess.DSessFromSess(ctx.Session) + dbName := sess.Session.GetCurrentDatabase() + headRef, err := sess.CWBHeadRef(ctx, dbName) + if err != nil { + return nil, err + } + + specs, err := mustExpressionsToString(ctx, d.exprs) + if err != nil { + return nil, err + } + if len(specs) == 1 { + return sql.RowsToRowIter(), nil + } + + commits := make([]*doltdb.Commit, len(specs)) + for i, spec := range specs { + cs, cErr := doltdb.NewCommitSpec(spec) + if cErr != nil { + return nil, err + } + optCmt, oErr := ddb.Resolve(ctx, cs, headRef) + if oErr != nil { + return nil, oErr + } + commit, isCommit := optCmt.ToCommit() + if !isCommit { + return nil, doltdb.ErrGhostCommitEncountered + } + commits[i] = commit + } + baseHash, err := commits[0].HashOf() + if err != nil { + return nil, err + } + + commitwalk.GetTopologicalOrderIterator(ctx, ddb, []hash.Hash{baseHash}, func(commit *doltdb.OptionalCommit) (bool, error) { return true, nil }) + + return nil, nil +} diff --git a/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go b/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go index dfc0469e23d..e0e9f574bea 100644 --- a/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go +++ b/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go @@ -113,9 +113,26 @@ func TestSchemaOverridesWithAdaptiveEncoding(t *testing.T) { // Convenience test for debugging a single query. Unskip and set to the desired query. func TestSingleScript(t *testing.T) { - t.Skip() + //t.Skip() - var scripts = []queries.ScriptTest{} + var scripts = []queries.ScriptTest{ + { + Name: "test dolt_log", + SetUpScript: []string{ + "call dolt_checkout('-b', 'b2');", + "call dolt_commit('--allow-empty', '-m', 'c1');", + "call dolt_branch('b1');", + "call dolt_commit('--allow-empty', '-m', 'c2');", + "call dolt_commit('--allow-empty', '-m', 'c3');", + }, + Assertions: []queries.ScriptTestAssertion{ + { + Query: "select * from dolt_log('b1..b2');", + Expected: []sql.Row{}, + }, + }, + }, + } for _, script := range scripts { harness := newDoltHarness(t) From dfdcc17f3ba4f300e4dcacf236d5590a5f8ab646 Mon Sep 17 00:00:00 2001 From: James Cor Date: Wed, 16 Apr 2025 16:38:50 -0700 Subject: [PATCH 03/22] implement and test dolt_diverge --- .../dolt_diverge_table_function.go | 36 ++++++++--- .../doltcore/sqle/dtablefunctions/init.go | 1 + .../sqle/enginetest/dolt_engine_test.go | 61 ++++++++++++++++--- .../sqle/enginetest/dolt_engine_tests.go | 24 ++++++++ .../doltcore/sqle/enginetest/dolt_queries.go | 43 +++++++++++++ 5 files changed, 150 insertions(+), 15 deletions(-) diff --git a/go/libraries/doltcore/sqle/dtablefunctions/dolt_diverge_table_function.go b/go/libraries/doltcore/sqle/dtablefunctions/dolt_diverge_table_function.go index e7efada330f..77e65740c3f 100644 --- a/go/libraries/doltcore/sqle/dtablefunctions/dolt_diverge_table_function.go +++ b/go/libraries/doltcore/sqle/dtablefunctions/dolt_diverge_table_function.go @@ -19,10 +19,7 @@ import ( "strings" "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" - "github.com/dolthub/dolt/go/libraries/doltcore/env/actions/commitwalk" "github.com/dolthub/dolt/go/libraries/doltcore/sqle/dsess" - "github.com/dolthub/dolt/go/store/hash" - "github.com/dolthub/go-mysql-server/sql" "github.com/dolthub/go-mysql-server/sql/types" ) @@ -151,18 +148,41 @@ func (d *DivergeTableFunction) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIt if oErr != nil { return nil, oErr } - commit, isCommit := optCmt.ToCommit() - if !isCommit { + commit, optCommitOk := optCmt.ToCommit() + if !optCommitOk { return nil, doltdb.ErrGhostCommitEncountered } commits[i] = commit } - baseHash, err := commits[0].HashOf() + + baseCommit := commits[0] + branchCommits := commits[1:] + baseHeight, err := baseCommit.Height() if err != nil { return nil, err } - commitwalk.GetTopologicalOrderIterator(ctx, ddb, []hash.Hash{baseHash}, func(commit *doltdb.OptionalCommit) (bool, error) { return true, nil }) + var rows []sql.Row + for i, branchCommit := range branchCommits { + branchHeight, bErr := branchCommit.Height() + if bErr != nil { + return nil, bErr + } + + ancOptCommit, ancErr := doltdb.GetCommitAncestor(ctx, baseCommit, branchCommit) + if ancErr != nil { + return nil, err + } + ancCommit, ancCommitOk := ancOptCommit.ToCommit() + if !ancCommitOk { + return nil, doltdb.ErrGhostCommitEncountered + } + ancHeight, _ := ancCommit.Height() + + ahead := branchHeight - ancHeight + behind := baseHeight - ancHeight + rows = append(rows, sql.Row{specs[i+1], ahead, behind}) + } - return nil, nil + return sql.RowsToRowIter(rows...), nil } diff --git a/go/libraries/doltcore/sqle/dtablefunctions/init.go b/go/libraries/doltcore/sqle/dtablefunctions/init.go index 01af6367a93..28bd5abdb8e 100644 --- a/go/libraries/doltcore/sqle/dtablefunctions/init.go +++ b/go/libraries/doltcore/sqle/dtablefunctions/init.go @@ -20,6 +20,7 @@ var DoltTableFunctions = []sql.TableFunction{ &DiffTableFunction{}, &DiffStatTableFunction{}, &DiffSummaryTableFunction{}, + &DivergeTableFunction{}, &LogTableFunction{}, &PatchTableFunction{}, &SchemaDiffTableFunction{}, diff --git a/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go b/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go index e0e9f574bea..1fc6a93915f 100644 --- a/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go +++ b/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go @@ -115,20 +115,57 @@ func TestSchemaOverridesWithAdaptiveEncoding(t *testing.T) { func TestSingleScript(t *testing.T) { //t.Skip() + // * anc + // |\ + // | * b1 + // | | + // | * b2 + // | + // * main + // \ + // * b3 + // | + // * b4 + // \ + // * b5 var scripts = []queries.ScriptTest{ { - Name: "test dolt_log", + Name: "test dolt_diverge(...)", SetUpScript: []string{ - "call dolt_checkout('-b', 'b2');", - "call dolt_commit('--allow-empty', '-m', 'c1');", "call dolt_branch('b1');", - "call dolt_commit('--allow-empty', '-m', 'c2');", - "call dolt_commit('--allow-empty', '-m', 'c3');", + "call dolt_branch('b2');", + "call dolt_commit('-m', 'main', '--allow-empty');", + + "call dolt_checkout('b2');", + "call dolt_commit('-m', 'b2', '--allow-empty');", + + "call dolt_checkout('main');", + "call dolt_branch('b3');", + "call dolt_branch('b4');", + "call dolt_checkout('b4');", + "call dolt_commit('-m', 'b4', '--allow-empty');", + + "call dolt_branch('b5');", + "call dolt_checkout('b5');", + "call dolt_commit('-m', 'b5', '--allow-empty');", }, Assertions: []queries.ScriptTestAssertion{ { - Query: "select * from dolt_log('b1..b2');", - Expected: []sql.Row{}, + Query: "select * from dolt_diverge('main', 'main', 'b1', 'b2', 'b3', 'b4', 'b5');", + Expected: []sql.Row{ + {"main", uint64(0), uint64(0)}, + {"b1", uint64(0), uint64(1)}, + {"b2", uint64(1), uint64(1)}, + {"b3", uint64(0), uint64(0)}, + {"b4", uint64(1), uint64(0)}, + {"b5", uint64(2), uint64(0)}, + }, + }, + { + Query: "select * from dolt_diverge('b2', 'b5');", + Expected: []sql.Row{ + {"b5", uint64(3), uint64(1)}, + }, }, }, }, @@ -1533,6 +1570,16 @@ func TestLogTableFunctionPrepared(t *testing.T) { RunLogTableFunctionTestsPrepared(t, harness) } +func TestDivergeTableFunction(t *testing.T) { + harness := newDoltEnginetestHarness(t) + RunDivergeTableFunctionTests(t, harness) +} + +func TestDivergeTableFunctionPrepared(t *testing.T) { + harness := newDoltEnginetestHarness(t) + RunDivergeTableFunctionTestsPrepared(t, harness) +} + func TestDoltReflog(t *testing.T) { h := newDoltEnginetestHarness(t) RunDoltReflogTests(t, h) diff --git a/go/libraries/doltcore/sqle/enginetest/dolt_engine_tests.go b/go/libraries/doltcore/sqle/enginetest/dolt_engine_tests.go index 4fccc5406f2..9ade60dc1d6 100755 --- a/go/libraries/doltcore/sqle/enginetest/dolt_engine_tests.go +++ b/go/libraries/doltcore/sqle/enginetest/dolt_engine_tests.go @@ -1249,6 +1249,30 @@ func RunLogTableFunctionTestsPrepared(t *testing.T, harness DoltEnginetestHarnes } } +func RunDivergeTableFunctionTests(t *testing.T, harness DoltEnginetestHarness) { + for _, test := range DivergeTableFunctionScriptTests { + t.Run(test.Name, func(t *testing.T) { + harness = harness.NewHarness(t) + defer harness.Close() + harness.Setup(setup.MydbData) + harness.SkipSetupCommit() + enginetest.TestScript(t, harness, test) + }) + } +} + +func RunDivergeTableFunctionTestsPrepared(t *testing.T, harness DoltEnginetestHarness) { + for _, test := range DivergeTableFunctionScriptTests { + t.Run(test.Name, func(t *testing.T) { + harness = harness.NewHarness(t) + defer harness.Close() + harness.Setup(setup.MydbData) + harness.SkipSetupCommit() + enginetest.TestScriptPrepared(t, harness, test) + }) + } +} + func RunCommitDiffSystemTableTests(t *testing.T, harness DoltEnginetestHarness) { for _, test := range CommitDiffSystemTableScriptTests { t.Run(test.Name, func(t *testing.T) { diff --git a/go/libraries/doltcore/sqle/enginetest/dolt_queries.go b/go/libraries/doltcore/sqle/enginetest/dolt_queries.go index 28b3a76bb00..3d80654a34b 100644 --- a/go/libraries/doltcore/sqle/enginetest/dolt_queries.go +++ b/go/libraries/doltcore/sqle/enginetest/dolt_queries.go @@ -4761,6 +4761,49 @@ var LogTableFunctionScriptTests = []queries.ScriptTest{ }, } +var DivergeTableFunctionScriptTests = []queries.ScriptTest{ + { + Name: "test dolt_diverge(...)", + SetUpScript: []string{ + "call dolt_branch('b1');", + "call dolt_branch('b2');", + "call dolt_commit('-m', 'main', '--allow-empty');", + + "call dolt_checkout('b2');", + "call dolt_commit('-m', 'b2', '--allow-empty');", + + "call dolt_checkout('main');", + "call dolt_branch('b3');", + "call dolt_branch('b4');", + "call dolt_checkout('b4');", + "call dolt_commit('-m', 'b4', '--allow-empty');", + + "call dolt_branch('b5');", + "call dolt_checkout('b5');", + "call dolt_commit('-m', 'b5', '--allow-empty');", + }, + Assertions: []queries.ScriptTestAssertion{ + { + Query: "select * from dolt_diverge('main', 'main', 'b1', 'b2', 'b3', 'b4', 'b5');", + Expected: []sql.Row{ + {"main", uint64(0), uint64(0)}, + {"b1", uint64(0), uint64(1)}, + {"b2", uint64(1), uint64(1)}, + {"b3", uint64(0), uint64(0)}, + {"b4", uint64(1), uint64(0)}, + {"b5", uint64(2), uint64(0)}, + }, + }, + { + Query: "select * from dolt_diverge('b2', 'b5');", + Expected: []sql.Row{ + {"b5", uint64(3), uint64(1)}, + }, + }, + }, + }, +} + var LargeJsonObjectScriptTests = []queries.ScriptTest{ { Name: "JSON under max length limit", From c9049e295805fe3d272516b23bc599f95ecdcf6c Mon Sep 17 00:00:00 2001 From: James Cor Date: Wed, 16 Apr 2025 16:40:11 -0700 Subject: [PATCH 04/22] revert engine testg --- .../sqle/enginetest/dolt_engine_test.go | 60 +------------------ 1 file changed, 3 insertions(+), 57 deletions(-) diff --git a/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go b/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go index 1fc6a93915f..0554a0991da 100644 --- a/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go +++ b/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go @@ -113,63 +113,9 @@ func TestSchemaOverridesWithAdaptiveEncoding(t *testing.T) { // Convenience test for debugging a single query. Unskip and set to the desired query. func TestSingleScript(t *testing.T) { - //t.Skip() - - // * anc - // |\ - // | * b1 - // | | - // | * b2 - // | - // * main - // \ - // * b3 - // | - // * b4 - // \ - // * b5 - var scripts = []queries.ScriptTest{ - { - Name: "test dolt_diverge(...)", - SetUpScript: []string{ - "call dolt_branch('b1');", - "call dolt_branch('b2');", - "call dolt_commit('-m', 'main', '--allow-empty');", - - "call dolt_checkout('b2');", - "call dolt_commit('-m', 'b2', '--allow-empty');", - - "call dolt_checkout('main');", - "call dolt_branch('b3');", - "call dolt_branch('b4');", - "call dolt_checkout('b4');", - "call dolt_commit('-m', 'b4', '--allow-empty');", - - "call dolt_branch('b5');", - "call dolt_checkout('b5');", - "call dolt_commit('-m', 'b5', '--allow-empty');", - }, - Assertions: []queries.ScriptTestAssertion{ - { - Query: "select * from dolt_diverge('main', 'main', 'b1', 'b2', 'b3', 'b4', 'b5');", - Expected: []sql.Row{ - {"main", uint64(0), uint64(0)}, - {"b1", uint64(0), uint64(1)}, - {"b2", uint64(1), uint64(1)}, - {"b3", uint64(0), uint64(0)}, - {"b4", uint64(1), uint64(0)}, - {"b5", uint64(2), uint64(0)}, - }, - }, - { - Query: "select * from dolt_diverge('b2', 'b5');", - Expected: []sql.Row{ - {"b5", uint64(3), uint64(1)}, - }, - }, - }, - }, - } + t.Skip() + + var scripts = []queries.ScriptTest{} for _, script := range scripts { harness := newDoltHarness(t) From cac827c17e65fab50059ce09dfdc01e335175091 Mon Sep 17 00:00:00 2001 From: jycor Date: Wed, 16 Apr 2025 23:53:02 +0000 Subject: [PATCH 05/22] [ga-format-pr] Run go/utils/repofmt/format_repo.sh and go/Godeps/update.sh --- go/libraries/doltcore/sqle/dfunctions/dolt_merge_base.go | 2 +- .../sqle/dtablefunctions/dolt_diverge_table_function.go | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/go/libraries/doltcore/sqle/dfunctions/dolt_merge_base.go b/go/libraries/doltcore/sqle/dfunctions/dolt_merge_base.go index a3c86231bf7..1ebc0bda3c8 100644 --- a/go/libraries/doltcore/sqle/dfunctions/dolt_merge_base.go +++ b/go/libraries/doltcore/sqle/dfunctions/dolt_merge_base.go @@ -17,7 +17,6 @@ package dfunctions import ( "errors" "fmt" - "github.com/dolthub/dolt/go/libraries/doltcore/ref" "github.com/dolthub/go-mysql-server/sql" "github.com/dolthub/go-mysql-server/sql/expression" @@ -25,6 +24,7 @@ import ( "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" "github.com/dolthub/dolt/go/libraries/doltcore/merge" + "github.com/dolthub/dolt/go/libraries/doltcore/ref" "github.com/dolthub/dolt/go/libraries/doltcore/sqle/dsess" ) diff --git a/go/libraries/doltcore/sqle/dtablefunctions/dolt_diverge_table_function.go b/go/libraries/doltcore/sqle/dtablefunctions/dolt_diverge_table_function.go index 77e65740c3f..48149b4e92f 100644 --- a/go/libraries/doltcore/sqle/dtablefunctions/dolt_diverge_table_function.go +++ b/go/libraries/doltcore/sqle/dtablefunctions/dolt_diverge_table_function.go @@ -18,10 +18,11 @@ import ( "fmt" "strings" - "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" - "github.com/dolthub/dolt/go/libraries/doltcore/sqle/dsess" "github.com/dolthub/go-mysql-server/sql" "github.com/dolthub/go-mysql-server/sql/types" + + "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" + "github.com/dolthub/dolt/go/libraries/doltcore/sqle/dsess" ) var _ sql.TableFunction = (*DivergeTableFunction)(nil) From 9afbac8703138dd547ba8e5080dac724417e1813 Mon Sep 17 00:00:00 2001 From: James Cor Date: Wed, 16 Apr 2025 16:54:33 -0700 Subject: [PATCH 06/22] more tests --- .../dtablefunctions/dolt_diverge_table_function.go | 3 +-- .../doltcore/sqle/enginetest/dolt_queries.go | 12 ++++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/go/libraries/doltcore/sqle/dtablefunctions/dolt_diverge_table_function.go b/go/libraries/doltcore/sqle/dtablefunctions/dolt_diverge_table_function.go index 77e65740c3f..6703d84727b 100644 --- a/go/libraries/doltcore/sqle/dtablefunctions/dolt_diverge_table_function.go +++ b/go/libraries/doltcore/sqle/dtablefunctions/dolt_diverge_table_function.go @@ -33,8 +33,7 @@ type DivergeTableFunction struct { // NewInstance creates a new instance of TableFunction interface func (d *DivergeTableFunction) NewInstance(ctx *sql.Context, db sql.Database, args []sql.Expression) (sql.Node, error) { - if len(args) < 2 { - // TODO: should this just return empty set when there's one argument? + if len(args) < 1 { return nil, sql.ErrInvalidArgumentNumber.New(d.Name(), "at least 2", len(args)) } return &DivergeTableFunction{ diff --git a/go/libraries/doltcore/sqle/enginetest/dolt_queries.go b/go/libraries/doltcore/sqle/enginetest/dolt_queries.go index 3d80654a34b..3160576d02b 100644 --- a/go/libraries/doltcore/sqle/enginetest/dolt_queries.go +++ b/go/libraries/doltcore/sqle/enginetest/dolt_queries.go @@ -4783,6 +4783,18 @@ var DivergeTableFunctionScriptTests = []queries.ScriptTest{ "call dolt_commit('-m', 'b5', '--allow-empty');", }, Assertions: []queries.ScriptTestAssertion{ + { + Query: "select * from dolt_diverge('main', 'non-existent-branch');", + ExpectedErrStr: "branch not found: non-existent-branch", + }, + { + Query: "select * from dolt_diverge();", + ExpectedErr: sql.ErrInvalidArgumentNumber, + }, + { + Query: "select * from dolt_diverge('main');", + Expected: []sql.Row{}, + }, { Query: "select * from dolt_diverge('main', 'main', 'b1', 'b2', 'b3', 'b4', 'b5');", Expected: []sql.Row{ From 370b202f2fdcb4478dfb7b393916c81ba1e1a3a4 Mon Sep 17 00:00:00 2001 From: James Cor Date: Wed, 16 Apr 2025 17:02:01 -0700 Subject: [PATCH 07/22] more refactoring --- .../doltcore/sqle/dfunctions/has_ancestor.go | 22 ++----------------- .../{dolt_merge_base.go => merge_base.go} | 1 - 2 files changed, 2 insertions(+), 21 deletions(-) rename go/libraries/doltcore/sqle/dfunctions/{dolt_merge_base.go => merge_base.go} (98%) diff --git a/go/libraries/doltcore/sqle/dfunctions/has_ancestor.go b/go/libraries/doltcore/sqle/dfunctions/has_ancestor.go index 03a9d927413..d11b0d2852c 100644 --- a/go/libraries/doltcore/sqle/dfunctions/has_ancestor.go +++ b/go/libraries/doltcore/sqle/dfunctions/has_ancestor.go @@ -69,19 +69,10 @@ func (a *HasAncestor) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { if err != nil { return nil, err } - - cs, err := doltdb.NewCommitSpec(headStr.(string)) + headCommit, err = resolveRefSpec(ctx, headRef, ddb, headStr.(string)) if err != nil { return nil, err } - optCmt, err := ddb.Resolve(ctx, cs, headRef) - if err != nil { - return nil, fmt.Errorf("error during has_ancestor check: ref not found '%s'", headStr) - } - headCommit, ok = optCmt.ToCommit() - if !ok { - return nil, doltdb.ErrGhostCommitEncountered - } } var ancCommit *doltdb.Commit @@ -94,19 +85,10 @@ func (a *HasAncestor) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { if err != nil { return nil, err } - cs, err := doltdb.NewCommitSpec(ancStr.(string)) + ancCommit, err = resolveRefSpec(ctx, headRef, ddb, ancStr.(string)) if err != nil { return nil, err } - optCmt, err := ddb.Resolve(ctx, cs, headRef) - if err != nil { - return nil, fmt.Errorf("error during has_ancestor check: ref not found '%s'", ancStr) - } - ancCommit, ok = optCmt.ToCommit() - if !ok { - return nil, doltdb.ErrGhostCommitEncountered - } - } headHash, err := headCommit.HashOf() diff --git a/go/libraries/doltcore/sqle/dfunctions/dolt_merge_base.go b/go/libraries/doltcore/sqle/dfunctions/merge_base.go similarity index 98% rename from go/libraries/doltcore/sqle/dfunctions/dolt_merge_base.go rename to go/libraries/doltcore/sqle/dfunctions/merge_base.go index a3c86231bf7..654ad985824 100644 --- a/go/libraries/doltcore/sqle/dfunctions/dolt_merge_base.go +++ b/go/libraries/doltcore/sqle/dfunctions/merge_base.go @@ -94,7 +94,6 @@ func (d MergeBase) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { return mergeBase.String(), nil } -// TODO: move this to resolve package func resolveRefSpec(ctx *sql.Context, headRef ref.DoltRef, doltDB *doltdb.DoltDB, spec string) (*doltdb.Commit, error) { cs, err := doltdb.NewCommitSpec(spec) if err != nil { From aab5d6717a50c0c81d49c2e8d63f99affe2c1b88 Mon Sep 17 00:00:00 2001 From: James Cor Date: Fri, 18 Apr 2025 13:27:27 -0700 Subject: [PATCH 08/22] rename and use commitwalk --- ...o => dolt_branch_status_table_function.go} | 118 ++++++++++++------ .../doltcore/sqle/dtablefunctions/init.go | 2 +- .../sqle/enginetest/dolt_engine_test.go | 8 +- .../sqle/enginetest/dolt_engine_tests.go | 8 +- .../doltcore/sqle/enginetest/dolt_queries.go | 14 +-- 5 files changed, 98 insertions(+), 52 deletions(-) rename go/libraries/doltcore/sqle/dtablefunctions/{dolt_diverge_table_function.go => dolt_branch_status_table_function.go} (55%) diff --git a/go/libraries/doltcore/sqle/dtablefunctions/dolt_diverge_table_function.go b/go/libraries/doltcore/sqle/dtablefunctions/dolt_branch_status_table_function.go similarity index 55% rename from go/libraries/doltcore/sqle/dtablefunctions/dolt_diverge_table_function.go rename to go/libraries/doltcore/sqle/dtablefunctions/dolt_branch_status_table_function.go index d18ab0a98ab..42524668515 100644 --- a/go/libraries/doltcore/sqle/dtablefunctions/dolt_diverge_table_function.go +++ b/go/libraries/doltcore/sqle/dtablefunctions/dolt_branch_status_table_function.go @@ -16,50 +16,53 @@ package dtablefunctions import ( "fmt" + "io" "strings" "github.com/dolthub/go-mysql-server/sql" "github.com/dolthub/go-mysql-server/sql/types" "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" + "github.com/dolthub/dolt/go/libraries/doltcore/env/actions/commitwalk" "github.com/dolthub/dolt/go/libraries/doltcore/sqle/dsess" + "github.com/dolthub/dolt/go/store/hash" ) -var _ sql.TableFunction = (*DivergeTableFunction)(nil) +var _ sql.TableFunction = (*BranchStatusTableFunction)(nil) -type DivergeTableFunction struct { +type BranchStatusTableFunction struct { db sql.Database exprs []sql.Expression } // NewInstance creates a new instance of TableFunction interface -func (d *DivergeTableFunction) NewInstance(ctx *sql.Context, db sql.Database, args []sql.Expression) (sql.Node, error) { +func (b *BranchStatusTableFunction) NewInstance(ctx *sql.Context, db sql.Database, args []sql.Expression) (sql.Node, error) { if len(args) < 1 { - return nil, sql.ErrInvalidArgumentNumber.New(d.Name(), "at least 2", len(args)) + return nil, sql.ErrInvalidArgumentNumber.New(b.Name(), "at least 2", len(args)) } - return &DivergeTableFunction{ + return &BranchStatusTableFunction{ db: db, exprs: args, }, nil } // Name implements the sql.Node interface -func (d *DivergeTableFunction) Name() string { - return "DOLT_DIVERGE" +func (b *BranchStatusTableFunction) Name() string { + return "DOLT_BRANCH_STATUS" } // String implements the Stringer interface -func (d *DivergeTableFunction) String() string { - exprStrs := make([]string, len(d.exprs)) - for i, expr := range d.exprs { +func (b *BranchStatusTableFunction) String() string { + exprStrs := make([]string, len(b.exprs)) + for i, expr := range b.exprs { exprStrs[i] = expr.String() } - return fmt.Sprintf("%s(%s)", d.Name(), strings.Join(exprStrs, ", ")) + return fmt.Sprintf("%s(%s)", b.Name(), strings.Join(exprStrs, ", ")) } // Resolved implements the sql.Resolvable interface -func (d *DivergeTableFunction) Resolved() bool { - for _, expr := range d.exprs { +func (b *BranchStatusTableFunction) Resolved() bool { + for _, expr := range b.exprs { if !expr.Resolved() { return false } @@ -68,36 +71,36 @@ func (d *DivergeTableFunction) Resolved() bool { } // Expressions implements the sql.Expressioner interface -func (d *DivergeTableFunction) Expressions() []sql.Expression { - return d.exprs +func (b *BranchStatusTableFunction) Expressions() []sql.Expression { + return b.exprs } // WithExpressions implements the sql.Expressioner interface -func (d *DivergeTableFunction) WithExpressions(exprs ...sql.Expression) (sql.Node, error) { - nd := *d +func (b *BranchStatusTableFunction) WithExpressions(exprs ...sql.Expression) (sql.Node, error) { + nd := *b nd.exprs = exprs return &nd, nil } // Database implements the sql.Databaser interface -func (d *DivergeTableFunction) Database() sql.Database { - return d.db +func (b *BranchStatusTableFunction) Database() sql.Database { + return b.db } // WithDatabase implements the sql.Databaser interface -func (d *DivergeTableFunction) WithDatabase(db sql.Database) (sql.Node, error) { - nd := *d +func (b *BranchStatusTableFunction) WithDatabase(db sql.Database) (sql.Node, error) { + nd := *b nd.db = db return &nd, nil } // IsReadOnly implements the sql.Node interface -func (d *DivergeTableFunction) IsReadOnly() bool { +func (b *BranchStatusTableFunction) IsReadOnly() bool { return true } // Schema implements the sql.Node interface -func (d *DivergeTableFunction) Schema() sql.Schema { +func (b *BranchStatusTableFunction) Schema() sql.Schema { return sql.Schema{ &sql.Column{Name: "branch", Type: types.Text, Nullable: false}, &sql.Column{Name: "commits_ahead", Type: types.Uint64, Nullable: false}, @@ -106,18 +109,18 @@ func (d *DivergeTableFunction) Schema() sql.Schema { } // Children implements the sql.Node interface -func (d *DivergeTableFunction) Children() []sql.Node { +func (b *BranchStatusTableFunction) Children() []sql.Node { return nil } // WithChildren implements the sql.Node interface -func (d *DivergeTableFunction) WithChildren(children ...sql.Node) (sql.Node, error) { - return d, nil +func (b *BranchStatusTableFunction) WithChildren(children ...sql.Node) (sql.Node, error) { + return b, nil } // RowIter implements the sql.Node interface -func (d *DivergeTableFunction) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIter, error) { - sqlDb, ok := d.db.(dsess.SqlDatabase) +func (b *BranchStatusTableFunction) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIter, error) { + sqlDb, ok := b.db.(dsess.SqlDatabase) if !ok { return nil, fmt.Errorf("unable to get dolt database") } @@ -130,7 +133,7 @@ func (d *DivergeTableFunction) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIt return nil, err } - specs, err := mustExpressionsToString(ctx, d.exprs) + specs, err := mustExpressionsToString(ctx, b.exprs) if err != nil { return nil, err } @@ -157,16 +160,22 @@ func (d *DivergeTableFunction) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIt baseCommit := commits[0] branchCommits := commits[1:] - baseHeight, err := baseCommit.Height() + + baseHash, err := baseCommit.HashOf() if err != nil { return nil, err } + isNotGhostCommit := func(commit *doltdb.OptionalCommit) (bool, error) { + _, commitOk := commit.ToCommit() + return commitOk, nil + } + var rows []sql.Row for i, branchCommit := range branchCommits { - branchHeight, bErr := branchCommit.Height() - if bErr != nil { - return nil, bErr + branchHash, hErr := branchCommit.HashOf() + if hErr != nil { + return nil, hErr } ancOptCommit, ancErr := doltdb.GetCommitAncestor(ctx, baseCommit, branchCommit) @@ -177,10 +186,47 @@ func (d *DivergeTableFunction) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIt if !ancCommitOk { return nil, doltdb.ErrGhostCommitEncountered } - ancHeight, _ := ancCommit.Height() + ancHash, hErr := ancCommit.HashOf() + if hErr != nil { + return nil, hErr + } - ahead := branchHeight - ancHeight - behind := baseHeight - ancHeight + var ahead, behind uint64 + if commitIter, iErr := commitwalk.GetTopologicalOrderIterator(ctx, ddb, []hash.Hash{branchHash}, isNotGhostCommit); iErr != nil { + return nil, iErr + } else { + for { + hash, _, cErr := commitIter.Next(ctx) + if cErr != nil { + if cErr == io.EOF { + break + } + return nil, err + } + if ancHash.Equal(hash) { + break + } + ahead++ + } + } + + if commitIter, iErr := commitwalk.GetTopologicalOrderIterator(ctx, ddb, []hash.Hash{baseHash}, isNotGhostCommit); iErr != nil { + return nil, iErr + } else { + for { + hash, _, cErr := commitIter.Next(ctx) + if cErr != nil { + if cErr == io.EOF { + break + } + return nil, err + } + if ancHash.Equal(hash) { + break + } + behind++ + } + } rows = append(rows, sql.Row{specs[i+1], ahead, behind}) } diff --git a/go/libraries/doltcore/sqle/dtablefunctions/init.go b/go/libraries/doltcore/sqle/dtablefunctions/init.go index 28bd5abdb8e..ea284dff5e3 100644 --- a/go/libraries/doltcore/sqle/dtablefunctions/init.go +++ b/go/libraries/doltcore/sqle/dtablefunctions/init.go @@ -20,7 +20,7 @@ var DoltTableFunctions = []sql.TableFunction{ &DiffTableFunction{}, &DiffStatTableFunction{}, &DiffSummaryTableFunction{}, - &DivergeTableFunction{}, + &BranchStatusTableFunction{}, &LogTableFunction{}, &PatchTableFunction{}, &SchemaDiffTableFunction{}, diff --git a/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go b/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go index 0554a0991da..c2eb3924e7b 100644 --- a/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go +++ b/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go @@ -1516,14 +1516,14 @@ func TestLogTableFunctionPrepared(t *testing.T) { RunLogTableFunctionTestsPrepared(t, harness) } -func TestDivergeTableFunction(t *testing.T) { +func TestBranchStatusTableFunction(t *testing.T) { harness := newDoltEnginetestHarness(t) - RunDivergeTableFunctionTests(t, harness) + RunBranchStatusTableFunctionTests(t, harness) } -func TestDivergeTableFunctionPrepared(t *testing.T) { +func TestBranchStatusTableFunctionPrepared(t *testing.T) { harness := newDoltEnginetestHarness(t) - RunDivergeTableFunctionTestsPrepared(t, harness) + RunBranchStatusTableFunctionTestsPrepared(t, harness) } func TestDoltReflog(t *testing.T) { diff --git a/go/libraries/doltcore/sqle/enginetest/dolt_engine_tests.go b/go/libraries/doltcore/sqle/enginetest/dolt_engine_tests.go index 9ade60dc1d6..0acd959e767 100755 --- a/go/libraries/doltcore/sqle/enginetest/dolt_engine_tests.go +++ b/go/libraries/doltcore/sqle/enginetest/dolt_engine_tests.go @@ -1249,8 +1249,8 @@ func RunLogTableFunctionTestsPrepared(t *testing.T, harness DoltEnginetestHarnes } } -func RunDivergeTableFunctionTests(t *testing.T, harness DoltEnginetestHarness) { - for _, test := range DivergeTableFunctionScriptTests { +func RunBranchStatusTableFunctionTests(t *testing.T, harness DoltEnginetestHarness) { + for _, test := range BranchStatusTableFunctionScriptTests { t.Run(test.Name, func(t *testing.T) { harness = harness.NewHarness(t) defer harness.Close() @@ -1261,8 +1261,8 @@ func RunDivergeTableFunctionTests(t *testing.T, harness DoltEnginetestHarness) { } } -func RunDivergeTableFunctionTestsPrepared(t *testing.T, harness DoltEnginetestHarness) { - for _, test := range DivergeTableFunctionScriptTests { +func RunBranchStatusTableFunctionTestsPrepared(t *testing.T, harness DoltEnginetestHarness) { + for _, test := range BranchStatusTableFunctionScriptTests { t.Run(test.Name, func(t *testing.T) { harness = harness.NewHarness(t) defer harness.Close() diff --git a/go/libraries/doltcore/sqle/enginetest/dolt_queries.go b/go/libraries/doltcore/sqle/enginetest/dolt_queries.go index 3160576d02b..e2f6fd63964 100644 --- a/go/libraries/doltcore/sqle/enginetest/dolt_queries.go +++ b/go/libraries/doltcore/sqle/enginetest/dolt_queries.go @@ -4761,9 +4761,9 @@ var LogTableFunctionScriptTests = []queries.ScriptTest{ }, } -var DivergeTableFunctionScriptTests = []queries.ScriptTest{ +var BranchStatusTableFunctionScriptTests = []queries.ScriptTest{ { - Name: "test dolt_diverge(...)", + Name: "test dolt_branch_status(...)", SetUpScript: []string{ "call dolt_branch('b1');", "call dolt_branch('b2');", @@ -4784,19 +4784,19 @@ var DivergeTableFunctionScriptTests = []queries.ScriptTest{ }, Assertions: []queries.ScriptTestAssertion{ { - Query: "select * from dolt_diverge('main', 'non-existent-branch');", + Query: "select * from dolt_branch_status('main', 'non-existent-branch');", ExpectedErrStr: "branch not found: non-existent-branch", }, { - Query: "select * from dolt_diverge();", + Query: "select * from dolt_branch_status();", ExpectedErr: sql.ErrInvalidArgumentNumber, }, { - Query: "select * from dolt_diverge('main');", + Query: "select * from dolt_branch_status('main');", Expected: []sql.Row{}, }, { - Query: "select * from dolt_diverge('main', 'main', 'b1', 'b2', 'b3', 'b4', 'b5');", + Query: "select * from dolt_branch_status('main', 'main', 'b1', 'b2', 'b3', 'b4', 'b5');", Expected: []sql.Row{ {"main", uint64(0), uint64(0)}, {"b1", uint64(0), uint64(1)}, @@ -4807,7 +4807,7 @@ var DivergeTableFunctionScriptTests = []queries.ScriptTest{ }, }, { - Query: "select * from dolt_diverge('b2', 'b5');", + Query: "select * from dolt_branch_status('b2', 'b5');", Expected: []sql.Row{ {"b5", uint64(3), uint64(1)}, }, From e8f232557dd6eb5d3c012401df9d85f92ed54c49 Mon Sep 17 00:00:00 2001 From: James Cor Date: Fri, 18 Apr 2025 14:03:57 -0700 Subject: [PATCH 09/22] more tests --- .../doltcore/sqle/enginetest/dolt_queries.go | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/go/libraries/doltcore/sqle/enginetest/dolt_queries.go b/go/libraries/doltcore/sqle/enginetest/dolt_queries.go index e2f6fd63964..7209415715e 100644 --- a/go/libraries/doltcore/sqle/enginetest/dolt_queries.go +++ b/go/libraries/doltcore/sqle/enginetest/dolt_queries.go @@ -4781,6 +4781,12 @@ var BranchStatusTableFunctionScriptTests = []queries.ScriptTest{ "call dolt_branch('b5');", "call dolt_checkout('b5');", "call dolt_commit('-m', 'b5', '--allow-empty');", + + "call dolt_tag('t1', 'b1');", + "call dolt_tag('t2', 'b2');", + "call dolt_tag('t3', 'b3');", + "call dolt_tag('t4', 'b4');", + "call dolt_tag('t5', 'b5');", }, Assertions: []queries.ScriptTestAssertion{ { @@ -4806,12 +4812,31 @@ var BranchStatusTableFunctionScriptTests = []queries.ScriptTest{ {"b5", uint64(2), uint64(0)}, }, }, + { + Query: "select * from dolt_branch_status('main', 't1', 't2', 't3', 't4', 't5');", + Expected: []sql.Row{ + {"t1", uint64(0), uint64(1)}, + {"t2", uint64(1), uint64(1)}, + {"t3", uint64(0), uint64(0)}, + {"t4", uint64(1), uint64(0)}, + {"t5", uint64(2), uint64(0)}, + }, + }, { Query: "select * from dolt_branch_status('b2', 'b5');", Expected: []sql.Row{ {"b5", uint64(3), uint64(1)}, }, }, + { + Query: "select * from dolt_branch_status('main', 'b5', 'HEAD', 'HEAD~1', 'HEAD~2');", + Expected: []sql.Row{ + {"b5", uint64(2), uint64(0)}, + {"HEAD", uint64(2), uint64(0)}, + {"HEAD~1", uint64(1), uint64(0)}, + {"HEAD~2", uint64(0), uint64(0)}, + }, + }, }, }, } From 9d8848c27ee28da5994daaf1d16cc402a6a5cbe3 Mon Sep 17 00:00:00 2001 From: James Cor Date: Fri, 18 Apr 2025 15:03:39 -0700 Subject: [PATCH 10/22] adding more complicated test --- .../doltcore/sqle/enginetest/dolt_queries.go | 102 +++++++++++++++++- 1 file changed, 100 insertions(+), 2 deletions(-) diff --git a/go/libraries/doltcore/sqle/enginetest/dolt_queries.go b/go/libraries/doltcore/sqle/enginetest/dolt_queries.go index 7209415715e..c549a012897 100644 --- a/go/libraries/doltcore/sqle/enginetest/dolt_queries.go +++ b/go/libraries/doltcore/sqle/enginetest/dolt_queries.go @@ -16,14 +16,13 @@ package enginetest import ( "fmt" - "strings" - "github.com/dolthub/go-mysql-server/enginetest/queries" "github.com/dolthub/go-mysql-server/sql" "github.com/dolthub/go-mysql-server/sql/plan" "github.com/dolthub/go-mysql-server/sql/types" "github.com/dolthub/vitess/go/vt/sqlparser" "github.com/google/uuid" + "strings" "github.com/dolthub/dolt/go/libraries/doltcore/sqle/dtablefunctions" ) @@ -4763,6 +4762,19 @@ var LogTableFunctionScriptTests = []queries.ScriptTest{ var BranchStatusTableFunctionScriptTests = []queries.ScriptTest{ { + // * anc + // |\ + // | * b1 + // | | + // | * b2 + // | + // * main + // \ + // * b3 + // | + // * b4 + // \ + // * b5 Name: "test dolt_branch_status(...)", SetUpScript: []string{ "call dolt_branch('b1');", @@ -4839,6 +4851,92 @@ var BranchStatusTableFunctionScriptTests = []queries.ScriptTest{ }, }, }, + { + // * ----------- + // |\ \ + // | * b1c1 * b2c1 + // | | | + // | * b2c2 (b1) * b2c2 + // | | + // * m1 * b2c3 (b2) + // | + // * m2 (main) + Name: "test dolt_branch_status with merge", + SetUpScript: []string{ + "call dolt_branch('b1');", + "call dolt_branch('b2');", + "call dolt_commit('-m', 'm1', '--allow-empty');", + "call dolt_commit('-m', 'm2', '--allow-empty');", + + "call dolt_checkout('b1');", + "call dolt_commit('-m', 'b1c1', '--allow-empty');", + "call dolt_commit('-m', 'b1c2', '--allow-empty');", + + "call dolt_checkout('b2');", + "call dolt_commit('-m', 'b2c1', '--allow-empty');", + "call dolt_commit('-m', 'b2c2', '--allow-empty');", + "call dolt_commit('-m', 'b2c3', '--allow-empty');", + }, + Assertions: []queries.ScriptTestAssertion{ + { + Query: "select * from dolt_branch_status('main', 'b1', 'b2');", + Expected: []sql.Row{ + {"b1", uint64(2), uint64(2)}, + {"b2", uint64(3), uint64(2)}, + }, + }, + { + Query: "select * from dolt_branch_status('b1', 'b2');", + Expected: []sql.Row{ + {"b2", uint64(3), uint64(2)}, + }, + }, + { + SkipResultsCheck: true, + Query: "call dolt_merge('b1')", // merge b1 into b2 + }, + { + // * ------------ + // |\ \ + // | \ \ + // | * b1c1 * b2c1 + // | | | + // | * b2c2 (b1) * b1c1 + // | | + // * m1 * b2c2 (b1) + // | | + // | * b1c2 + // | | + // | * b2c3 + // | | + // | * merge b1 (b2) + // * m2 (main) + Query: "select message from dolt_log;", + Expected: []sql.Row{ + {"Merge branch 'b1' into b2"}, + {"b2c3"}, + {"b1c2"}, + {"b2c2"}, + {"b1c1"}, + {"b2c1"}, + {"Initialize data repository"}, + }, + }, + { + Query: "select * from dolt_branch_status('main', 'b1', 'b2');", + Expected: []sql.Row{ + {"b1", uint64(2), uint64(2)}, + {"b2", uint64(6), uint64(2)}, + }, + }, + { + Query: "select * from dolt_branch_status('b1', 'b2');", + Expected: []sql.Row{ + {"b2", uint64(2), uint64(0)}, + }, + }, + }, + }, } var LargeJsonObjectScriptTests = []queries.ScriptTest{ From 729f52827084253a7d8c953e0e09bc6fb5f73d80 Mon Sep 17 00:00:00 2001 From: jycor Date: Fri, 18 Apr 2025 22:11:43 +0000 Subject: [PATCH 11/22] [ga-format-pr] Run go/utils/repofmt/format_repo.sh and go/Godeps/update.sh --- go/libraries/doltcore/sqle/enginetest/dolt_queries.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/go/libraries/doltcore/sqle/enginetest/dolt_queries.go b/go/libraries/doltcore/sqle/enginetest/dolt_queries.go index c549a012897..f66f3d33a29 100644 --- a/go/libraries/doltcore/sqle/enginetest/dolt_queries.go +++ b/go/libraries/doltcore/sqle/enginetest/dolt_queries.go @@ -16,13 +16,14 @@ package enginetest import ( "fmt" + "strings" + "github.com/dolthub/go-mysql-server/enginetest/queries" "github.com/dolthub/go-mysql-server/sql" "github.com/dolthub/go-mysql-server/sql/plan" "github.com/dolthub/go-mysql-server/sql/types" "github.com/dolthub/vitess/go/vt/sqlparser" "github.com/google/uuid" - "strings" "github.com/dolthub/dolt/go/libraries/doltcore/sqle/dtablefunctions" ) From e6110aa71f3f1c525ffac551be21b7a64d72aef0 Mon Sep 17 00:00:00 2001 From: Neil Macneale IV Date: Mon, 21 Apr 2025 13:42:11 -0700 Subject: [PATCH 12/22] Addional test with complicated history --- .../doltcore/sqle/enginetest/dolt_queries.go | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/go/libraries/doltcore/sqle/enginetest/dolt_queries.go b/go/libraries/doltcore/sqle/enginetest/dolt_queries.go index f66f3d33a29..f230640c733 100644 --- a/go/libraries/doltcore/sqle/enginetest/dolt_queries.go +++ b/go/libraries/doltcore/sqle/enginetest/dolt_queries.go @@ -4938,6 +4938,86 @@ var BranchStatusTableFunctionScriptTests = []queries.ScriptTest{ }, }, }, + { + // * anc + // |\ + // "C1" * \---- * "C7" + // | | + // "C2" * | + // | | + // "C3" * t1 | + // |\ | + // | \---- * t2 "M1" + // | | + // "C4" * * b1 "C8" + // |\ / + // "C5" * \ / + // | * b2 "M2" + // | + // "C6" * main + + Name: "test dolt_branch_status(...)", + SetUpScript: []string{ + "call dolt_tag('anc', 'HEAD');", + "call dolt_branch('b1');", + "call dolt_commit('-m', 'C1', '--allow-empty');", + "call dolt_commit('-m', 'C2', '--allow-empty');", + "call dolt_commit('-m', 'C3', '--allow-empty');", + "call dolt_tag('t1', 'HEAD');", + "call dolt_commit('-m', 'C4', '--allow-empty');", + "call dolt_branch('b2');", + "call dolt_commit('-m', 'C5', '--allow-empty');", + "call dolt_commit('-m', 'C6', '--allow-empty');", + + "call dolt_checkout('b1');", + "call dolt_commit('-m', 'C7', '--allow-empty');", + "call dolt_merge('t1', '-m', 'M1');", + "call dolt_tag('t2', 'HEAD');", + "call dolt_commit('-m', 'C8', '--allow-empty');", + + "call dolt_checkout('b2');", + "call dolt_merge('b1', '-m', 'M2');", + }, + Assertions: []queries.ScriptTestAssertion{ + { + Query: "select * from dolt_branch_status('main', 'b2');", + Expected: []sql.Row{ + {"b2", uint64(1), uint64(2)}, // Currently Failing here. + }, + }, + { + Query: "select * from dolt_branch_status('main', 'b1');", + Expected: []sql.Row{ + {"b1", uint64(2), uint64(3)}, + }, + }, + { + Query: "select * from dolt_branch_status('anc', 'b2');", + Expected: []sql.Row{ + {"b2", uint64(8), uint64(0)}, + }, + }, + { + Query: "select * from dolt_branch_status('b2', 'anc');", + Expected: []sql.Row{ + {"anc", uint64(0), uint64(8)}, + }, + }, + { + Query: "select * from dolt_branch_status('t1', 'anc', 't2','t2~1', 'main', 'b1', 'b2', 'b2^1', 'b2^2' );", + Expected: []sql.Row{ + {"anc", uint64(0), uint64(3)}, + {"t2", uint64(1), uint64(0)}, + {"t2~1", uint64(1), uint64(3)}, + {"main", uint64(3), uint64(0)}, + {"b1", uint64(2), uint64(0)}, + {"b2", uint64(4), uint64(0)}, + {"b2^1", uint64(1), uint64(0)}, + {"b2^2", uint64(2), uint64(0)}, + }, + }, + }, + }, } var LargeJsonObjectScriptTests = []queries.ScriptTest{ From 5a40973785a0275852f64a2dfa9ae83728d86bf4 Mon Sep 17 00:00:00 2001 From: James Cor Date: Fri, 2 May 2025 11:09:13 -0700 Subject: [PATCH 13/22] fix merge with main --- go/libraries/doltcore/sqle/dfunctions/merge_base.go | 2 +- .../dtablefunctions/dolt_branch_status_table_function.go | 4 ++-- go/libraries/doltcore/sqle/enginetest/dolt_queries.go | 8 +++++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/go/libraries/doltcore/sqle/dfunctions/merge_base.go b/go/libraries/doltcore/sqle/dfunctions/merge_base.go index bd94be29ebe..95014aed722 100644 --- a/go/libraries/doltcore/sqle/dfunctions/merge_base.go +++ b/go/libraries/doltcore/sqle/dfunctions/merge_base.go @@ -51,7 +51,7 @@ func (d MergeBase) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { if !ok { return nil, sql.ErrDatabaseNotFound.New(dbName) } - headRef, err := dbData.Rsr.CWBHeadRef() + headRef, err := dbData.Rsr.CWBHeadRef(ctx) if err != nil { return nil, err } diff --git a/go/libraries/doltcore/sqle/dtablefunctions/dolt_branch_status_table_function.go b/go/libraries/doltcore/sqle/dtablefunctions/dolt_branch_status_table_function.go index 42524668515..d641ace4691 100644 --- a/go/libraries/doltcore/sqle/dtablefunctions/dolt_branch_status_table_function.go +++ b/go/libraries/doltcore/sqle/dtablefunctions/dolt_branch_status_table_function.go @@ -192,7 +192,7 @@ func (b *BranchStatusTableFunction) RowIter(ctx *sql.Context, row sql.Row) (sql. } var ahead, behind uint64 - if commitIter, iErr := commitwalk.GetTopologicalOrderIterator(ctx, ddb, []hash.Hash{branchHash}, isNotGhostCommit); iErr != nil { + if commitIter, iErr := commitwalk.GetTopologicalOrderIterator[doltdb.Context](ctx, ddb, []hash.Hash{branchHash}, isNotGhostCommit); iErr != nil { return nil, iErr } else { for { @@ -210,7 +210,7 @@ func (b *BranchStatusTableFunction) RowIter(ctx *sql.Context, row sql.Row) (sql. } } - if commitIter, iErr := commitwalk.GetTopologicalOrderIterator(ctx, ddb, []hash.Hash{baseHash}, isNotGhostCommit); iErr != nil { + if commitIter, iErr := commitwalk.GetTopologicalOrderIterator[doltdb.Context](ctx, ddb, []hash.Hash{baseHash}, isNotGhostCommit); iErr != nil { return nil, iErr } else { for { diff --git a/go/libraries/doltcore/sqle/enginetest/dolt_queries.go b/go/libraries/doltcore/sqle/enginetest/dolt_queries.go index a17283ebda5..f7dcaf3448b 100644 --- a/go/libraries/doltcore/sqle/enginetest/dolt_queries.go +++ b/go/libraries/doltcore/sqle/enginetest/dolt_queries.go @@ -4877,6 +4877,12 @@ var BranchStatusTableFunctionScriptTests = []queries.ScriptTest{ {"HEAD~2", uint64(0), uint64(0)}, }, }, + { + Query: "select commits_ahead, commits_behind from dolt_branch_status('main', dolt_hashof('b5'));", + Expected: []sql.Row{ + {uint64(2), uint64(0)}, + }, + }, }, }, { @@ -5009,7 +5015,7 @@ var BranchStatusTableFunctionScriptTests = []queries.ScriptTest{ { Query: "select * from dolt_branch_status('main', 'b2');", Expected: []sql.Row{ - {"b2", uint64(1), uint64(2)}, // Currently Failing here. + {"b2", uint64(3), uint64(2)}, // Currently Failing here. }, }, { From d93e111d95d808b417259ba01894ee0383eb1368 Mon Sep 17 00:00:00 2001 From: James Cor Date: Fri, 2 May 2025 13:30:36 -0700 Subject: [PATCH 14/22] debugging --- go/libraries/doltcore/doltdb/commit.go | 4 ++ .../sqle/enginetest/dolt_engine_test.go | 72 +++++++++---------- 2 files changed, 40 insertions(+), 36 deletions(-) diff --git a/go/libraries/doltcore/doltdb/commit.go b/go/libraries/doltcore/doltdb/commit.go index 83829d6918c..f0c87c0f4ed 100644 --- a/go/libraries/doltcore/doltdb/commit.go +++ b/go/libraries/doltcore/doltdb/commit.go @@ -18,6 +18,7 @@ import ( "context" "errors" "fmt" + "sort" "github.com/dolthub/dolt/go/store/datas" "github.com/dolthub/dolt/go/store/hash" @@ -116,6 +117,9 @@ func (c *Commit) ParentHashes(ctx context.Context) ([]hash.Hash, error) { for i, pr := range c.parents { hashes[i] = pr.Addr() } + sort.Slice(hashes, func(i, j int) bool { + return hashes[i].Less(hashes[j]) + }) return hashes, nil } diff --git a/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go b/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go index 452429a98a7..fbc30aa1721 100644 --- a/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go +++ b/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go @@ -114,52 +114,52 @@ func TestSchemaOverridesWithAdaptiveEncoding(t *testing.T) { // Convenience test for debugging a single query. Unskip and set to the desired query. func TestSingleScript(t *testing.T) { //t.Skip() + + +sql.Row{"v3ovmbhvfpsl60i7ipg9b0vljsc0vcga", "C6", interface {}(nil), interface {}(nil)}, +sql.Row{"o9712qt6v19bdbn4gtp9ivha86i6ragf", "C5", interface {}(nil), interface {}(nil)}, +sql.Row{"bdvq579k1fhsfg0putcvv2plbpmo4k34", "C4", "bdvq579k1fhsfg0putcvv2plbpmo4k34", "C4"}, +sql.Row{"v2puca30nbv69vtqtoo02d66r5hscogp", "C3", "v2puca30nbv69vtqtoo02d66r5hscogp", "C3"}, +sql.Row{"1enqqtnn7tmdmsl01782t2l8sfob5s9a", "C2", "1enqqtnn7tmdmsl01782t2l8sfob5s9a", "C2"}, +sql.Row{"uhngue3m4jcrucr1phttaqd4h5plu4it", "C1", "uhngue3m4jcrucr1phttaqd4h5plu4it", "C1"}, +sql.Row{"oj3aon78aeoftall6saoafdhshb9g1c5", "checkpoint enginetest database mydb", "oj3aon78aeoftall6saoafdhshb9g1c5", "checkpoint enginetest database mydb"}, +sql.Row{"gltfgpf6g23r8ht07hg9rs3elm85g92d", "Initialize data repository", "gltfgpf6g23r8ht07hg9rs3elm85g92d", "Initialize data repository"}, + + var scripts = []queries.ScriptTest{ { - Name: "Database syntax properly handles inter-CALL communication", + Name: "test dolt_branch_status(...)", SetUpScript: []string{ - `CREATE PROCEDURE p1() -BEGIN - DECLARE str VARCHAR(20); - CALL p2(str); - SET str = CONCAT('a', str); - SELECT str; -END`, - `CREATE PROCEDURE p2(OUT param VARCHAR(20)) -BEGIN - SET param = 'b'; -END`, - "CALL DOLT_ADD('-A');", - "CALL DOLT_COMMIT('-m', 'First procedures');", - "CALL DOLT_BRANCH('p12');", - "DROP PROCEDURE p1;", - "DROP PROCEDURE p2;", - `CREATE PROCEDURE p1() -BEGIN - DECLARE str VARCHAR(20); - CALL p2(str); - SET str = CONCAT('c', str); - SELECT str; -END`, - `CREATE PROCEDURE p2(OUT param VARCHAR(20)) -BEGIN - SET param = 'd'; -END`, - "CALL DOLT_ADD('-A');", - "CALL DOLT_COMMIT('-m', 'Second procedures');", + "call dolt_tag('anc', 'HEAD');", + "call dolt_branch('b1');", + "call dolt_commit('-m', 'C1', '--allow-empty');", + "call dolt_commit('-m', 'C2', '--allow-empty');", + "call dolt_commit('-m', 'C3', '--allow-empty');", + "call dolt_tag('t1', 'HEAD');", + "call dolt_commit('-m', 'C4', '--allow-empty');", + "call dolt_branch('b2');", + "call dolt_commit('-m', 'C5', '--allow-empty');", + "call dolt_commit('-m', 'C6', '--allow-empty');", + "call dolt_checkout('b1');", + "call dolt_commit('-m', 'C7', '--allow-empty');", + "call dolt_merge('t1', '-m', 'M1');", + "call dolt_tag('t2', 'HEAD');", + "call dolt_commit('-m', 'C8', '--allow-empty');", + "call dolt_checkout('b2');", + "call dolt_merge('b1', '-m', 'M2');", }, Assertions: []queries.ScriptTestAssertion{ { - Query: "CALL p1();", - Expected: []sql.Row{{"cd"}}, + Query: "select d1.commit_hash, d1.message, d2.commit_hash, d2.message from dolt_log('b2') d1 left join dolt_log('main') d2 on d1.commit_hash = d2.commit_hash;", + Expected: []sql.Row{}, }, { - Query: "CALL `mydb/main`.p1();", - Expected: []sql.Row{{"cd"}}, + Query: "select d1.commit_hash, d1.message, d2.commit_hash, d2.message from dolt_log('main') d1 left join dolt_log('b2') d2 on d1.commit_hash = d2.commit_hash;", + Expected: []sql.Row{}, }, { - Query: "CALL `mydb/p12`.p1();", - Expected: []sql.Row{{"ab"}}, + Query: "select * from dolt_branch_status('main', 'b2')", + Expected: []sql.Row{}, }, }, }, From ed360e52b82427fd2c43352e68b170bc7b0410eb Mon Sep 17 00:00:00 2001 From: James Cor Date: Tue, 6 May 2025 10:47:53 -0700 Subject: [PATCH 15/22] testing --- .../doltcore/sqle/enginetest/dolt_engine_test.go | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go b/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go index fbc30aa1721..07e1a1a3868 100644 --- a/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go +++ b/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go @@ -114,18 +114,6 @@ func TestSchemaOverridesWithAdaptiveEncoding(t *testing.T) { // Convenience test for debugging a single query. Unskip and set to the desired query. func TestSingleScript(t *testing.T) { //t.Skip() - - -sql.Row{"v3ovmbhvfpsl60i7ipg9b0vljsc0vcga", "C6", interface {}(nil), interface {}(nil)}, -sql.Row{"o9712qt6v19bdbn4gtp9ivha86i6ragf", "C5", interface {}(nil), interface {}(nil)}, -sql.Row{"bdvq579k1fhsfg0putcvv2plbpmo4k34", "C4", "bdvq579k1fhsfg0putcvv2plbpmo4k34", "C4"}, -sql.Row{"v2puca30nbv69vtqtoo02d66r5hscogp", "C3", "v2puca30nbv69vtqtoo02d66r5hscogp", "C3"}, -sql.Row{"1enqqtnn7tmdmsl01782t2l8sfob5s9a", "C2", "1enqqtnn7tmdmsl01782t2l8sfob5s9a", "C2"}, -sql.Row{"uhngue3m4jcrucr1phttaqd4h5plu4it", "C1", "uhngue3m4jcrucr1phttaqd4h5plu4it", "C1"}, -sql.Row{"oj3aon78aeoftall6saoafdhshb9g1c5", "checkpoint enginetest database mydb", "oj3aon78aeoftall6saoafdhshb9g1c5", "checkpoint enginetest database mydb"}, -sql.Row{"gltfgpf6g23r8ht07hg9rs3elm85g92d", "Initialize data repository", "gltfgpf6g23r8ht07hg9rs3elm85g92d", "Initialize data repository"}, - - var scripts = []queries.ScriptTest{ { Name: "test dolt_branch_status(...)", From deda322ecd0b60eeee0369255329022a9efa4ffc Mon Sep 17 00:00:00 2001 From: James Cor Date: Tue, 6 May 2025 12:39:36 -0700 Subject: [PATCH 16/22] fix --- go/libraries/doltcore/doltdb/commit.go | 5 -- .../sqle/enginetest/dolt_engine_test.go | 72 ++++++++++--------- 2 files changed, 37 insertions(+), 40 deletions(-) diff --git a/go/libraries/doltcore/doltdb/commit.go b/go/libraries/doltcore/doltdb/commit.go index f0c87c0f4ed..7bd543c78f6 100644 --- a/go/libraries/doltcore/doltdb/commit.go +++ b/go/libraries/doltcore/doltdb/commit.go @@ -18,8 +18,6 @@ import ( "context" "errors" "fmt" - "sort" - "github.com/dolthub/dolt/go/store/datas" "github.com/dolthub/dolt/go/store/hash" "github.com/dolthub/dolt/go/store/prolly" @@ -117,9 +115,6 @@ func (c *Commit) ParentHashes(ctx context.Context) ([]hash.Hash, error) { for i, pr := range c.parents { hashes[i] = pr.Addr() } - sort.Slice(hashes, func(i, j int) bool { - return hashes[i].Less(hashes[j]) - }) return hashes, nil } diff --git a/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go b/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go index 07e1a1a3868..cc125e85ff5 100644 --- a/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go +++ b/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go @@ -113,41 +113,53 @@ func TestSchemaOverridesWithAdaptiveEncoding(t *testing.T) { // Convenience test for debugging a single query. Unskip and set to the desired query. func TestSingleScript(t *testing.T) { - //t.Skip() + t.Skip() var scripts = []queries.ScriptTest{ { - Name: "test dolt_branch_status(...)", + Name: "Database syntax properly handles inter-CALL communication", SetUpScript: []string{ - "call dolt_tag('anc', 'HEAD');", - "call dolt_branch('b1');", - "call dolt_commit('-m', 'C1', '--allow-empty');", - "call dolt_commit('-m', 'C2', '--allow-empty');", - "call dolt_commit('-m', 'C3', '--allow-empty');", - "call dolt_tag('t1', 'HEAD');", - "call dolt_commit('-m', 'C4', '--allow-empty');", - "call dolt_branch('b2');", - "call dolt_commit('-m', 'C5', '--allow-empty');", - "call dolt_commit('-m', 'C6', '--allow-empty');", - "call dolt_checkout('b1');", - "call dolt_commit('-m', 'C7', '--allow-empty');", - "call dolt_merge('t1', '-m', 'M1');", - "call dolt_tag('t2', 'HEAD');", - "call dolt_commit('-m', 'C8', '--allow-empty');", - "call dolt_checkout('b2');", - "call dolt_merge('b1', '-m', 'M2');", + `CREATE PROCEDURE p1() +BEGIN + DECLARE str VARCHAR(20); + CALL p2(str); + SET str = CONCAT('a', str); + SELECT str; +END`, + `CREATE PROCEDURE p2(OUT param VARCHAR(20)) +BEGIN + SET param = 'b'; +END`, + "CALL DOLT_ADD('-A');", + "CALL DOLT_COMMIT('-m', 'First procedures');", + "CALL DOLT_BRANCH('p12');", + "DROP PROCEDURE p1;", + "DROP PROCEDURE p2;", + `CREATE PROCEDURE p1() +BEGIN + DECLARE str VARCHAR(20); + CALL p2(str); + SET str = CONCAT('c', str); + SELECT str; +END`, + `CREATE PROCEDURE p2(OUT param VARCHAR(20)) +BEGIN + SET param = 'd'; +END`, + "CALL DOLT_ADD('-A');", + "CALL DOLT_COMMIT('-m', 'Second procedures');", }, Assertions: []queries.ScriptTestAssertion{ { - Query: "select d1.commit_hash, d1.message, d2.commit_hash, d2.message from dolt_log('b2') d1 left join dolt_log('main') d2 on d1.commit_hash = d2.commit_hash;", - Expected: []sql.Row{}, + Query: "CALL p1();", + Expected: []sql.Row{{"cd"}}, }, { - Query: "select d1.commit_hash, d1.message, d2.commit_hash, d2.message from dolt_log('main') d1 left join dolt_log('b2') d2 on d1.commit_hash = d2.commit_hash;", - Expected: []sql.Row{}, + Query: "CALL `mydb/main`.p1();", + Expected: []sql.Row{{"cd"}}, }, { - Query: "select * from dolt_branch_status('main', 'b2')", - Expected: []sql.Row{}, + Query: "CALL `mydb/p12`.p1();", + Expected: []sql.Row{{"ab"}}, }, }, }, @@ -1552,16 +1564,6 @@ func TestLogTableFunctionPrepared(t *testing.T) { RunLogTableFunctionTestsPrepared(t, harness) } -func TestBranchStatusTableFunction(t *testing.T) { - harness := newDoltEnginetestHarness(t) - RunBranchStatusTableFunctionTests(t, harness) -} - -func TestBranchStatusTableFunctionPrepared(t *testing.T) { - harness := newDoltEnginetestHarness(t) - RunBranchStatusTableFunctionTestsPrepared(t, harness) -} - func TestDoltReflog(t *testing.T) { h := newDoltEnginetestHarness(t) RunDoltReflogTests(t, h) From 059ce83565c05ff654a8d7564288879da9ad931d Mon Sep 17 00:00:00 2001 From: jycor Date: Tue, 6 May 2025 19:48:32 +0000 Subject: [PATCH 17/22] [ga-format-pr] Run go/utils/repofmt/format_repo.sh and go/Godeps/update.sh --- go/libraries/doltcore/doltdb/commit.go | 1 + 1 file changed, 1 insertion(+) diff --git a/go/libraries/doltcore/doltdb/commit.go b/go/libraries/doltcore/doltdb/commit.go index 7bd543c78f6..83829d6918c 100644 --- a/go/libraries/doltcore/doltdb/commit.go +++ b/go/libraries/doltcore/doltdb/commit.go @@ -18,6 +18,7 @@ import ( "context" "errors" "fmt" + "github.com/dolthub/dolt/go/store/datas" "github.com/dolthub/dolt/go/store/hash" "github.com/dolthub/dolt/go/store/prolly" From 493028d0e0fd1db1fd63cfc0de0cfcf26dc1db9e Mon Sep 17 00:00:00 2001 From: James Cor Date: Tue, 6 May 2025 15:56:07 -0700 Subject: [PATCH 18/22] restore test functions --- .../doltcore/sqle/enginetest/dolt_engine_test.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go b/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go index cc125e85ff5..321dfc39711 100644 --- a/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go +++ b/go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go @@ -1564,6 +1564,16 @@ func TestLogTableFunctionPrepared(t *testing.T) { RunLogTableFunctionTestsPrepared(t, harness) } +func TestBranchStatusTableFunction(t *testing.T) { + harness := newDoltEnginetestHarness(t) + RunBranchStatusTableFunctionTests(t, harness) +} + +func TestBranchStatusTableFunctionPrepared(t *testing.T) { + harness := newDoltEnginetestHarness(t) + RunBranchStatusTableFunctionTestsPrepared(t, harness) +} + func TestDoltReflog(t *testing.T) { h := newDoltEnginetestHarness(t) RunDoltReflogTests(t, h) From 0e4376e9bc8ee6ab81e12c22c942f8de85e1821d Mon Sep 17 00:00:00 2001 From: James Cor Date: Fri, 30 May 2025 13:49:25 -0700 Subject: [PATCH 19/22] fix and add tests --- .../dolt_branch_status_table_function.go | 95 ++++++++++--------- .../doltcore/sqle/enginetest/dolt_queries.go | 24 ++--- 2 files changed, 63 insertions(+), 56 deletions(-) diff --git a/go/libraries/doltcore/sqle/dtablefunctions/dolt_branch_status_table_function.go b/go/libraries/doltcore/sqle/dtablefunctions/dolt_branch_status_table_function.go index d641ace4691..69dd849a3d1 100644 --- a/go/libraries/doltcore/sqle/dtablefunctions/dolt_branch_status_table_function.go +++ b/go/libraries/doltcore/sqle/dtablefunctions/dolt_branch_status_table_function.go @@ -118,6 +118,38 @@ func (b *BranchStatusTableFunction) WithChildren(children ...sql.Node) (sql.Node return b, nil } +func isNotGhostCommit(commit *doltdb.OptionalCommit) (bool, error) { + _, commitOk := commit.ToCommit() + return commitOk, nil +} + +func (b *BranchStatusTableFunction) getCommitMap(ctx *sql.Context, ddb *doltdb.DoltDB, startHash hash.Hash) (map[string]struct{}, error) { + commitHashes := make(map[string]struct{}) + commitIter, err := commitwalk.GetTopologicalOrderIterator[doltdb.Context](ctx, ddb, []hash.Hash{startHash}, isNotGhostCommit) + if err != nil { + return nil, err + } + for { + _, optCmt, cErr := commitIter.Next(ctx) + if cErr != nil { + if cErr == io.EOF { + break + } + return nil, cErr + } + commit, isReal := optCmt.ToCommit() + if !isReal { + continue + } + commitHash, hErr := commit.HashOf() + if hErr != nil { + return nil, hErr + } + commitHashes[commitHash.String()] = struct{}{} + } + return commitHashes, nil +} + // RowIter implements the sql.Node interface func (b *BranchStatusTableFunction) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIter, error) { sqlDb, ok := b.db.(dsess.SqlDatabase) @@ -166,64 +198,39 @@ func (b *BranchStatusTableFunction) RowIter(ctx *sql.Context, row sql.Row) (sql. return nil, err } - isNotGhostCommit := func(commit *doltdb.OptionalCommit) (bool, error) { - _, commitOk := commit.ToCommit() - return commitOk, nil + // TODO: There is definitely a more efficient algorithm. + // We waste memory and time here by always traversing until initial commit. + + baseAncestors, err := b.getCommitMap(ctx, ddb, baseHash) + if err != nil { + return nil, err } var rows []sql.Row for i, branchCommit := range branchCommits { + var ahead, behind uint64 branchHash, hErr := branchCommit.HashOf() if hErr != nil { return nil, hErr } - ancOptCommit, ancErr := doltdb.GetCommitAncestor(ctx, baseCommit, branchCommit) - if ancErr != nil { - return nil, err - } - ancCommit, ancCommitOk := ancOptCommit.ToCommit() - if !ancCommitOk { - return nil, doltdb.ErrGhostCommitEncountered - } - ancHash, hErr := ancCommit.HashOf() - if hErr != nil { - return nil, hErr + // same commit will have no differences + if branchHash.Equal(baseHash) { + rows = append(rows, sql.Row{specs[i+1], ahead, behind}) + continue } - var ahead, behind uint64 - if commitIter, iErr := commitwalk.GetTopologicalOrderIterator[doltdb.Context](ctx, ddb, []hash.Hash{branchHash}, isNotGhostCommit); iErr != nil { - return nil, iErr - } else { - for { - hash, _, cErr := commitIter.Next(ctx) - if cErr != nil { - if cErr == io.EOF { - break - } - return nil, err - } - if ancHash.Equal(hash) { - break - } + branchAncestors, bErr := b.getCommitMap(ctx, ddb, branchHash) + if bErr != nil { + return nil, bErr + } + for branchAncestor := range branchAncestors { + if _, ok = baseAncestors[branchAncestor]; !ok { ahead++ } } - - if commitIter, iErr := commitwalk.GetTopologicalOrderIterator[doltdb.Context](ctx, ddb, []hash.Hash{baseHash}, isNotGhostCommit); iErr != nil { - return nil, iErr - } else { - for { - hash, _, cErr := commitIter.Next(ctx) - if cErr != nil { - if cErr == io.EOF { - break - } - return nil, err - } - if ancHash.Equal(hash) { - break - } + for baseAncestor := range baseAncestors { + if _, ok = branchAncestors[baseAncestor]; !ok { behind++ } } diff --git a/go/libraries/doltcore/sqle/enginetest/dolt_queries.go b/go/libraries/doltcore/sqle/enginetest/dolt_queries.go index 313bf34435a..1732a6d5b4e 100644 --- a/go/libraries/doltcore/sqle/enginetest/dolt_queries.go +++ b/go/libraries/doltcore/sqle/enginetest/dolt_queries.go @@ -4797,12 +4797,12 @@ var BranchStatusTableFunctionScriptTests = []queries.ScriptTest{ // | * b2 // | // * main - // \ - // * b3 - // | - // * b4 // \ - // * b5 + // * b3 + // | + // * b4 + // \ + // * b5 Name: "test dolt_branch_status(...)", SetUpScript: []string{ "call dolt_branch('b1');", @@ -4966,7 +4966,7 @@ var BranchStatusTableFunctionScriptTests = []queries.ScriptTest{ { Query: "select * from dolt_branch_status('b1', 'b2');", Expected: []sql.Row{ - {"b2", uint64(2), uint64(0)}, + {"b2", uint64(4), uint64(0)}, }, }, }, @@ -5015,13 +5015,13 @@ var BranchStatusTableFunctionScriptTests = []queries.ScriptTest{ { Query: "select * from dolt_branch_status('main', 'b2');", Expected: []sql.Row{ - {"b2", uint64(3), uint64(2)}, // Currently Failing here. + {"b2", uint64(4), uint64(2)}, }, }, { Query: "select * from dolt_branch_status('main', 'b1');", Expected: []sql.Row{ - {"b1", uint64(2), uint64(3)}, + {"b1", uint64(3), uint64(3)}, }, }, { @@ -5040,13 +5040,13 @@ var BranchStatusTableFunctionScriptTests = []queries.ScriptTest{ Query: "select * from dolt_branch_status('t1', 'anc', 't2','t2~1', 'main', 'b1', 'b2', 'b2^1', 'b2^2' );", Expected: []sql.Row{ {"anc", uint64(0), uint64(3)}, - {"t2", uint64(1), uint64(0)}, + {"t2", uint64(2), uint64(0)}, {"t2~1", uint64(1), uint64(3)}, {"main", uint64(3), uint64(0)}, - {"b1", uint64(2), uint64(0)}, - {"b2", uint64(4), uint64(0)}, + {"b1", uint64(3), uint64(0)}, + {"b2", uint64(5), uint64(0)}, {"b2^1", uint64(1), uint64(0)}, - {"b2^2", uint64(2), uint64(0)}, + {"b2^2", uint64(3), uint64(0)}, }, }, }, From d5641d7cf0b77f52537ea0f600db67fda7a7b86d Mon Sep 17 00:00:00 2001 From: James Cor Date: Mon, 2 Jun 2025 10:48:12 -0700 Subject: [PATCH 20/22] feedback --- .../dolt_branch_status_table_function.go | 7 +++- .../doltcore/sqle/enginetest/dolt_queries.go | 42 +++++++++++-------- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/go/libraries/doltcore/sqle/dtablefunctions/dolt_branch_status_table_function.go b/go/libraries/doltcore/sqle/dtablefunctions/dolt_branch_status_table_function.go index 69dd849a3d1..4e0594585f2 100644 --- a/go/libraries/doltcore/sqle/dtablefunctions/dolt_branch_status_table_function.go +++ b/go/libraries/doltcore/sqle/dtablefunctions/dolt_branch_status_table_function.go @@ -37,8 +37,8 @@ type BranchStatusTableFunction struct { // NewInstance creates a new instance of TableFunction interface func (b *BranchStatusTableFunction) NewInstance(ctx *sql.Context, db sql.Database, args []sql.Expression) (sql.Node, error) { - if len(args) < 1 { - return nil, sql.ErrInvalidArgumentNumber.New(b.Name(), "at least 2", len(args)) + if len(args) == 0 { + return nil, sql.ErrInvalidArgumentNumber.New(b.Name(), "at least 1", len(args)) } return &BranchStatusTableFunction{ db: db, @@ -169,6 +169,9 @@ func (b *BranchStatusTableFunction) RowIter(ctx *sql.Context, row sql.Row) (sql. if err != nil { return nil, err } + if len(specs) == 0 { + return nil, sql.ErrInvalidArgumentNumber.New(b.Name(), "at least 1", 0) + } if len(specs) == 1 { return sql.RowsToRowIter(), nil } diff --git a/go/libraries/doltcore/sqle/enginetest/dolt_queries.go b/go/libraries/doltcore/sqle/enginetest/dolt_queries.go index 32885e6409a..40b32c1c577 100644 --- a/go/libraries/doltcore/sqle/enginetest/dolt_queries.go +++ b/go/libraries/doltcore/sqle/enginetest/dolt_queries.go @@ -4865,14 +4865,22 @@ var BranchStatusTableFunctionScriptTests = []queries.ScriptTest{ Name: "test dolt_branch_status(...)", SetUpScript: []string{ "call dolt_branch('b1');", - "call dolt_branch('b2');", + "call dolt_commit('-m', 'main', '--allow-empty');", + "call dolt_checkout('b1');", + "call dolt_commit('-m', 'b1', '--allow-empty');", + + "call dolt_branch('b2');", "call dolt_checkout('b2');", "call dolt_commit('-m', 'b2', '--allow-empty');", "call dolt_checkout('main');", "call dolt_branch('b3');", + + "call dolt_checkout('b3');", + "call dolt_commit('-m', 'b3', '--allow-empty');", + "call dolt_branch('b4');", "call dolt_checkout('b4');", "call dolt_commit('-m', 'b4', '--allow-empty');", @@ -4904,42 +4912,42 @@ var BranchStatusTableFunctionScriptTests = []queries.ScriptTest{ Query: "select * from dolt_branch_status('main', 'main', 'b1', 'b2', 'b3', 'b4', 'b5');", Expected: []sql.Row{ {"main", uint64(0), uint64(0)}, - {"b1", uint64(0), uint64(1)}, - {"b2", uint64(1), uint64(1)}, - {"b3", uint64(0), uint64(0)}, - {"b4", uint64(1), uint64(0)}, - {"b5", uint64(2), uint64(0)}, + {"b1", uint64(1), uint64(1)}, + {"b2", uint64(2), uint64(1)}, + {"b3", uint64(1), uint64(0)}, + {"b4", uint64(2), uint64(0)}, + {"b5", uint64(3), uint64(0)}, }, }, { Query: "select * from dolt_branch_status('main', 't1', 't2', 't3', 't4', 't5');", Expected: []sql.Row{ - {"t1", uint64(0), uint64(1)}, - {"t2", uint64(1), uint64(1)}, - {"t3", uint64(0), uint64(0)}, - {"t4", uint64(1), uint64(0)}, - {"t5", uint64(2), uint64(0)}, + {"t1", uint64(1), uint64(1)}, + {"t2", uint64(2), uint64(1)}, + {"t3", uint64(1), uint64(0)}, + {"t4", uint64(2), uint64(0)}, + {"t5", uint64(3), uint64(0)}, }, }, { Query: "select * from dolt_branch_status('b2', 'b5');", Expected: []sql.Row{ - {"b5", uint64(3), uint64(1)}, + {"b5", uint64(4), uint64(2)}, }, }, { Query: "select * from dolt_branch_status('main', 'b5', 'HEAD', 'HEAD~1', 'HEAD~2');", Expected: []sql.Row{ - {"b5", uint64(2), uint64(0)}, - {"HEAD", uint64(2), uint64(0)}, - {"HEAD~1", uint64(1), uint64(0)}, - {"HEAD~2", uint64(0), uint64(0)}, + {"b5", uint64(3), uint64(0)}, + {"HEAD", uint64(3), uint64(0)}, + {"HEAD~1", uint64(2), uint64(0)}, + {"HEAD~2", uint64(1), uint64(0)}, }, }, { Query: "select commits_ahead, commits_behind from dolt_branch_status('main', dolt_hashof('b5'));", Expected: []sql.Row{ - {uint64(2), uint64(0)}, + {uint64(3), uint64(0)}, }, }, }, From 0cc520cb571ccb327a451d73b4d7ce702ebb5a58 Mon Sep 17 00:00:00 2001 From: James Cor Date: Mon, 2 Jun 2025 11:37:57 -0700 Subject: [PATCH 21/22] return correct error --- .../sqle/dtablefunctions/dolt_branch_status_table_function.go | 2 +- go/libraries/doltcore/sqle/enginetest/dolt_queries.go | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/go/libraries/doltcore/sqle/dtablefunctions/dolt_branch_status_table_function.go b/go/libraries/doltcore/sqle/dtablefunctions/dolt_branch_status_table_function.go index 4e0594585f2..24c9bca23a2 100644 --- a/go/libraries/doltcore/sqle/dtablefunctions/dolt_branch_status_table_function.go +++ b/go/libraries/doltcore/sqle/dtablefunctions/dolt_branch_status_table_function.go @@ -180,7 +180,7 @@ func (b *BranchStatusTableFunction) RowIter(ctx *sql.Context, row sql.Row) (sql. for i, spec := range specs { cs, cErr := doltdb.NewCommitSpec(spec) if cErr != nil { - return nil, err + return nil, cErr } optCmt, oErr := ddb.Resolve(ctx, cs, headRef) if oErr != nil { diff --git a/go/libraries/doltcore/sqle/enginetest/dolt_queries.go b/go/libraries/doltcore/sqle/enginetest/dolt_queries.go index 40b32c1c577..49d0c3b617f 100644 --- a/go/libraries/doltcore/sqle/enginetest/dolt_queries.go +++ b/go/libraries/doltcore/sqle/enginetest/dolt_queries.go @@ -4896,6 +4896,10 @@ var BranchStatusTableFunctionScriptTests = []queries.ScriptTest{ "call dolt_tag('t5', 'b5');", }, Assertions: []queries.ScriptTestAssertion{ + { + Query: "select * from dolt_branch_status('main', '');", + ExpectedErrStr: "string is not a valid branch or hash", + }, { Query: "select * from dolt_branch_status('main', 'non-existent-branch');", ExpectedErrStr: "branch not found: non-existent-branch", From 6999fa45148c6572160b9d8cde53f24112af09c7 Mon Sep 17 00:00:00 2001 From: James Cor Date: Mon, 2 Jun 2025 13:25:13 -0700 Subject: [PATCH 22/22] use CommitClosure instead --- .../dolt_branch_status_table_function.go | 59 +++++-------------- 1 file changed, 15 insertions(+), 44 deletions(-) diff --git a/go/libraries/doltcore/sqle/dtablefunctions/dolt_branch_status_table_function.go b/go/libraries/doltcore/sqle/dtablefunctions/dolt_branch_status_table_function.go index 24c9bca23a2..8a2ff0b46f7 100644 --- a/go/libraries/doltcore/sqle/dtablefunctions/dolt_branch_status_table_function.go +++ b/go/libraries/doltcore/sqle/dtablefunctions/dolt_branch_status_table_function.go @@ -16,16 +16,13 @@ package dtablefunctions import ( "fmt" - "io" "strings" "github.com/dolthub/go-mysql-server/sql" "github.com/dolthub/go-mysql-server/sql/types" "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" - "github.com/dolthub/dolt/go/libraries/doltcore/env/actions/commitwalk" "github.com/dolthub/dolt/go/libraries/doltcore/sqle/dsess" - "github.com/dolthub/dolt/go/store/hash" ) var _ sql.TableFunction = (*BranchStatusTableFunction)(nil) @@ -118,38 +115,6 @@ func (b *BranchStatusTableFunction) WithChildren(children ...sql.Node) (sql.Node return b, nil } -func isNotGhostCommit(commit *doltdb.OptionalCommit) (bool, error) { - _, commitOk := commit.ToCommit() - return commitOk, nil -} - -func (b *BranchStatusTableFunction) getCommitMap(ctx *sql.Context, ddb *doltdb.DoltDB, startHash hash.Hash) (map[string]struct{}, error) { - commitHashes := make(map[string]struct{}) - commitIter, err := commitwalk.GetTopologicalOrderIterator[doltdb.Context](ctx, ddb, []hash.Hash{startHash}, isNotGhostCommit) - if err != nil { - return nil, err - } - for { - _, optCmt, cErr := commitIter.Next(ctx) - if cErr != nil { - if cErr == io.EOF { - break - } - return nil, cErr - } - commit, isReal := optCmt.ToCommit() - if !isReal { - continue - } - commitHash, hErr := commit.HashOf() - if hErr != nil { - return nil, hErr - } - commitHashes[commitHash.String()] = struct{}{} - } - return commitHashes, nil -} - // RowIter implements the sql.Node interface func (b *BranchStatusTableFunction) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIter, error) { sqlDb, ok := b.db.(dsess.SqlDatabase) @@ -200,40 +165,46 @@ func (b *BranchStatusTableFunction) RowIter(ctx *sql.Context, row sql.Row) (sql. if err != nil { return nil, err } - - // TODO: There is definitely a more efficient algorithm. - // We waste memory and time here by always traversing until initial commit. - - baseAncestors, err := b.getCommitMap(ctx, ddb, baseHash) + baseCommitClosure, err := baseCommit.GetCommitClosure(ctx) if err != nil { return nil, err } + baseAncestors, err := baseCommitClosure.AsHashSet(ctx) + if err != nil { + return nil, err + } + baseAncestors.Insert(baseHash) var rows []sql.Row for i, branchCommit := range branchCommits { - var ahead, behind uint64 branchHash, hErr := branchCommit.HashOf() if hErr != nil { return nil, hErr } // same commit will have no differences + var ahead, behind uint64 if branchHash.Equal(baseHash) { rows = append(rows, sql.Row{specs[i+1], ahead, behind}) continue } - branchAncestors, bErr := b.getCommitMap(ctx, ddb, branchHash) + branchCommitClosure, bErr := branchCommit.GetCommitClosure(ctx) + if bErr != nil { + return nil, bErr + } + branchAncestors, bErr := branchCommitClosure.AsHashSet(ctx) if bErr != nil { return nil, bErr } + branchAncestors.Insert(branchHash) for branchAncestor := range branchAncestors { - if _, ok = baseAncestors[branchAncestor]; !ok { + if !baseAncestors.Has(branchAncestor) { ahead++ } } for baseAncestor := range baseAncestors { - if _, ok = branchAncestors[baseAncestor]; !ok { + if !branchAncestors.Has(baseAncestor) { behind++ } }