unified merge() and dolt_merge(), updated BATS to stage changes before committing, some sql-server tests still failing

This commit is contained in:
Andy Arthur
2022-03-14 11:46:06 -07:00
parent 607ba8d0bc
commit 3bf3cf43c8
9 changed files with 99 additions and 214 deletions
@@ -34,7 +34,7 @@ func NewCommitFunc(args ...sql.Expression) (sql.Expression, error) {
// Eval implements the Expression interface.
func (cf *CommitFunc) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) {
return makeDoltCommit(ctx, row, cf.Children())
return doDoltCommit(ctx, row, cf.Children())
}
// String implements the Stringer interface.
@@ -41,10 +41,10 @@ func NewDoltCommitFunc(args ...sql.Expression) (sql.Expression, error) {
}
func (d DoltCommitFunc) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) {
return makeDoltCommit(ctx, row, d.Children())
return doDoltCommit(ctx, row, d.Children())
}
func makeDoltCommit(ctx *sql.Context, row sql.Row, exprs []sql.Expression) (interface{}, error) {
func doDoltCommit(ctx *sql.Context, row sql.Row, exprs []sql.Expression) (interface{}, error) {
// Get the information for the sql context.
dbName := ctx.GetCurrentDatabase()
ap := cli.CreateCommitArgParser()
@@ -32,6 +32,10 @@ import (
"github.com/dolthub/dolt/go/libraries/utils/argparser"
)
func NewDoltMergeFunc(args ...sql.Expression) (sql.Expression, error) {
return &DoltMergeFunc{expression.NaryExpression{ChildExpressions: args}}, nil
}
const DoltMergeFuncName = "dolt_merge"
type DoltMergeFunc struct {
@@ -46,6 +50,10 @@ const (
)
func (d DoltMergeFunc) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) {
return doDoltCommit(ctx, row, d.Children())
}
func doDoltMerge(ctx *sql.Context, row sql.Row, exprs []sql.Expression) (interface{}, error) {
dbName := ctx.GetCurrentDatabase()
if len(dbName) == 0 {
@@ -55,7 +63,7 @@ func (d DoltMergeFunc) Eval(ctx *sql.Context, row sql.Row) (interface{}, error)
sess := dsess.DSessFromSess(ctx.Session)
ap := cli.CreateMergeArgParser()
args, err := getDoltArgs(ctx, row, d.Children())
args, err := getDoltArgs(ctx, row, exprs)
if err != nil {
return noConflicts, err
@@ -401,6 +409,25 @@ func mergeRootToWorking(
return ws, nil
}
func checkForUncommittedChanges(root *doltdb.RootValue, headRoot *doltdb.RootValue) error {
rh, err := root.HashOf()
if err != nil {
return err
}
hrh, err := headRoot.HashOf()
if err != nil {
return err
}
if rh != hrh {
return ErrUncommittedChanges.New()
}
return nil
}
func checkForConflicts(tblToStats map[string]*merge.MergeStats) bool {
for _, stats := range tblToStats {
if stats.Operation == merge.TableModified && stats.Conflicts > 0 {
@@ -428,7 +455,3 @@ func (d DoltMergeFunc) Type() sql.Type {
func (d DoltMergeFunc) WithChildren(children ...sql.Expression) (sql.Expression, error) {
return NewDoltMergeFunc(children...)
}
func NewDoltMergeFunc(args ...sql.Expression) (sql.Expression, error) {
return &DoltMergeFunc{expression.NaryExpression{ChildExpressions: args}}, nil
}
+1 -186
View File
@@ -15,19 +15,11 @@
package dfunctions
import (
"errors"
"fmt"
"strings"
"github.com/dolthub/go-mysql-server/sql"
goerrors "gopkg.in/src-d/go-errors.v1"
"github.com/dolthub/dolt/go/cmd/dolt/cli"
"github.com/dolthub/dolt/go/libraries/doltcore/doltdb"
"github.com/dolthub/dolt/go/libraries/doltcore/merge"
"github.com/dolthub/dolt/go/libraries/doltcore/sqle/dsess"
"github.com/dolthub/dolt/go/store/datas"
"github.com/dolthub/dolt/go/store/hash"
)
const MergeFuncName = "merge"
@@ -46,184 +38,7 @@ func NewMergeFunc(args ...sql.Expression) (sql.Expression, error) {
// Eval implements the Expression interface.
// todo(andy): merge with DOLT_MERGE()
func (cf *MergeFunc) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) {
sess := dsess.DSessFromSess(ctx.Session)
// TODO: Move to a separate MERGE argparser.
ap := cli.CreateCommitArgParser()
args, err := getDoltArgs(ctx, row, cf.Children())
if err != nil {
return nil, err
}
apr, err := ap.Parse(args)
if err != nil {
return nil, err
}
// The fist argument should be the branch name.
branchName := apr.Arg(0)
var name, email string
if authorStr, ok := apr.GetValue(cli.AuthorParam); ok {
name, email, err = cli.ParseAuthor(authorStr)
if err != nil {
return nil, err
}
} else {
name = sess.Username()
email = sess.Email()
}
dbName := sess.GetCurrentDatabase()
ddb, ok := sess.GetDoltDB(ctx, dbName)
if !ok {
return nil, sql.ErrDatabaseNotFound.New(dbName)
}
roots, ok := sess.GetRoots(ctx, dbName)
if !ok {
return nil, sql.ErrDatabaseNotFound.New(dbName)
}
head, hh, headRoot, err := getHead(ctx, sess, dbName)
if err != nil {
return nil, err
}
err = checkForUncommittedChanges(roots.Working, headRoot)
if err != nil {
return nil, err
}
cm, cmh, err := getBranchCommit(ctx, branchName, ddb)
if err != nil {
return nil, err
}
// No need to write a merge commit, if the head can ffw to the commit coming from the branch.
canFF, err := head.CanFastForwardTo(ctx, cm)
if err != nil {
return nil, err
}
if canFF {
ancRoot, err := head.GetRootValue()
if err != nil {
return nil, err
}
mergedRoot, err := cm.GetRootValue()
if err != nil {
return nil, err
}
if cvPossible, err := merge.MayHaveConstraintViolations(ctx, ancRoot, mergedRoot); err != nil {
return nil, err
} else if !cvPossible {
return cmh.String(), nil
}
}
dbState, ok, err := sess.LookupDbState(ctx, dbName)
if err != nil {
return nil, err
} else if !ok {
return nil, fmt.Errorf("Could not load database %s", dbName)
}
mergeRoot, _, err := merge.MergeCommits(ctx, head, cm, dbState.EditOpts())
if err != nil {
return nil, err
}
h, err := ddb.WriteRootValue(ctx, mergeRoot)
if err != nil {
return nil, err
}
commitMessage := fmt.Sprintf("SQL Generated commit merging %s into %s", hh.String(), cmh.String())
meta, err := datas.NewCommitMeta(name, email, commitMessage)
if err != nil {
return nil, err
}
mergeCommit, err := ddb.CommitDanglingWithParentCommits(ctx, h, []*doltdb.Commit{head, cm}, meta)
if err != nil {
return nil, err
}
h, err = mergeCommit.HashOf()
if err != nil {
return nil, err
}
return h.String(), nil
}
func checkForUncommittedChanges(root *doltdb.RootValue, headRoot *doltdb.RootValue) error {
rh, err := root.HashOf()
if err != nil {
return err
}
hrh, err := headRoot.HashOf()
if err != nil {
return err
}
if rh != hrh {
return ErrUncommittedChanges.New()
}
return nil
}
func getBranchCommit(ctx *sql.Context, val interface{}, ddb *doltdb.DoltDB) (*doltdb.Commit, hash.Hash, error) {
paramStr, ok := val.(string)
if !ok {
return nil, hash.Hash{}, errors.New("branch name is not a string")
}
branchRef, err := getBranchInsensitive(ctx, paramStr, ddb)
if err != nil {
return nil, hash.Hash{}, err
}
cm, err := ddb.ResolveCommitRef(ctx, branchRef)
if err != nil {
return nil, hash.Hash{}, err
}
cmh, err := cm.HashOf()
if err != nil {
return nil, hash.Hash{}, err
}
return cm, cmh, nil
}
func getHead(ctx *sql.Context, sess *dsess.DoltSession, dbName string) (*doltdb.Commit, hash.Hash, *doltdb.RootValue, error) {
head, err := sess.GetHeadCommit(ctx, dbName)
if err != nil {
return nil, hash.Hash{}, nil, err
}
hh, err := head.HashOf()
if err != nil {
return nil, hash.Hash{}, nil, err
}
headRoot, err := head.GetRootValue()
if err != nil {
return nil, hash.Hash{}, nil, err
}
return head, hh, headRoot, nil
return doDoltMerge(ctx, row, cf.Children())
}
// String implements the Stringer interface.
@@ -15,13 +15,16 @@
package dfunctions
import (
"errors"
"fmt"
"github.com/dolthub/go-mysql-server/sql"
"github.com/dolthub/go-mysql-server/sql/expression"
"github.com/dolthub/dolt/go/libraries/doltcore/doltdb"
"github.com/dolthub/dolt/go/libraries/doltcore/merge"
"github.com/dolthub/dolt/go/libraries/doltcore/sqle/dsess"
"github.com/dolthub/dolt/go/store/hash"
)
const SquashFuncName = "squash"
@@ -120,3 +123,50 @@ func (s SquashFunc) WithChildren(children ...sql.Expression) (sql.Expression, er
return NewSquashFunc(children[0]), nil
}
func getBranchCommit(ctx *sql.Context, val interface{}, ddb *doltdb.DoltDB) (*doltdb.Commit, hash.Hash, error) {
paramStr, ok := val.(string)
if !ok {
return nil, hash.Hash{}, errors.New("branch name is not a string")
}
branchRef, err := getBranchInsensitive(ctx, paramStr, ddb)
if err != nil {
return nil, hash.Hash{}, err
}
cm, err := ddb.ResolveCommitRef(ctx, branchRef)
if err != nil {
return nil, hash.Hash{}, err
}
cmh, err := cm.HashOf()
if err != nil {
return nil, hash.Hash{}, err
}
return cm, cmh, nil
}
func getHead(ctx *sql.Context, sess *dsess.DoltSession, dbName string) (*doltdb.Commit, hash.Hash, *doltdb.RootValue, error) {
head, err := sess.GetHeadCommit(ctx, dbName)
if err != nil {
return nil, hash.Hash{}, nil, err
}
hh, err := head.HashOf()
if err != nil {
return nil, hash.Hash{}, nil, err
}
headRoot, err := head.GetRootValue()
if err != nil {
return nil, hash.Hash{}, nil, err
}
return head, hh, headRoot, nil
}
+4 -8
View File
@@ -208,20 +208,16 @@ teardown() {
dolt config --global --add user.email "joshn@doe.com"
dolt init
dolt sql -q "
CREATE TABLE test (
pk int primary key
)"
dolt sql -q "CREATE TABLE test (pk int primary key)"
dolt config --global --unset user.name
dolt config --global --unset user.email
run dolt sql -q "SET @@dolt_repo_$$_head = COMMIT('-a', '-m', 'updated stuff')"
[ "$status" -eq 0 ]
dolt sql -q "SET @@dolt_repo_$$_head = COMMIT('-a', '-m', 'updated stuff')"
dolt config --global --add user.name "bats tester"
run dolt sql -q "SET @@dolt_repo_$$_head = COMMIT('-a', '-m', 'updated stuff')"
[ "$status" -eq 0 ]
dolt sql -q "INSERT INTO test VALUES (1);"
dolt sql -q "SET @@dolt_repo_$$_head = COMMIT('-a', '-m', 'updated stuff')"
}
@test "config: DOLT_COMMIT uses default values when user.name or user.email is unset." {
+1
View File
@@ -90,6 +90,7 @@ teardown() {
cd repo1
dolt config --local --add sqlserver.global.dolt_replicate_to_remote backup1
dolt sql -q "create table t1 (a int primary key)"
dolt add -A
dolt sql -q "UPDATE dolt_branches SET hash = COMMIT('--author', '{user_name} <{email_address}>','-m', 'cm') WHERE name = 'main' AND hash = @@repo1_head"
cd ..
@@ -35,7 +35,7 @@ def commit_and_update_branch(dc, commit_message, expected_hashes, branch_name):
expected_hash += "hash = %s" % eh
expected_hash += ")"
query_str = 'UPDATE dolt_branches SET hash = Commit("-m", "%s") WHERE name = "%s" AND %s' % (commit_message, branch_name, expected_hash)
query_str = 'UPDATE dolt_branches SET hash = Commit("-am", "%s") WHERE name = "%s" AND %s' % (commit_message, branch_name, expected_hash)
_, row_count = query(dc, query_str)
if row_count != 1:
+11 -11
View File
@@ -303,7 +303,7 @@ teardown() {
INSERT INTO one_pk (pk) VALUES (0);
INSERT INTO one_pk (pk,c1) VALUES (1,1);
INSERT INTO one_pk (pk,c1,c2) VALUES (2,2,2),(3,3,3);
SET @@repo1_head=commit('-m', 'test commit message', '--author', 'John Doe <john@example.com>');
SET @@repo1_head=commit('-am', 'test commit message', '--author', 'John Doe <john@example.com>');
INSERT INTO dolt_branches (name,hash) VALUES ('test_branch', @@repo1_head);"
# validate new branch was created
@@ -347,7 +347,7 @@ teardown() {
INSERT INTO one_pk (pk) VALUES (0);
INSERT INTO one_pk (pk,c1) VALUES (1,1);
INSERT INTO one_pk (pk,c1,c2) VALUES (2,2,2),(3,3,3);
SET @@repo1_head=commit('-m', 'test commit message');
SET @@repo1_head=commit('-am', 'test commit message');
INSERT INTO dolt_branches (name,hash) VALUES ('test_branch', @@repo1_head);"
# validate new branch was created
@@ -372,12 +372,12 @@ teardown() {
multi_query repo1 0 "
SET @@repo1_head=hashof('main');
UPDATE one_pk SET c1=10 WHERE pk=2;
SET @@repo1_head=commit('-m', 'Change c 1 to 10');
SET @@repo1_head=commit('-am', 'Change c 1 to 10');
INSERT INTO dolt_branches (name,hash) VALUES ('main', @@repo1_head);
SET @@repo1_head=hashof('test_branch');
INSERT INTO one_pk (pk,c1,c2) VALUES (4,4,4);
SET @@repo1_head=commit('-m', 'add 4');
SET @@repo1_head=commit('-am', 'add 4');
INSERT INTO dolt_branches (name,hash) VALUES ('test_branch', @@repo1_head);"
multi_query repo1 0 "
@@ -421,10 +421,10 @@ teardown() {
INSERT INTO one_pk (pk) VALUES (0);
INSERT INTO one_pk (pk,c1) VALUES (1,1);
INSERT INTO one_pk (pk,c1,c2) VALUES (2,2,2),(3,3,3);
SET @@repo1_head=commit('-m', 'test commit message');
SET @@repo1_head=commit('-am', 'test commit message');
INSERT INTO dolt_branches (name,hash) VALUES ('test_branch', @@repo1_head);
INSERT INTO one_pk (pk,c1,c2) VALUES (4,4,4),(5,5,5);
SET @@repo1_head=commit('-m', 'second commit');
SET @@repo1_head=commit('-am', 'second commit');
INSERT INTO dolt_branches (name,hash) VALUES ('test_branch', @@repo1_head);
"
@@ -437,7 +437,7 @@ teardown() {
# Squash the test_branch into main even though it is a fast-forward merge.
multi_query repo1 0 "
SET @@repo1_working = squash('test_branch');
SET @@repo1_head = COMMIT('-m', 'cm1');
SET @@repo1_head = COMMIT('-am', 'cm1');
UPDATE dolt_branches SET hash = @@repo1_head WHERE name= 'main';"
# Validate tables and data on main
@@ -451,14 +451,14 @@ teardown() {
multi_query repo1 0 "
SET @@repo1_head=hashof('main');
UPDATE one_pk SET c1=10 WHERE pk=2;
SET @@repo1_head=commit('-m', 'Change c 1 to 10');
SET @@repo1_head=commit('-am', 'Change c 1 to 10');
UPDATE dolt_branches SET hash = @@repo1_head WHERE name= 'main';
SET @@repo1_head=hashof('test_branch');
INSERT INTO one_pk (pk,c1,c2) VALUES (6,6,6);
SET @@repo1_head=commit('-m', 'add 6');
SET @@repo1_head=commit('-am', 'add 6');
INSERT INTO one_pk (pk,c1,c2) VALUES (7,7,7);
SET @@repo1_head=commit('-m', 'add 7');
SET @@repo1_head=commit('-am', 'add 7');
INSERT INTO dolt_branches (name,hash) VALUES ('test_branch', @@repo1_head);"
# Validate that running a squash operation without updating the working variable itself alone does not
@@ -871,7 +871,7 @@ SQL
PRIMARY KEY (pk)
);
INSERT INTO one_pk (pk,c1,c2) VALUES (2,2,2),(3,3,3);
SET @@repo1_head=commit('-m', 'test commit message', '--author', 'John Doe <john@example.com>');
SET @@repo1_head=commit('-am', 'test commit message', '--author', 'John Doe <john@example.com>');
INSERT INTO dolt_branches (name,hash) VALUES ('main', @@repo1_head);"
dolt add .