forked from src-d/go-mysql-server
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathengine.go
122 lines (101 loc) · 2.93 KB
/
engine.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package sqle // import "gopkg.in/src-d/go-mysql-server.v0"
import (
opentracing "github.com/opentracing/opentracing-go"
"github.com/sirupsen/logrus"
"gopkg.in/src-d/go-mysql-server.v0/auth"
"gopkg.in/src-d/go-mysql-server.v0/sql"
"gopkg.in/src-d/go-mysql-server.v0/sql/analyzer"
"gopkg.in/src-d/go-mysql-server.v0/sql/expression/function"
"gopkg.in/src-d/go-mysql-server.v0/sql/parse"
"gopkg.in/src-d/go-mysql-server.v0/sql/plan"
)
// Config for the Engine.
type Config struct {
// VersionPostfix to display with the `VERSION()` UDF.
VersionPostfix string
// Auth used for authentication and authorization.
Auth auth.Auth
}
// Engine is a SQL engine.
type Engine struct {
Catalog *sql.Catalog
Analyzer *analyzer.Analyzer
Auth auth.Auth
}
// New creates a new Engine with custom configuration. To create an Engine with
// the default settings use `NewDefault`.
func New(c *sql.Catalog, a *analyzer.Analyzer, cfg *Config) *Engine {
var versionPostfix string
if cfg != nil {
versionPostfix = cfg.VersionPostfix
}
c.RegisterFunctions(function.Defaults)
c.RegisterFunction("version", sql.FunctionN(function.NewVersion(versionPostfix)))
c.RegisterFunction("database", sql.Function0(function.NewDatabase(c)))
// use auth.None if auth is not specified
var au auth.Auth
if cfg == nil || cfg.Auth == nil {
au = new(auth.None)
} else {
au = cfg.Auth
}
return &Engine{c, a, au}
}
// NewDefault creates a new default Engine.
func NewDefault() *Engine {
c := sql.NewCatalog()
a := analyzer.NewDefault(c)
return New(c, a, nil)
}
// Query executes a query.
func (e *Engine) Query(
ctx *sql.Context,
query string,
) (sql.Schema, sql.RowIter, error) {
span, ctx := ctx.Span("query", opentracing.Tag{Key: "query", Value: query})
defer span.Finish()
logrus.WithField("query", query).Debug("executing query")
parsed, err := parse.Parse(ctx, query)
if err != nil {
return nil, nil, err
}
var perm = auth.ReadPerm
var typ = sql.QueryProcess
switch parsed.(type) {
case *plan.CreateIndex:
typ = sql.CreateIndexProcess
perm = auth.ReadPerm | auth.WritePerm
case *plan.InsertInto, *plan.DropIndex, *plan.UnlockTables, *plan.LockTables:
perm = auth.ReadPerm | auth.WritePerm
}
err = e.Auth.Allowed(ctx, perm)
if err != nil {
return nil, nil, err
}
ctx, err = e.Catalog.AddProcess(ctx, typ, query)
defer func() {
if err != nil && ctx != nil {
e.Catalog.Done(ctx.Pid())
}
}()
if err != nil {
return nil, nil, err
}
analyzed, err := e.Analyzer.Analyze(ctx, parsed)
if err != nil {
return nil, nil, err
}
iter, err := analyzed.RowIter(ctx)
if err != nil {
return nil, nil, err
}
return analyzed.Schema(), iter, nil
}
// AddDatabase adds the given database to the catalog.
func (e *Engine) AddDatabase(db sql.Database) {
e.Catalog.AddDatabase(db)
}
// Init performs all the initialization requirements for the engine to work.
func (e *Engine) Init() error {
return e.Catalog.LoadIndexes(e.Catalog.AllDatabases())
}