diff --git a/enginetest/enginetests.go b/enginetest/enginetests.go index 0ac30ef706..18f5ab129c 100644 --- a/enginetest/enginetests.go +++ b/enginetest/enginetests.go @@ -17,6 +17,7 @@ package enginetest import ( "context" "fmt" + "io" "net" "strings" "testing" @@ -5392,6 +5393,115 @@ func TestPrepared(t *testing.T, harness Harness) { } } +func TestTypesOverWire(t *testing.T, h Harness, sessionBuilder server.SessionBuilder) { + harness, ok := h.(ClientHarness) + if !ok { + t.Skip("Cannot run TestTypesOverWire as the harness must implement ClientHarness") + } + harness.Setup(setup.MydbData) + + port := getEmptyPort(t) + for _, script := range queries.TypeWireTests { + t.Run(script.Name, func(t *testing.T) { + ctx := NewContextWithClient(harness, sql.Client{ + User: "root", + Address: "localhost", + }) + serverConfig := server.Config{ + Protocol: "tcp", + Address: fmt.Sprintf("localhost:%d", port), + MaxConnections: 1000, + } + + engine := mustNewEngine(t, harness) + defer engine.Close() + engine.Analyzer.Catalog.MySQLDb.AddRootAccount() + for _, statement := range script.SetUpScript { + if sh, ok := harness.(SkippingHarness); ok { + if sh.SkipQueryTest(statement) { + t.Skip() + } + } + RunQueryWithContext(t, engine, harness, ctx, statement) + } + + s, err := server.NewServer(serverConfig, engine, sessionBuilder, nil) + require.NoError(t, err) + go func() { + err := s.Start() + require.NoError(t, err) + }() + defer func() { + require.NoError(t, s.Close()) + }() + + conn, err := dbr.Open("mysql", fmt.Sprintf("root:@tcp(localhost:%d)/", port), nil) + require.NoError(t, err) + _, err = conn.Exec("USE mydb;") + require.NoError(t, err) + for queryIdx, query := range script.Queries { + r, err := conn.Query(query) + if assert.NoError(t, err) { + sch, engineIter, err := engine.Query(ctx, query) + require.NoError(t, err) + expectedRowSet := script.Results[queryIdx] + expectedRowIdx := 0 + var engineRow sql.Row + for engineRow, err = engineIter.Next(ctx); err == nil; engineRow, err = engineIter.Next(ctx) { + if !assert.True(t, r.Next()) { + break + } + expectedRow := expectedRowSet[expectedRowIdx] + expectedRowIdx++ + connRow := make([]*string, len(engineRow)) + interfaceRow := make([]any, len(connRow)) + for i := range connRow { + interfaceRow[i] = &connRow[i] + } + err = r.Scan(interfaceRow...) + if !assert.NoError(t, err) { + break + } + expectedEngineRow := make([]*string, len(engineRow)) + for i := range engineRow { + sqlVal, err := sch[i].Type.SQL(nil, engineRow[i]) + if !assert.NoError(t, err) { + break + } + if !sqlVal.IsNull() { + str := sqlVal.ToString() + expectedEngineRow[i] = &str + } + } + + for i := range expectedEngineRow { + expectedVal := expectedEngineRow[i] + connVal := connRow[i] + if !assert.Equal(t, expectedVal == nil, connVal == nil) { + continue + } + if expectedVal != nil { + assert.Equal(t, *expectedVal, *connVal) + if script.Name == "JSON" { + // Different integrators may return their JSON strings with different spacing, so we + // special case the test since the spacing is not significant + *connVal = strings.Replace(*connVal, `, `, `,`, -1) + *connVal = strings.Replace(*connVal, `: "`, `:"`, -1) + } + assert.Equal(t, expectedRow[i], *connVal) + } + } + } + assert.True(t, err == io.EOF) + assert.False(t, r.Next()) + require.NoError(t, r.Close()) + } + } + require.NoError(t, conn.Close()) + }) + } +} + type memoryPersister struct { users []*mysql_db.User roles []*mysql_db.RoleEdge diff --git a/enginetest/memory_engine_test.go b/enginetest/memory_engine_test.go index e5d0bdbef9..7d4d6f4a37 100644 --- a/enginetest/memory_engine_test.go +++ b/enginetest/memory_engine_test.go @@ -19,11 +19,11 @@ import ( "log" "testing" - "github.com/dolthub/go-mysql-server/enginetest/scriptgen/setup" - "github.com/dolthub/go-mysql-server/enginetest" "github.com/dolthub/go-mysql-server/enginetest/queries" + "github.com/dolthub/go-mysql-server/enginetest/scriptgen/setup" "github.com/dolthub/go-mysql-server/memory" + "github.com/dolthub/go-mysql-server/server" "github.com/dolthub/go-mysql-server/sql" "github.com/dolthub/go-mysql-server/sql/analyzer" "github.com/dolthub/go-mysql-server/sql/expression" @@ -751,6 +751,10 @@ func TestKeylessUniqueIndex(t *testing.T) { enginetest.TestKeylessUniqueIndex(t, enginetest.NewDefaultMemoryHarness()) } +func TestTypesOverWire(t *testing.T) { + enginetest.TestTypesOverWire(t, enginetest.NewDefaultMemoryHarness(), server.DefaultSessionBuilder) +} + func mergableIndexDriver(dbs []sql.Database) sql.IndexDriver { return memory.NewIndexDriver("mydb", map[string][]sql.DriverIndex{ "mytable": { diff --git a/enginetest/mysqlshim/connection.go b/enginetest/mysqlshim/connection.go index adf7dd88fa..e987b18b69 100644 --- a/enginetest/mysqlshim/connection.go +++ b/enginetest/mysqlshim/connection.go @@ -40,6 +40,10 @@ func NewMySQLShim(user string, password string, host string, port int) (*MySQLSh if err != nil { return nil, err } + err = conn.Ping() + if err != nil { + return nil, err + } return &MySQLShim{conn, make(map[string]string)}, nil } diff --git a/enginetest/mysqlshim/iter.go b/enginetest/mysqlshim/iter.go index a074a19f5e..0fc7c4664c 100644 --- a/enginetest/mysqlshim/iter.go +++ b/enginetest/mysqlshim/iter.go @@ -45,12 +45,12 @@ func newMySQLIter(rows *dsql.Rows) mysqlIter { scanType = reflect.TypeOf("") case reflect.TypeOf(dsql.NullBool{}): scanType = reflect.TypeOf(true) - //case reflect.TypeOf(dsql.NullByte{}): // Not supported in go 1.15, need to upgrade to 1.17 - // scanType = reflect.TypeOf(byte(0)) + case reflect.TypeOf(dsql.NullByte{}): + scanType = reflect.TypeOf(byte(0)) case reflect.TypeOf(dsql.NullFloat64{}): scanType = reflect.TypeOf(float64(0)) - //case reflect.TypeOf(dsql.NullInt16{}): // Not supported in go 1.15, need to upgrade to 1.17 - // scanType = reflect.TypeOf(int16(0)) + case reflect.TypeOf(dsql.NullInt16{}): + scanType = reflect.TypeOf(int16(0)) case reflect.TypeOf(dsql.NullInt32{}): scanType = reflect.TypeOf(int32(0)) case reflect.TypeOf(dsql.NullInt64{}): diff --git a/enginetest/mysqlshim/mysql_harness.go b/enginetest/mysqlshim/mysql_harness.go index 96bc761fdd..f3bc954e11 100644 --- a/enginetest/mysqlshim/mysql_harness.go +++ b/enginetest/mysqlshim/mysql_harness.go @@ -15,6 +15,7 @@ package mysqlshim import ( + "context" "fmt" "strings" "testing" @@ -30,16 +31,36 @@ import ( type MySQLHarness struct { shim *MySQLShim skippedQueries map[string]struct{} + setupData []setup.SetupScript + session sql.Session } -func (m *MySQLHarness) Setup(source ...[]setup.SetupScript) { - //TODO implement me - panic("implement me") +//TODO: refactor to remove enginetest cycle +var _ enginetest.Harness = (*MySQLHarness)(nil) +var _ enginetest.IndexHarness = (*MySQLHarness)(nil) +var _ enginetest.ForeignKeyHarness = (*MySQLHarness)(nil) +var _ enginetest.KeylessTableHarness = (*MySQLHarness)(nil) +var _ enginetest.ClientHarness = (*MySQLHarness)(nil) +var _ enginetest.SkippingHarness = (*MySQLHarness)(nil) + +func (m *MySQLHarness) Setup(setupData ...[]setup.SetupScript) { + m.setupData = nil + for i := range setupData { + m.setupData = append(m.setupData, setupData[i]...) + } + return } func (m *MySQLHarness) NewEngine(t *testing.T) (*sqle.Engine, error) { - //TODO implement me - panic("implement me") + return enginetest.NewEngineWithProviderSetup(t, m, m.shim, m.setupData) +} + +func (m *MySQLHarness) NewContextWithClient(client sql.Client) *sql.Context { + session := sql.NewBaseSessionWithClientServer("address", client, 1) + return sql.NewContext( + context.Background(), + sql.WithSession(session), + ) } func (m *MySQLHarness) Cleanup() error { @@ -58,19 +79,13 @@ type MySQLTable struct { tableName string } -var _ enginetest.Harness = (*MySQLHarness)(nil) -var _ enginetest.SkippingHarness = (*MySQLHarness)(nil) -var _ enginetest.IndexHarness = (*MySQLHarness)(nil) -var _ enginetest.ForeignKeyHarness = (*MySQLHarness)(nil) -var _ enginetest.KeylessTableHarness = (*MySQLHarness)(nil) - // NewMySQLHarness returns a new MySQLHarness. func NewMySQLHarness(user string, password string, host string, port int) (*MySQLHarness, error) { shim, err := NewMySQLShim(user, password, host, port) if err != nil { return nil, err } - return &MySQLHarness{shim, make(map[string]struct{})}, nil + return &MySQLHarness{shim, make(map[string]struct{}), nil, nil}, nil } // Parallelism implements the interface Harness. @@ -126,7 +141,14 @@ func (m *MySQLHarness) NewTable(db sql.Database, name string, schema sql.Primary // NewContext implements the interface Harness. func (m *MySQLHarness) NewContext() *sql.Context { - return sql.NewEmptyContext() + if m.session == nil { + m.session = enginetest.NewBaseSession() + } + + return sql.NewContext( + context.Background(), + sql.WithSession(m.session), + ) } // SkipQueryTest implements the interface SkippingHarness. diff --git a/enginetest/queries/type_wire_queries.go b/enginetest/queries/type_wire_queries.go new file mode 100644 index 0000000000..32aee3de28 --- /dev/null +++ b/enginetest/queries/type_wire_queries.go @@ -0,0 +1,727 @@ +// Copyright 2022 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 queries + +import "github.com/dolthub/go-mysql-server/sql" + +// TypeWireTest is used to ensure that types are properly represented over the wire (vs being directly returned from the +// engine). +type TypeWireTest struct { + Name string + SetUpScript []string + Queries []string + Results [][]sql.Row +} + +// TypeWireTests are used to ensure that types are properly represented over the wire (vs being directly returned from +// the engine). +var TypeWireTests = []TypeWireTest{ + { + Name: "TINYINT", + SetUpScript: []string{ + `CREATE TABLE test (pk TINYINT PRIMARY KEY, v1 TINYINT);`, + `INSERT INTO test VALUES (-75, "-25"), (0, 0), (107.2, 0025), (120, -120);`, + `UPDATE test SET v1 = v1 - 1 WHERE pk < 0;`, + `DELETE FROM test WHERE pk > "119";`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT v1, pk FROM test ORDER BY pk;`, + `SELECT v1*2, pk+1 FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"-75", "-26"}, {"0", "0"}, {"107", "25"}}, + {{"-26", "-75"}, {"0", "0"}, {"25", "107"}}, + {{"-52", "-74"}, {"0", "1"}, {"50", "108"}}, + }, + }, + { + Name: "SMALLINT", + SetUpScript: []string{ + `CREATE TABLE test (pk SMALLINT PRIMARY KEY, v1 SMALLINT);`, + `INSERT INTO test VALUES (-75, "-2531"), (0, 0), (2547.2, 03325), (9999, 9999);`, + `UPDATE test SET v1 = v1 - 1 WHERE pk < 0;`, + `DELETE FROM test WHERE pk >= "9999";`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT v1, pk FROM test ORDER BY pk;`, + `SELECT v1*2, pk+1 FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"-75", "-2532"}, {"0", "0"}, {"2547", "3325"}}, + {{"-2532", "-75"}, {"0", "0"}, {"3325", "2547"}}, + {{"-5064", "-74"}, {"0", "1"}, {"6650", "2548"}}, + }, + }, + { + Name: "MEDIUMINT", + SetUpScript: []string{ + `CREATE TABLE test (pk MEDIUMINT PRIMARY KEY, v1 MEDIUMINT);`, + `INSERT INTO test VALUES (0, 0), (2547.2, 03325), (999999, 999999);`, + `UPDATE test SET v1 = v1 - 1 WHERE pk < 0;`, + `DELETE FROM test WHERE pk > "99999";`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT v1, pk FROM test ORDER BY pk;`, + `SELECT v1*2, pk+1 FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"0", "0"}, {"2547", "3325"}}, + {{"0", "0"}, {"3325", "2547"}}, + {{"0", "1"}, {"6650", "2548"}}, + }, + }, + { + Name: "INT", + SetUpScript: []string{ + `CREATE TABLE test (pk INT PRIMARY KEY, v1 INT);`, + `INSERT INTO test VALUES (-75, "-2531"), (0, 0), (2547.2, 03325), (999999, 999999);`, + `UPDATE test SET v1 = v1 - 1 WHERE pk < 0;`, + `DELETE FROM test WHERE pk > "99999";`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT v1, pk FROM test ORDER BY pk;`, + `SELECT v1*2, pk+1 FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"-75", "-2532"}, {"0", "0"}, {"2547", "3325"}}, + {{"-2532", "-75"}, {"0", "0"}, {"3325", "2547"}}, + {{"-5064", "-74"}, {"0", "1"}, {"6650", "2548"}}, + }, + }, + { + Name: "BIGINT", + SetUpScript: []string{ + `CREATE TABLE test (pk BIGINT PRIMARY KEY, v1 BIGINT);`, + `INSERT INTO test VALUES (-75, "-2531"), (0, 0), (2547.2, 03325), (999999, 999999);`, + `UPDATE test SET v1 = v1 - 1 WHERE pk < 0;`, + `DELETE FROM test WHERE pk > "99999";`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT v1, pk FROM test ORDER BY pk;`, + `SELECT v1*2, pk+1 FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"-75", "-2532"}, {"0", "0"}, {"2547", "3325"}}, + {{"-2532", "-75"}, {"0", "0"}, {"3325", "2547"}}, + {{"-5064", "-74"}, {"0", "1"}, {"6650", "2548"}}, + }, + }, + { + Name: "TINYINT UNSIGNED", + SetUpScript: []string{ + `CREATE TABLE test (pk TINYINT UNSIGNED PRIMARY KEY, v1 TINYINT UNSIGNED);`, + `INSERT INTO test VALUES (0, 0), (25, "26"), (32.1, 0126), (255, 255);`, + `UPDATE test SET v1 = v1 - 1 WHERE pk > 0 AND pk < 30;`, + `DELETE FROM test WHERE pk >= "255";`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT v1, pk FROM test ORDER BY pk;`, + `SELECT v1*2, pk+1 FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"0", "0"}, {"25", "25"}, {"32", "126"}}, + {{"0", "0"}, {"25", "25"}, {"126", "32"}}, + {{"0", "1"}, {"50", "26"}, {"252", "33"}}, + }, + }, + { + Name: "SMALLINT UNSIGNED", + SetUpScript: []string{ + `CREATE TABLE test (pk SMALLINT UNSIGNED PRIMARY KEY, v1 SMALLINT UNSIGNED);`, + `INSERT INTO test VALUES (0, 0), (25, "2531"), (2547.2, 03325), (9999, 9999);`, + `UPDATE test SET v1 = v1 - 1 WHERE pk > 0 AND pk < 100;`, + `DELETE FROM test WHERE pk >= "9999";`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT v1, pk FROM test ORDER BY pk;`, + `SELECT v1*2, pk+1 FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"0", "0"}, {"25", "2530"}, {"2547", "3325"}}, + {{"0", "0"}, {"2530", "25"}, {"3325", "2547"}}, + {{"0", "1"}, {"5060", "26"}, {"6650", "2548"}}, + }, + }, + { + Name: "MEDIUMINT UNSIGNED", + SetUpScript: []string{ + `CREATE TABLE test (pk MEDIUMINT UNSIGNED PRIMARY KEY, v1 MEDIUMINT UNSIGNED);`, + `INSERT INTO test VALUES (75, "2531"), (0, 0), (2547.2, 03325), (999999, 999999);`, + `UPDATE test SET v1 = v1 + 1 WHERE pk < 100;`, + `DELETE FROM test WHERE pk > "99999";`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT v1, pk FROM test ORDER BY pk;`, + `SELECT v1*2, pk+1 FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"0", "1"}, {"75", "2532"}, {"2547", "3325"}}, + {{"1", "0"}, {"2532", "75"}, {"3325", "2547"}}, + {{"2", "1"}, {"5064", "76"}, {"6650", "2548"}}, + }, + }, + { + Name: "INT UNSIGNED", + SetUpScript: []string{ + `CREATE TABLE test (pk INT UNSIGNED PRIMARY KEY, v1 INT UNSIGNED);`, + `INSERT INTO test VALUES (75, "2531"), (0, 0), (2547.2, 03325), (999999, 999999);`, + `UPDATE test SET v1 = v1 + 1 WHERE pk < 100;`, + `DELETE FROM test WHERE pk > "99999";`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT v1, pk FROM test ORDER BY pk;`, + `SELECT v1*2, pk+1 FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"0", "1"}, {"75", "2532"}, {"2547", "3325"}}, + {{"1", "0"}, {"2532", "75"}, {"3325", "2547"}}, + {{"2", "1"}, {"5064", "76"}, {"6650", "2548"}}, + }, + }, + { + Name: "BIGINT UNSIGNED", + SetUpScript: []string{ + `CREATE TABLE test (pk BIGINT UNSIGNED PRIMARY KEY, v1 BIGINT UNSIGNED);`, + `INSERT INTO test VALUES (75, "2531"), (0, 0), (2547.2, 03325), (999999, 999999);`, + `UPDATE test SET v1 = v1 + 1 WHERE pk < 100;`, + `DELETE FROM test WHERE pk > "99999";`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT v1, pk FROM test ORDER BY pk;`, + `SELECT v1*2, pk+1 FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"0", "1"}, {"75", "2532"}, {"2547", "3325"}}, + {{"1", "0"}, {"2532", "75"}, {"3325", "2547"}}, + {{"2", "1"}, {"5064", "76"}, {"6650", "2548"}}, + }, + }, + { + Name: "FLOAT", + SetUpScript: []string{ + `CREATE TABLE test (pk FLOAT PRIMARY KEY, v1 FLOAT);`, + `INSERT INTO test VALUES (-75.11, "-2531"), (0, 0), ("2547.2", 03325), (999999, 999999);`, + `UPDATE test SET v1 = v1 - 1 WHERE pk < 0;`, + `DELETE FROM test WHERE pk > "99999";`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT v1, pk FROM test ORDER BY pk;`, + `SELECT v1*2, pk+1 FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"-75.11", "-2532"}, {"0", "0"}, {"2547.2", "3325"}}, + {{"-2532", "-75.11"}, {"0", "0"}, {"3325", "2547.2"}}, + {{"-5064", "-74.11000061035156"}, {"0", "1"}, {"6650", "2548.199951171875"}}, + }, + }, + { + Name: "DOUBLE", + SetUpScript: []string{ + `CREATE TABLE test (pk DOUBLE PRIMARY KEY, v1 DOUBLE);`, + `INSERT INTO test VALUES (-75.11, "-2531"), (0, 0), ("2547.2", 03325), (999999, 999999);`, + `UPDATE test SET v1 = v1 - 1 WHERE pk < 0;`, + `DELETE FROM test WHERE pk > "99999";`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT v1, pk FROM test ORDER BY pk;`, + `SELECT v1*2, pk+1 FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"-75.11", "-2532"}, {"0", "0"}, {"2547.2", "3325"}}, + {{"-2532", "-75.11"}, {"0", "0"}, {"3325", "2547.2"}}, + {{"-5064", "-74.11"}, {"0", "1"}, {"6650", "2548.2"}}, + }, + }, + { + Name: "DECIMAL", + SetUpScript: []string{ + `CREATE TABLE test (pk DECIMAL(5,0) PRIMARY KEY, v1 DECIMAL(25,5));`, + `INSERT INTO test VALUES (-75, "-2531.356"), (0, 0), (2547.2, 03325), (99999, 999999);`, + `UPDATE test SET v1 = v1 - 1 WHERE pk < 0;`, + `DELETE FROM test WHERE pk >= "99999";`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT v1, pk FROM test ORDER BY pk;`, + `SELECT v1*2, pk+1 FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"-75", "-2532.35600"}, {"0", "0.00000"}, {"2547", "3325.00000"}}, + {{"-2532.35600", "-75"}, {"0.00000", "0"}, {"3325.00000", "2547"}}, + {{"-5064.712", "-74"}, {"0", "1"}, {"6650", "2548"}}, + }, + }, + { + Name: "BIT", + SetUpScript: []string{ + `CREATE TABLE test (pk BIT(55) PRIMARY KEY, v1 BIT(1), v2 BIT(24));`, + `INSERT INTO test VALUES (75, 0, "21"), (0, 0, 0), (2547.2, 1, 03325), (999999, 1, 999999);`, + `UPDATE test SET v2 = v2 - 1 WHERE pk > 0 AND pk < 100;`, + `DELETE FROM test WHERE pk > 99999;`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT v2, v1, pk FROM test ORDER BY pk;`, + `SELECT v1*1, pk/10, v2+1 FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"\x00\x00\x00\x00\x00\x00\x00", "\x00", "\x00\x00\x00"}, {"\x00\x00\x00\x00\x00\x00K", "\x00", "\x0020"}, {"\x00\x00\x00\x00\x00\t\xf3", "", "\x00 \xfd"}}, + {{"\x00\x00\x00", "\x00", "\x00\x00\x00\x00\x00\x00\x00"}, {"\x0020", "\x00", "\x00\x00\x00\x00\x00\x00K"}, {"\x00 \xfd", "", "\x00\x00\x00\x00\x00\t\xf3"}}, + {{"0", "0", "1"}, {"0", "7.5", "12849"}, {"1", "254.7", "3326"}}, + }, + }, + { + Name: "YEAR", + SetUpScript: []string{ + `CREATE TABLE test (pk YEAR PRIMARY KEY, v1 YEAR);`, + `INSERT INTO test VALUES (1901, 1901), (1950, "1950"), (1979.2, 01986), (2122, 2122);`, + `UPDATE test SET v1 = v1 + 1 WHERE pk < 1975;`, + `DELETE FROM test WHERE pk > "2100";`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT v1, pk FROM test ORDER BY pk;`, + `SELECT v1+3, pk+2 FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"1901", "1902"}, {"1950", "1951"}, {"1979", "1986"}}, + {{"1902", "1901"}, {"1951", "1950"}, {"1986", "1979"}}, + {{"1905", "1903"}, {"1954", "1952"}, {"1989", "1981"}}, + }, + }, + { + Name: "TIMESTAMP", + SetUpScript: []string{ + `CREATE TABLE test (pk TIMESTAMP PRIMARY KEY, v1 TIMESTAMP);`, + `INSERT INTO test VALUES ("1980-04-12 12:02:11", "1986-08-02 17:04:22"), ("1999-11-28 13:06:33", "2022-01-14 15:08:44"), ("2020-05-06 18:10:55", "1975-09-15 11:12:16");`, + `UPDATE test SET v1 = "2000-01-01 00:00:00" WHERE pk < "1990-01-01 00:00:00";`, + `DELETE FROM test WHERE pk > "2015-01-01 00:00:00";`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT pk, v1 FROM test ORDER BY pk;`, + `SELECT v1, pk FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"1980-04-12 12:02:11", "2000-01-01 00:00:00"}, {"1999-11-28 13:06:33", "2022-01-14 15:08:44"}}, + {{"1980-04-12 12:02:11", "2000-01-01 00:00:00"}, {"1999-11-28 13:06:33", "2022-01-14 15:08:44"}}, + {{"2000-01-01 00:00:00", "1980-04-12 12:02:11"}, {"2022-01-14 15:08:44", "1999-11-28 13:06:33"}}, + }, + }, + { + Name: "DATETIME", + SetUpScript: []string{ + `CREATE TABLE test (pk DATETIME PRIMARY KEY, v1 DATETIME);`, + `INSERT INTO test VALUES ("1000-04-12 12:02:11", "1986-08-02 17:04:22"), ("1999-11-28 13:06:33", "2022-01-14 15:08:44"), ("5020-05-06 18:10:55", "1975-09-15 11:12:16");`, + `UPDATE test SET v1 = "2000-01-01 00:00:00" WHERE pk < "1990-01-01 00:00:00";`, + `DELETE FROM test WHERE pk > "5000-01-01 00:00:00";`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT pk, v1 FROM test ORDER BY pk;`, + `SELECT v1, pk FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"1000-04-12 12:02:11", "2000-01-01 00:00:00"}, {"1999-11-28 13:06:33", "2022-01-14 15:08:44"}}, + {{"1000-04-12 12:02:11", "2000-01-01 00:00:00"}, {"1999-11-28 13:06:33", "2022-01-14 15:08:44"}}, + {{"2000-01-01 00:00:00", "1000-04-12 12:02:11"}, {"2022-01-14 15:08:44", "1999-11-28 13:06:33"}}, + }, + }, + { + Name: "DATE", + SetUpScript: []string{ + `CREATE TABLE test (pk DATE PRIMARY KEY, v1 DATE);`, + `INSERT INTO test VALUES ("1000-04-12", "1986-08-02"), ("1999-11-28", "2022-01-14"), ("5020-05-06", "1975-09-15");`, + `UPDATE test SET v1 = "2000-01-01" WHERE pk < "1990-01-01";`, + `DELETE FROM test WHERE pk > "5000-01-01";`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT pk, v1 FROM test ORDER BY pk;`, + `SELECT v1, pk FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"1000-04-12", "2000-01-01"}, {"1999-11-28", "2022-01-14"}}, + {{"1000-04-12", "2000-01-01"}, {"1999-11-28", "2022-01-14"}}, + {{"2000-01-01", "1000-04-12"}, {"2022-01-14", "1999-11-28"}}, + }, + }, + { + Name: "TIME", + SetUpScript: []string{ + `CREATE TABLE test (pk TIME PRIMARY KEY, v1 TIME);`, + `INSERT INTO test VALUES ("-800:00:00", "-20:21:22"), ("00:00:00", "00:00:00"), ("10:26:57", "30:53:14"), ("700:23:51", "300:25:52");`, + `UPDATE test SET v1 = "-120:12:20" WHERE pk < "00:00:00";`, + `DELETE FROM test WHERE pk > "600:00:00";`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT pk, v1 FROM test ORDER BY pk;`, + `SELECT v1, pk FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"-800:00:00", "-120:12:20"}, {"00:00:00", "00:00:00"}, {"10:26:57", "30:53:14"}}, + {{"-800:00:00", "-120:12:20"}, {"00:00:00", "00:00:00"}, {"10:26:57", "30:53:14"}}, + {{"-120:12:20", "-800:00:00"}, {"00:00:00", "00:00:00"}, {"30:53:14", "10:26:57"}}, + }, + }, + { + Name: "CHAR", + SetUpScript: []string{ + `CREATE TABLE test (pk BIGINT PRIMARY KEY, v1 CHAR(5), v2 CHAR(10));`, + `INSERT INTO test VALUES (1, "abc", "def"), (2, "c-a", "123"), (3, "__2", 456), (4, "?hi?", "\\n");`, + `UPDATE test SET v1 = "a-c" WHERE pk = 2;`, + `DELETE FROM test WHERE pk = 4;`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT pk, v2, v1 FROM test ORDER BY pk;`, + `SELECT CONCAT(v1, "r"), pk, v2 FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"1", "abc", "def"}, {"2", "a-c", "123"}, {"3", "__2", "456"}}, + {{"1", "def", "abc"}, {"2", "123", "a-c"}, {"3", "456", "__2"}}, + {{"abcr", "1", "def"}, {"a-cr", "2", "123"}, {"__2r", "3", "456"}}, + }, + }, + { + Name: "VARCHAR", + SetUpScript: []string{ + `CREATE TABLE test (pk BIGINT PRIMARY KEY, v1 VARCHAR(5), v2 VARCHAR(10));`, + `INSERT INTO test VALUES (1, "abc", "def"), (2, "c-a", "123"), (3, "__2", 456), (4, "?hi?", "\\n");`, + `UPDATE test SET v1 = CONCAT(v1, "x") WHERE pk = 2;`, + `DELETE FROM test WHERE pk = 4;`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT pk, v2, v1 FROM test ORDER BY pk;`, + `SELECT CONCAT(v1, "r"), pk, v2 FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"1", "abc", "def"}, {"2", "c-ax", "123"}, {"3", "__2", "456"}}, + {{"1", "def", "abc"}, {"2", "123", "c-ax"}, {"3", "456", "__2"}}, + {{"abcr", "1", "def"}, {"c-axr", "2", "123"}, {"__2r", "3", "456"}}, + }, + }, + { + Name: "BINARY", + SetUpScript: []string{ + `CREATE TABLE test (pk BIGINT PRIMARY KEY, v1 BINARY(5), v2 BINARY(10));`, + `INSERT INTO test VALUES (1, "abc", "def"), (2, "c-a", "123"), (3, "__2", 456), (4, "?hi?", "\\n");`, + `UPDATE test SET v1 = "a-c" WHERE pk = 2;`, + `DELETE FROM test WHERE pk = 4;`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT pk, v2, v1 FROM test ORDER BY pk;`, + `SELECT CONCAT(v1, "r"), pk, v2 FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"1", "abc\x00\x00", "def\x00\x00\x00\x00\x00\x00\x00"}, {"2", "a-c\x00\x00", "123\x00\x00\x00\x00\x00\x00\x00"}, {"3", "__2\x00\x00", "456\x00\x00\x00\x00\x00\x00\x00"}}, + {{"1", "def\x00\x00\x00\x00\x00\x00\x00", "abc\x00\x00"}, {"2", "123\x00\x00\x00\x00\x00\x00\x00", "a-c\x00\x00"}, {"3", "456\x00\x00\x00\x00\x00\x00\x00", "__2\x00\x00"}}, + {{"abc\x00\x00r", "1", "def\x00\x00\x00\x00\x00\x00\x00"}, {"a-c\x00\x00r", "2", "123\x00\x00\x00\x00\x00\x00\x00"}, {"__2\x00\x00r", "3", "456\x00\x00\x00\x00\x00\x00\x00"}}, + }, + }, + { + Name: "VARBINARY", + SetUpScript: []string{ + `CREATE TABLE test (pk BIGINT PRIMARY KEY, v1 VARBINARY(5), v2 VARBINARY(10));`, + `INSERT INTO test VALUES (1, "abc", "def"), (2, "c-a", "123"), (3, "__2", 456), (4, "?hi?", "\\n");`, + `UPDATE test SET v1 = CONCAT(v1, "x") WHERE pk = 2;`, + `DELETE FROM test WHERE pk = 4;`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT pk, v2, v1 FROM test ORDER BY pk;`, + `SELECT CONCAT(v1, "r"), pk, v2 FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"1", "abc", "def"}, {"2", "c-ax", "123"}, {"3", "__2", "456"}}, + {{"1", "def", "abc"}, {"2", "123", "c-ax"}, {"3", "456", "__2"}}, + {{"abcr", "1", "def"}, {"c-axr", "2", "123"}, {"__2r", "3", "456"}}, + }, + }, + { + Name: "TINYTEXT", + SetUpScript: []string{ + `CREATE TABLE test (pk BIGINT PRIMARY KEY, v1 TINYTEXT, v2 TINYTEXT);`, + `INSERT INTO test VALUES (1, "abc", "def"), (2, "c-a", "123"), (3, "__2", 456), (4, "?hi?", "\\n");`, + `UPDATE test SET v1 = CONCAT(v1, "x") WHERE pk = 2;`, + `DELETE FROM test WHERE pk = 4;`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT pk, v2, v1 FROM test ORDER BY pk;`, + `SELECT CONCAT(v1, "r"), pk, v2 FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"1", "abc", "def"}, {"2", "c-ax", "123"}, {"3", "__2", "456"}}, + {{"1", "def", "abc"}, {"2", "123", "c-ax"}, {"3", "456", "__2"}}, + {{"abcr", "1", "def"}, {"c-axr", "2", "123"}, {"__2r", "3", "456"}}, + }, + }, + { + Name: "TEXT", + SetUpScript: []string{ + `CREATE TABLE test (pk BIGINT PRIMARY KEY, v1 TEXT, v2 TEXT);`, + `INSERT INTO test VALUES (1, "abc", "def"), (2, "c-a", "123"), (3, "__2", 456), (4, "?hi?", "\\n");`, + `UPDATE test SET v1 = CONCAT(v1, "x") WHERE pk = 2;`, + `DELETE FROM test WHERE pk = 4;`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT pk, v2, v1 FROM test ORDER BY pk;`, + `SELECT CONCAT(v1, "r"), pk, v2 FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"1", "abc", "def"}, {"2", "c-ax", "123"}, {"3", "__2", "456"}}, + {{"1", "def", "abc"}, {"2", "123", "c-ax"}, {"3", "456", "__2"}}, + {{"abcr", "1", "def"}, {"c-axr", "2", "123"}, {"__2r", "3", "456"}}, + }, + }, + { + Name: "MEDIUMTEXT", + SetUpScript: []string{ + `CREATE TABLE test (pk BIGINT PRIMARY KEY, v1 MEDIUMTEXT, v2 MEDIUMTEXT);`, + `INSERT INTO test VALUES (1, "abc", "def"), (2, "c-a", "123"), (3, "__2", 456), (4, "?hi?", "\\n");`, + `UPDATE test SET v1 = CONCAT(v1, "x") WHERE pk = 2;`, + `DELETE FROM test WHERE pk = 4;`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT pk, v2, v1 FROM test ORDER BY pk;`, + `SELECT CONCAT(v1, "r"), pk, v2 FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"1", "abc", "def"}, {"2", "c-ax", "123"}, {"3", "__2", "456"}}, + {{"1", "def", "abc"}, {"2", "123", "c-ax"}, {"3", "456", "__2"}}, + {{"abcr", "1", "def"}, {"c-axr", "2", "123"}, {"__2r", "3", "456"}}, + }, + }, + { + Name: "LONGTEXT", + SetUpScript: []string{ + `CREATE TABLE test (pk BIGINT PRIMARY KEY, v1 LONGTEXT, v2 LONGTEXT);`, + `INSERT INTO test VALUES (1, "abc", "def"), (2, "c-a", "123"), (3, "__2", 456), (4, "?hi?", "\\n");`, + `UPDATE test SET v1 = CONCAT(v1, "x") WHERE pk = 2;`, + `DELETE FROM test WHERE pk = 4;`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT pk, v2, v1 FROM test ORDER BY pk;`, + `SELECT CONCAT(v1, "r"), pk, v2 FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"1", "abc", "def"}, {"2", "c-ax", "123"}, {"3", "__2", "456"}}, + {{"1", "def", "abc"}, {"2", "123", "c-ax"}, {"3", "456", "__2"}}, + {{"abcr", "1", "def"}, {"c-axr", "2", "123"}, {"__2r", "3", "456"}}, + }, + }, + { + Name: "TINYBLOB", + SetUpScript: []string{ + `CREATE TABLE test (pk BIGINT PRIMARY KEY, v1 TINYBLOB, v2 TINYBLOB);`, + `INSERT INTO test VALUES (1, "abc", "def"), (2, "c-a", "123"), (3, "__2", 456), (4, "?hi?", "\\n");`, + `UPDATE test SET v1 = CONCAT(v1, "x") WHERE pk = 2;`, + `DELETE FROM test WHERE pk = 4;`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT pk, v2, v1 FROM test ORDER BY pk;`, + `SELECT CONCAT(v1, "r"), pk, v2 FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"1", "abc", "def"}, {"2", "c-ax", "123"}, {"3", "__2", "456"}}, + {{"1", "def", "abc"}, {"2", "123", "c-ax"}, {"3", "456", "__2"}}, + {{"abcr", "1", "def"}, {"c-axr", "2", "123"}, {"__2r", "3", "456"}}, + }, + }, + { + Name: "BLOB", + SetUpScript: []string{ + `CREATE TABLE test (pk BIGINT PRIMARY KEY, v1 BLOB, v2 BLOB);`, + `INSERT INTO test VALUES (1, "abc", "def"), (2, "c-a", "123"), (3, "__2", 456), (4, "?hi?", "\\n");`, + `UPDATE test SET v1 = CONCAT(v1, "x") WHERE pk = 2;`, + `DELETE FROM test WHERE pk = 4;`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT pk, v2, v1 FROM test ORDER BY pk;`, + `SELECT CONCAT(v1, "r"), pk, v2 FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"1", "abc", "def"}, {"2", "c-ax", "123"}, {"3", "__2", "456"}}, + {{"1", "def", "abc"}, {"2", "123", "c-ax"}, {"3", "456", "__2"}}, + {{"abcr", "1", "def"}, {"c-axr", "2", "123"}, {"__2r", "3", "456"}}, + }, + }, + { + Name: "MEDIUMBLOB", + SetUpScript: []string{ + `CREATE TABLE test (pk BIGINT PRIMARY KEY, v1 MEDIUMBLOB, v2 MEDIUMBLOB);`, + `INSERT INTO test VALUES (1, "abc", "def"), (2, "c-a", "123"), (3, "__2", 456), (4, "?hi?", "\\n");`, + `UPDATE test SET v1 = CONCAT(v1, "x") WHERE pk = 2;`, + `DELETE FROM test WHERE pk = 4;`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT pk, v2, v1 FROM test ORDER BY pk;`, + `SELECT CONCAT(v1, "r"), pk, v2 FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"1", "abc", "def"}, {"2", "c-ax", "123"}, {"3", "__2", "456"}}, + {{"1", "def", "abc"}, {"2", "123", "c-ax"}, {"3", "456", "__2"}}, + {{"abcr", "1", "def"}, {"c-axr", "2", "123"}, {"__2r", "3", "456"}}, + }, + }, + { + Name: "LONGBLOB", + SetUpScript: []string{ + `CREATE TABLE test (pk BIGINT PRIMARY KEY, v1 LONGBLOB, v2 LONGBLOB);`, + `INSERT INTO test VALUES (1, "abc", "def"), (2, "c-a", "123"), (3, "__2", 456), (4, "?hi?", "\\n");`, + `UPDATE test SET v1 = CONCAT(v1, "x") WHERE pk = 2;`, + `DELETE FROM test WHERE pk = 4;`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT pk, v2, v1 FROM test ORDER BY pk;`, + `SELECT CONCAT(v1, "r"), pk, v2 FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"1", "abc", "def"}, {"2", "c-ax", "123"}, {"3", "__2", "456"}}, + {{"1", "def", "abc"}, {"2", "123", "c-ax"}, {"3", "456", "__2"}}, + {{"abcr", "1", "def"}, {"c-axr", "2", "123"}, {"__2r", "3", "456"}}, + }, + }, + { + Name: "ENUM", + SetUpScript: []string{ + `CREATE TABLE test (pk ENUM("a","b","c") PRIMARY KEY, v1 ENUM("x","y","z"));`, + `INSERT INTO test VALUES (1, 1), ("b", "y"), (3, "z");`, + `UPDATE test SET v1 = "x" WHERE pk = 2;`, + `DELETE FROM test WHERE pk > 2;`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT pk, v1 FROM test ORDER BY pk;`, + `SELECT v1, pk FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"a", "x"}, {"b", "x"}}, + {{"a", "x"}, {"b", "x"}}, + {{"x", "a"}, {"x", "b"}}, + }, + }, + { + Name: "SET", + SetUpScript: []string{ + `CREATE TABLE test (pk SET("a","b","c") PRIMARY KEY, v1 SET("w","x","y","z"));`, + `INSERT INTO test VALUES (0, 1), ("b", "y"), ("b,c", "z,z"), ("a,c,b", 10);`, + `UPDATE test SET v1 = "y,x,w" WHERE pk >= 4`, + `DELETE FROM test WHERE pk > "b,c";`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT pk, v1 FROM test ORDER BY pk;`, + `SELECT v1, pk FROM test ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"", "w"}, {"b", "y"}, {"b,c", "w,x,y"}}, + {{"", "w"}, {"b", "y"}, {"b,c", "w,x,y"}}, + {{"w", ""}, {"y", "b"}, {"w,x,y", "b,c"}}, + }, + }, + //TODO: fix GEOMETRY and friends, basic queries are broken + //{ + // Name: "GEOMETRY", + // SetUpScript: []string{ + // `CREATE TABLE test (pk BIGINT PRIMARY KEY, v1 GEOMETRY);`, + // `INSERT INTO test VALUES (1, POINT(1, 2)), (2, LINESTRING(POINT(1, 2), POINT(3, 4))), (3, ST_GeomFromText('POLYGON((0 0,0 3,3 0,0 0),(1 1,1 2,2 1,1 1))'));`, + // }, + // Queries: []string{ + // `SELECT * FROM test ORDER BY pk;`, + // `SELECT pk, v1 FROM test ORDER BY pk;`, + // `SELECT ST_ASWKT(v1), pk FROM test ORDER BY pk;`, + // }, + //}, + //{ + // Name: "POINT", + // SetUpScript: []string{ + // `CREATE TABLE test (pk BIGINT PRIMARY KEY, v1 POINT);`, + // `INSERT INTO test VALUES (1, POINT(1, 2)), (2, POINT(3.4, 5.6)), (3, POINT(10, -20)), (4, POINT(1000, -1000));`, + // `DELETE FROM test WHERE pk = 4;`, + // }, + // Queries: []string{ + // `SELECT * FROM test ORDER BY pk;`, + // `SELECT pk, v1 FROM test ORDER BY pk;`, + // `SELECT ST_ASWKT(v1), pk FROM test ORDER BY pk;`, + // }, + //}, + //{ + // Name: "LINESTRING", + // SetUpScript: []string{ + // `CREATE TABLE test (pk BIGINT PRIMARY KEY, v1 LINESTRING);`, + // `INSERT INTO test VALUES (1, LINESTRING(POINT(1, 2), POINT(3, 4))), (2, LINESTRING(POINT(5, 6), POINT(7, 8)));`, + // }, + // Queries: []string{ + // `SELECT * FROM test ORDER BY pk;`, + // `SELECT pk, v1 FROM test ORDER BY pk;`, + // `SELECT ST_ASWKT(v1), pk FROM test ORDER BY pk;`, + // }, + //}, + //{ + // Name: "POLYGON", + // SetUpScript: []string{ + // `CREATE TABLE test (pk BIGINT PRIMARY KEY, v1 POLYGON);`, + // `INSERT INTO test VALUES (1, ST_GeomFromText('POLYGON((0 0,0 3,3 0,0 0),(1 1,1 2,2 1,1 1))'));`, + // }, + // Queries: []string{ + // `SELECT * FROM test ORDER BY pk;`, + // `SELECT pk, v1 FROM test ORDER BY pk;`, + // `SELECT ST_ASWKT(v1), pk FROM test ORDER BY pk;`, + // }, + //}, + { + Name: "JSON", + SetUpScript: []string{ + `CREATE TABLE test (pk BIGINT PRIMARY KEY, v1 JSON);`, + `INSERT INTO test VALUES (1, '{"key1": {"key": "value"}}'), (2, '{"key1": "value1", "key2": "value2"}'), (3, '{"key1": {"key": [2,3]}}');`, + `UPDATE test SET v1 = '["a", 1]' WHERE pk = 1;`, + `DELETE FROM test WHERE pk = 3;`, + }, + Queries: []string{ + `SELECT * FROM test ORDER BY pk;`, + `SELECT v1, pk FROM test ORDER BY pk;`, + `SELECT pk, JSON_ARRAYAGG(v1) FROM (SELECT * FROM test ORDER BY pk) as sub GROUP BY v1 ORDER BY pk;`, + }, + Results: [][]sql.Row{ + {{"1", "[\"a\",1]"}, {"2", "{\"key1\":\"value1\",\"key2\":\"value2\"}"}}, + {{"[\"a\",1]", "1"}, {"{\"key1\":\"value1\",\"key2\":\"value2\"}", "2"}}, + {{"1", "[[\"a\",1]]"}, {"2", "[{\"key1\":\"value1\",\"key2\":\"value2\"}]"}}, + }, + }, +} diff --git a/sql/expression/comparison.go b/sql/expression/comparison.go index 17b6cd0fe1..f00f097a35 100644 --- a/sql/expression/comparison.go +++ b/sql/expression/comparison.go @@ -62,11 +62,12 @@ func (c *comparison) Compare(ctx *sql.Context, row sql.Row) (int, error) { return c.Left().Type().Compare(left, right) } - // ENUM and SET must be considered when doing comparisons, as they can match arbitrary strings to numbers based on - // their elements. For other types it seems there are other considerations, therefore we only take the type for - // ENUM and SET, and default to direct literal comparisons for all other types. Eventually we will need to make our - // comparisons context-sensitive, as all comparisons should probably be based on the column/variable if present. - // Until then, this is a workaround specifically for ENUM and SET. + // ENUM, SET, and TIME must be excluded when doing comparisons, as they're too restrictive to use as a comparison + // base. + // + // The best overall method would be to assign type priority. For example, INT would have a higher priority than + // TINYINT. This could then be combined with the origin of the value (table column, procedure param, etc.) to + // determine the best type for any comparison (tie-breakers can be simple rules such as the current left preference). var compareType sql.Type switch c.Left().(type) { case *GetField, *UserVar, *SystemVar, *ProcedureParam: @@ -80,7 +81,8 @@ func (c *comparison) Compare(ctx *sql.Context, row sql.Row) (int, error) { if compareType != nil { _, isEnum := compareType.(sql.EnumType) _, isSet := compareType.(sql.SetType) - if !isEnum && !isSet { + _, isTime := compareType.(sql.TimeType) + if !isEnum && !isSet && !isTime { compareType = nil } } @@ -115,11 +117,12 @@ func (c *comparison) NullSafeCompare(ctx *sql.Context, row sql.Row) (int, error) return c.Left().Type().Compare(left, right) } - // ENUM and SET must be considered when doing comparisons, as they can match arbitrary strings to numbers based on - // their elements. For other types it seems there are other considerations, therefore we only take the type for - // ENUM and SET, and default to direct literal comparisons for all other types. Eventually we will need to make our - // comparisons context-sensitive, as all comparisons should probably be based on the column/variable if present. - // Until then, this is a workaround specifically for ENUM and SET. + // ENUM, SET, and TIME must be excluded when doing comparisons, as they're too restrictive to use as a comparison + // base. + // + // The best overall method would be to assign type priority. For example, INT would have a higher priority than + // TINYINT. This could then be combined with the origin of the value (table column, procedure param, etc.) to + // determine the best type for any comparison (tie-breakers can be simple rules such as the current left preference). var compareType sql.Type switch c.Left().(type) { case *GetField, *UserVar, *SystemVar, *ProcedureParam: @@ -133,7 +136,8 @@ func (c *comparison) NullSafeCompare(ctx *sql.Context, row sql.Row) (int, error) if compareType != nil { _, isEnum := compareType.(sql.EnumType) _, isSet := compareType.(sql.SetType) - if !isEnum && !isSet { + _, isTime := compareType.(sql.TimeType) + if !isEnum && !isSet && !isTime { compareType = nil } } diff --git a/sql/numbertype.go b/sql/numbertype.go index 0b6d703b92..f162cd3f19 100644 --- a/sql/numbertype.go +++ b/sql/numbertype.go @@ -371,9 +371,9 @@ func (t numberTypeImpl) SQL(dest []byte, v interface{}) (sqltypes.Value, error) case sqltypes.Uint8, sqltypes.Uint16, sqltypes.Uint24, sqltypes.Uint32, sqltypes.Uint64: dest = strconv.AppendUint(dest, mustUint64(v), 10) case sqltypes.Float32: - dest = strconv.AppendFloat(dest, float64(v.(float32)), 'f', -1, 32) + dest = strconv.AppendFloat(dest, float64(v.(float32)), 'g', -1, 32) case sqltypes.Float64: - dest = strconv.AppendFloat(dest, v.(float64), 'f', -1, 64) + dest = strconv.AppendFloat(dest, v.(float64), 'g', -1, 64) default: panic(ErrInvalidBaseType.New(t.baseType.String(), "number")) }