Skip to content
This repository was archived by the owner on Jan 28, 2021. It is now read-only.

Implement SHOW VARIABLES #452

Merged
merged 4 commits into from
Oct 16, 2018
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
32 changes: 32 additions & 0 deletions engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"io"
"io/ioutil"
"math"
"os"
"strings"
"testing"
Expand Down Expand Up @@ -418,6 +419,37 @@ var queries = []struct {
{"c", int32(0)},
},
},
{
`SHOW VARIABLES`,
[]sql.Row{
{"auto_increment_increment", int64(1)},
{"time_zone", time.Local.String()},
{"system_time_zone", time.Local.String()},
{"max_allowed_packet", math.MaxInt32},
{"sql_mode", ""},
{"gtid_mode", int32(0)},
{"ndbinfo_version", ""},
},
},
{
`SHOW VARIABLES LIKE 'gtid_mode`,
[]sql.Row{
{"gtid_mode", int32(0)},
},
},
{
`SHOW VARIABLES LIKE 'gtid%`,
[]sql.Row{
{"gtid_mode", int32(0)},
},
},
{
`SHOW GLOBAL VARIABLES LIKE '%mode`,
[]sql.Row{
{"sql_mode", ""},
{"gtid_mode", int32(0)},
},
},
}

func TestQueries(t *testing.T) {
Expand Down
3 changes: 3 additions & 0 deletions sql/parse/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ var (
createIndexRegex = regexp.MustCompile(`^create\s+index\s+`)
dropIndexRegex = regexp.MustCompile(`^drop\s+index\s+`)
showIndexRegex = regexp.MustCompile(`^show\s+(index|indexes|keys)\s+(from|in)\s+\S+\s*`)
showVariablesRegex = regexp.MustCompile(`^show\s+(.*)?variables\s*`)
describeRegex = regexp.MustCompile(`^(describe|desc|explain)\s+(.*)\s+`)
fullProcessListRegex = regexp.MustCompile(`^show\s+(full\s+)?processlist$`)
)
Expand Down Expand Up @@ -69,6 +70,8 @@ func Parse(ctx *sql.Context, query string) (sql.Node, error) {
return parseDropIndex(s)
case showIndexRegex.MatchString(lowerQuery):
return parseShowIndex(s)
case showVariablesRegex.MatchString(lowerQuery):
return parseShowVariables(ctx, s)
case describeRegex.MatchString(lowerQuery):
return parseDescribeQuery(ctx, s)
case fullProcessListRegex.MatchString(lowerQuery):
Expand Down
5 changes: 5 additions & 0 deletions sql/parse/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,11 @@ var fixtures = map[string]sql.Node{
},
plan.NewUnresolvedTable("bar", "foo"),
),
`SHOW VARIABLES`: plan.NewShowVariables(sql.NewEmptyContext().GetAll(), ""),
`SHOW GLOBAL VARIABLES`: plan.NewShowVariables(sql.NewEmptyContext().GetAll(), ""),
`SHOW SESSION VARIABLES`: plan.NewShowVariables(sql.NewEmptyContext().GetAll(), ""),
`SHOW VARIABLES LIKE 'gtid_mode'`: plan.NewShowVariables(sql.NewEmptyContext().GetAll(), "gtid_mode"),
`SHOW SESSION VARIABLES LIKE 'autocommit'`: plan.NewShowVariables(sql.NewEmptyContext().GetAll(), "autocommit"),
}

