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

Adds support for Show variables #7547

Merged
merged 5 commits into from
Feb 26, 2021
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
17 changes: 17 additions & 0 deletions go/test/endtoend/vtgate/misc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,23 @@ func TestFlush(t *testing.T) {
exec(t, conn, "flush local tables t1, t2")
}

func TestShowVariables(t *testing.T) {
defer cluster.PanicHandler(t)
ctx := context.Background()
conn, err := mysql.Connect(ctx, &vtParams)
require.NoError(t, err)
defer conn.Close()
res := exec(t, conn, "show variables like \"%version%\";")
found := false
for _, row := range res.Rows {
if row[0].ToString() == "version" {
assert.Contains(t, row[1].ToString(), "vitess")
found = true
}
}
require.True(t, found, "Expected a row for version in show query")
}

func assertMatches(t *testing.T, conn *mysql.Conn, query, expected string) {
t.Helper()
qr := exec(t, conn, query)
Expand Down
12 changes: 9 additions & 3 deletions go/vt/sqlparser/analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,17 @@ func CachePlan(stmt Statement) bool {
return false
}

//IsSetStatement takes Statement and returns if the statement is set statement.
func IsSetStatement(stmt Statement) bool {
switch stmt.(type) {
//MustRewriteAST takes Statement and returns true if RewriteAST must run on it for correct execution irrespective of user flags.
func MustRewriteAST(stmt Statement) bool {
switch node := stmt.(type) {
case *Set:
return true
case *Show:
switch node.Internal.(type) {
case *ShowBasic:
return true
}
return false
}
return false
}
Expand Down
7 changes: 7 additions & 0 deletions go/vt/sqlparser/ast_rewriting.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,13 @@ func (er *expressionRewriter) rewrite(cursor *Cursor) bool {
node.Expr = aliasTableName
cursor.Replace(node)
}
case *ShowBasic:
if node.Command == VariableGlobal || node.Command == VariableSession {
varsToAdd := sysvars.GetInterestingVariables()
for _, sysVar := range varsToAdd {
er.bindVars.AddSysVar(sysVar)
}
}
}
return true
}
Expand Down
34 changes: 34 additions & 0 deletions go/vt/sqlparser/ast_rewriting_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,40 @@ func TestRewrites(in *testing.T) {
in: "CALL proc(@foo)",
expected: "CALL proc(:__vtudvfoo)",
udv: 1,
}, {
in: "SHOW VARIABLES",
expected: "SHOW VARIABLES",
autocommit: true,
clientFoundRows: true,
skipQueryPlanCache: true,
sqlSelectLimit: true,
transactionMode: true,
workload: true,
version: true,
versionComment: true,
ddlStrategy: true,
sessionUUID: true,
sessionEnableSystemSettings: true,
rawGTID: true,
rawTimeout: true,
sessTrackGTID: true,
}, {
in: "SHOW GLOBAL VARIABLES",
expected: "SHOW GLOBAL VARIABLES",
autocommit: true,
clientFoundRows: true,
skipQueryPlanCache: true,
sqlSelectLimit: true,
transactionMode: true,
workload: true,
version: true,
versionComment: true,
ddlStrategy: true,
sessionUUID: true,
sessionEnableSystemSettings: true,
rawGTID: true,
rawTimeout: true,
sessTrackGTID: true,
}}

for _, tc := range tests {
Expand Down
13 changes: 13 additions & 0 deletions go/vt/sysvars/sysvars.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,3 +238,16 @@ var (
{Name: "version_tokens_session"},
}
)

// GetInterestingVariables is used to return all the variables that may be listed in a SHOW VARIABLES command.
func GetInterestingVariables() []string {
var res []string
// Add all the vitess aware variables
for _, variable := range VitessAware {
res = append(res, variable.Name)
}
// Also add version and version comment
res = append(res, Version.Name)
res = append(res, VersionComment.Name)
return res
}
14 changes: 14 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.

97 changes: 97 additions & 0 deletions go/vt/vtgate/engine/replace_variables.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
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"
)

var _ Primitive = (*ReplaceVariables)(nil)

// ReplaceVariables is used in SHOW VARIABLES statements so that it replaces the values for vitess-aware variables
type ReplaceVariables struct {
Input Primitive
noTxNeeded
}

// NewReplaceVariables is used to create a new ReplaceVariables primitive
func NewReplaceVariables(input Primitive) *ReplaceVariables {
return &ReplaceVariables{Input: input}
}

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

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

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

// Execute implements the Primitive interface
func (r *ReplaceVariables) 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
}
replaceVariables(qr, bindVars)
return qr, nil
}

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

// GetFields implements the Primitive interface
func (r *ReplaceVariables) GetFields(vcursor VCursor, bindVars map[string]*querypb.BindVariable) (*sqltypes.Result, error) {
return r.Input.GetFields(vcursor, bindVars)
}

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

