Skip to content

Commit

Permalink
Support Questions status variable (#2422)
Browse files Browse the repository at this point in the history
  • Loading branch information
jycor committed Mar 29, 2024
1 parent 6bd8beb commit 97f8899
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 5 deletions.
17 changes: 16 additions & 1 deletion server/handler.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2020-2021 Dolthub, Inc.
// Copyright 2020-2024 Dolthub, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -335,6 +335,16 @@ func (h *Handler) ComBinlogDumpGTID(c *mysql.Conn, logFile string, logPos uint64

var queryLoggingRegex = regexp.MustCompile(`[\r\n\t ]+`)

func incrementStatusVariableQuestions(ctx *sql.Context) {
// ignore all errors relating to status updates
if _, globalQuesVal, ok := sql.StatusVariables.GetGlobal("Questions"); ok {
sql.StatusVariables.SetGlobal("Questions", globalQuesVal.(int64)+1)
}
if sessQuesVal, err2 := ctx.Session.GetStatusVariable(ctx, "Questions"); err2 == nil {
ctx.Session.SetStatusVariable(ctx, "Questions", sessQuesVal.(int64)+1)
}
}

func (h *Handler) doQuery(
c *mysql.Conn,
query string,
Expand Down Expand Up @@ -388,6 +398,11 @@ func (h *Handler) doQuery(

ctx.GetLogger().Tracef("beginning execution")

// TODO: a goroutine might be worth it here, as read/writing status variables go through a mutex
defer func() {
incrementStatusVariableQuestions(ctx)
}()

oCtx := ctx
eg, ctx := ctx.NewErrgroup()

Expand Down
161 changes: 160 additions & 1 deletion server/handler_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2020-2021 Dolthub, Inc.
// Copyright 2020-2024 Dolthub, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -1199,3 +1199,162 @@ func newConn(id uint32) *mysql.Conn {
Conn: new(mockConn),
}
}

func dummyCb(_ *sqltypes.Result, _ bool) error {
return nil
}

func TestStatusVariableQuestions(t *testing.T) {
variables.InitStatusVariables()

e, pro := setupMemDB(require.New(t))
dbFunc := pro.Database
handler := &Handler{
e: e,
sm: NewSessionManager(
testSessionBuilder(pro),
sql.NoopTracer,
dbFunc,
sql.NewMemoryManager(nil),
sqle.NewProcessList(),
"foo",
),
readTimeout: time.Second,
}

conn1 := newConn(1)
handler.NewConnection(conn1)
err := handler.ComInitDB(conn1, "test")
require.NoError(t, err)
sess1 := handler.sm.sessions[1]

_, globalVal, ok := sql.StatusVariables.GetGlobal("Questions")
require.True(t, ok)
require.Equal(t, int64(0), globalVal)

sessVal, err := sess1.GetStatusVariable(nil, "Questions")
require.NoError(t, err)
require.Equal(t, int64(0), sessVal)

// Call ComQuery 5 times
for i := 0; i < 5; i++ {
err = handler.ComQuery(conn1, "SELECT 1", dummyCb)
require.NoError(t, err)
}

_, globalVal, ok = sql.StatusVariables.GetGlobal("Questions")
require.True(t, ok)
require.Equal(t, int64(5), globalVal)

sessVal, err = sess1.GetStatusVariable(nil, "Questions")
require.NoError(t, err)
require.Equal(t, int64(5), sessVal)

conn2 := newConn(2)
handler.NewConnection(conn2)
err = handler.ComInitDB(conn2, "test")
require.NoError(t, err)
sess2 := handler.sm.sessions[2]

// Get 5 syntax errors
for i := 0; i < 5; i++ {
err = handler.ComQuery(conn2, "syntax error", dummyCb)
require.Error(t, err)
}

_, globalVal, ok = sql.StatusVariables.GetGlobal("Questions")
require.True(t, ok)
require.Equal(t, int64(10), globalVal)

sessVal, err = sess1.GetStatusVariable(nil, "Questions")
require.NoError(t, err)
require.Equal(t, int64(5), sessVal)

// Errors also increment Questions (it's 2x on Windows for some reason)
sessVal, err = sess2.GetStatusVariable(nil, "Questions")
require.NoError(t, err)
require.Equal(t, int64(5), sessVal)

conn3 := newConn(3)
handler.NewConnection(conn3)
err = handler.ComInitDB(conn3, "test")
require.NoError(t, err)
sess3 := handler.sm.sessions[3]

err = handler.ComQuery(conn3, "create procedure p() begin select 1; select 2; select 3; end", dummyCb)
require.NoError(t, err)

_, globalVal, ok = sql.StatusVariables.GetGlobal("Questions")
require.True(t, ok)
require.Equal(t, int64(11), globalVal)

sessVal, err = sess3.GetStatusVariable(nil, "Questions")
require.NoError(t, err)
require.Equal(t, int64(1), sessVal)

// Calling stored procedure with multiple queries only increment Questions once.
err = handler.ComQuery(conn3, "call p()", dummyCb)
require.NoError(t, err)

_, globalVal, ok = sql.StatusVariables.GetGlobal("Questions")
require.True(t, ok)
require.Equal(t, int64(12), globalVal)

sessVal, err = sess1.GetStatusVariable(nil, "Questions")
require.NoError(t, err)
require.Equal(t, int64(5), sessVal)

sessVal, err = sess2.GetStatusVariable(nil, "Questions")
require.NoError(t, err)
require.Equal(t, int64(5), sessVal)

sessVal, err = sess3.GetStatusVariable(nil, "Questions")
require.NoError(t, err)
require.Equal(t, int64(2), sessVal)

conn4 := newConn(4)
handler.NewConnection(conn4)
err = handler.ComInitDB(conn4, "test")
require.NoError(t, err)
sess4 := handler.sm.sessions[4]

// TODO: implement and test that ComPing does not increment Questions
// TODO: implement and test that ComStatistics does not increment Questions
// TODO: implement and test that ComStmtClose does not increment Questions
// TODO: implement and test that ComStmtReset does not increment Questions

// Prepare does not increment Questions
prepare := &mysql.PrepareData{
StatementID: 0,
PrepareStmt: "select ?",
ParamsCount: 0,
ParamsType: nil,
ColumnNames: nil,
BindVars: map[string]*query.BindVariable{
"v1": {Type: query.Type_INT8, Value: []byte("5")},
},
}

_, err = handler.ComPrepare(conn4, prepare.PrepareStmt, samplePrepareData)
require.NoError(t, err)

_, globalVal, ok = sql.StatusVariables.GetGlobal("Questions")
require.True(t, ok)
require.Equal(t, int64(12), globalVal)

sessVal, err = sess4.GetStatusVariable(nil, "Questions")
require.NoError(t, err)
require.Equal(t, int64(0), sessVal)

// Execute does increment Questions
err = handler.ComStmtExecute(conn4, prepare, func(*sqltypes.Result) error { return nil })
require.NoError(t, err)

_, globalVal, ok = sql.StatusVariables.GetGlobal("Questions")
require.True(t, ok)
require.Equal(t, int64(13), globalVal)

sessVal, err = sess4.GetStatusVariable(nil, "Questions")
require.NoError(t, err)
require.Equal(t, int64(1), sessVal)
}
5 changes: 4 additions & 1 deletion sql/variables/status_variables.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ func (g *globalStatusVariables) NewSessionMap() map[string]sql.StatusVarValue {
if v.Var.GetScope() == sql.StatusVariableScope_Global {
continue
}
sessionMap[k] = v
sessionMap[k] = sql.StatusVarValue{
Var: v.Var,
Val: v.Var.GetDefault(),
}
}
return sessionMap
}
Expand Down
4 changes: 2 additions & 2 deletions sql/variables/status_variables_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,11 @@ func TestStatusVariables(t *testing.T) {
require.True(ok)
require.Equal(int64(200), globalVal)

// New Session preserves values with Both scope
// New Session does not preserve values with Both scope
newSess := sql.NewBaseSessionWithClientServer("foo", sql.Client{Address: "baz2", User: "bar2"}, 2)
sessVal, err = newSess.GetStatusVariable(ctx, "Bytes_received")
require.NoError(err)
require.Equal(int64(200), sessVal)
require.Equal(int64(0), sessVal)

// New Session does not preserve values with Session scope
sessVal, err = newSess.GetStatusVariable(ctx, "Compression")
Expand Down

0 comments on commit 97f8899

Please sign in to comment.