func TestParse(t *testing.T) {
Expand Down
47 changes: 47 additions & 0 deletions sql/parse/variables.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package parse

import (
"bufio"
"strings"

"gopkg.in/src-d/go-mysql-server.v0/sql"
"gopkg.in/src-d/go-mysql-server.v0/sql/plan"
)

func parseShowVariables(ctx *sql.Context, s string) (sql.Node, error) {
var pattern string

r := bufio.NewReader(strings.NewReader(s))
for _, fn := range []parseFunc{
expect("show"),
skipSpaces,
func(in *bufio.Reader) error {
var s string
readIdent(&s)(in)
switch s {
case "global", "session":
skipSpaces(in)
return expect("variables")(in)
case "variables":
return nil
}
return errUnexpectedSyntax.New("show [global | session] variables", s)
},
skipSpaces,
func(in *bufio.Reader) error {
if expect("like")(in) == nil {
skipSpaces(in)
readValue(&pattern)(in)
}
return nil
},
skipSpaces,
checkEOF,
} {
if err := fn(r); err != nil {
return nil, err
}
}

return plan.NewShowVariables(ctx.Session.GetAll(), pattern), nil
}
90 changes: 90 additions & 0 deletions sql/plan/showvariables.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package plan

import (
"fmt"

"gopkg.in/src-d/go-mysql-server.v0/sql"
"gopkg.in/src-d/go-mysql-server.v0/sql/expression"
)

// ShowVariables is a node that shows the global and session variables
type ShowVariables struct {
config map[string]sql.TypedValue
pattern string
}

// NewShowVariables returns a new ShowVariables reference.
// config is a variables lookup table
// like is a "like pattern". If like is an empty string it will return all variables.
func NewShowVariables(config map[string]sql.TypedValue, like string) *ShowVariables {
return &ShowVariables{
config: config,
pattern: like,
}
}

// Resolved implements sql.Node interface. The function always returns true.
func (sv *ShowVariables) Resolved() bool {
return true
}

// TransformUp implements the sq.Transformable interface.
func (sv *ShowVariables) TransformUp(f sql.TransformNodeFunc) (sql.Node, error) {
return f(NewShowVariables(sv.config, sv.pattern))
}

// TransformExpressionsUp implements the sql.Transformable interface.
func (sv *ShowVariables) TransformExpressionsUp(f sql.TransformExprFunc) (sql.Node, error) {
return sv, nil
}

// String implements the Stringer interface.
func (sv *ShowVariables) String() string {
var like string
if sv.pattern != "" {
like = fmt.Sprintf(" LIKE '%s'", sv.pattern)
}
return fmt.Sprintf("SHOW VARIABLES%s", like)
}

// Schema returns a new Schema reference for "SHOW VARIABLES" query.
func (*ShowVariables) Schema() sql.Schema {
return sql.Schema{
&sql.Column{Name: "Variable_name", Type: sql.Text, Nullable: false},
&sql.Column{Name: "Value", Type: sql.Text, Nullable: true},
}
}

// Children implements sql.Node interface. The function always returns nil.
func (*ShowVariables) Children() []sql.Node { return nil }

// RowIter implements the sql.Node interface.
// The function returns an iterator for filtered variables (based on like pattern)
func (sv *ShowVariables) RowIter(ctx *sql.Context) (sql.RowIter, error) {
var (
rows []sql.Row
like sql.Expression
)
if sv.pattern != "" {
like = expression.NewLike(
expression.NewGetField(0, sql.Text, "", false),
expression.NewGetField(1, sql.Text, sv.pattern, false),
)
}

for k, v := range sv.config {
if like != nil {
b, err := like.Eval(ctx, sql.NewRow(k, sv.pattern))
if err != nil {
return nil, err
}
if !b.(bool) {
continue
}
}

rows = append(rows, sql.NewRow(k, v.Value))
}

return sql.RowsToRowIter(rows...), nil
}
68 changes: 68 additions & 0 deletions sql/plan/showvariables_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package plan

import (
"io"
"testing"

"github.com/stretchr/testify/require"
"gopkg.in/src-d/go-mysql-server.v0/sql"
)

func TestShowVariables(t *testing.T) {
require := require.New(t)

ctx := sql.NewEmptyContext()
config := ctx.Session.GetAll()
sv := NewShowVariables(config, "")
require.True(sv.Resolved())

it, err := sv.RowIter(ctx)
require.NoError(err)

for row, err := it.Next(); err == nil; row, err = it.Next() {
key := row[0].(string)
val := row[1]

t.Logf("key: %s\tval: %v\n", key, val)

require.Equal(config[key].Value, val)
delete(config, key)
}
if err != io.EOF {
require.NoError(err)
}
require.NoError(it.Close())
require.Equal(0, len(config))
}

func TestShowVariablesWithLike(t *testing.T) {
require := require.New(t)

vars := map[string]sql.TypedValue{
"int1": {Typ: sql.Int32, Value: 1},
"int2": {Typ: sql.Int32, Value: 2},
"txt": {Typ: sql.Text, Value: "abcdefghijklmnoprstuwxyz"},
}

sv := NewShowVariables(vars, "int%")
require.True(sv.Resolved())

it, err := sv.RowIter(sql.NewEmptyContext())
require.NoError(err)

for row, err := it.Next(); err == nil; row, err = it.Next() {
key := row[0].(string)
val := row[1]
require.Equal(vars[key].Value, val)
require.Equal(sql.Int32, vars[key].Typ)
delete(vars, key)
}
if err != io.EOF {
require.NoError(err)
}
require.NoError(it.Close())
require.Equal(1, len(vars))

_, ok := vars["txt"]
require.True(ok)
}
42 changes: 29 additions & 13 deletions sql/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ type Session interface {
Set(key string, typ Type, value interface{})
// Get session configuration.
Get(key string) (Type, interface{})
// GetAll returns a copy of session configuration
GetAll() map[string]TypedValue
// ID returns the unique ID of the connection.
ID() uint32
}
Expand All @@ -38,7 +40,7 @@ type BaseSession struct {
addr string
user string
mu sync.RWMutex
config map[string]typedValue
config map[string]TypedValue
}

// User returns the current user of the session.
Expand All @@ -51,7 +53,7 @@ func (s *BaseSession) Address() string { return s.addr }
func (s *BaseSession) Set(key string, typ Type, value interface{}) {
s.mu.Lock()
defer s.mu.Unlock()
s.config[key] = typedValue{typ, value}
s.config[key] = TypedValue{typ, value}
}

// Get implements the Session interface.
Expand All @@ -63,24 +65,38 @@ func (s *BaseSession) Get(key string) (Type, interface{}) {
return Null, nil
}

return v.typ, v.value
return v.Typ, v.Value
}

