Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
03a21be
small refactor for dolt merge
jycor Apr 15, 2025
2dfe538
partial implementation and tests
jycor Apr 16, 2025
dfdcc17
implement and test dolt_diverge
jycor Apr 16, 2025
c9049e2
revert engine testg
jycor Apr 16, 2025
cac827c
[ga-format-pr] Run go/utils/repofmt/format_repo.sh and go/Godeps/upda…
jycor Apr 16, 2025
9afbac8
more tests
jycor Apr 16, 2025
370b202
more refactoring
jycor Apr 17, 2025
49bbdaa
Merge branch 'james/diverge' of github.com:dolthub/dolt into james/di…
jycor Apr 17, 2025
aab5d67
rename and use commitwalk
Apr 18, 2025
e8f2325
more tests
Apr 18, 2025
9d8848c
adding more complicated test
Apr 18, 2025
729f528
[ga-format-pr] Run go/utils/repofmt/format_repo.sh and go/Godeps/upda…
jycor Apr 18, 2025
e6110aa
Addional test with complicated history
macneale4 Apr 21, 2025
9b65333
merge with main
May 1, 2025
5a40973
fix merge with main
May 2, 2025
d93e111
debugging
May 2, 2025
ed360e5
testing
May 6, 2025
d7aad36
Merge branch 'main' into james/diverge
May 6, 2025
deda322
fix
May 6, 2025
059ce83
[ga-format-pr] Run go/utils/repofmt/format_repo.sh and go/Godeps/upda…
jycor May 6, 2025
493028d
restore test functions
May 6, 2025
c98d334
Merge branch 'james/diverge' of github.com:dolthub/dolt into james/di…
May 30, 2025
7da5aaa
Merge branch 'main' into james/diverge
May 30, 2025
0e4376e
fix and add tests
May 30, 2025
be07f60
merge with main
May 30, 2025
d5641d7
feedback
Jun 2, 2025
0cc520c
return correct error
Jun 2, 2025
6999fa4
use CommitClosure instead
Jun 2, 2025
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
22 changes: 2 additions & 20 deletions go/libraries/doltcore/sqle/dfunctions/has_ancestor.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,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"
)

Expand All @@ -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
Expand All @@ -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
}
Expand All @@ -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
}
Expand All @@ -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.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
// 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/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)

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) < 1 {
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, optCommitOk := optCmt.ToCommit()
if !optCommitOk {
return nil, doltdb.ErrGhostCommitEncountered
}
commits[i] = commit
}

baseCommit := commits[0]
branchCommits := commits[1:]
baseHeight, err := baseCommit.Height()
if err != nil {
return nil, err
}

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 sql.RowsToRowIter(rows...), nil
}
1 change: 1 addition & 0 deletions go/libraries/doltcore/sqle/dtablefunctions/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ var DoltTableFunctions = []sql.TableFunction{
&DiffTableFunction{},
&DiffStatTableFunction{},
&DiffSummaryTableFunction{},
&DivergeTableFunction{},
&LogTableFunction{},
&PatchTableFunction{},
&SchemaDiffTableFunction{},
Expand Down
10 changes: 10 additions & 0 deletions go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1516,6 +1516,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)
Expand Down
Loading
Loading