surrealpatch/sql/parser.go

233 lines
4.9 KiB
Go
Raw Normal View History

2016-02-26 17:27:07 +00:00
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package sql
import (
2016-05-23 12:32:02 +00:00
"bytes"
2016-02-26 17:27:07 +00:00
"io"
"strings"
2016-05-23 12:32:02 +00:00
"github.com/abcum/fibre"
2016-02-26 17:27:07 +00:00
)
// parser represents a parser.
type parser struct {
s *scanner
2016-05-23 12:32:02 +00:00
c *fibre.Context
2016-09-07 15:44:23 +00:00
v map[string]interface{}
2016-02-26 17:27:07 +00:00
buf struct {
n int // buffer size
tok Token // last read token
lit string // last read literal
val interface{} // Last read value
2016-02-26 17:27:07 +00:00
}
}
// newParser returns a new instance of Parser.
func newParser(c *fibre.Context, v map[string]interface{}) *parser {
return &parser{c: c, v: v}
}
2016-05-23 12:32:02 +00:00
// Parse parses sql from a []byte, string, or io.Reader.
func Parse(c *fibre.Context, i interface{}, v map[string]interface{}) (*Query, error) {
switch x := i.(type) {
2016-05-23 12:32:02 +00:00
default:
return nil, &EmptyError{}
case []byte:
return parseBytes(c, x, v)
2016-05-23 12:32:02 +00:00
case string:
return parseString(c, x, v)
2016-05-23 12:32:02 +00:00
case io.Reader:
return parseBuffer(c, x, v)
2016-05-23 12:32:02 +00:00
}
}
// parseBytes parses a byte array.
func parseBytes(c *fibre.Context, i []byte, v map[string]interface{}) (*Query, error) {
2016-05-23 12:32:02 +00:00
r := bytes.NewReader(i)
p := newParser(c, v)
p.s = newScanner(p, r)
return p.parse()
2016-05-23 12:32:02 +00:00
}
// parseString parses a string.
func parseString(c *fibre.Context, i string, v map[string]interface{}) (*Query, error) {
r := strings.NewReader(i)
p := newParser(c, v)
p.s = newScanner(p, r)
return p.parse()
}
// parseBuffer parses a buffer.
func parseBuffer(c *fibre.Context, r io.Reader, v map[string]interface{}) (*Query, error) {
p := newParser(c, v)
p.s = newScanner(p, r)
return p.parse()
2016-02-26 17:27:07 +00:00
}
// parse parses single or multiple SQL queries.
func (p *parser) parse() (*Query, error) {
return p.parseMulti()
2016-02-26 17:27:07 +00:00
}
// parseMulti parses multiple SQL SELECT statements.
func (p *parser) parseMulti() (*Query, error) {
2016-02-26 17:27:07 +00:00
var statements Statements
2016-02-27 12:05:35 +00:00
2016-02-26 17:27:07 +00:00
var semi bool
2016-02-27 12:05:35 +00:00
var text bool
2016-02-26 17:27:07 +00:00
for {
if tok, _, _ := p.scan(); tok == EOF {
2016-02-27 12:05:35 +00:00
if !text {
return nil, &EmptyError{}
}
2016-02-26 17:27:07 +00:00
return &Query{Statements: statements}, nil
} else if !semi && tok == SEMICOLON {
semi = true
} else {
2016-02-27 12:05:35 +00:00
text = true
2016-02-26 17:27:07 +00:00
p.unscan()
s, err := p.parseSingle()
2016-02-26 17:27:07 +00:00
if err != nil {
return nil, err
}
statements = append(statements, s)
semi = false
}
}
}
// parseSingle parses a single SQL SELECT statement.
func (p *parser) parseSingle() (Statement, error) {
2016-02-26 17:27:07 +00:00
2016-10-14 06:54:26 +00:00
tok, _, err := p.shouldBe(USE, INFO, LET, BEGIN, CANCEL, COMMIT, ROLLBACK, SELECT, CREATE, UPDATE, INSERT, UPSERT, MODIFY, DELETE, RELATE, DEFINE, REMOVE)
2016-02-26 17:27:07 +00:00
switch tok {
2016-05-23 12:32:02 +00:00
case USE:
2016-09-20 23:34:21 +00:00
return p.parseUseStatement()
2016-05-23 12:32:02 +00:00
2016-09-19 10:08:44 +00:00
case INFO:
2016-09-20 23:34:21 +00:00
return p.parseInfoStatement()
2016-09-19 10:08:44 +00:00
2016-09-06 13:30:59 +00:00
case BEGIN:
2016-09-20 23:34:21 +00:00
return p.parseBeginStatement()
2016-09-06 13:30:59 +00:00
case CANCEL, ROLLBACK:
2016-09-20 23:34:21 +00:00
return p.parseCancelStatement()
2016-09-06 13:30:59 +00:00
case COMMIT:
2016-09-20 23:34:21 +00:00
return p.parseCommitStatement()
2016-09-06 13:30:59 +00:00
2016-02-26 17:27:07 +00:00
case SELECT:
2016-09-20 23:34:21 +00:00
return p.parseSelectStatement()
2016-05-23 12:32:02 +00:00
case CREATE, INSERT:
2016-09-20 23:34:21 +00:00
return p.parseCreateStatement()
2016-05-23 12:32:02 +00:00
case UPDATE, UPSERT:
2016-09-20 23:34:21 +00:00
return p.parseUpdateStatement()
2016-02-26 17:27:07 +00:00
case MODIFY:
2016-09-20 23:34:21 +00:00
return p.parseModifyStatement()
2016-02-26 17:27:07 +00:00
case DELETE:
2016-09-20 23:34:21 +00:00
return p.parseDeleteStatement()
2016-02-26 17:27:07 +00:00
case RELATE:
2016-09-20 23:34:21 +00:00
return p.parseRelateStatement()
2016-02-26 17:27:07 +00:00
case DEFINE:
2016-09-20 23:34:21 +00:00
return p.parseDefineStatement()
2016-02-26 17:27:07 +00:00
case REMOVE:
2016-09-20 23:34:21 +00:00
return p.parseRemoveStatement()
2016-02-26 17:27:07 +00:00
default:
2016-05-23 12:32:02 +00:00
return nil, err
2016-02-26 17:27:07 +00:00
}
}
func (p *parser) mightBe(expected ...Token) (tok Token, lit string, found bool) {
2016-02-26 17:27:07 +00:00
tok, lit, _ = p.scan()
2016-02-26 17:27:07 +00:00
if found = p.in(tok, expected); !found {
2016-02-26 17:27:07 +00:00
p.unscan()
}
return
}
func (p *parser) shouldBe(expected ...Token) (tok Token, lit string, err error) {
2016-02-26 17:27:07 +00:00
tok, lit, _ = p.scan()
2016-02-26 17:27:07 +00:00
if found := p.in(tok, expected); !found {
2016-02-26 17:27:07 +00:00
p.unscan()
err = &ParseError{Found: lit, Expected: lookup(expected)}
}
return
}
// scan scans the next non-whitespace token.
func (p *parser) scan() (tok Token, lit string, val interface{}) {
tok, lit, val = p.seek()
for {
if tok == WS {
tok, lit, val = p.seek()
} else {
break
}
}
return
}
func (p *parser) hold(tok Token) (val interface{}) {
if tok == p.buf.tok {
return p.buf.val
}
return nil
}
// seek returns the next token from the underlying scanner.
2016-02-26 17:27:07 +00:00
// If a token has been unscanned then read that instead.
func (p *parser) seek() (tok Token, lit string, val interface{}) {
2016-02-26 17:27:07 +00:00
// If we have a token on the buffer, then return it.
if p.buf.n != 0 {
p.buf.n = 0
return p.buf.tok, p.buf.lit, p.buf.val
2016-02-26 17:27:07 +00:00
}
// Otherwise read the next token from the scanner.
tok, lit, val = p.s.scan()
2016-02-26 17:27:07 +00:00
// Save it to the buffer in case we unscan later.
p.buf.tok, p.buf.lit, p.buf.val = tok, lit, val
2016-02-26 17:27:07 +00:00
return
2016-02-26 17:27:07 +00:00
}
// unscan pushes the previously read token back onto the buffer.
func (p *parser) unscan() {
p.buf.n = 1
2016-02-26 17:27:07 +00:00
}