Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion enginetest/enginetests.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func TestQueries(t *testing.T, harness Harness) {
if IsServerEngine(e) && tt.SkipServerEngine {
t.Skip("skipping for server engine")
}
TestQueryWithContext(t, ctx, e, harness, tt.Query, tt.Expected, tt.ExpectedColumns, nil, nil)
TestQueryWithEngine(t, harness, e, tt)
})
}

Expand Down
96 changes: 94 additions & 2 deletions enginetest/evaluation.go
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,27 @@ func TestQueryWithEngine(t *testing.T, harness Harness, e QueryEngine, tt querie
}

ctx := NewContext(harness)
TestQueryWithContext(t, ctx, e, harness, tt.Query, tt.Expected, tt.ExpectedColumns, tt.Bindings, nil)

if tt.ExpectedErr != nil {
AssertErr(t, e, harness, tt.Query, tt.Bindings, tt.ExpectedErr)
} else if tt.ExpectedErrStr != "" {
AssertErrWithCtx(t, e, harness, ctx, tt.Query, tt.Bindings, nil, tt.ExpectedErrStr)
} else if tt.ExpectedWarning != 0 {
if IsServerEngine(e) && tt.SkipServerEngine {
t.Skip()
}
AssertWarningAndTestQuery(t, e, ctx, harness,
tt.Query,
tt.Expected,
tt.ExpectedColumns,
tt.ExpectedWarning,
tt.ExpectedWarningsCount,
tt.ExpectedWarningMessageSubstring,
false,
)
} else {
TestQueryWithContext(t, ctx, e, harness, tt.Query, tt.Expected, tt.ExpectedColumns, tt.Bindings, nil)
}
})
}

Expand Down Expand Up @@ -539,7 +559,17 @@ func TestPreparedQueryWithEngine(t *testing.T, harness Harness, e QueryEngine, t
}
}
ctx := NewContext(harness)
TestPreparedQueryWithContext(t, ctx, e, harness, tt.Query, tt.Expected, tt.ExpectedColumns, nil, false)

if tt.ExpectedErr != nil {
AssertErr(t, e, harness, tt.Query, tt.Bindings, tt.ExpectedErr)
} else if tt.ExpectedErrStr != "" {
AssertErrWithCtx(t, e, harness, ctx, tt.Query, tt.Bindings, nil, tt.ExpectedErrStr)
} else if tt.ExpectedWarning != 0 {
AssertWarningAndTestPreparedQuery(t, e, ctx, harness, tt.Query, tt.Expected, tt.ExpectedColumns,
tt.ExpectedWarning, tt.ExpectedWarningsCount, tt.ExpectedWarningMessageSubstring, false)
} else {
TestPreparedQueryWithContext(t, ctx, e, harness, tt.Query, tt.Expected, tt.ExpectedColumns, nil, false)
}
})
}

Expand Down Expand Up @@ -1136,6 +1166,68 @@ func AssertWarningAndTestQuery(
validateEngine(t, ctx, harness, e)
}

// AssertWarningAndTestPreparedQuery is similar to AssertWarningAndTestQuery but works with prepared statements
func AssertWarningAndTestPreparedQuery(
t *testing.T,
e QueryEngine,
ctx *sql.Context,
harness Harness,
query string,
expected []sql.Row,
expectedCols []*sql.Column,
expectedCode int,
expectedWarningsCount int,
expectedWarningMessageSubstring string,
skipResultsCheck bool,
) {
req := require.New(t)
if ctx == nil {
ctx = NewContext(harness)
}
ctx.ClearWarnings()
ctx = ctx.WithQuery(query)

sch, iter, _, err := e.QueryWithBindings(ctx, query, nil, nil, nil)
req.NoError(err, "Unexpected error for query %s", query)

rows, err := sql.RowIterToRows(ctx, iter)
req.NoError(err, "Unexpected error for query %s", query)

if !IsServerEngine(e) {
// check warnings depend on context, which ServerEngine does not depend on
if expectedWarningsCount > 0 {
assert.Equal(t, expectedWarningsCount, len(ctx.Warnings()))
// Verify that if warnings are expected, we also configured a specific value check.
if expectedCode == 0 && len(expectedWarningMessageSubstring) == 0 {
req.Fail("Invalid test setup. Warning expected, but no value validation was configured.")
}
} else {
if expectedCode != 0 || len(expectedWarningMessageSubstring) != 0 {
req.Fail("Invalid test setup. No warnings expected, but value validation was configured")
}
assert.Zero(t, len(ctx.Warnings()), "Unexpected warnings")
}

if expectedCode > 0 {
// Not ideal. We are only supporting all warning codes being identical in a given test.
for _, warning := range ctx.Warnings() {
assert.Equal(t, expectedCode, warning.Code, "Unexpected warning code")
}
}
if len(expectedWarningMessageSubstring) > 0 {
// Not ideal. All messages must have the same substring for a given test.
for _, warning := range ctx.Warnings() {
assert.Contains(t, warning.Message, expectedWarningMessageSubstring, "Unexpected warning message")
}
}
}

if !skipResultsCheck {
CheckResults(ctx, t, harness, expected, expectedCols, sch, rows, query, e)
}
validateEngine(t, ctx, harness, e)
}

