Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Metadata in SHOW queries #7540

Merged
merged 10 commits into from
Feb 26, 2021
12 changes: 12 additions & 0 deletions go/test/endtoend/vtgate/misc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,18 @@ func TestShowColumns(t *testing.T) {
assertMatches(t, conn, "SHOW columns FROM `t5_null_vindex` in `ks`", expected)
}

func TestShowTables(t *testing.T) {
conn, err := mysql.Connect(context.Background(), &vtParams)
require.NoError(t, err)
defer conn.Close()

query := "show tables;"
qr := exec(t, conn, query)

assert.Equal(t, "information_schema", qr.Fields[0].Database)
assert.Equal(t, "Tables_in_ks", qr.Fields[0].Name)
}

func TestCastConvert(t *testing.T) {
conn, err := mysql.Connect(context.Background(), &vtParams)
require.NoError(t, err)
Expand Down
25 changes: 25 additions & 0 deletions go/vt/vtgate/engine/cached_size.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

118 changes: 118 additions & 0 deletions go/vt/vtgate/engine/rename_fields.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
Copyright 2021 The Vitess Authors.

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 engine

import (
"vitess.io/vitess/go/sqltypes"
querypb "vitess.io/vitess/go/vt/proto/query"
"vitess.io/vitess/go/vt/proto/vtrpc"
"vitess.io/vitess/go/vt/vterrors"
)

var _ Primitive = (*RenameFields)(nil)

// RenameFields is a primitive that renames the fields
type RenameFields struct {
Cols []string
Indices []int
Input Primitive
noTxNeeded
}

// NewRenameField creates a new rename field
func NewRenameField(cols []string, indices []int, input Primitive) (*RenameFields, error) {
if len(cols) != len(indices) {
return nil, vterrors.New(vtrpc.Code_INTERNAL, "Unequal length of columns and indices in RenameField primitive")
}
return &RenameFields{
Cols: cols,
Indices: indices,
Input: input,
}, nil
}

// RouteType implements the primitive interface
func (r *RenameFields) RouteType() string {
return r.Input.RouteType()
}

// GetKeyspaceName implements the primitive interface
func (r *RenameFields) GetKeyspaceName() string {
return r.Input.GetKeyspaceName()
}

// GetTableName implements the primitive interface
func (r *RenameFields) GetTableName() string {
return r.Input.GetTableName()
}

// Execute implements the primitive interface
func (r *RenameFields) Execute(vcursor VCursor, bindVars map[string]*querypb.BindVariable, wantfields bool) (*sqltypes.Result, error) {
qr, err := r.Input.Execute(vcursor, bindVars, wantfields)
if err != nil {
return nil, err
}
if wantfields {
r.renameFields(qr)
}
return qr, nil
}

func (r *RenameFields) renameFields(qr *sqltypes.Result) {
for ind, index := range r.Indices {
colName := r.Cols[ind]
qr.Fields[index].Name = colName
}
}

// StreamExecute implements the primitive interface
func (r *RenameFields) StreamExecute(vcursor VCursor, bindVars map[string]*querypb.BindVariable, wantfields bool, callback func(*sqltypes.Result) error) error {
if wantfields {
innerCallback := callback
callback = func(result *sqltypes.Result) error {
r.renameFields(result)
return innerCallback(result)
}
}
return r.Input.StreamExecute(vcursor, bindVars, wantfields, callback)
}

// GetFields implements the primitive interface
func (r *RenameFields) GetFields(vcursor VCursor, bindVars map[string]*querypb.BindVariable) (*sqltypes.Result, error) {
qr, err := r.Input.GetFields(vcursor, bindVars)
if err != nil {
return nil, err
}
r.renameFields(qr)
return qr, nil
}

// Inputs implements the primitive interface
func (r *RenameFields) Inputs() []Primitive {
return []Primitive{r.Input}
}

// description implements the primitive interface
func (r *RenameFields) description() PrimitiveDescription {
return PrimitiveDescription{
OperatorType: "RenameFields",
Other: map[string]interface{}{
"Indices": r.Indices,
"Columns": r.Cols,
},
}
}
23 changes: 18 additions & 5 deletions go/vt/vtgate/planbuilder/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,32 +174,45 @@ func buildDBPlan(show *sqlparser.ShowBasic, vschema ContextVSchema) (engine.Prim

func buildPlanWithDB(show *sqlparser.ShowBasic, vschema ContextVSchema) (engine.Primitive, error) {
dbName := show.DbName
if sqlparser.SystemSchema(dbName) {
dbDestination := show.DbName
if sqlparser.SystemSchema(dbDestination) {
ks, err := vschema.AnyKeyspace()
if err != nil {
return nil, err
}
dbName = ks.Name
dbDestination = ks.Name
} else {
// Remove Database Name from the query.
show.DbName = ""
}
destination, keyspace, _, err := vschema.TargetDestination(dbName)
destination, keyspace, _, err := vschema.TargetDestination(dbDestination)
if err != nil {
return nil, err
}
if destination == nil {
destination = key.DestinationAnyShard{}
}

if dbName == "" {
dbName = keyspace.Name
}

query := sqlparser.String(show)
return &engine.Send{
var plan engine.Primitive
plan = &engine.Send{
Keyspace: keyspace,
TargetDestination: destination,
Query: query,
IsDML: false,
SingleShardOnly: true,
}, nil
}
if show.Command == sqlparser.Table {
plan, err = engine.NewRenameField([]string{"Tables_in_" + dbName}, []int{0}, plan)
if err != nil {
return nil, err
}
}
return plan, nil

}

Expand Down
88 changes: 60 additions & 28 deletions go/vt/vtgate/planbuilder/testdata/show_cases.txt
Original file line number Diff line number Diff line change
Expand Up @@ -424,15 +424,26 @@
"QueryType": "SHOW",
"Original": "show tables",
"Instructions": {
"OperatorType": "Send",
"Keyspace": {
"Name": "main",
"Sharded": false
},
"TargetDestination": "AnyShard()",
"IsDML": false,
"Query": "show tables",
"SingleShardOnly": true
"OperatorType": "RenameFields",
"Columns": [
"Tables_in_main"
],
"Indices": [
0
],
"Inputs": [
{
"OperatorType": "Send",
"Keyspace": {
"Name": "main",
"Sharded": false
},
"TargetDestination": "AnyShard()",
"IsDML": false,
"Query": "show tables",
"SingleShardOnly": true
}
]
}
}

Expand All @@ -442,15 +453,26 @@
"QueryType": "SHOW",
"Original": "show tables from user",
"Instructions": {
"OperatorType": "Send",
"Keyspace": {
"Name": "user",
"Sharded": true
},
"TargetDestination": "AnyShard()",
"IsDML": false,
"Query": "show tables",
"SingleShardOnly": true
"OperatorType": "RenameFields",
"Columns": [
"Tables_in_user"
],
"Indices": [
0
],
"Inputs": [
{
"OperatorType": "Send",
"Keyspace": {
"Name": "user",
"Sharded": true
},
"TargetDestination": "AnyShard()",
"IsDML": false,
"Query": "show tables",
"SingleShardOnly": true
}
]
}
}

Expand All @@ -460,15 +482,25 @@
"QueryType": "SHOW",
"Original": "show tables from performance_schema",
"Instructions": {
"OperatorType": "Send",
"Keyspace": {
"Name": "main",
"Sharded": false
},
"TargetDestination": "AnyShard()",
"IsDML": false,
"Query": "show tables from performance_schema",
"SingleShardOnly": true
"OperatorType": "RenameFields",
"Columns": [
"Tables_in_performance_schema"
],
"Indices": [
0
],
"Inputs": [
{
"OperatorType": "Send",
"Keyspace": {
"Name": "main",
"Sharded": false
},
"TargetDestination": "AnyShard()",
"IsDML": false,
"Query": "show tables from performance_schema",
"SingleShardOnly": true
}
]
}
}

