featurebase/sql/show.go
Garrison Davis 0f5a56c958 Stop using string keys in contexts
This fixes the OriginalIP and RequestUserID in the main featurebase
package, and the Access and Refresh tokens, the UserInfo, and the
[]string of Indexes passed with context.Context(s) in the authn package.

An empty struct was used for all of these keys (and relevant helper
functions we added) to avoid allocations where possible while still
using the context functionality.

Some of the logic in the server.GetIndexes function was fixed.
2022-11-04 15:01:40 -06:00

136 lines
3.3 KiB
Go

// Copyright 2021 Molecula Corp. All rights reserved.
package sql
import (
"context"
"fmt"
pilosa "github.com/molecula/featurebase/v3"
"github.com/molecula/featurebase/v3/authn"
pproto "github.com/molecula/featurebase/v3/proto"
"github.com/pkg/errors"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"vitess.io/vitess/go/vt/sqlparser"
)
// ShowHandler executes SQL show table/field statements
type ShowHandler struct {
api *pilosa.API
}
// NewShowHandler constructor
func NewShowHandler(api *pilosa.API) *ShowHandler {
return &ShowHandler{
api: api,
}
}
// Handle executes mapped SQL
func (s *ShowHandler) Handle(ctx context.Context, mapped *MappedSQL) (pproto.ToRowser, error) {
stmt, ok := mapped.Statement.(*sqlparser.Show)
if !ok {
return nil, fmt.Errorf("statement is not type show: %T", mapped.Statement)
}
switch stmt.Type {
case "tables":
return s.execShowTables(ctx, stmt)
case "fields":
return s.execShowFields(ctx, stmt)
default:
return nil, fmt.Errorf("cannot show: %s", stmt.Type)
}
}
func (s *ShowHandler) execShowTables(ctx context.Context, showStmt *sqlparser.Show) (pproto.ToRowser, error) {
indexInfo, err := s.api.Schema(ctx, false)
if err != nil {
return nil, errors.Wrap(err, "getting schema")
}
allowed, ok := authn.GetIndexes(ctx)
result := make(pproto.ConstRowser, 0)
for _, ii := range indexInfo {
if ok {
// if authorization is turned on, allowed will be a list
// so we have to check if the index is in the allowed list
found := false
for _, idx := range allowed {
if ii.Name == idx {
found = true
break
}
}
if !found {
continue
}
}
result = append(result, pproto.RowResponse{
Headers: []*pproto.ColumnInfo{
{Name: "Table", Datatype: "string"},
},
Columns: []*pproto.ColumnResponse{
{ColumnVal: &pproto.ColumnResponse_StringVal{StringVal: ii.Name}},
},
})
}
// Sort the result.
return OrderBy(result, []string{"Table"}, []string{"asc"}), nil
}
func (s *ShowHandler) execShowFields(ctx context.Context, showStmt *sqlparser.Show) (pproto.ToRowser, error) {
indexName := showStmt.OnTable.ToViewName().Name.String()
allowed, ok := authn.GetIndexes(ctx)
if ok {
found := false
for _, idx := range allowed {
if idx == indexName {
found = true
break
}
}
if !found {
return nil, status.Error(codes.PermissionDenied, "insufficient permissions to access requested tables")
}
}
index, err := s.api.Index(ctx, indexName)
if err != nil {
return nil, errors.Wrap(err, "getting schema")
}
if index == nil {
return nil, errors.WithMessage(pilosa.ErrIndexNotFound, indexName)
}
fields := index.Fields()
result := make(pproto.ConstRowser, 0, len(fields))
for _, f := range fields {
if f.Name() == "_exists" {
continue
}
typeName := f.Type()
if f.Keys() {
typeName = "keyed-" + typeName
}
if f.ForeignIndex() != "" {
typeName = "foreign-" + typeName
}
result = append(result, pproto.RowResponse{
Headers: []*pproto.ColumnInfo{
{Name: "Field", Datatype: "string"},
{Name: "Type", Datatype: "string"},
},
Columns: []*pproto.ColumnResponse{
{ColumnVal: &pproto.ColumnResponse_StringVal{StringVal: f.Name()}},
{ColumnVal: &pproto.ColumnResponse_StringVal{StringVal: typeName}},
},
})
}
// Sort the result.
return OrderBy(result, []string{"Field"}, []string{"asc"}), nil
}