func assertSchemasEqualWithDefaults(t *testing.T, expected, actual sql.Schema) bool {
if len(expected) != len(actual) {
return assert.Equal(t, expected, actual)
Expand Down
210 changes: 210 additions & 0 deletions enginetest/queries/function_queries.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,224 @@
package queries

import (
"fmt"
"time"

"github.com/dolthub/vitess/go/mysql"

"github.com/dolthub/go-mysql-server/sql"
"github.com/dolthub/go-mysql-server/sql/expression/function"
"github.com/dolthub/go-mysql-server/sql/types"
)

// FunctionQueryTests contains queries that primarily test SQL function calls
var FunctionQueryTests = []QueryTest{
// Truncate function https://github.com/dolthub/dolt/issues/9916
{
Query: "SELECT TRUNCATE(1.223,1)",
Expected: []sql.Row{
{"1.2"},
},
},
{
Query: "SELECT TRUNCATE(1.999,1)",
Expected: []sql.Row{
{"1.9"},
},
},
{
Query: "SELECT TRUNCATE(1.999,0)",
Expected: []sql.Row{
{"1"},
},
},
{
Query: "SELECT TRUNCATE(-1.999,1)",
Expected: []sql.Row{
{"-1.9"},
},
},
{
Query: "SELECT TRUNCATE(122,-2)",
Expected: []sql.Row{
{100},
},
},
{
Query: "SELECT TRUNCATE(10.28*100,0)",
Expected: []sql.Row{
{"1028"},
},
},
{
Query: "SELECT TRUNCATE(NULL,1)",
Expected: []sql.Row{
{nil},
},
},
{
Query: "SELECT TRUNCATE(1.223,NULL)",
Expected: []sql.Row{
{nil},
},
},
{
Query: "SELECT TRUNCATE(0.5,0)",
Expected: []sql.Row{
{"0"},
},
},
{
Query: "SELECT TRUNCATE(-0.5,0)",
Expected: []sql.Row{
{"0"},
},
},
{
Query: "SELECT TRUNCATE(1.223,100)",
Expected: []sql.Row{
{"1.223"},
},
},
{
Query: "SELECT TRUNCATE(1.223,-100)",
Expected: []sql.Row{
{"0"},
},
},
{
Query: "SELECT TRUNCATE('abc',1)",
Expected: []sql.Row{
{0.0},
},
},
{
Query: "SELECT TRUNCATE(1.223,'xyz')",
Expected: []sql.Row{
{"1"},
},
},
{
Query: "SELECT TRUNCATE(1.223,1.5)",
Expected: []sql.Row{
{"1.22"},
},
},
{
Query: "SELECT TRUNCATE(1.223,1.7)",
Expected: []sql.Row{
{"1.22"},
},
},
{
Query: "SELECT TRUNCATE(1.223,0.1)",
Expected: []sql.Row{
{"1"},
},
},
{
Query: "SELECT TRUNCATE(1.223,0.9)",
Expected: []sql.Row{
{"1.2"},
},
},
{
Query: "SELECT TRUNCATE(1.223,-0.5)",
Expected: []sql.Row{
{"0"},
},
},
{
Query: "SELECT TRUNCATE(1.223,-0.9)",
Expected: []sql.Row{
{"0"},
},
},
{
Dialect: "mysql",
Query: "SELECT TRUNCATE('123abc',1)",
Expected: []sql.Row{
{123.0},
},
ExpectedWarning: mysql.ERTruncatedWrongValue,
ExpectedWarningsCount: 1,
ExpectedWarningMessageSubstring: fmt.Sprintf(sql.ErrTruncatedIncorrect.Message, types.Float64.String(), "123abc"),
},
{
Dialect: "mysql",
Query: "SELECT TRUNCATE('1.5abc',1)",
Expected: []sql.Row{
{1.5},
},
ExpectedWarning: mysql.ERTruncatedWrongValue,
ExpectedWarningsCount: 1,
ExpectedWarningMessageSubstring: fmt.Sprintf(sql.ErrTruncatedIncorrect.Message, types.Float64.String(), "1.5abc"),
},
{
Dialect: "mysql",
Query: "SELECT TRUNCATE('999xyz',2)",
Expected: []sql.Row{
{999.0},
},
ExpectedWarning: mysql.ERTruncatedWrongValue,
ExpectedWarningsCount: 1,
ExpectedWarningMessageSubstring: fmt.Sprintf(sql.ErrTruncatedIncorrect.Message, types.Float64.String(), "999xyz"),
},
{
Dialect: "mysql",
Query: "SELECT TRUNCATE(1.223,'1.5abc')",
Expected: []sql.Row{
{"1.2"},
},
ExpectedWarning: mysql.ERTruncatedWrongValue,
ExpectedWarningsCount: 2, // Both input and precision conversions generate warnings
ExpectedWarningMessageSubstring: fmt.Sprintf(sql.ErrTruncatedIncorrect.Message, types.Int32.String(), "1.5abc"),
},
{
Dialect: "mysql",
Query: "SELECT TRUNCATE(1.223,'0.5')",
Expected: []sql.Row{
{"1"},
},
ExpectedWarning: mysql.ERTruncatedWrongValue,
ExpectedWarningsCount: 2, // Both input and precision conversions generate warnings
ExpectedWarningMessageSubstring: fmt.Sprintf(sql.ErrTruncatedIncorrect.Message, types.Int32.String(), "0.5"),
},
{
Dialect: "mysql",
Query: "SELECT TRUNCATE(1.223,'2.7')",
Expected: []sql.Row{
{"1.22"},
},
ExpectedWarning: mysql.ERTruncatedWrongValue,
ExpectedWarningsCount: 2, // Both input and precision conversions generate warnings
ExpectedWarningMessageSubstring: fmt.Sprintf(sql.ErrTruncatedIncorrect.Message, types.Int32.String(), "2.7"),
},
{
Dialect: "mysql",
Query: "SELECT TRUNCATE(1.223,'invalid_precision')",
Expected: []sql.Row{
{"1"},
},
ExpectedWarning: mysql.ERTruncatedWrongValue,
ExpectedWarningsCount: 2, // Both input and precision conversions generate warnings
ExpectedWarningMessageSubstring: fmt.Sprintf(sql.ErrTruncatedIncorrect.Message, types.Int32.String(), "invalid_precision"),
},
{
Query: "SELECT TRUNCATE()",
ExpectedErr: sql.ErrInvalidArgumentNumber,
ExpectedErrStr: fmt.Sprintf(sql.ErrInvalidArgumentNumber.Message, function.TruncateFunctionName, 2, 0),
},
{
Query: "SELECT TRUNCATE(1)",
ExpectedErr: sql.ErrInvalidArgumentNumber,
ExpectedErrStr: fmt.Sprintf(sql.ErrInvalidArgumentNumber.Message, function.TruncateFunctionName, 2, 1),
},
{
Query: "SELECT TRUNCATE(1,2,3)",
ExpectedErr: sql.ErrInvalidArgumentNumber,
ExpectedErrStr: fmt.Sprintf(sql.ErrInvalidArgumentNumber.Message, function.TruncateFunctionName, 2, 3),
},
// String Functions
{
Query: `SELECT CONCAT("a", "b", "c")`,
Expand Down
15 changes: 14 additions & 1 deletion enginetest/queries/queries.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,20 @@ type QueryTest struct {
// Query is the query string to execute
Query string
// Expected is the expected result of the query
Expected []sql.Row
Expected []sql.Row
ExpectedErr *errors.Kind
// ExpectedErrStr should be set for tests that expect a specific error string this is not linked to a custom error.
// In most cases, errors should be linked to a custom error, however there are exceptions where this is not possible,
// such as the use of the SIGNAL statement.
ExpectedErrStr string
// ExpectedWarning contains the expected warning code when a query generates warnings but not errors.
ExpectedWarning int
// ExpectedWarningsCount is used to test the expected number of warnings generated by a query.
// The ExpectedWarning field must be set for warning counts to be checked.
ExpectedWarningsCount int
// ExpectedWarningMessageSubstring is used to test the contents of warning messages generated by a
// query. The ExpectedWarning field must be set for warning messages to be checked.
ExpectedWarningMessageSubstring string
// ExpectedColumns is the set of expected column names for the query results, if specified.
// Only the Name and Type matter of the columns are checked.
ExpectedColumns sql.Schema
Expand Down
Loading