6 changes: 3 additions & 3 deletions go/vt/vtgate/vtgate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import (
"strings"
"testing"

"vitess.io/vitess/go/test/utils"

"context"

"github.com/golang/protobuf/proto"
Expand Down Expand Up @@ -207,9 +209,7 @@ func TestVTGateStreamExecute(t *testing.T) {
}, {
Rows: sandboxconn.StreamRowResult.Rows,
}}
if !reflect.DeepEqual(want, qrs) {
t.Errorf("want \n%+v, got \n%+v", want, qrs)
}
utils.MustMatch(t, want, qrs)
if !proto.Equal(sbc.Options[0], executeOptions) {
t.Errorf("got ExecuteOptions \n%+v, want \n%+v", sbc.Options[0], executeOptions)
}
Expand Down
23 changes: 21 additions & 2 deletions go/vt/vttablet/sandboxconn/sandboxconn.go
Original file line number Diff line number Diff line change
Expand Up @@ -505,15 +505,15 @@ func (sbc *SandboxConn) getNextResult(stmt sqlparser.Statement) *sqltypes.Result
}
if stmt == nil {
// if we didn't get a valid query, we'll assume we need a SELECT
return SingleRowResult
return getSingleRowResult()
}
switch stmt.(type) {
case *sqlparser.Select,
*sqlparser.Union,
*sqlparser.Show,
sqlparser.Explain,
*sqlparser.OtherRead:
return SingleRowResult
return getSingleRowResult()
case *sqlparser.Set,
sqlparser.DDLStatement,
*sqlparser.AlterVschema,
Expand Down Expand Up @@ -551,6 +551,25 @@ func (sbc *SandboxConn) StringQueries() []string {
return result
}

// getSingleRowResult is used to get a SingleRowResult but it creates separate fields because some tests change the fields
// If these fields are not created separately then the constants value also changes which leads to some other tests failing later
func getSingleRowResult() *sqltypes.Result {
singleRowResult := &sqltypes.Result{
InsertID: SingleRowResult.InsertID,
StatusFlags: SingleRowResult.StatusFlags,
Rows: SingleRowResult.Rows,
}

for _, field := range SingleRowResult.Fields {
singleRowResult.Fields = append(singleRowResult.Fields, &querypb.Field{
Name: field.Name,
Type: field.Type,
})
}

return singleRowResult
}

// SingleRowResult is returned when there is no pre-stored result.
var SingleRowResult = &sqltypes.Result{
Fields: []*querypb.Field{
Expand Down