Skip to content

Commit

Permalink
incorporated first set of feedback on backend /api/vexplain
Browse files Browse the repository at this point in the history
Signed-off-by: c-r-dev <[email protected]>
  • Loading branch information
c-r-dev committed Jan 19, 2025
1 parent 4099f0e commit a79c71f
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 89 deletions.
29 changes: 4 additions & 25 deletions go/vt/vtadmin/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -2661,33 +2661,12 @@ func (api *API) VExplain(ctx context.Context, req *vtadminpb.VExplainRequest) (*
return nil, vterrors.VT09017("Invalid VExplain statement")
}

var (
response *vtadminpb.VExplainResponse
wg sync.WaitGroup
er concurrency.AllErrorRecorder
m sync.Mutex
)

wg.Add(1)
response, err := c.GetVExplain(ctx, req, stmt.(*sqlparser.VExplainStmt))

go func(c *cluster.Cluster) {
defer wg.Done()
resp, err := c.GetVExplain(ctx, req, stmt.(*sqlparser.VExplainStmt))

if err != nil {
er.RecordError(err)
return
}
m.Lock()
response = resp
m.Unlock()
}(c)

wg.Wait()

if er.HasErrors() {
return nil, er.Error()
if err != nil {
return nil, err
}

return response, nil
}

Expand Down
61 changes: 1 addition & 60 deletions go/vt/vtadmin/cluster/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ limitations under the License.
package cluster

