diff --git a/go/mysql/endtoend/query_test.go b/go/mysql/endtoend/query_test.go index e966d5d2031..1827372b17c 100644 --- a/go/mysql/endtoend/query_test.go +++ b/go/mysql/endtoend/query_test.go @@ -17,12 +17,14 @@ limitations under the License. package endtoend import ( + "context" "fmt" "math/rand" "strings" "testing" - "context" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqltypes" @@ -285,3 +287,46 @@ func TestWarningsDeprecateEOF(t *testing.T) { func TestWarningsNoDeprecateEOF(t *testing.T) { doTestWarnings(t, true) } + +func TestSysInfo(t *testing.T) { + ctx := context.Background() + conn, err := mysql.Connect(ctx, &connParams) + require.NoError(t, err) + defer conn.Close() + + _, err = conn.ExecuteFetch("drop table if exists `a`", 1000, true) + require.NoError(t, err) + + _, err = conn.ExecuteFetch("CREATE TABLE `a` (`one` int NOT NULL,`two` int NOT NULL,PRIMARY KEY (`one`,`two`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", 1000, true) + require.NoError(t, err) + defer conn.ExecuteFetch("drop table `a`", 1000, true) + + qr, err := conn.ExecuteFetch(`SELECT + column_name column_name, + data_type data_type, + column_type full_data_type, + character_maximum_length character_maximum_length, + numeric_precision numeric_precision, + numeric_scale numeric_scale, + datetime_precision datetime_precision, + column_default column_default, + is_nullable is_nullable, + extra extra, + table_name table_name + FROM information_schema.columns + WHERE table_schema = 'vttest' and table_name = 'a' + ORDER BY ordinal_position`, 1000, true) + require.NoError(t, err) + require.Equal(t, 2, len(qr.Rows)) + + // is_nullable + assert.Equal(t, `VARCHAR("NO")`, qr.Rows[0][8].String()) + assert.Equal(t, `VARCHAR("NO")`, qr.Rows[1][8].String()) + + // table_name + assert.Equal(t, `VARCHAR("a")`, qr.Rows[0][10].String()) + assert.Equal(t, `VARCHAR("a")`, qr.Rows[1][10].String()) + + assert.EqualValues(t, sqltypes.Uint64, qr.Fields[4].Type) + assert.EqualValues(t, querypb.Type_UINT64, qr.Rows[0][4].Type()) +} diff --git a/go/test/endtoend/vtgate/misc_test.go b/go/test/endtoend/vtgate/misc_test.go index fba70cfbc7e..042c5062205 100644 --- a/go/test/endtoend/vtgate/misc_test.go +++ b/go/test/endtoend/vtgate/misc_test.go @@ -592,7 +592,7 @@ func TestSubQueryOnTopOfSubQuery(t *testing.T) { exec(t, conn, `insert into t1(id1, id2) values (1, 1), (2, 2), (3, 3), (4, 4), (5, 5)`) exec(t, conn, `insert into t2(id3, id4) values (1, 3), (2, 4)`) - assertMatches(t, conn, "select id1 from t1 where id1 not in (select id3 from t2) and id2 in (select id4 from t2)", `[[INT64(3)] [INT64(4)]]`) + assertMatches(t, conn, "select id1 from t1 where id1 not in (select id3 from t2) and id2 in (select id4 from t2) order by id1", `[[INT64(3)] [INT64(4)]]`) } func assertMatches(t *testing.T, conn *mysql.Conn, query, expected string) { diff --git a/go/test/endtoend/vtgate/unsharded/main_test.go b/go/test/endtoend/vtgate/unsharded/main_test.go index cc4e2235d99..547b12ef2af 100644 --- a/go/test/endtoend/vtgate/unsharded/main_test.go +++ b/go/test/endtoend/vtgate/unsharded/main_test.go @@ -25,6 +25,7 @@ import ( "time" "vitess.io/vitess/go/vt/log" + querypb "vitess.io/vitess/go/vt/proto/query" "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/assert" @@ -396,6 +397,45 @@ func TestReservedConnDML(t *testing.T) { exec(t, conn, `commit`) } +func TestNumericPrecisionScale(t *testing.T) { + defer cluster.PanicHandler(t) + ctx := context.Background() + vtParams := mysql.ConnParams{ + Host: "localhost", + Port: clusterInstance.VtgateMySQLPort, + } + conn, err := mysql.Connect(ctx, &vtParams) + require.NoError(t, err) + defer conn.Close() + + _ = exec(t, conn, "CREATE TABLE `a` (`one` bigint NOT NULL PRIMARY KEY) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4") + require.NoError(t, err) + defer exec(t, conn, "drop table `a`") + + qr := exec(t, conn, "select numeric_precision, numeric_scale from information_schema.columns where table_name = 'a'") + require.Equal(t, 1, len(qr.Rows)) + + /* + We expect UINT64 to be returned as type for field and rows from VTGate to client. + + require.Equal(t, querypb.Type_UINT64, qr.Fields[0].Type) + require.Equal(t, querypb.Type_UINT64, qr.Fields[1].Type) + require.Equal(t, sqltypes.Uint64, qr.Rows[0][0].Type()) + require.Equal(t, sqltypes.Uint64, qr.Rows[0][1].Type()) + + But, the field query from mysql returns field at UINT32 and row types as UINT64. + Our conversion on VTGate on receiving data from VTTablet the Rows are converted to Field Types. + So, we see UINT32 for both fields and rows. + + This issue is only with MySQL 8.0. In CI we use 5.7 as well. So asserting with both the values. + */ + + assert.True(t, qr.Fields[0].Type == querypb.Type_UINT64 || qr.Fields[0].Type == querypb.Type_UINT32) + assert.True(t, qr.Fields[1].Type == querypb.Type_UINT64 || qr.Fields[1].Type == querypb.Type_UINT32) + assert.True(t, qr.Rows[0][0].Type() == sqltypes.Uint64 || qr.Rows[0][0].Type() == sqltypes.Uint32) + assert.True(t, qr.Rows[0][1].Type() == sqltypes.Uint64 || qr.Rows[0][1].Type() == sqltypes.Uint32) +} + func exec(t *testing.T, conn *mysql.Conn, query string) *sqltypes.Result { t.Helper() qr, err := conn.ExecuteFetch(query, 1000, true) diff --git a/go/vt/vttablet/endtoend/main_test.go b/go/vt/vttablet/endtoend/main_test.go index bae2ac50a9f..a5d27fc26c4 100644 --- a/go/vt/vttablet/endtoend/main_test.go +++ b/go/vt/vttablet/endtoend/main_test.go @@ -303,7 +303,7 @@ var tableACLConfig = `{ }, { "name": "sys_table", - "table_names_or_prefixes": ["tables", "user", "processlist", "mutex_instances"], + "table_names_or_prefixes": ["tables", "user", "processlist", "mutex_instances", "columns", "a"], "readers": ["dev"], "writers": ["dev"], "admins": ["dev"] diff --git a/go/vt/vttablet/endtoend/misc_test.go b/go/vt/vttablet/endtoend/misc_test.go index b65c8cbc8dc..068170d779b 100644 --- a/go/vt/vttablet/endtoend/misc_test.go +++ b/go/vt/vttablet/endtoend/misc_test.go @@ -779,3 +779,68 @@ func TestSelectBooleanSystemVariables(t *testing.T) { require.Equal(t, tc.Type, qr.Fields[0].Type, fmt.Sprintf("invalid type, wants: %+v, but got: %+v\n", tc.Type, qr.Fields[0].Type)) } } + +func TestSysSchema(t *testing.T) { + client := framework.NewClient() + _, err := client.Execute("drop table if exists `a`", nil) + require.NoError(t, err) + + _, err = client.Execute("CREATE TABLE `a` (`one` int NOT NULL,`two` int NOT NULL,PRIMARY KEY (`one`,`two`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", nil) + require.NoError(t, err) + defer client.Execute("drop table `a`", nil) + + qr, err := client.Execute(`SELECT + column_name column_name, + data_type data_type, + column_type full_data_type, + character_maximum_length character_maximum_length, + numeric_precision numeric_precision, + numeric_scale numeric_scale, + datetime_precision datetime_precision, + column_default column_default, + is_nullable is_nullable, + extra extra, + table_name table_name + FROM information_schema.columns + WHERE 1 != 1 + ORDER BY ordinal_position`, nil) + require.NoError(t, err) + + // This is mysql behaviour that we are receiving Uint32 on field query even though the column is Uint64. + // assert.EqualValues(t, sqltypes.Uint64, qr.Fields[4].Type) - ideally this should be received + // The issue is only in MySQL 8.0 , As CI is on MySQL 5.7 need to check with Uint64 + assert.True(t, qr.Fields[4].Type == sqltypes.Uint64 || qr.Fields[4].Type == sqltypes.Uint32) + + qr, err = client.Execute(`SELECT + column_name column_name, + data_type data_type, + column_type full_data_type, + character_maximum_length character_maximum_length, + numeric_precision numeric_precision, + numeric_scale numeric_scale, + datetime_precision datetime_precision, + column_default column_default, + is_nullable is_nullable, + extra extra, + table_name table_name + FROM information_schema.columns + WHERE table_schema = 'vttest' and table_name = 'a' + ORDER BY ordinal_position`, nil) + require.NoError(t, err) + require.Equal(t, 2, len(qr.Rows)) + + // is_nullable + assert.Equal(t, `VARCHAR("NO")`, qr.Rows[0][8].String()) + assert.Equal(t, `VARCHAR("NO")`, qr.Rows[1][8].String()) + + // table_name + assert.Equal(t, `VARCHAR("a")`, qr.Rows[0][10].String()) + assert.Equal(t, `VARCHAR("a")`, qr.Rows[1][10].String()) + + // The field Type and the row value type are not matching and because of this wrong packet is send regarding the data of bigint unsigned to the client on vttestserver. + // On, Vitess cluster using protobuf we are doing the row conversion to field type and so the final row type send to client is same as field type. + // assert.EqualValues(t, sqltypes.Uint64, qr.Fields[4].Type) - We would have received this but because of field caching we are receiving Uint32. + // The issue is only in MySQL 8.0 , As CI is on MySQL 5.7 need to check with Uint64 + assert.True(t, qr.Fields[4].Type == sqltypes.Uint64 || qr.Fields[4].Type == sqltypes.Uint32) + assert.Equal(t, querypb.Type_UINT64, qr.Rows[0][4].Type()) +}