added bats and error handling

This commit is contained in:
Andy Arthur
2020-06-11 16:24:50 -05:00
parent 1f347869d6
commit 2114d29cbc
4 changed files with 78 additions and 39 deletions

View File

@@ -45,8 +45,7 @@ teardown() {
dolt add .
dolt commit -m rows
dolt sql -q 'update quiz set c2 = "1" where pk = 0'
dolt query_diff 'select test.pk, test.c1, test.c2, quiz.pk, quiz.c1 from test join quiz on test.c2 = quiz.c2 order by test.c2'
run dolt query_diff 'select test.pk, test.c1, test.c2, quiz.pk, quiz.c1 from test join quiz on test.c2 = quiz.c2 order by test.c2'
run dolt query_diff 'select test.pk, test.c1, test.c2, quiz.pk, quiz.c1 from test join quiz on test.c2 = quiz.c2 order by test.pk, quiz.pk'
[ "$status" -eq 0 ]
[[ "$output" =~ "| | pk | c1 | c2 | pk | c1 |" ]]
[[ "$output" =~ "| - | 0 | 0 | 0 | 0 | 0 |" ]]
@@ -66,3 +65,22 @@ teardown() {
[[ "$output" =~ "| - | 1 | 1 | 1 |" ]]
[[ "$output" =~ "| + | 2 | 2 | 2 |" ]]
}
@test "dolt query_diff query error" {
dolt add .
dolt commit -m 'added tables'
run dolt query_diff head^ head 'select * from test order by pk'
[ "$status" -ne 0 ]
[[ "$output" =~ "error executing query on from root" ]]
run dolt query_diff head head^ 'select * from test order by pk'
[ "$status" -ne 0 ]
[[ "$output" =~ "error executing query on to root" ]]
}
@test "dolt query diff prints query plan if query is undiffable" {
dolt add .
dolt commit -m rows
run dolt query_diff 'select * from test'
[ "$status" -ne 0 ]
[[ "$output" =~ "query plan:" ]]
}

View File

@@ -88,7 +88,7 @@ func (cmd QueryDiffCmd) Exec(ctx context.Context, commandStr string, args []stri
help, usage := cli.HelpAndUsagePrinters(cli.GetCommandDocumentation(commandStr, queryDiffDocs, ap))
apr := cli.ParseArgs(ap, args, help)
from, to, leftover, err := GetDiffRoots(ctx, dEnv, apr.Args())
from, to, leftover, err := getDiffRoots(ctx, dEnv, apr.Args())
var verr errhand.VerboseError
if err != nil {
@@ -109,7 +109,7 @@ func (cmd QueryDiffCmd) Exec(ctx context.Context, commandStr string, args []stri
return HandleVErrAndExitCode(verr, usage)
}
func GetDiffRoots(ctx context.Context, dEnv *env.DoltEnv, args []string) (from, to *doltdb.RootValue, leftover []string, err error) {
func getDiffRoots(ctx context.Context, dEnv *env.DoltEnv, args []string) (from, to *doltdb.RootValue, leftover []string, err error) {
headRoot, err := dEnv.StagedRoot(ctx)
if err != nil {
return nil, nil, nil, err
@@ -177,30 +177,7 @@ func maybeResolve(ctx context.Context, dEnv *env.DoltEnv, spec string) (*doltdb.
}
func validateQueryDiff(ctx context.Context, dEnv *env.DoltEnv, from *doltdb.RootValue, to *doltdb.RootValue, query string) errhand.VerboseError {
//sqlCtx, eng, err := makeSqlEngine(ctx, dEnv, to)
//if err != nil {
// return errhand.BuildDError("Cannot diff query, query is not ordered. Error describing query plan").AddCause(err).Build()
//}
//
//query = fmt.Sprintf("describe %s", query)
//_, iter, err := processQuery(sqlCtx, query, eng)
//if err != nil {
// return errhand.BuildDError("Cannot diff query, query is not ordered. Error describing query plan").AddCause(err).Build()
//}
//
//var qp strings.Builder
//for {
// r, err := iter.Next()
// if err == io.EOF {
// break
// } else if err != nil {
// return errhand.BuildDError("Cannot diff query, query is not ordered. Error describing query plan").AddCause(err).Build()
// }
// sv, _ := typeinfo.StringDefaultType.ConvertValueToNomsValue(r[0])
// qp.WriteString(fmt.Sprintf("%s\n", string(sv.(types.String))))
//}
//
//return errhand.BuildDError("Cannot diff query, query is not ordered. Add ORDER BY statement.\nquery plan:\n%s", qp.String()).Build()
return nil
}

View File

@@ -19,6 +19,7 @@ import (
"errors"
"fmt"
"io"
"strings"
sqle "github.com/liquidata-inc/go-mysql-server"
"github.com/liquidata-inc/go-mysql-server/sql"
@@ -49,7 +50,7 @@ func MakeQueryDiffer(ctx context.Context, dEnv *env.DoltEnv, fromRoot, toRoot *d
return nil, err
}
from, to, err := hackThatPlan(fromCtx, toCtx, fromEng, toEng, query)
from, to, err := modifyQueryPlans(fromCtx, toCtx, fromEng, toEng, query)
if err != nil {
return nil, err
}
@@ -125,8 +126,7 @@ type NodeDiffer interface {
ToNode() sql.Node
}
// todo: consult Engine.Query() for logic re: perms, catalog
func hackThatPlan(fromCtx *sql.Context, toCtx *sql.Context, fromEng *sqle.Engine, toEng *sqle.Engine, query string) (fromPlan, toPlan sql.Node, err error) {
func modifyQueryPlans(fromCtx *sql.Context, toCtx *sql.Context, fromEng *sqle.Engine, toEng *sqle.Engine, query string) (fromPlan, toPlan sql.Node, err error) {
parsed, err := parse.Parse(fromCtx, query)
if err != nil {
return nil, nil, err
@@ -134,14 +134,23 @@ func hackThatPlan(fromCtx *sql.Context, toCtx *sql.Context, fromEng *sqle.Engine
fromPlan, err = fromEng.Analyzer.Analyze(fromCtx, parsed)
if err != nil {
return nil, nil, err
return nil, nil, fmt.Errorf("error executing query on from root: %s", err.Error())
}
toPlan, err = toEng.Analyzer.Analyze(toCtx, parsed)
err = recursiveValidateQueryPlan(fromPlan)
if err != nil {
return nil, nil, err
return nil, nil, errWithQueryPlan(fromCtx, fromEng, query, err)
}
fromPlan, toPlan, err = recurseModifyPlans(fromCtx, toCtx, fromPlan, toPlan)
toPlan, err = toEng.Analyzer.Analyze(toCtx, parsed)
if err != nil {
return nil, nil, fmt.Errorf("error executing query on to root: %s", err.Error())
}
err = recursiveValidateQueryPlan(toPlan)
if err != nil {
return nil, nil, errWithQueryPlan(toCtx, toEng, query, err)
}
fromPlan, toPlan, err = recursiveModifyQueryPlans(fromCtx, toCtx, fromPlan, toPlan)
if err != nil {
return nil, nil, err
}
@@ -149,7 +158,20 @@ func hackThatPlan(fromCtx *sql.Context, toCtx *sql.Context, fromEng *sqle.Engine
return fromPlan, toPlan, nil
}
func recurseModifyPlans(fromCtx, toCtx *sql.Context, from, to sql.Node) (modFrom, modTo sql.Node, err error) {
func recursiveValidateQueryPlan(p sql.Node) error {
switch p.(type) {
case *plan.Sort:
return nil
default:
cc := p.Children()
if cc == nil {
return fmt.Errorf("query plan does not contain a sort node")
}
return recursiveValidateQueryPlan(cc[0])
}
}
func recursiveModifyQueryPlans(fromCtx, toCtx *sql.Context, from, to sql.Node) (modFrom, modTo sql.Node, err error) {
switch from.(type) {
case *plan.Sort:
nd, err := newSortNodeDiffer(fromCtx, toCtx, from.(*plan.Sort), to.(*plan.Sort))
@@ -161,9 +183,9 @@ func recurseModifyPlans(fromCtx, toCtx *sql.Context, from, to sql.Node) (modFrom
fc := from.Children()
tc := to.Children()
if fc == nil || tc == nil {
return nil, nil, fmt.Errorf("reached bottom of query plan")
panic("query plan does not contain a sort node")
}
fc[0], tc[0], err = recurseModifyPlans(fromCtx, toCtx, fc[0], tc[0])
fc[0], tc[0], err = recursiveModifyQueryPlans(fromCtx, toCtx, fc[0], tc[0])
if err != nil {
return nil, nil, err
}
@@ -212,3 +234,24 @@ func makeSqlEngine(ctx context.Context, dEnv *env.DoltEnv, root *doltdb.RootValu
return sqlCtx, engine, nil
}
func errWithQueryPlan(ctx *sql.Context, eng *sqle.Engine, query string, cause error) error {
_, iter, err := eng.Query(ctx, fmt.Sprintf("describe %s", query))
if err != nil {
return fmt.Errorf("cannot diff query. Error describing query plan: %s\n", err.Error())
}
var qp strings.Builder
qp.WriteString("query plan:\n")
for {
r, err := iter.Next()
if err == io.EOF {
break
} else if err != nil {
return fmt.Errorf("cannot diff query. Error describing query plan: %s\n", err.Error())
}
qp.WriteString(fmt.Sprintf("\t%s\n", r[0].(string)))
}
return fmt.Errorf("cannot diff query: %s\n%s", cause.Error(), qp.String())
}

View File

@@ -52,6 +52,7 @@ var setupCommon = []testCommand{
{commands.SqlCmd{}, []string{"-q", "create table quiz (pk int not null primary key, c0 int)"}},
{commands.SqlCmd{}, []string{"-q", "insert into quiz values (0,10), (1,11), (2,22), (3,33)"}},
{commands.AddCmd{}, []string{"."}},
{commands.CommitCmd{}, []string{"-m", "setup common"}},
}
var queryDifferTests = []queryDifferTest{
@@ -133,7 +134,7 @@ func testQueryDiffer(t *testing.T, test queryDifferTest) {
assert.Equal(t, 0, exitCode)
}
fromRoot, err := dEnv.StagedRoot(ctx)
fromRoot, err := dEnv.HeadRoot(ctx)
require.NoError(t, err)
toRoot, err := dEnv.WorkingRoot(ctx)
require.NoError(t, err)