mirror of
https://github.com/Oxalide/vsphere-influxdb-go.git
synced 2023-10-10 11:36:51 +00:00
add vendoring with go dep
This commit is contained in:
158
vendor/github.com/influxdata/influxdb/stress/v2/stressql/parser.go
generated
vendored
Normal file
158
vendor/github.com/influxdata/influxdb/stress/v2/stressql/parser.go
generated
vendored
Normal file
@@ -0,0 +1,158 @@
|
||||
package stressql
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/influxdata/influxdb/influxql"
|
||||
"github.com/influxdata/influxdb/stress/v2/statement"
|
||||
stressql "github.com/influxdata/influxdb/stress/v2/stressql/statement"
|
||||
)
|
||||
|
||||
// Token represents a lexical token.
|
||||
type Token int
|
||||
|
||||
// These are the lexical tokens used by the file parser
|
||||
const (
|
||||
ILLEGAL Token = iota
|
||||
EOF
|
||||
STATEMENT
|
||||
BREAK
|
||||
)
|
||||
|
||||
var eof = rune(0)
|
||||
|
||||
func check(e error) {
|
||||
if e != nil {
|
||||
log.Fatal(e)
|
||||
}
|
||||
}
|
||||
|
||||
func isNewline(r rune) bool {
|
||||
return r == '\n'
|
||||
}
|
||||
|
||||
// Scanner scans the file and tokenizes the raw text
|
||||
type Scanner struct {
|
||||
r *bufio.Reader
|
||||
}
|
||||
|
||||
// NewScanner returns a Scanner
|
||||
func NewScanner(r io.Reader) *Scanner {
|
||||
return &Scanner{r: bufio.NewReader(r)}
|
||||
}
|
||||
|
||||
func (s *Scanner) read() rune {
|
||||
ch, _, err := s.r.ReadRune()
|
||||
if err != nil {
|
||||
return eof
|
||||
}
|
||||
return ch
|
||||
}
|
||||
|
||||
func (s *Scanner) unread() { _ = s.r.UnreadRune() }
|
||||
|
||||
func (s *Scanner) peek() rune {
|
||||
ch := s.read()
|
||||
s.unread()
|
||||
return ch
|
||||
}
|
||||
|
||||
// Scan moves the Scanner forward one character
|
||||
func (s *Scanner) Scan() (tok Token, lit string) {
|
||||
ch := s.read()
|
||||
|
||||
if isNewline(ch) {
|
||||
s.unread()
|
||||
return s.scanNewlines()
|
||||
} else if ch == eof {
|
||||
return EOF, ""
|
||||
} else {
|
||||
s.unread()
|
||||
return s.scanStatements()
|
||||
}
|
||||
// golint marks as unreachable code
|
||||
// return ILLEGAL, string(ch)
|
||||
}
|
||||
|
||||
func (s *Scanner) scanNewlines() (tok Token, lit string) {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteRune(s.read())
|
||||
|
||||
for {
|
||||
if ch := s.read(); ch == eof {
|
||||
break
|
||||
} else if !isNewline(ch) {
|
||||
s.unread()
|
||||
break
|
||||
} else {
|
||||
buf.WriteRune(ch)
|
||||
}
|
||||
}
|
||||
|
||||
return BREAK, buf.String()
|
||||
}
|
||||
|
||||
func (s *Scanner) scanStatements() (tok Token, lit string) {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteRune(s.read())
|
||||
|
||||
for {
|
||||
if ch := s.read(); ch == eof {
|
||||
break
|
||||
} else if isNewline(ch) && isNewline(s.peek()) {
|
||||
s.unread()
|
||||
break
|
||||
} else if isNewline(ch) {
|
||||
s.unread()
|
||||
buf.WriteRune(ch)
|
||||
} else {
|
||||
buf.WriteRune(ch)
|
||||
}
|
||||
}
|
||||
|
||||
return STATEMENT, buf.String()
|
||||
}
|
||||
|
||||
// ParseStatements takes a configFile and returns a slice of Statements
|
||||
func ParseStatements(file string) ([]statement.Statement, error) {
|
||||
seq := []statement.Statement{}
|
||||
|
||||
f, err := os.Open(file)
|
||||
check(err)
|
||||
|
||||
s := NewScanner(f)
|
||||
|
||||
for {
|
||||
t, l := s.Scan()
|
||||
|
||||
if t == EOF {
|
||||
break
|
||||
}
|
||||
_, err := influxql.ParseStatement(l)
|
||||
if err == nil {
|
||||
|
||||
seq = append(seq, &statement.InfluxqlStatement{Query: l, StatementID: stressql.RandStr(10)})
|
||||
} else if t == BREAK {
|
||||
continue
|
||||
} else {
|
||||
f := strings.NewReader(l)
|
||||
p := stressql.NewParser(f)
|
||||
s, err := p.Parse()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
seq = append(seq, s)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
f.Close()
|
||||
|
||||
return seq, nil
|
||||
|
||||
}
|
16
vendor/github.com/influxdata/influxdb/stress/v2/stressql/parser_test.go
generated
vendored
Normal file
16
vendor/github.com/influxdata/influxdb/stress/v2/stressql/parser_test.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
package stressql
|
||||
|
||||
import "testing"
|
||||
|
||||
// Pulls the default configFile and makes sure it parses
|
||||
func TestParseStatements(t *testing.T) {
|
||||
stmts, err := ParseStatements("../iql/file.iql")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
expected := 15
|
||||
got := len(stmts)
|
||||
if expected != got {
|
||||
t.Errorf("expected: %v\ngot: %v\n", expected, got)
|
||||
}
|
||||
}
|
682
vendor/github.com/influxdata/influxdb/stress/v2/stressql/statement/parser.go
generated
vendored
Normal file
682
vendor/github.com/influxdata/influxdb/stress/v2/stressql/statement/parser.go
generated
vendored
Normal file
@@ -0,0 +1,682 @@
|
||||
package statement
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/influxdata/influxdb/stress/v2/statement"
|
||||
)
|
||||
|
||||
// Token represents a lexical token.
|
||||
type Token int
|
||||
|
||||
// The following tokens represent the different values in the AST that make up stressql
|
||||
const (
|
||||
ILLEGAL Token = iota
|
||||
EOF
|
||||
|
||||
WS
|
||||
|
||||
literalBeg
|
||||
// IDENT and the following are InfluxQL literal tokens.
|
||||
IDENT // main
|
||||
NUMBER // 12345.67
|
||||
DURATIONVAL // 13h
|
||||
STRING // "abc"
|
||||
BADSTRING // "abc
|
||||
TEMPLATEVAR // %f
|
||||
literalEnd
|
||||
|
||||
COMMA // ,
|
||||
LPAREN // (
|
||||
RPAREN // )
|
||||
LBRACKET // [
|
||||
RBRACKET // ]
|
||||
PIPE // |
|
||||
PERIOD // .
|
||||
|
||||
keywordBeg
|
||||
SET
|
||||
USE
|
||||
QUERY
|
||||
INSERT
|
||||
GO
|
||||
DO
|
||||
WAIT
|
||||
STR
|
||||
INT
|
||||
FLOAT
|
||||
EXEC
|
||||
keywordEnd
|
||||
)
|
||||
|
||||
var eof = rune(1)
|
||||
|
||||
func isWhitespace(ch rune) bool { return ch == ' ' || ch == '\t' || ch == '\n' }
|
||||
|
||||
func isDigit(r rune) bool {
|
||||
return r >= '0' && r <= '9'
|
||||
}
|
||||
|
||||
func isLetter(ch rune) bool {
|
||||
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '@')
|
||||
}
|
||||
|
||||
// Scanner scans over the file and converts the raw text into tokens
|
||||
type Scanner struct {
|
||||
r *bufio.Reader
|
||||
}
|
||||
|
||||
// NewScanner returns a Scanner
|
||||
func NewScanner(r io.Reader) *Scanner {
|
||||
return &Scanner{r: bufio.NewReader(r)}
|
||||
}
|
||||
|
||||
func (s *Scanner) read() rune {
|
||||
ch, _, err := s.r.ReadRune()
|
||||
if err != nil {
|
||||
return eof
|
||||
}
|
||||
return ch
|
||||
}
|
||||
|
||||
func (s *Scanner) unread() { _ = s.r.UnreadRune() }
|
||||
|
||||
// Scan moves to the next character in the file and returns a tokenized version as well as the literal
|
||||
func (s *Scanner) Scan() (tok Token, lit string) {
|
||||
ch := s.read()
|
||||
|
||||
if isWhitespace(ch) {
|
||||
s.unread()
|
||||
return s.scanWhitespace()
|
||||
} else if isLetter(ch) {
|
||||
s.unread()
|
||||
return s.scanIdent()
|
||||
} else if isDigit(ch) {
|
||||
s.unread()
|
||||
return s.scanNumber()
|
||||
}
|
||||
|
||||
switch ch {
|
||||
case eof:
|
||||
return EOF, ""
|
||||
case '"':
|
||||
s.unread()
|
||||
return s.scanIdent()
|
||||
case '%':
|
||||
s.unread()
|
||||
return s.scanTemplateVar()
|
||||
case ',':
|
||||
return COMMA, ","
|
||||
case '.':
|
||||
return PERIOD, "."
|
||||
case '(':
|
||||
return LPAREN, "("
|
||||
case ')':
|
||||
return RPAREN, ")"
|
||||
case '[':
|
||||
return LBRACKET, "["
|
||||
case ']':
|
||||
return RBRACKET, "]"
|
||||
case '|':
|
||||
return PIPE, "|"
|
||||
}
|
||||
|
||||
return ILLEGAL, string(ch)
|
||||
}
|
||||
|
||||
func (s *Scanner) scanWhitespace() (tok Token, lit string) {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteRune(s.read())
|
||||
|
||||
for {
|
||||
if ch := s.read(); ch == eof {
|
||||
break
|
||||
} else if !isWhitespace(ch) {
|
||||
s.unread()
|
||||
break
|
||||
} else {
|
||||
buf.WriteRune(ch)
|
||||
}
|
||||
}
|
||||
|
||||
return WS, buf.String()
|
||||
}
|
||||
|
||||
func (s *Scanner) scanIdent() (tok Token, lit string) {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteRune(s.read())
|
||||
|
||||
for {
|
||||
if ch := s.read(); ch == eof {
|
||||
break
|
||||
} else if !isLetter(ch) && !isDigit(ch) && ch != '_' && ch != ':' && ch != '=' && ch != '-' {
|
||||
s.unread()
|
||||
break
|
||||
} else {
|
||||
_, _ = buf.WriteRune(ch)
|
||||
}
|
||||
}
|
||||
|
||||
switch strings.ToUpper(buf.String()) {
|
||||
case "SET":
|
||||
return SET, buf.String()
|
||||
case "USE":
|
||||
return USE, buf.String()
|
||||
case "QUERY":
|
||||
return QUERY, buf.String()
|
||||
case "INSERT":
|
||||
return INSERT, buf.String()
|
||||
case "EXEC":
|
||||
return EXEC, buf.String()
|
||||
case "WAIT":
|
||||
return WAIT, buf.String()
|
||||
case "GO":
|
||||
return GO, buf.String()
|
||||
case "DO":
|
||||
return DO, buf.String()
|
||||
case "STR":
|
||||
return STR, buf.String()
|
||||
case "FLOAT":
|
||||
return FLOAT, buf.String()
|
||||
case "INT":
|
||||
return INT, buf.String()
|
||||
}
|
||||
|
||||
return IDENT, buf.String()
|
||||
}
|
||||
|
||||
func (s *Scanner) scanTemplateVar() (tok Token, lit string) {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteRune(s.read())
|
||||
buf.WriteRune(s.read())
|
||||
|
||||
return TEMPLATEVAR, buf.String()
|
||||
}
|
||||
|
||||
func (s *Scanner) scanNumber() (tok Token, lit string) {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteRune(s.read())
|
||||
|
||||
for {
|
||||
if ch := s.read(); ch == eof {
|
||||
break
|
||||
} else if ch == 'n' || ch == 's' || ch == 'm' {
|
||||
_, _ = buf.WriteRune(ch)
|
||||
return DURATIONVAL, buf.String()
|
||||
} else if !isDigit(ch) {
|
||||
s.unread()
|
||||
break
|
||||
} else {
|
||||
_, _ = buf.WriteRune(ch)
|
||||
}
|
||||
}
|
||||
|
||||
return NUMBER, buf.String()
|
||||
}
|
||||
|
||||
/////////////////////////////////
|
||||
// PARSER ///////////////////////
|
||||
/////////////////////////////////
|
||||
|
||||
// Parser turns the file from raw text into an AST
|
||||
type Parser struct {
|
||||
s *Scanner
|
||||
buf struct {
|
||||
tok Token
|
||||
lit string
|
||||
n int
|
||||
}
|
||||
}
|
||||
|
||||
// NewParser creates a new Parser
|
||||
func NewParser(r io.Reader) *Parser {
|
||||
return &Parser{s: NewScanner(r)}
|
||||
}
|
||||
|
||||
// Parse returns a Statement
|
||||
func (p *Parser) Parse() (statement.Statement, error) {
|
||||
tok, lit := p.scanIgnoreWhitespace()
|
||||
|
||||
switch tok {
|
||||
case QUERY:
|
||||
p.unscan()
|
||||
return p.ParseQueryStatement()
|
||||
case INSERT:
|
||||
p.unscan()
|
||||
return p.ParseInsertStatement()
|
||||
case EXEC:
|
||||
p.unscan()
|
||||
return p.ParseExecStatement()
|
||||
case SET:
|
||||
p.unscan()
|
||||
return p.ParseSetStatement()
|
||||
case GO:
|
||||
p.unscan()
|
||||
return p.ParseGoStatement()
|
||||
case WAIT:
|
||||
p.unscan()
|
||||
return p.ParseWaitStatement()
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("Improper syntax\n unknown token found between statements, token: %v\n", lit)
|
||||
}
|
||||
|
||||
// ParseQueryStatement returns a QueryStatement
|
||||
func (p *Parser) ParseQueryStatement() (*statement.QueryStatement, error) {
|
||||
stmt := &statement.QueryStatement{
|
||||
StatementID: RandStr(10),
|
||||
}
|
||||
if tok, lit := p.scanIgnoreWhitespace(); tok != QUERY {
|
||||
return nil, fmt.Errorf("Error parsing Query Statement\n Expected: QUERY\n Found: %v\n", lit)
|
||||
}
|
||||
|
||||
tok, lit := p.scanIgnoreWhitespace()
|
||||
if tok != IDENT {
|
||||
return nil, fmt.Errorf("Error parsing Query Statement\n Expected: IDENT\n Found: %v\n", lit)
|
||||
}
|
||||
|
||||
stmt.Name = lit
|
||||
|
||||
for {
|
||||
tok, lit := p.scan()
|
||||
if tok == TEMPLATEVAR {
|
||||
stmt.TemplateString += "%v"
|
||||
stmt.Args = append(stmt.Args, lit)
|
||||
} else if tok == DO {
|
||||
tok, lit := p.scanIgnoreWhitespace()
|
||||
if tok != NUMBER {
|
||||
return nil, fmt.Errorf("Error parsing Query Statement\n Expected: NUMBER\n Found: %v\n", lit)
|
||||
}
|
||||
// Parse out the integer
|
||||
i, err := strconv.ParseInt(lit, 10, 64)
|
||||
if err != nil {
|
||||
log.Fatalf("Error parsing integer in Query Statement:\n string: %v\n error: %v\n", lit, err)
|
||||
}
|
||||
stmt.Count = int(i)
|
||||
break
|
||||
} else if tok == WS && lit == "\n" {
|
||||
continue
|
||||
} else {
|
||||
stmt.TemplateString += lit
|
||||
}
|
||||
}
|
||||
|
||||
return stmt, nil
|
||||
|
||||
}
|
||||
|
||||
// ParseInsertStatement returns a InsertStatement
|
||||
func (p *Parser) ParseInsertStatement() (*statement.InsertStatement, error) {
|
||||
|
||||
// Initialize the InsertStatement with a statementId
|
||||
stmt := &statement.InsertStatement{
|
||||
StatementID: RandStr(10),
|
||||
}
|
||||
|
||||
// If the first word is INSERT
|
||||
if tok, lit := p.scanIgnoreWhitespace(); tok != INSERT {
|
||||
return nil, fmt.Errorf("Error parsing Insert Statement\n Expected: INSERT\n Found: %v\n", lit)
|
||||
}
|
||||
|
||||
// Next should come the NAME of the statement. It is IDENT type
|
||||
tok, lit := p.scanIgnoreWhitespace()
|
||||
if tok != IDENT {
|
||||
return nil, fmt.Errorf("Error parsing Insert Statement\n Expected: IDENT\n Found: %v\n", lit)
|
||||
}
|
||||
|
||||
// Set the Name
|
||||
stmt.Name = lit
|
||||
|
||||
// Next char should be a newline
|
||||
tok, lit = p.scan()
|
||||
if tok != WS {
|
||||
return nil, fmt.Errorf("Error parsing Insert Statement\n Expected: WS\n Found: %v\n", lit)
|
||||
}
|
||||
|
||||
// We are now scanning the tags line
|
||||
var prev Token
|
||||
inTags := true
|
||||
|
||||
for {
|
||||
// Start for loop by scanning
|
||||
tok, lit = p.scan()
|
||||
|
||||
// If scaned is WS then we are just entering tags or leaving tags or fields
|
||||
if tok == WS {
|
||||
|
||||
// If previous is COMMA then we are leaving measurement, continue
|
||||
if prev == COMMA {
|
||||
continue
|
||||
}
|
||||
// Otherwise we need to add a space to the template string and we are out of tags
|
||||
stmt.TemplateString += " "
|
||||
inTags = false
|
||||
} else if tok == LBRACKET {
|
||||
// If we are still inTags and there is a LBRACKET we are adding another template
|
||||
if inTags {
|
||||
stmt.TagCount++
|
||||
}
|
||||
|
||||
// Add a space to fill template string with template result
|
||||
stmt.TemplateString += "%v"
|
||||
|
||||
// parse template should return a template type
|
||||
expr, err := p.ParseTemplate()
|
||||
|
||||
// If there is a Template parsing error return it
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Add template to parsed select statement
|
||||
stmt.Templates = append(stmt.Templates, expr)
|
||||
|
||||
// A number signifies that we are in the Timestamp section
|
||||
} else if tok == NUMBER {
|
||||
// Add a space to fill template string with timestamp
|
||||
stmt.TemplateString += "%v"
|
||||
p.unscan()
|
||||
|
||||
// Parse out the Timestamp
|
||||
ts, err := p.ParseTimestamp()
|
||||
|
||||
// If there is a Timestamp parsing error return it
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Set the Timestamp
|
||||
stmt.Timestamp = ts
|
||||
|
||||
// Break loop as InsertStatement ends
|
||||
break
|
||||
} else if tok != IDENT && tok != COMMA {
|
||||
return nil, fmt.Errorf("Error parsing Insert Statement\n Expected: IDENT or COMMA\n Found: %v\n", lit)
|
||||
} else {
|
||||
prev = tok
|
||||
stmt.TemplateString += lit
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return stmt, nil
|
||||
}
|
||||
|
||||
// ParseTemplate returns a Template
|
||||
func (p *Parser) ParseTemplate() (*statement.Template, error) {
|
||||
|
||||
// Blank template
|
||||
tmplt := &statement.Template{}
|
||||
|
||||
for {
|
||||
// Scan to start loop
|
||||
tok, lit := p.scanIgnoreWhitespace()
|
||||
|
||||
// If the tok == IDENT explicit tags are passed. Add them to the list of tags
|
||||
if tok == IDENT {
|
||||
tmplt.Tags = append(tmplt.Tags, lit)
|
||||
|
||||
// Different flavors of functions
|
||||
} else if tok == INT || tok == FLOAT || tok == STR {
|
||||
p.unscan()
|
||||
|
||||
// Parse out the function
|
||||
fn, err := p.ParseFunction()
|
||||
|
||||
// If there is a Function parsing error return it
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Set the Function on the Template
|
||||
tmplt.Function = fn
|
||||
|
||||
// End of Function
|
||||
} else if tok == RBRACKET {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return tmplt, nil
|
||||
}
|
||||
|
||||
// ParseExecStatement returns a ExecStatement
|
||||
func (p *Parser) ParseExecStatement() (*statement.ExecStatement, error) {
|
||||
// NEEDS TO PARSE ACTUAL PATH TO SCRIPT CURRENTLY ONLY DOES
|
||||
// IDENT SCRIPT NAMES
|
||||
|
||||
stmt := &statement.ExecStatement{
|
||||
StatementID: RandStr(10),
|
||||
}
|
||||
|
||||
if tok, lit := p.scanIgnoreWhitespace(); tok != EXEC {
|
||||
return nil, fmt.Errorf("Error parsing Exec Statement\n Expected: EXEC\n Found: %v\n", lit)
|
||||
}
|
||||
|
||||
tok, lit := p.scanIgnoreWhitespace()
|
||||
if tok != IDENT {
|
||||
return nil, fmt.Errorf("Error parsing Exec Statement\n Expected: IDENT\n Found: %v\n", lit)
|
||||
}
|
||||
|
||||
stmt.Script = lit
|
||||
|
||||
return stmt, nil
|
||||
}
|
||||
|
||||
// ParseSetStatement returns a SetStatement
|
||||
func (p *Parser) ParseSetStatement() (*statement.SetStatement, error) {
|
||||
|
||||
stmt := &statement.SetStatement{
|
||||
StatementID: RandStr(10),
|
||||
}
|
||||
|
||||
if tok, lit := p.scanIgnoreWhitespace(); tok != SET {
|
||||
return nil, fmt.Errorf("Error parsing Set Statement\n Expected: SET\n Found: %v\n", lit)
|
||||
}
|
||||
|
||||
tok, lit := p.scanIgnoreWhitespace()
|
||||
if tok != IDENT {
|
||||
return nil, fmt.Errorf("Error parsing Set Statement\n Expected: IDENT\n Found: %v\n", lit)
|
||||
}
|
||||
|
||||
stmt.Var = lit
|
||||
|
||||
tok, lit = p.scanIgnoreWhitespace()
|
||||
|
||||
if tok != LBRACKET {
|
||||
return nil, fmt.Errorf("Error parsing Set Statement\n Expected: RBRACKET\n Found: %v\n", lit)
|
||||
}
|
||||
|
||||
for {
|
||||
tok, lit = p.scanIgnoreWhitespace()
|
||||
if tok == RBRACKET {
|
||||
break
|
||||
} else if lit != "-" && lit != ":" && tok != IDENT && tok != NUMBER && tok != DURATIONVAL && tok != PERIOD && tok != PIPE {
|
||||
return nil, fmt.Errorf("Error parsing Set Statement\n Expected: IDENT || NUMBER || DURATION\n Found: %v\n", lit)
|
||||
}
|
||||
stmt.Value += lit
|
||||
}
|
||||
|
||||
return stmt, nil
|
||||
}
|
||||
|
||||
// ParseWaitStatement returns a WaitStatement
|
||||
func (p *Parser) ParseWaitStatement() (*statement.WaitStatement, error) {
|
||||
|
||||
stmt := &statement.WaitStatement{
|
||||
StatementID: RandStr(10),
|
||||
}
|
||||
|
||||
if tok, lit := p.scanIgnoreWhitespace(); tok != WAIT {
|
||||
return nil, fmt.Errorf("Error parsing Wait Statement\n Expected: WAIT\n Found: %v\n", lit)
|
||||
}
|
||||
|
||||
return stmt, nil
|
||||
}
|
||||
|
||||
// ParseGoStatement returns a GoStatement
|
||||
func (p *Parser) ParseGoStatement() (*statement.GoStatement, error) {
|
||||
|
||||
stmt := &statement.GoStatement{}
|
||||
stmt.StatementID = RandStr(10)
|
||||
|
||||
if tok, lit := p.scanIgnoreWhitespace(); tok != GO {
|
||||
return nil, fmt.Errorf("Error parsing Go Statement\n Expected: GO\n Found: %v\n", lit)
|
||||
}
|
||||
|
||||
var body statement.Statement
|
||||
var err error
|
||||
|
||||
tok, _ := p.scanIgnoreWhitespace()
|
||||
switch tok {
|
||||
case QUERY:
|
||||
p.unscan()
|
||||
body, err = p.ParseQueryStatement()
|
||||
case INSERT:
|
||||
p.unscan()
|
||||
body, err = p.ParseInsertStatement()
|
||||
case EXEC:
|
||||
p.unscan()
|
||||
body, err = p.ParseExecStatement()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stmt.Statement = body
|
||||
|
||||
return stmt, nil
|
||||
|
||||
}
|
||||
|
||||
// ParseFunction returns a Function
|
||||
func (p *Parser) ParseFunction() (*statement.Function, error) {
|
||||
|
||||
fn := &statement.Function{}
|
||||
|
||||
_, lit := p.scanIgnoreWhitespace()
|
||||
fn.Type = lit
|
||||
|
||||
_, lit = p.scanIgnoreWhitespace()
|
||||
fn.Fn = lit
|
||||
|
||||
tok, lit := p.scanIgnoreWhitespace()
|
||||
if tok != LPAREN {
|
||||
return nil, fmt.Errorf("Error parsing Insert template function\n Expected: LPAREN\n Found: %v\n", lit)
|
||||
}
|
||||
|
||||
tok, lit = p.scanIgnoreWhitespace()
|
||||
if tok != NUMBER {
|
||||
return nil, fmt.Errorf("Error parsing Insert template function\n Expected: NUMBER\n Found: %v\n", lit)
|
||||
}
|
||||
|
||||
// Parse out the integer
|
||||
i, err := strconv.ParseInt(lit, 10, 64)
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Error parsing integer in Insert template function:\n string: %v\n error: %v\n", lit, err)
|
||||
}
|
||||
|
||||
fn.Argument = int(i)
|
||||
|
||||
tok, _ = p.scanIgnoreWhitespace()
|
||||
if tok != RPAREN {
|
||||
return nil, fmt.Errorf("Error parsing Insert template function\n Expected: RPAREN\n Found: %v\n", lit)
|
||||
}
|
||||
|
||||
tok, lit = p.scanIgnoreWhitespace()
|
||||
if tok != NUMBER {
|
||||
return nil, fmt.Errorf("Error parsing Insert template function\n Expected: NUMBER\n Found: %v\n", lit)
|
||||
}
|
||||
|
||||
// Parse out the integer
|
||||
i, err = strconv.ParseInt(lit, 10, 64)
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Error parsing integer in Insert template function:\n string: %v\n error: %v\n", lit, err)
|
||||
}
|
||||
|
||||
fn.Count = int(i)
|
||||
|
||||
return fn, nil
|
||||
}
|
||||
|
||||
// ParseTimestamp returns a Timestamp
|
||||
func (p *Parser) ParseTimestamp() (*statement.Timestamp, error) {
|
||||
|
||||
ts := &statement.Timestamp{}
|
||||
|
||||
tok, lit := p.scanIgnoreWhitespace()
|
||||
if tok != NUMBER {
|
||||
return nil, fmt.Errorf("Error parsing Insert timestamp\n Expected: NUMBER\n Found: %v\n", lit)
|
||||
}
|
||||
|
||||
// Parse out the integer
|
||||
i, err := strconv.ParseInt(lit, 10, 64)
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Error parsing integer in Insert timestamp:\n string: %v\n error: %v\n", lit, err)
|
||||
}
|
||||
|
||||
ts.Count = int(i)
|
||||
|
||||
tok, lit = p.scanIgnoreWhitespace()
|
||||
if tok != DURATIONVAL {
|
||||
return nil, fmt.Errorf("Error parsing Insert timestamp\n Expected: DURATION\n Found: %v\n", lit)
|
||||
}
|
||||
|
||||
// Parse out the duration
|
||||
dur, err := time.ParseDuration(lit)
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Error parsing duration in Insert timestamp:\n string: %v\n error: %v\n", lit, err)
|
||||
}
|
||||
|
||||
ts.Duration = dur
|
||||
|
||||
return ts, nil
|
||||
}
|
||||
|
||||
func (p *Parser) scan() (tok Token, lit string) {
|
||||
// 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
|
||||
}
|
||||
|
||||
// Otherwise read the next token from the scanner.
|
||||
tok, lit = p.s.Scan()
|
||||
|
||||
// Save it to the buffer in case we unscan later.
|
||||
p.buf.tok, p.buf.lit = tok, lit
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// scanIgnoreWhitespace scans the next non-whitespace token.
|
||||
func (p *Parser) scanIgnoreWhitespace() (tok Token, lit string) {
|
||||
tok, lit = p.scan()
|
||||
if tok == WS {
|
||||
tok, lit = p.scan()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// unscan pushes the previously read token back onto the buffer.
|
||||
func (p *Parser) unscan() { p.buf.n = 1 }
|
||||
|
||||
// RandStr returns a string of random characters with length n
|
||||
func RandStr(n int) string {
|
||||
b := make([]byte, n/2)
|
||||
_, _ = rand.Read(b)
|
||||
return fmt.Sprintf("%x", b)
|
||||
}
|
243
vendor/github.com/influxdata/influxdb/stress/v2/stressql/statement/parser_test.go
generated
vendored
Normal file
243
vendor/github.com/influxdata/influxdb/stress/v2/stressql/statement/parser_test.go
generated
vendored
Normal file
@@ -0,0 +1,243 @@
|
||||
package statement
|
||||
|
||||
import (
|
||||
// "fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/influxdata/influxdb/stress/v2/statement"
|
||||
)
|
||||
|
||||
func newParserFromString(s string) *Parser {
|
||||
f := strings.NewReader(s)
|
||||
p := NewParser(f)
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func TestParser_ParseStatement(t *testing.T) {
|
||||
var tests = []struct {
|
||||
skip bool
|
||||
s string
|
||||
stmt statement.Statement
|
||||
err string
|
||||
}{
|
||||
|
||||
// QUERY
|
||||
|
||||
{
|
||||
s: "QUERY basicCount\nSELECT count(%f) FROM cpu\nDO 100",
|
||||
stmt: &statement.QueryStatement{Name: "basicCount", TemplateString: "SELECT count(%v) FROM cpu", Args: []string{"%f"}, Count: 100},
|
||||
},
|
||||
|
||||
{
|
||||
s: "QUERY basicCount\nSELECT count(%f) FROM %m\nDO 100",
|
||||
stmt: &statement.QueryStatement{Name: "basicCount", TemplateString: "SELECT count(%v) FROM %v", Args: []string{"%f", "%m"}, Count: 100},
|
||||
},
|
||||
|
||||
{
|
||||
skip: true, // SHOULD CAUSE AN ERROR
|
||||
s: "QUERY\nSELECT count(%f) FROM %m\nDO 100",
|
||||
err: "Missing Name",
|
||||
},
|
||||
|
||||
// INSERT
|
||||
|
||||
{
|
||||
s: "INSERT mockCpu\ncpu,\nhost=[us-west|us-east|eu-north],server_id=[str rand(7) 1000]\nbusy=[int rand(1000) 100],free=[float rand(10) 0]\n100000 10s",
|
||||
stmt: &statement.InsertStatement{
|
||||
Name: "mockCpu",
|
||||
TemplateString: "cpu,host=%v,server_id=%v busy=%v,free=%v %v",
|
||||
TagCount: 2,
|
||||
Templates: []*statement.Template{
|
||||
&statement.Template{
|
||||
Tags: []string{"us-west", "us-east", "eu-north"},
|
||||
},
|
||||
&statement.Template{
|
||||
Function: &statement.Function{Type: "str", Fn: "rand", Argument: 7, Count: 1000},
|
||||
},
|
||||
&statement.Template{
|
||||
Function: &statement.Function{Type: "int", Fn: "rand", Argument: 1000, Count: 100},
|
||||
},
|
||||
&statement.Template{
|
||||
Function: &statement.Function{Type: "float", Fn: "rand", Argument: 10, Count: 0},
|
||||
},
|
||||
},
|
||||
Timestamp: &statement.Timestamp{
|
||||
Count: 100000,
|
||||
Duration: time.Duration(10 * time.Second),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
s: "INSERT mockCpu\ncpu,host=[us-west|us-east|eu-north],server_id=[str rand(7) 1000]\nbusy=[int rand(1000) 100],free=[float rand(10) 0]\n100000 10s",
|
||||
stmt: &statement.InsertStatement{
|
||||
Name: "mockCpu",
|
||||
TemplateString: "cpu,host=%v,server_id=%v busy=%v,free=%v %v",
|
||||
TagCount: 2,
|
||||
Templates: []*statement.Template{
|
||||
&statement.Template{
|
||||
Tags: []string{"us-west", "us-east", "eu-north"},
|
||||
},
|
||||
&statement.Template{
|
||||
Function: &statement.Function{Type: "str", Fn: "rand", Argument: 7, Count: 1000},
|
||||
},
|
||||
&statement.Template{
|
||||
Function: &statement.Function{Type: "int", Fn: "rand", Argument: 1000, Count: 100},
|
||||
},
|
||||
&statement.Template{
|
||||
Function: &statement.Function{Type: "float", Fn: "rand", Argument: 10, Count: 0},
|
||||
},
|
||||
},
|
||||
Timestamp: &statement.Timestamp{
|
||||
Count: 100000,
|
||||
Duration: time.Duration(10 * time.Second),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
s: "INSERT mockCpu\n[str rand(1000) 10],\nhost=[us-west|us-east|eu-north],server_id=[str rand(7) 1000],other=x\nbusy=[int rand(1000) 100],free=[float rand(10) 0]\n100000 10s",
|
||||
stmt: &statement.InsertStatement{
|
||||
Name: "mockCpu",
|
||||
TemplateString: "%v,host=%v,server_id=%v,other=x busy=%v,free=%v %v",
|
||||
TagCount: 3,
|
||||
Templates: []*statement.Template{
|
||||
&statement.Template{
|
||||
Function: &statement.Function{Type: "str", Fn: "rand", Argument: 1000, Count: 10},
|
||||
},
|
||||
&statement.Template{
|
||||
Tags: []string{"us-west", "us-east", "eu-north"},
|
||||
},
|
||||
&statement.Template{
|
||||
Function: &statement.Function{Type: "str", Fn: "rand", Argument: 7, Count: 1000},
|
||||
},
|
||||
&statement.Template{
|
||||
Function: &statement.Function{Type: "int", Fn: "rand", Argument: 1000, Count: 100},
|
||||
},
|
||||
&statement.Template{
|
||||
Function: &statement.Function{Type: "float", Fn: "rand", Argument: 10, Count: 0},
|
||||
},
|
||||
},
|
||||
Timestamp: &statement.Timestamp{
|
||||
Count: 100000,
|
||||
Duration: time.Duration(10 * time.Second),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
skip: true, // Expected error not working
|
||||
s: "INSERT\ncpu,\nhost=[us-west|us-east|eu-north],server_id=[str rand(7) 1000]\nbusy=[int rand(1000) 100],free=[float rand(10) 0]\n100000 10s",
|
||||
err: `found ",", expected WS`,
|
||||
},
|
||||
|
||||
// EXEC
|
||||
|
||||
{
|
||||
s: `EXEC other_script`,
|
||||
stmt: &statement.ExecStatement{Script: "other_script"},
|
||||
},
|
||||
|
||||
{
|
||||
skip: true, // Implement
|
||||
s: `EXEC other_script.sh`,
|
||||
stmt: &statement.ExecStatement{Script: "other_script.sh"},
|
||||
},
|
||||
|
||||
{
|
||||
skip: true, // Implement
|
||||
s: `EXEC ../other_script.sh`,
|
||||
stmt: &statement.ExecStatement{Script: "../other_script.sh"},
|
||||
},
|
||||
|
||||
{
|
||||
skip: true, // Implement
|
||||
s: `EXEC /path/to/some/other_script.sh`,
|
||||
stmt: &statement.ExecStatement{Script: "/path/to/some/other_script.sh"},
|
||||
},
|
||||
|
||||
// GO
|
||||
|
||||
{
|
||||
skip: true,
|
||||
s: "GO INSERT mockCpu\ncpu,\nhost=[us-west|us-east|eu-north],server_id=[str rand(7) 1000]\nbusy=[int rand(1000) 100],free=[float rand(10) 0]\n100000 10s",
|
||||
stmt: &statement.GoStatement{
|
||||
Statement: &statement.InsertStatement{
|
||||
Name: "mockCpu",
|
||||
TemplateString: "cpu,host=%v,server_id=%v busy=%v,free=%v %v",
|
||||
Templates: []*statement.Template{
|
||||
&statement.Template{
|
||||
Tags: []string{"us-west", "us-east", "eu-north"},
|
||||
},
|
||||
&statement.Template{
|
||||
Function: &statement.Function{Type: "str", Fn: "rand", Argument: 7, Count: 1000},
|
||||
},
|
||||
&statement.Template{
|
||||
Function: &statement.Function{Type: "int", Fn: "rand", Argument: 1000, Count: 100},
|
||||
},
|
||||
&statement.Template{
|
||||
Function: &statement.Function{Type: "float", Fn: "rand", Argument: 10, Count: 0},
|
||||
},
|
||||
},
|
||||
Timestamp: &statement.Timestamp{
|
||||
Count: 100000,
|
||||
Duration: time.Duration(10 * time.Second),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
skip: true,
|
||||
s: "GO QUERY basicCount\nSELECT count(free) FROM cpu\nDO 100",
|
||||
stmt: &statement.GoStatement{
|
||||
Statement: &statement.QueryStatement{Name: "basicCount", TemplateString: "SELECT count(free) FROM cpu", Count: 100},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
skip: true,
|
||||
s: `GO EXEC other_script`,
|
||||
stmt: &statement.GoStatement{
|
||||
Statement: &statement.ExecStatement{Script: "other_script"},
|
||||
},
|
||||
},
|
||||
|
||||
// SET
|
||||
|
||||
{
|
||||
s: `SET database [stress]`,
|
||||
stmt: &statement.SetStatement{Var: "database", Value: "stress"},
|
||||
},
|
||||
|
||||
// WAIT
|
||||
|
||||
{
|
||||
s: `Wait`,
|
||||
stmt: &statement.WaitStatement{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tst := range tests {
|
||||
|
||||
if tst.skip {
|
||||
continue
|
||||
}
|
||||
|
||||
stmt, err := newParserFromString(tst.s).Parse()
|
||||
tst.stmt.SetID("x")
|
||||
|
||||
if err != nil && err.Error() != tst.err {
|
||||
t.Errorf("REAL ERROR: %v\nExpected ERROR: %v\n", err, tst.err)
|
||||
} else if err != nil && tst.err == err.Error() {
|
||||
t.Errorf("REAL ERROR: %v\nExpected ERROR: %v\n", err, tst.err)
|
||||
} else if stmt.SetID("x"); !reflect.DeepEqual(stmt, tst.stmt) {
|
||||
t.Errorf("Expected\n%#v\n%#v", tst.stmt, stmt)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user