// description implements the Primitive interface
func (r *ReplaceVariables) description() PrimitiveDescription {
return PrimitiveDescription{
OperatorType: "ReplaceVariables",
}
}

func replaceVariables(qr *sqltypes.Result, bindVars map[string]*querypb.BindVariable) {
for i, row := range qr.Rows {
variableName := row[0].ToString()
res, found := bindVars["__vt"+variableName]
if found {
qr.Rows[i][1] = sqltypes.NewVarChar(string(res.GetValue()))
}
}
}
2 changes: 1 addition & 1 deletion go/vt/vtgate/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -1237,7 +1237,7 @@ func (e *Executor) getPlan(vcursor *vcursorImpl, sql string, comments sqlparser.
vcursor.SetIgnoreMaxMemoryRows(ignoreMaxMemoryRows)

// Normalize if possible and retry.
if (e.normalize && sqlparser.CanNormalize(stmt)) || sqlparser.IsSetStatement(stmt) {
if (e.normalize && sqlparser.CanNormalize(stmt)) || sqlparser.MustRewriteAST(stmt) {
parameterize := e.normalize // the public flag is called normalize
result, err := sqlparser.PrepareAST(stmt, bindVars, "vtg", parameterize, vcursor.keyspace)
if err != nil {
Expand Down
14 changes: 12 additions & 2 deletions go/vt/vtgate/planbuilder/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,10 @@ func buildShowBasicPlan(show *sqlparser.ShowBasic, vschema ContextVSchema) (engi
switch show.Command {
case sqlparser.Charset:
return buildCharsetPlan(show)
case sqlparser.Collation, sqlparser.Function, sqlparser.Privilege, sqlparser.Procedure,
sqlparser.VariableGlobal, sqlparser.VariableSession:
case sqlparser.Collation, sqlparser.Function, sqlparser.Privilege, sqlparser.Procedure:
return buildSendAnywherePlan(show, vschema)
case sqlparser.VariableGlobal, sqlparser.VariableSession:
return buildVariablePlan(show, vschema)
case sqlparser.Column, sqlparser.Index:
return buildShowTblPlan(show, vschema)
case sqlparser.Database, sqlparser.Keyspace:
Expand Down Expand Up @@ -98,6 +99,15 @@ func buildSendAnywherePlan(show *sqlparser.ShowBasic, vschema ContextVSchema) (e
}, nil
}

func buildVariablePlan(show *sqlparser.ShowBasic, vschema ContextVSchema) (engine.Primitive, error) {
plan, err := buildSendAnywherePlan(show, vschema)
if err != nil {
return nil, err
}
plan = engine.NewReplaceVariables(plan)
return plan, nil
}

func buildShowTblPlan(show *sqlparser.ShowBasic, vschema ContextVSchema) (engine.Primitive, error) {
if show.DbName != "" {
show.Tbl.Qualifier = sqlparser.NewTableIdent(show.DbName)
Expand Down
46 changes: 37 additions & 9 deletions go/vt/vtgate/planbuilder/testdata/show_cases.txt
Original file line number Diff line number Diff line change
Expand Up @@ -220,15 +220,43 @@
"QueryType": "SHOW",
"Original": "show variables",
"Instructions": {
"OperatorType": "Send",
"Keyspace": {
"Name": "main",
"Sharded": false
},
"TargetDestination": "AnyShard()",
"IsDML": false,
"Query": "show variables",
"SingleShardOnly": true
"OperatorType": "ReplaceVariables",
"Inputs": [
{
"OperatorType": "Send",
"Keyspace": {
"Name": "main",
"Sharded": false
},
"TargetDestination": "AnyShard()",
"IsDML": false,
"Query": "show variables",
"SingleShardOnly": true
}
]
}
}

# show global variables
"show global variables"
{
"QueryType": "SHOW",
"Original": "show global variables",
"Instructions": {
"OperatorType": "ReplaceVariables",
"Inputs": [
{
"OperatorType": "Send",
"Keyspace": {
"Name": "main",
"Sharded": false
},
"TargetDestination": "AnyShard()",
"IsDML": false,
"Query": "show global variables",
"SingleShardOnly": true
}
]
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,19 @@
"QueryType": "SHOW",
"Original": "show variables",
"Instructions": {
"OperatorType": "Send",
"Keyspace": {
"Name": "main",
"Sharded": false
},
"TargetDestination": "AnyShard()",
"IsDML": false,
"Query": "show variables",
"SingleShardOnly": true
"OperatorType": "ReplaceVariables",
"Inputs": [
{
"OperatorType": "Send",
"Keyspace": {
"Name": "main",
"Sharded": false
},
"TargetDestination": "AnyShard()",
"IsDML": false,
"Query": "show variables",
"SingleShardOnly": true
}
]
}
}