import (
"bytes"
"context"
"database/sql"
"encoding/json"
Expand All @@ -28,7 +27,6 @@ import (
"sort"
"strings"
"sync"
"text/tabwriter"
"text/template"
"time"

Expand Down Expand Up @@ -2524,64 +2522,7 @@ func (c *Cluster) GetVExplain(ctx context.Context, req *vtadminpb.VExplainReques
}

func (c *Cluster) getVExplain(ctx context.Context, query string, vexplainStmt *sqlparser.VExplainStmt) (*vtadminpb.VExplainResponse, error) {
rows, err := c.DB.VExplain(ctx, query)
if err != nil {
return nil, err
}
switch vexplainStmt.Type {
case sqlparser.QueriesVExplainType:
return convertVExplainQueriesResultToString(rows)
case sqlparser.AllVExplainType, sqlparser.TraceVExplainType, sqlparser.PlanVExplainType:
return convertVExplainResultToString(rows)
default:
return nil, nil
}
}

func convertVExplainResultToString(rows *sql.Rows) (*vtadminpb.VExplainResponse, error) {
var queryPlan string
for rows.Next() {
if err := rows.Scan(&queryPlan); err != nil {
return nil, err
}
}
return &vtadminpb.VExplainResponse{
Response: queryPlan,
}, nil
}

func convertVExplainQueriesResultToString(rows *sql.Rows) (*vtadminpb.VExplainResponse, error) {

var buf bytes.Buffer
w := tabwriter.NewWriter(&buf, 0, 0, 0, ' ', tabwriter.AlignRight)

sep := []byte("|")
newLine := []byte("\n")
cols, _ := rows.Columns()

if _, err := w.Write([]byte(strings.Join(cols, string(sep)) + string(newLine))); err != nil {
return nil, err
}

row := make([][]byte, len(cols))
rowPtr := make([]any, len(cols))
for i := range row {
rowPtr[i] = &row[i]
}

for rows.Next() {
if err := rows.Scan(rowPtr...); err != nil {
return nil, err
}
if _, err := w.Write(append(bytes.Join(row, sep), newLine...)); err != nil {
return nil, err
}
}
w.Flush()

return &vtadminpb.VExplainResponse{
Response: buf.String(),
}, nil
return c.DB.VExplain(ctx, query, vexplainStmt)
}

// Debug returns a map of debug information for a cluster.
Expand Down
68 changes: 64 additions & 4 deletions go/vt/vtadmin/vtsql/vtsql.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@ limitations under the License.
package vtsql

import (
"bytes"
"context"
"database/sql"
"fmt"
"strings"
"sync"
"text/tabwriter"
"time"

"google.golang.org/grpc/credentials/insecure"
Expand All @@ -31,6 +34,7 @@ import (
"vitess.io/vitess/go/trace"
"vitess.io/vitess/go/vt/callerid"
"vitess.io/vitess/go/vt/log"
"vitess.io/vitess/go/vt/sqlparser"
"vitess.io/vitess/go/vt/vitessdriver"
"vitess.io/vitess/go/vt/vtadmin/cluster/resolver"
"vitess.io/vitess/go/vt/vtadmin/debug"
Expand All @@ -45,8 +49,8 @@ type DB interface {
// ShowTablets executes `SHOW vitess_tablets` and returns the result.
ShowTablets(ctx context.Context) (*sql.Rows, error)

// VExplain executes query - `vexplain [ALL|PLAN|QUERIES] query` and returns the results
VExplain(ctx context.Context, query string) (*sql.Rows, error)
// VExplain executes query - `vexplain [ALL|PLAN|QUERIES|TRACE|KEYS] query` and returns the results
VExplain(ctx context.Context, query string, vexplainStmt *sqlparser.VExplainStmt) (*vtadminpb.VExplainResponse, error)

// Ping behaves like (*sql.DB).Ping.
Ping() error
Expand Down Expand Up @@ -178,13 +182,69 @@ func (vtgate *VTGateProxy) ShowTablets(ctx context.Context) (*sql.Rows, error) {
}

// VExplain is part of the DB interface.
func (vtgate *VTGateProxy) VExplain(ctx context.Context, query string) (*sql.Rows, error) {
func (vtgate *VTGateProxy) VExplain(ctx context.Context, query string, vexplainStmt *sqlparser.VExplainStmt) (*vtadminpb.VExplainResponse, error) {
span, ctx := trace.NewSpan(ctx, "VTGateProxy.VExplain")
defer span.Finish()

vtadminproto.AnnotateClusterSpan(vtgate.cluster, span)

return vtgate.conn.QueryContext(vtgate.getQueryContext(ctx), query)
rows, err := vtgate.conn.QueryContext(vtgate.getQueryContext(ctx), query)

if err != nil {
return nil, err
}
switch vexplainStmt.Type {
case sqlparser.QueriesVExplainType:
return convertVExplainQueriesResultToString(rows)
case sqlparser.AllVExplainType, sqlparser.TraceVExplainType, sqlparser.PlanVExplainType, sqlparser.KeysVExplainType:
return convertVExplainResultToString(rows)
default:
return nil, nil
}
}
func convertVExplainResultToString(rows *sql.Rows) (*vtadminpb.VExplainResponse, error) {
var queryPlan string
for rows.Next() {
if err := rows.Scan(&queryPlan); err != nil {
return nil, err
}
}
return &vtadminpb.VExplainResponse{
Response: queryPlan,
}, nil
}

func convertVExplainQueriesResultToString(rows *sql.Rows) (*vtadminpb.VExplainResponse, error) {
var buf bytes.Buffer
w := tabwriter.NewWriter(&buf, 0, 0, 0, ' ', tabwriter.AlignRight)

sep := []byte("|")
newLine := []byte("\n")
cols, _ := rows.Columns()

if _, err := w.Write([]byte(strings.Join(cols, string(sep)) + string(newLine))); err != nil {
return nil, err
}

row := make([][]byte, len(cols))
rowPtr := make([]any, len(cols))
for i := range row {
rowPtr[i] = &row[i]
}

for rows.Next() {
if err := rows.Scan(rowPtr...); err != nil {
return nil, err
}
if _, err := w.Write(append(bytes.Join(row, sep), newLine...)); err != nil {
return nil, err
}
}
w.Flush()

return &vtadminpb.VExplainResponse{
Response: buf.String(),
}, nil
}

// Ping is part of the DB interface.
Expand Down

0 comments on commit a79c71f

Please sign in to comment.