// GetAll returns a copy of session configuration
func (s *BaseSession) GetAll() map[string]TypedValue {
m := make(map[string]TypedValue)
s.mu.RLock()
defer s.mu.RUnlock()

for k, v := range s.config {
m[k] = v
}
return m
}

// ID implements the Session interface.
func (s *BaseSession) ID() uint32 { return s.id }

type typedValue struct {
typ Type
value interface{}
type TypedValue struct {
Typ Type
Value interface{}
}

func defaultSessionConfig() map[string]typedValue {
return map[string]typedValue{
"auto_increment_increment": typedValue{Int64, int64(1)},
"time_zone": typedValue{Text, time.Local.String()},
"system_time_zone": typedValue{Text, time.Local.String()},
"max_allowed_packet": typedValue{Int32, math.MaxInt32},
"sql_mode": typedValue{Text, ""},
func defaultSessionConfig() map[string]TypedValue {
return map[string]TypedValue{
"auto_increment_increment": TypedValue{Int64, int64(1)},
"time_zone": TypedValue{Text, time.Local.String()},
"system_time_zone": TypedValue{Text, time.Local.String()},
"max_allowed_packet": TypedValue{Int32, math.MaxInt32},
"sql_mode": TypedValue{Text, ""},
"gtid_mode": TypedValue{Int32, int32(0)},
"ndbinfo_version": TypedValue{Text, ""},
}
}

Expand Down
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy