From 0e0eedaf5f867740c3d60feee4f95a5b60db3525 Mon Sep 17 00:00:00 2001 From: Arvid Fahlstrom Myrman <885076+arvidfm@users.noreply.github.com> Date: Mon, 10 Jun 2024 20:58:37 +0100 Subject: [PATCH 1/2] add type conversion for complex types --- rows.go | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/rows.go b/rows.go index b507b1b..c7802f0 100644 --- a/rows.go +++ b/rows.go @@ -4,8 +4,10 @@ import ( "database/sql/driver" "errors" "fmt" - gms "github.com/dolthub/go-mysql-server/sql" "io" + + gms "github.com/dolthub/go-mysql-server/sql" + "github.com/dolthub/go-mysql-server/sql/types" ) var _ driver.Rows = (*doltRows)(nil) @@ -58,6 +60,24 @@ func (rows *doltRows) Next(dest []driver.Value) error { if err != nil { return fmt.Errorf("error processing column %d: %w", i, err) } + } else if geomValue, ok := nextRow[i].(types.GeometryValue); ok { + dest[i] = geomValue.Serialize() + } else if enumType, ok := rows.sch[i].Type.(gms.EnumType); ok { + if v, _, err := enumType.Convert(nextRow[i]); err != nil { + return fmt.Errorf("could not convert to expected enum type for column %d: %w", i, err) + } else if enumStr, ok := enumType.At(int(v.(uint16))); !ok { + return fmt.Errorf("not a valid enum index for column %d: %v", i, v) + } else { + dest[i] = enumStr + } + } else if setType, ok := rows.sch[i].Type.(gms.SetType); ok { + if v, _, err := setType.Convert(nextRow[i]); err != nil { + return fmt.Errorf("could not convert to expected set type for column %d: %w", i, err) + } else if setStr, err := setType.BitsToString(v.(uint64)); err != nil { + return fmt.Errorf("could not convert value to set string for column %d: %w", i, err) + } else { + dest[i] = setStr + } } else { dest[i] = nextRow[i] } From e7fd0599f18ca9f5f00ba9f024743d5982643e57 Mon Sep 17 00:00:00 2001 From: Arvid Fahlstrom Myrman <885076+arvidfm@users.noreply.github.com> Date: Mon, 10 Jun 2024 20:58:47 +0100 Subject: [PATCH 2/2] add tests for type conversion --- smoke_test.go | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/smoke_test.go b/smoke_test.go index 63a8f74..17ae4bb 100644 --- a/smoke_test.go +++ b/smoke_test.go @@ -136,6 +136,43 @@ func TestQueryContextInitialization(t *testing.T) { require.NoError(t, conn.Close()) } +// TestTypes asserts that various MySQL types are returned as the expected Go type by the driver. +func TestTypes(t *testing.T) { + conn, cleanupFunc := initializeTestDatabaseConnection(t, false) + defer cleanupFunc() + + ctx := context.Background() + _, err := conn.ExecContext(ctx, ` +create table testtable ( + enum_col ENUM('a', 'b', 'c'), + set_col SET('a', 'b', 'c'), + json_col JSON, + blob_col BLOB, + text_col TEXT, + geom_col POINT, + date_col DATETIME +); + +insert into testtable values ('b', 'a,c', '{"key": 42}', 'data', 'text', Point(5, -5), NOW()); +`) + require.NoError(t, err) + + row := conn.QueryRowContext(ctx, "select * from testtable") + vals := make([]any, 7) + ptrs := make([]any, 7) + for i := range vals { + ptrs[i] = &vals[i] + } + require.NoError(t, row.Scan(ptrs...)) + require.Equal(t, "b", vals[0]) + require.Equal(t, "a,c", vals[1]) + require.Equal(t, `{"key": 42}`, vals[2]) + require.Equal(t, []byte(`data`), vals[3]) + require.Equal(t, "text", vals[4]) + require.IsType(t, []byte(nil), vals[5]) + require.IsType(t, time.Time{}, vals[6]) +} + // initializeTestDatabaseConnection create a test database called testdb and initialize a database/sql connection // using the Dolt driver. The connection, |conn|, is returned, and |cleanupFunc| is a function that the test function // should defer in order to properly dispose of test resources.