2014-11-17 22:54:35 +00:00
package influxql
2014-11-22 04:12:48 +00:00
import (
2015-01-18 21:45:22 +00:00
"bytes"
2014-11-22 04:12:48 +00:00
"errors"
"fmt"
"io"
2015-01-05 18:24:50 +00:00
"math"
2014-12-06 18:17:58 +00:00
"regexp"
2014-11-22 04:12:48 +00:00
"strconv"
"strings"
"time"
)
2014-12-21 17:59:36 +00:00
const (
// DateFormat represents the format for date literals.
DateFormat = "2006-01-02"
// DateTimeFormat represents the format for date time literals.
DateTimeFormat = "2006-01-02 15:04:05.999999"
)
2014-12-15 15:34:32 +00:00
2014-11-22 04:12:48 +00:00
// Parser represents an InfluxQL parser.
type Parser struct {
s * bufScanner
}
2015-06-28 06:54:34 +00:00
// NewParser returns a new instance of Parser.
2014-11-22 04:12:48 +00:00
func NewParser ( r io . Reader ) * Parser {
return & Parser { s : newBufScanner ( r ) }
}
2015-01-23 09:44:56 +00:00
// ParseQuery parses a query string and returns its AST representation.
func ParseQuery ( s string ) ( * Query , error ) { return NewParser ( strings . NewReader ( s ) ) . ParseQuery ( ) }
2015-05-28 04:06:09 +00:00
// ParseStatement parses a statement string and returns its AST representation.
func ParseStatement ( s string ) ( Statement , error ) {
return NewParser ( strings . NewReader ( s ) ) . ParseStatement ( )
}
// MustParseStatement parses a statement string and returns its AST. Panic on error.
func MustParseStatement ( s string ) Statement {
stmt , err := ParseStatement ( s )
if err != nil {
panic ( err . Error ( ) )
}
return stmt
}
2015-01-23 09:44:56 +00:00
// ParseExpr parses an expression string and returns its AST representation.
func ParseExpr ( s string ) ( Expr , error ) { return NewParser ( strings . NewReader ( s ) ) . ParseExpr ( ) }
2014-11-22 23:33:21 +00:00
// ParseQuery parses an InfluxQL string and returns a Query AST object.
func ( p * Parser ) ParseQuery ( ) ( * Query , error ) {
var statements Statements
2015-03-06 13:52:25 +00:00
var semi bool
2014-11-22 23:33:21 +00:00
2015-03-06 13:52:25 +00:00
for {
if tok , _ , _ := p . scanIgnoreWhitespace ( ) ; tok == EOF {
return & Query { Statements : statements } , nil
} else if ! semi && tok == SEMICOLON {
semi = true
} else {
p . unscan ( )
s , err := p . ParseStatement ( )
if err != nil {
return nil , err
}
statements = append ( statements , s )
semi = false
2014-11-25 04:49:09 +00:00
}
2014-11-22 23:33:21 +00:00
}
}
2014-11-22 04:12:48 +00:00
// ParseStatement parses an InfluxQL string and returns a Statement AST object.
func ( p * Parser ) ParseStatement ( ) ( Statement , error ) {
// Inspect the first token.
2014-11-22 23:33:21 +00:00
tok , pos , lit := p . scanIgnoreWhitespace ( )
2014-11-22 04:12:48 +00:00
switch tok {
case SELECT :
2015-01-06 21:30:27 +00:00
return p . parseSelectStatement ( targetNotRequired )
2014-11-22 23:33:21 +00:00
case DELETE :
return p . parseDeleteStatement ( )
2015-01-26 03:40:50 +00:00
case SHOW :
return p . parseShowStatement ( )
2014-11-25 04:49:09 +00:00
case CREATE :
2015-01-05 03:03:18 +00:00
return p . parseCreateStatement ( )
2014-11-22 23:33:21 +00:00
case DROP :
2015-01-05 03:32:49 +00:00
return p . parseDropStatement ( )
2015-01-03 03:56:26 +00:00
case GRANT :
return p . parseGrantStatement ( )
2015-01-03 07:06:18 +00:00
case REVOKE :
return p . parseRevokeStatement ( )
2015-01-05 18:24:50 +00:00
case ALTER :
return p . parseAlterStatement ( )
2015-04-03 14:14:09 +00:00
case SET :
2015-06-26 19:30:00 +00:00
return p . parseSetPasswordUserStatement ( )
2014-11-22 04:12:48 +00:00
default :
2015-04-03 14:14:09 +00:00
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "SELECT" , "DELETE" , "SHOW" , "CREATE" , "DROP" , "GRANT" , "REVOKE" , "ALTER" , "SET" } , pos )
2014-11-22 04:12:48 +00:00
}
}
2015-01-26 03:40:50 +00:00
// parseShowStatement parses a string and returns a list statement.
// This function assumes the SHOW token has already been consumed.
func ( p * Parser ) parseShowStatement ( ) ( Statement , error ) {
2015-01-05 03:03:18 +00:00
tok , pos , lit := p . scanIgnoreWhitespace ( )
2015-01-14 16:53:17 +00:00
switch tok {
case CONTINUOUS :
2015-01-26 03:40:50 +00:00
return p . parseShowContinuousQueriesStatement ( )
2015-05-24 07:27:02 +00:00
case GRANTS :
return p . parseGrantsForUserStatement ( )
2015-01-14 16:53:17 +00:00
case DATABASES :
2015-01-26 03:40:50 +00:00
return p . parseShowDatabasesStatement ( )
2015-03-10 19:46:05 +00:00
case SERVERS :
return p . parseShowServersStatement ( )
2015-01-14 16:53:17 +00:00
case FIELD :
tok , pos , lit := p . scanIgnoreWhitespace ( )
if tok == KEYS {
2015-01-26 03:40:50 +00:00
return p . parseShowFieldKeysStatement ( )
2015-01-05 03:03:18 +00:00
}
2015-01-14 16:53:17 +00:00
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "KEYS" , "VALUES" } , pos )
case MEASUREMENTS :
2015-01-26 03:40:50 +00:00
return p . parseShowMeasurementsStatement ( )
2015-01-14 16:53:17 +00:00
case RETENTION :
tok , pos , lit := p . scanIgnoreWhitespace ( )
if tok == POLICIES {
2015-01-26 03:40:50 +00:00
return p . parseShowRetentionPoliciesStatement ( )
2015-01-13 20:21:06 +00:00
}
2015-01-14 16:53:17 +00:00
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "POLICIES" } , pos )
case SERIES :
2015-01-26 03:40:50 +00:00
return p . parseShowSeriesStatement ( )
2015-03-12 23:07:41 +00:00
case STATS :
return p . parseShowStatsStatement ( )
2015-03-24 03:13:54 +00:00
case DIAGNOSTICS :
return p . parseShowDiagnosticsStatement ( )
2015-01-14 16:53:17 +00:00
case TAG :
tok , pos , lit := p . scanIgnoreWhitespace ( )
if tok == KEYS {
2015-01-26 03:40:50 +00:00
return p . parseShowTagKeysStatement ( )
2015-01-14 16:53:17 +00:00
} else if tok == VALUES {
2015-01-26 03:40:50 +00:00
return p . parseShowTagValuesStatement ( )
2015-01-14 16:53:17 +00:00
}
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "KEYS" , "VALUES" } , pos )
case USERS :
2015-01-26 03:40:50 +00:00
return p . parseShowUsersStatement ( )
2015-01-05 03:03:18 +00:00
}
2015-05-24 07:27:02 +00:00
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "CONTINUOUS" , "DATABASES" , "FIELD" , "GRANTS" , "MEASUREMENTS" , "RETENTION" , "SERIES" , "SERVERS" , "TAG" , "USERS" } , pos )
2015-01-05 03:03:18 +00:00
}
// parseCreateStatement parses a string and returns a create statement.
2015-03-05 22:45:47 +00:00
// This function assumes the CREATE token has already been consumed.
2015-01-05 03:03:18 +00:00
func ( p * Parser ) parseCreateStatement ( ) ( Statement , error ) {
tok , pos , lit := p . scanIgnoreWhitespace ( )
if tok == CONTINUOUS {
return p . parseCreateContinuousQueryStatement ( )
} else if tok == DATABASE {
return p . parseCreateDatabaseStatement ( )
} else if tok == USER {
return p . parseCreateUserStatement ( )
} else if tok == RETENTION {
tok , pos , lit = p . scanIgnoreWhitespace ( )
if tok != POLICY {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "POLICY" } , pos )
}
return p . parseCreateRetentionPolicyStatement ( )
}
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "CONTINUOUS" , "DATABASE" , "USER" , "RETENTION" } , pos )
}
2015-01-05 03:32:49 +00:00
// parseDropStatement parses a string and returns a drop statement.
// This function assumes the DROP token has already been consumed.
func ( p * Parser ) parseDropStatement ( ) ( Statement , error ) {
tok , pos , lit := p . scanIgnoreWhitespace ( )
if tok == SERIES {
2015-01-05 03:56:25 +00:00
return p . parseDropSeriesStatement ( )
2015-02-23 20:51:52 +00:00
} else if tok == MEASUREMENT {
return p . parseDropMeasurementStatement ( )
2015-01-05 03:56:25 +00:00
} else if tok == CONTINUOUS {
return p . parseDropContinuousQueryStatement ( )
} else if tok == DATABASE {
return p . parseDropDatabaseStatement ( )
2015-01-13 21:46:07 +00:00
} else if tok == RETENTION {
2015-02-01 18:47:48 +00:00
if tok , pos , lit := p . scanIgnoreWhitespace ( ) ; tok != POLICY {
2015-01-13 21:46:07 +00:00
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "POLICY" } , pos )
}
2015-02-01 18:47:48 +00:00
return p . parseDropRetentionPolicyStatement ( )
2015-01-05 03:56:25 +00:00
} else if tok == USER {
return p . parseDropUserStatement ( )
}
2015-01-05 03:32:49 +00:00
2015-02-23 20:51:52 +00:00
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "SERIES" , "CONTINUOUS" , "MEASUREMENT" } , pos )
2015-01-05 03:32:49 +00:00
}
2015-01-05 18:24:50 +00:00
// parseAlterStatement parses a string and returns an alter statement.
// This function assumes the ALTER token has already been consumed.
func ( p * Parser ) parseAlterStatement ( ) ( Statement , error ) {
tok , pos , lit := p . scanIgnoreWhitespace ( )
if tok == RETENTION {
if tok , pos , lit = p . scanIgnoreWhitespace ( ) ; tok != POLICY {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "POLICY" } , pos )
}
return p . parseAlterRetentionPolicyStatement ( )
}
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "RETENTION" } , pos )
}
2015-06-26 19:30:00 +00:00
// parseSetPasswordUserStatement parses a string and returns a set statement.
2015-04-03 14:14:09 +00:00
// This function assumes the SET token has already been consumed.
2015-06-26 19:30:00 +00:00
func ( p * Parser ) parseSetPasswordUserStatement ( ) ( * SetPasswordUserStatement , error ) {
2015-04-03 14:14:09 +00:00
stmt := & SetPasswordUserStatement { }
2015-06-26 19:30:00 +00:00
// Consume the required PASSWORD FOR tokens.
if err := p . parseTokens ( [ ] Token { PASSWORD , FOR } ) ; err != nil {
return nil , err
2015-04-03 14:14:09 +00:00
}
// Parse username
ident , err := p . parseIdent ( )
if err != nil {
return nil , err
}
stmt . Name = ident
// Consume the required = token.
if tok , pos , lit := p . scanIgnoreWhitespace ( ) ; tok != EQ {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "=" } , pos )
}
// Parse new user's password
if ident , err = p . parseString ( ) ; err != nil {
return nil , err
}
stmt . Password = ident
return stmt , nil
}
2015-01-05 02:50:56 +00:00
// parseCreateRetentionPolicyStatement parses a string and returns a create retention policy statement.
// This function assumes the CREATE RETENTION POLICY tokens have already been consumed.
func ( p * Parser ) parseCreateRetentionPolicyStatement ( ) ( * CreateRetentionPolicyStatement , error ) {
stmt := & CreateRetentionPolicyStatement { }
// Parse the retention policy name.
2015-01-19 23:12:33 +00:00
ident , err := p . parseIdent ( )
2015-01-05 02:50:56 +00:00
if err != nil {
return nil , err
}
stmt . Name = ident
// Consume the required ON token.
if tok , pos , lit := p . scanIgnoreWhitespace ( ) ; tok != ON {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "ON" } , pos )
}
// Parse the database name.
2015-01-19 23:12:33 +00:00
ident , err = p . parseIdent ( )
2015-01-05 02:50:56 +00:00
if err != nil {
return nil , err
}
2015-01-09 22:50:33 +00:00
stmt . Database = ident
2015-01-05 02:50:56 +00:00
// Parse required DURATION token.
tok , pos , lit := p . scanIgnoreWhitespace ( )
if tok != DURATION {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "DURATION" } , pos )
}
// Parse duration value
2015-01-05 18:24:50 +00:00
d , err := p . parseDuration ( )
2015-01-05 02:50:56 +00:00
if err != nil {
2015-01-05 18:24:50 +00:00
return nil , err
2015-01-05 02:50:56 +00:00
}
stmt . Duration = d
// Parse required REPLICATION token.
if tok , pos , lit = p . scanIgnoreWhitespace ( ) ; tok != REPLICATION {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "REPLICATION" } , pos )
}
// Parse replication value.
2015-01-05 18:24:50 +00:00
n , err := p . parseInt ( 1 , math . MaxInt32 )
if err != nil {
return nil , err
}
stmt . Replication = n
// Parse optional DEFAULT token.
if tok , pos , lit = p . scanIgnoreWhitespace ( ) ; tok == DEFAULT {
stmt . Default = true
} else {
p . unscan ( )
}
return stmt , nil
}
// parseAlterRetentionPolicyStatement parses a string and returns an alter retention policy statement.
2015-06-28 06:54:34 +00:00
// This function assumes the ALTER RETENTION POLICY tokens have already been consumed.
2015-01-05 18:24:50 +00:00
func ( p * Parser ) parseAlterRetentionPolicyStatement ( ) ( * AlterRetentionPolicyStatement , error ) {
stmt := & AlterRetentionPolicyStatement { }
// Parse the retention policy name.
2015-04-09 20:37:20 +00:00
tok , pos , lit := p . scanIgnoreWhitespace ( )
if tok == DEFAULT {
stmt . Name = "default"
} else if tok == IDENT {
stmt . Name = lit
} else {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "identifier" } , pos )
2015-01-05 18:24:50 +00:00
}
// Consume the required ON token.
2015-04-09 20:37:20 +00:00
if tok , pos , lit = p . scanIgnoreWhitespace ( ) ; tok != ON {
2015-01-05 18:24:50 +00:00
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "ON" } , pos )
}
// Parse the database name.
2015-04-09 20:37:20 +00:00
ident , err := p . parseIdent ( )
2015-01-05 18:24:50 +00:00
if err != nil {
return nil , err
}
2015-01-09 22:50:33 +00:00
stmt . Database = ident
2015-01-05 18:24:50 +00:00
2015-01-09 14:09:55 +00:00
// Loop through option tokens (DURATION, REPLICATION, DEFAULT, etc.).
2015-01-05 18:24:50 +00:00
maxNumOptions := 3
Loop :
for i := 0 ; i < maxNumOptions ; i ++ {
tok , pos , lit := p . scanIgnoreWhitespace ( )
switch tok {
case DURATION :
d , err := p . parseDuration ( )
if err != nil {
return nil , err
}
stmt . Duration = & d
case REPLICATION :
n , err := p . parseInt ( 1 , math . MaxInt32 )
if err != nil {
return nil , err
}
stmt . Replication = & n
case DEFAULT :
stmt . Default = true
default :
if i < 1 {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "DURATION" , "RETENTION" , "DEFAULT" } , pos )
}
p . unscan ( )
break Loop
}
}
return stmt , nil
}
// parseInt parses a string and returns an integer literal.
func ( p * Parser ) parseInt ( min , max int ) ( int , error ) {
tok , pos , lit := p . scanIgnoreWhitespace ( )
if tok != NUMBER {
return 0 , newParseError ( tokstr ( tok , lit ) , [ ] string { "number" } , pos )
2015-01-05 02:50:56 +00:00
}
// Return an error if the number has a fractional part.
if strings . Contains ( lit , "." ) {
2015-01-05 18:24:50 +00:00
return 0 , & ParseError { Message : "number must be an integer" , Pos : pos }
2015-01-05 02:50:56 +00:00
}
2015-01-05 18:24:50 +00:00
// Convert string to int.
2015-01-05 20:44:11 +00:00
n , err := strconv . Atoi ( lit )
2015-01-05 02:50:56 +00:00
if err != nil {
2015-01-05 18:24:50 +00:00
return 0 , & ParseError { Message : err . Error ( ) , Pos : pos }
2015-01-05 20:44:11 +00:00
} else if min > n || n > max {
2015-01-05 18:24:50 +00:00
return 0 , & ParseError {
2015-01-05 20:46:52 +00:00
Message : fmt . Sprintf ( "invalid value %d: must be %d <= n <= %d" , n , min , max ) ,
2015-01-05 18:24:50 +00:00
Pos : pos ,
}
2015-01-05 02:50:56 +00:00
}
2015-01-05 20:44:11 +00:00
return n , nil
2015-01-05 18:24:50 +00:00
}
2015-02-24 20:29:10 +00:00
// parseUInt32 parses a string and returns a 32-bit unsigned integer literal.
func ( p * Parser ) parseUInt32 ( ) ( uint32 , error ) {
tok , pos , lit := p . scanIgnoreWhitespace ( )
if tok != NUMBER {
return 0 , newParseError ( tokstr ( tok , lit ) , [ ] string { "number" } , pos )
}
// Convert string to unsigned 32-bit integer
n , err := strconv . ParseUint ( lit , 10 , 32 )
if err != nil {
return 0 , & ParseError { Message : err . Error ( ) , Pos : pos }
}
return uint32 ( n ) , nil
}
2015-04-08 22:46:56 +00:00
// parseUInt64 parses a string and returns a 64-bit unsigned integer literal.
func ( p * Parser ) parseUInt64 ( ) ( uint64 , error ) {
tok , pos , lit := p . scanIgnoreWhitespace ( )
if tok != NUMBER {
return 0 , newParseError ( tokstr ( tok , lit ) , [ ] string { "number" } , pos )
}
// Convert string to unsigned 64-bit integer
n , err := strconv . ParseUint ( lit , 10 , 64 )
if err != nil {
return 0 , & ParseError { Message : err . Error ( ) , Pos : pos }
}
return uint64 ( n ) , nil
}
2015-01-05 18:24:50 +00:00
// parseDuration parses a string and returns a duration literal.
// This function assumes the DURATION token has already been consumed.
func ( p * Parser ) parseDuration ( ) ( time . Duration , error ) {
tok , pos , lit := p . scanIgnoreWhitespace ( )
2015-03-05 23:19:43 +00:00
if tok != DURATION_VAL && tok != INF {
2015-01-05 18:24:50 +00:00
return 0 , newParseError ( tokstr ( tok , lit ) , [ ] string { "duration" } , pos )
}
2015-03-05 23:19:43 +00:00
if tok == INF {
return 0 , nil
}
2015-01-05 18:24:50 +00:00
d , err := ParseDuration ( lit )
if err != nil {
return 0 , & ParseError { Message : err . Error ( ) , Pos : pos }
2015-01-05 02:50:56 +00:00
}
2015-01-05 18:24:50 +00:00
return d , nil
2015-01-05 02:50:56 +00:00
}
2015-01-29 17:09:05 +00:00
// parseIdent parses an identifier.
2015-01-19 23:12:33 +00:00
func ( p * Parser ) parseIdent ( ) ( string , error ) {
2015-01-05 02:50:56 +00:00
tok , pos , lit := p . scanIgnoreWhitespace ( )
2015-01-19 20:01:32 +00:00
if tok != IDENT {
2015-01-05 02:50:56 +00:00
return "" , newParseError ( tokstr ( tok , lit ) , [ ] string { "identifier" } , pos )
}
return lit , nil
}
2015-01-29 17:09:05 +00:00
// parseIdentList parses a comma delimited list of identifiers.
func ( p * Parser ) parseIdentList ( ) ( [ ] string , error ) {
// Parse first (required) identifier.
ident , err := p . parseIdent ( )
if err != nil {
return nil , err
}
idents := [ ] string { ident }
// Parse remaining (optional) identifiers.
for {
if tok , _ , _ := p . scanIgnoreWhitespace ( ) ; tok != COMMA {
p . unscan ( )
return idents , nil
}
if ident , err = p . parseIdent ( ) ; err != nil {
return nil , err
}
idents = append ( idents , ident )
}
}
2015-03-28 00:40:21 +00:00
// parseSegmentedIdents parses a segmented identifiers.
// e.g., "db"."rp".measurement or "db"..measurement
func ( p * Parser ) parseSegmentedIdents ( ) ( [ ] string , error ) {
ident , err := p . parseIdent ( )
if err != nil {
return nil , err
}
idents := [ ] string { ident }
// Parse remaining (optional) identifiers.
for {
if tok , _ , _ := p . scan ( ) ; tok != DOT {
// No more segments so we're done.
p . unscan ( )
break
}
if ch := p . peekRune ( ) ; ch == '/' {
// Next segment is a regex so we're done.
break
2015-08-27 23:23:21 +00:00
} else if ch == ':' {
// Next segment is context-specific so let caller handle it.
break
2015-03-28 00:40:21 +00:00
} else if ch == '.' {
// Add an empty identifier.
idents = append ( idents , "" )
continue
}
// Parse the next identifier.
if ident , err = p . parseIdent ( ) ; err != nil {
return nil , err
}
idents = append ( idents , ident )
}
if len ( idents ) > 3 {
msg := fmt . Sprintf ( "too many segments in %s" , QuoteIdent ( idents ... ) )
return nil , & ParseError { Message : msg }
}
return idents , nil
}
2015-01-19 20:01:32 +00:00
// parserString parses a string.
func ( p * Parser ) parseString ( ) ( string , error ) {
tok , pos , lit := p . scanIgnoreWhitespace ( )
if tok != STRING {
return "" , newParseError ( tokstr ( tok , lit ) , [ ] string { "string" } , pos )
}
return lit , nil
}
2015-01-03 07:06:18 +00:00
// parseRevokeStatement parses a string and returns a revoke statement.
2015-06-28 06:54:34 +00:00
// This function assumes the REVOKE token has already been consumed.
2015-07-10 20:39:33 +00:00
func ( p * Parser ) parseRevokeStatement ( ) ( Statement , error ) {
2015-01-30 02:56:23 +00:00
// Parse the privilege to be revoked.
2015-01-03 03:56:26 +00:00
priv , err := p . parsePrivilege ( )
if err != nil {
return nil , err
}
2015-07-10 20:39:33 +00:00
// Check for ON or FROM clauses.
2015-01-03 07:06:18 +00:00
tok , pos , lit := p . scanIgnoreWhitespace ( )
if tok == ON {
2015-07-10 20:39:33 +00:00
stmt , err := p . parseRevokeOnStatement ( )
2015-01-19 23:12:33 +00:00
if err != nil {
return nil , err
2015-01-03 07:06:18 +00:00
}
2015-07-10 20:39:33 +00:00
stmt . Privilege = priv
return stmt , nil
} else if tok == FROM {
// Admin privilege is only revoked on ALL PRIVILEGES.
if priv != AllPrivileges {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "ON" } , pos )
}
return p . parseRevokeAdminStatement ( )
}
2015-01-03 07:06:18 +00:00
2015-07-10 20:39:33 +00:00
// Only ON or FROM clauses are allowed after privilege.
if priv == AllPrivileges {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "ON" , "FROM" } , pos )
2015-01-03 03:56:26 +00:00
}
2015-07-10 20:39:33 +00:00
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "ON" } , pos )
}
// parseRevokeOnStatement parses a string and returns a revoke statement.
// This function assumes the [PRIVILEGE] ON tokens have already been consumed.
func ( p * Parser ) parseRevokeOnStatement ( ) ( * RevokeStatement , error ) {
stmt := & RevokeStatement { }
// Parse the name of the database.
lit , err := p . parseIdent ( )
if err != nil {
return nil , err
}
stmt . On = lit
// Parse FROM clause.
tok , pos , lit := p . scanIgnoreWhitespace ( )
2015-01-03 03:56:26 +00:00
2015-01-03 07:06:18 +00:00
// Check for required FROM token.
if tok != FROM {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "FROM" } , pos )
}
2015-07-10 20:39:33 +00:00
// Parse the name of the user.
2015-01-19 23:12:33 +00:00
lit , err = p . parseIdent ( )
if err != nil {
return nil , err
2015-01-03 03:56:26 +00:00
}
2015-01-03 07:06:18 +00:00
stmt . User = lit
return stmt , nil
}
2015-07-10 20:39:33 +00:00
// parseRevokeAdminStatement parses a string and returns a revoke admin statement.
// This function assumes the ALL [PRVILEGES] FROM token has already been consumed.
func ( p * Parser ) parseRevokeAdminStatement ( ) ( * RevokeAdminStatement , error ) {
// Admin privilege is always false when revoke admin clause is called.
stmt := & RevokeAdminStatement { }
// Parse the name of the user.
lit , err := p . parseIdent ( )
if err != nil {
return nil , err
}
stmt . User = lit
return stmt , nil
}
2015-01-03 07:06:18 +00:00
// parseGrantStatement parses a string and returns a grant statement.
// This function assumes the GRANT token has already been consumed.
2015-07-10 20:39:33 +00:00
func ( p * Parser ) parseGrantStatement ( ) ( Statement , error ) {
2015-01-03 07:06:18 +00:00
// Parse the privilege to be granted.
priv , err := p . parsePrivilege ( )
if err != nil {
return nil , err
}
2015-07-10 20:39:33 +00:00
// Check for ON or TO clauses.
2015-01-03 07:06:18 +00:00
tok , pos , lit := p . scanIgnoreWhitespace ( )
if tok == ON {
2015-07-10 20:39:33 +00:00
stmt , err := p . parseGrantOnStatement ( )
2015-01-19 23:12:33 +00:00
if err != nil {
return nil , err
2015-01-03 07:06:18 +00:00
}
2015-07-10 20:39:33 +00:00
stmt . Privilege = priv
return stmt , nil
} else if tok == TO {
// Admin privilege is only granted on ALL PRIVILEGES.
if priv != AllPrivileges {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "ON" } , pos )
}
return p . parseGrantAdminStatement ( )
}
2015-01-03 07:06:18 +00:00
2015-07-10 20:39:33 +00:00
// Only ON or TO clauses are allowed after privilege.
if priv == AllPrivileges {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "ON" , "TO" } , pos )
2015-01-03 07:06:18 +00:00
}
2015-07-10 20:39:33 +00:00
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "ON" } , pos )
}
// parseGrantOnStatement parses a string and returns a grant statement.
// This function assumes the [PRIVILEGE] ON tokens have already been consumed.
func ( p * Parser ) parseGrantOnStatement ( ) ( * GrantStatement , error ) {
stmt := & GrantStatement { }
// Parse the name of the database.
lit , err := p . parseIdent ( )
if err != nil {
return nil , err
}
stmt . On = lit
// Parse TO clause.
tok , pos , lit := p . scanIgnoreWhitespace ( )
2015-01-03 03:56:26 +00:00
2015-01-03 07:06:18 +00:00
// Check for required TO token.
if tok != TO {
2015-01-03 03:56:26 +00:00
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "TO" } , pos )
}
2015-07-10 20:39:33 +00:00
// Parse the name of the user.
2015-01-19 23:12:33 +00:00
lit , err = p . parseIdent ( )
if err != nil {
return nil , err
2015-01-03 03:56:26 +00:00
}
stmt . User = lit
return stmt , nil
}
2015-07-10 20:39:33 +00:00
// parseGrantAdminStatement parses a string and returns a grant admin statement.
// This function assumes the ALL [PRVILEGES] TO tokens have already been consumed.
func ( p * Parser ) parseGrantAdminStatement ( ) ( * GrantAdminStatement , error ) {
// Admin privilege is always true when grant admin clause is called.
stmt := & GrantAdminStatement { }
// Parse the name of the user.
lit , err := p . parseIdent ( )
if err != nil {
return nil , err
}
stmt . User = lit
return stmt , nil
}
2015-01-03 03:56:26 +00:00
// parsePrivilege parses a string and returns a Privilege
func ( p * Parser ) parsePrivilege ( ) ( Privilege , error ) {
tok , pos , lit := p . scanIgnoreWhitespace ( )
switch tok {
case READ :
return ReadPrivilege , nil
case WRITE :
return WritePrivilege , nil
case ALL :
// Consume optional PRIVILEGES token
tok , pos , lit = p . scanIgnoreWhitespace ( )
if tok != PRIVILEGES {
p . unscan ( )
}
return AllPrivileges , nil
}
return 0 , newParseError ( tokstr ( tok , lit ) , [ ] string { "READ" , "WRITE" , "ALL [PRIVILEGES]" } , pos )
}
2014-11-22 04:12:48 +00:00
// parseSelectStatement parses a select string and returns a Statement AST object.
// This function assumes the SELECT token has already been consumed.
2015-01-06 21:30:27 +00:00
func ( p * Parser ) parseSelectStatement ( tr targetRequirement ) ( * SelectStatement , error ) {
2014-11-22 04:12:48 +00:00
stmt := & SelectStatement { }
2015-01-25 20:34:49 +00:00
var err error
2014-11-22 04:12:48 +00:00
2015-05-12 16:13:44 +00:00
// Parse fields: "FIELD+".
2015-01-25 20:34:49 +00:00
if stmt . Fields , err = p . parseFields ( ) ; err != nil {
2014-11-22 04:12:48 +00:00
return nil , err
}
2015-01-06 21:30:27 +00:00
// Parse target: "INTO"
2015-01-25 20:34:49 +00:00
if stmt . Target , err = p . parseTarget ( tr ) ; err != nil {
2015-01-06 21:30:27 +00:00
return nil , err
}
2015-03-06 13:52:25 +00:00
// Parse source: "FROM".
2014-12-06 18:17:58 +00:00
if tok , pos , lit := p . scanIgnoreWhitespace ( ) ; tok != FROM {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "FROM" } , pos )
}
2015-08-27 23:23:21 +00:00
if stmt . Sources , err = p . parseSources ( stmt ) ; err != nil {
2014-11-22 04:12:48 +00:00
return nil , err
}
// Parse condition: "WHERE EXPR".
2015-01-25 20:34:49 +00:00
if stmt . Condition , err = p . parseCondition ( ) ; err != nil {
2014-11-22 04:12:48 +00:00
return nil , err
}
// Parse dimensions: "GROUP BY DIMENSION+".
2015-01-25 20:34:49 +00:00
if stmt . Dimensions , err = p . parseDimensions ( ) ; err != nil {
2014-11-22 04:12:48 +00:00
return nil , err
}
2015-03-12 01:05:31 +00:00
// Parse fill options: "fill(<option>)"
if stmt . Fill , stmt . FillValue , err = p . parseFill ( ) ; err != nil {
return nil , err
}
2014-12-15 00:54:51 +00:00
// Parse sort: "ORDER BY FIELD+".
2015-01-25 20:34:49 +00:00
if stmt . SortFields , err = p . parseOrderBy ( ) ; err != nil {
2014-12-16 17:32:08 +00:00
return nil , err
2014-12-15 00:54:51 +00:00
}
2015-01-25 20:34:49 +00:00
// Parse limit: "LIMIT <n>".
2015-03-13 00:59:38 +00:00
if stmt . Limit , err = p . parseOptionalTokenAndInt ( LIMIT ) ; err != nil {
2015-01-25 20:34:49 +00:00
return nil , err
}
// Parse offset: "OFFSET <n>".
2015-03-13 00:59:38 +00:00
if stmt . Offset , err = p . parseOptionalTokenAndInt ( OFFSET ) ; err != nil {
2014-11-22 04:12:48 +00:00
return nil , err
}
2015-03-10 01:46:05 +00:00
// Parse series limit: "SLIMIT <n>".
2015-03-13 00:59:38 +00:00
if stmt . SLimit , err = p . parseOptionalTokenAndInt ( SLIMIT ) ; err != nil {
2015-03-10 01:46:05 +00:00
return nil , err
}
// Parse series offset: "SOFFSET <n>".
2015-03-13 00:59:38 +00:00
if stmt . SOffset , err = p . parseOptionalTokenAndInt ( SOFFSET ) ; err != nil {
2015-03-10 01:46:05 +00:00
return nil , err
}
2015-03-19 15:41:18 +00:00
// Set if the query is a raw data query or one with an aggregate
stmt . IsRawQuery = true
2015-03-19 23:21:17 +00:00
WalkFunc ( stmt . Fields , func ( n Node ) {
if _ , ok := n . ( * Call ) ; ok {
2015-03-19 15:41:18 +00:00
stmt . IsRawQuery = false
}
2015-03-19 23:21:17 +00:00
} )
2015-03-19 15:41:18 +00:00
2015-05-19 15:11:12 +00:00
if err := stmt . validate ( tr ) ; err != nil {
2015-05-12 14:42:39 +00:00
return nil , err
2015-05-11 21:49:04 +00:00
}
2014-11-22 23:33:21 +00:00
return stmt , nil
}
2015-01-06 21:30:27 +00:00
// targetRequirement specifies whether or not a target clause is required.
type targetRequirement int
const (
targetRequired targetRequirement = iota
targetNotRequired
)
// parseTarget parses a string and returns a Target.
func ( p * Parser ) parseTarget ( tr targetRequirement ) ( * Target , error ) {
if tok , pos , lit := p . scanIgnoreWhitespace ( ) ; tok != INTO {
if tr == targetRequired {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "INTO" } , pos )
}
p . unscan ( )
return nil , nil
}
2015-03-28 00:40:21 +00:00
// db, rp, and / or measurement
idents , err := p . parseSegmentedIdents ( )
2015-01-06 21:30:27 +00:00
if err != nil {
return nil , err
}
2015-08-27 23:23:21 +00:00
if len ( idents ) < 3 {
// Check for source measurement reference.
if ch := p . peekRune ( ) ; ch == ':' {
if err := p . parseTokens ( [ ] Token { COLON , MEASUREMENT } ) ; err != nil {
return nil , err
}
// Append empty measurement name.
idents = append ( idents , "" )
}
}
2015-03-28 00:40:21 +00:00
t := & Target { Measurement : & Measurement { } }
2015-08-27 23:23:21 +00:00
t . Measurement . Parent = t
2015-01-06 21:30:27 +00:00
2015-03-28 00:40:21 +00:00
switch len ( idents ) {
case 1 :
t . Measurement . Name = idents [ 0 ]
case 2 :
t . Measurement . RetentionPolicy = idents [ 0 ]
t . Measurement . Name = idents [ 1 ]
case 3 :
t . Measurement . Database = idents [ 0 ]
t . Measurement . RetentionPolicy = idents [ 1 ]
t . Measurement . Name = idents [ 2 ]
2015-01-06 21:30:27 +00:00
}
2015-03-28 00:40:21 +00:00
return t , nil
2015-01-06 21:30:27 +00:00
}
2014-11-22 23:33:21 +00:00
// parseDeleteStatement parses a delete string and returns a DeleteStatement.
// This function assumes the DELETE token has already been consumed.
func ( p * Parser ) parseDeleteStatement ( ) ( * DeleteStatement , error ) {
stmt := & DeleteStatement { }
2014-12-06 18:17:58 +00:00
// Parse source
if tok , pos , lit := p . scanIgnoreWhitespace ( ) ; tok != FROM {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "FROM" } , pos )
}
2015-08-27 23:23:21 +00:00
source , err := p . parseSource ( stmt )
2014-11-22 23:33:21 +00:00
if err != nil {
return nil , err
}
stmt . Source = source
// Parse condition: "WHERE EXPR".
condition , err := p . parseCondition ( )
if err != nil {
return nil , err
}
stmt . Condition = condition
return stmt , nil
}
2015-01-26 03:40:50 +00:00
// parseShowSeriesStatement parses a string and returns a ShowSeriesStatement.
// This function assumes the "SHOW SERIES" tokens have already been consumed.
func ( p * Parser ) parseShowSeriesStatement ( ) ( * ShowSeriesStatement , error ) {
stmt := & ShowSeriesStatement { }
2015-01-25 20:34:49 +00:00
var err error
2014-12-10 14:37:15 +00:00
2015-01-28 04:36:19 +00:00
// Parse optional FROM.
if tok , _ , _ := p . scanIgnoreWhitespace ( ) ; tok == FROM {
2015-08-27 23:23:21 +00:00
if stmt . Sources , err = p . parseSources ( stmt ) ; err != nil {
2015-01-28 04:36:19 +00:00
return nil , err
}
} else {
p . unscan ( )
}
2014-12-10 14:37:15 +00:00
// Parse condition: "WHERE EXPR".
2015-01-25 20:34:49 +00:00
if stmt . Condition , err = p . parseCondition ( ) ; err != nil {
2014-12-10 14:37:15 +00:00
return nil , err
}
2014-12-15 00:54:51 +00:00
// Parse sort: "ORDER BY FIELD+".
2015-01-25 20:34:49 +00:00
if stmt . SortFields , err = p . parseOrderBy ( ) ; err != nil {
2014-12-16 17:32:08 +00:00
return nil , err
2014-12-15 00:54:51 +00:00
}
2015-01-25 20:34:49 +00:00
// Parse limit: "LIMIT <n>".
2015-03-13 00:59:38 +00:00
if stmt . Limit , err = p . parseOptionalTokenAndInt ( LIMIT ) ; err != nil {
2015-01-25 20:34:49 +00:00
return nil , err
}
// Parse offset: "OFFSET <n>".
2015-03-13 00:59:38 +00:00
if stmt . Offset , err = p . parseOptionalTokenAndInt ( OFFSET ) ; err != nil {
2014-12-10 14:37:15 +00:00
return nil , err
}
2014-11-22 23:33:21 +00:00
return stmt , nil
}
2015-01-26 03:40:50 +00:00
// parseShowMeasurementsStatement parses a string and returns a ShowSeriesStatement.
// This function assumes the "SHOW MEASUREMENTS" tokens have already been consumed.
func ( p * Parser ) parseShowMeasurementsStatement ( ) ( * ShowMeasurementsStatement , error ) {
stmt := & ShowMeasurementsStatement { }
2015-01-25 20:34:49 +00:00
var err error
2014-12-16 02:48:22 +00:00
// Parse condition: "WHERE EXPR".
2015-01-25 20:34:49 +00:00
if stmt . Condition , err = p . parseCondition ( ) ; err != nil {
2014-12-16 02:48:22 +00:00
return nil , err
}
// Parse sort: "ORDER BY FIELD+".
2015-01-25 20:34:49 +00:00
if stmt . SortFields , err = p . parseOrderBy ( ) ; err != nil {
2014-12-16 17:32:08 +00:00
return nil , err
2014-12-16 02:48:22 +00:00
}
2015-01-25 20:34:49 +00:00
// Parse limit: "LIMIT <n>".
2015-03-13 00:59:38 +00:00
if stmt . Limit , err = p . parseOptionalTokenAndInt ( LIMIT ) ; err != nil {
2015-01-25 20:34:49 +00:00
return nil , err
}
// Parse offset: "OFFSET <n>".
2015-03-13 00:59:38 +00:00
if stmt . Offset , err = p . parseOptionalTokenAndInt ( OFFSET ) ; err != nil {
2014-12-16 02:48:22 +00:00
return nil , err
}
return stmt , nil
}
2015-01-26 03:40:50 +00:00
// parseShowRetentionPoliciesStatement parses a string and returns a ShowRetentionPoliciesStatement.
// This function assumes the "SHOW RETENTION POLICIES" tokens have been consumed.
func ( p * Parser ) parseShowRetentionPoliciesStatement ( ) ( * ShowRetentionPoliciesStatement , error ) {
stmt := & ShowRetentionPoliciesStatement { }
2015-01-13 20:21:06 +00:00
2015-07-16 10:05:24 +00:00
// Expect an "ON" keyword.
if tok , pos , lit := p . scanIgnoreWhitespace ( ) ; tok != ON {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "ON" } , pos )
}
// Parse the database.
2015-01-19 23:12:33 +00:00
ident , err := p . parseIdent ( )
2015-01-13 20:21:06 +00:00
if err != nil {
return nil , err
}
stmt . Database = ident
return stmt , nil
}
2015-01-26 03:40:50 +00:00
// parseShowTagKeysStatement parses a string and returns a ShowSeriesStatement.
// This function assumes the "SHOW TAG KEYS" tokens have already been consumed.
func ( p * Parser ) parseShowTagKeysStatement ( ) ( * ShowTagKeysStatement , error ) {
stmt := & ShowTagKeysStatement { }
2015-01-25 20:34:49 +00:00
var err error
2014-12-16 02:48:22 +00:00
2015-01-29 01:26:15 +00:00
// Parse optional source.
if tok , _ , _ := p . scanIgnoreWhitespace ( ) ; tok == FROM {
2015-08-27 23:23:21 +00:00
if stmt . Sources , err = p . parseSources ( stmt ) ; err != nil {
2015-01-29 01:26:15 +00:00
return nil , err
}
} else {
p . unscan ( )
2014-12-16 02:48:22 +00:00
}
// Parse condition: "WHERE EXPR".
2015-01-25 20:34:49 +00:00
if stmt . Condition , err = p . parseCondition ( ) ; err != nil {
2014-12-16 02:48:22 +00:00
return nil , err
}
// Parse sort: "ORDER BY FIELD+".
2015-01-25 20:34:49 +00:00
if stmt . SortFields , err = p . parseOrderBy ( ) ; err != nil {
2014-12-16 17:32:08 +00:00
return nil , err
2014-12-16 02:48:22 +00:00
}
2015-01-25 20:34:49 +00:00
// Parse limit: "LIMIT <n>".
2015-03-13 00:59:38 +00:00
if stmt . Limit , err = p . parseOptionalTokenAndInt ( LIMIT ) ; err != nil {
2015-01-25 20:34:49 +00:00
return nil , err
}
// Parse offset: "OFFSET <n>".
2015-03-13 00:59:38 +00:00
if stmt . Offset , err = p . parseOptionalTokenAndInt ( OFFSET ) ; err != nil {
2014-12-16 02:48:22 +00:00
return nil , err
}
return stmt , nil
}
2015-01-26 03:40:50 +00:00
// parseShowTagValuesStatement parses a string and returns a ShowSeriesStatement.
// This function assumes the "SHOW TAG VALUES" tokens have already been consumed.
func ( p * Parser ) parseShowTagValuesStatement ( ) ( * ShowTagValuesStatement , error ) {
stmt := & ShowTagValuesStatement { }
2015-01-25 20:34:49 +00:00
var err error
2014-12-16 02:48:22 +00:00
2015-01-29 17:09:05 +00:00
// Parse optional source.
if tok , _ , _ := p . scanIgnoreWhitespace ( ) ; tok == FROM {
2015-08-27 23:23:21 +00:00
if stmt . Sources , err = p . parseSources ( stmt ) ; err != nil {
2015-01-29 17:09:05 +00:00
return nil , err
}
} else {
p . unscan ( )
2014-12-16 02:48:22 +00:00
}
2015-01-29 17:09:05 +00:00
// Parse required WITH KEY.
if stmt . TagKeys , err = p . parseTagKeys ( ) ; err != nil {
2014-12-16 02:48:22 +00:00
return nil , err
}
// Parse condition: "WHERE EXPR".
2015-01-25 20:34:49 +00:00
if stmt . Condition , err = p . parseCondition ( ) ; err != nil {
2014-12-16 02:48:22 +00:00
return nil , err
}
// Parse sort: "ORDER BY FIELD+".
2015-01-25 20:34:49 +00:00
if stmt . SortFields , err = p . parseOrderBy ( ) ; err != nil {
2014-12-16 17:32:08 +00:00
return nil , err
2014-12-16 02:48:22 +00:00
}
2015-01-25 20:34:49 +00:00
// Parse limit: "LIMIT <n>".
2015-03-13 00:59:38 +00:00
if stmt . Limit , err = p . parseOptionalTokenAndInt ( LIMIT ) ; err != nil {
2015-01-25 20:34:49 +00:00
return nil , err
}
// Parse offset: "OFFSET <n>".
2015-03-13 00:59:38 +00:00
if stmt . Offset , err = p . parseOptionalTokenAndInt ( OFFSET ) ; err != nil {
2014-12-16 02:48:22 +00:00
return nil , err
}
return stmt , nil
}
2015-01-29 17:09:05 +00:00
// parseTagKeys parses a string and returns a list of tag keys.
func ( p * Parser ) parseTagKeys ( ) ( [ ] string , error ) {
var err error
// Parse required WITH KEY tokens.
if err := p . parseTokens ( [ ] Token { WITH , KEY } ) ; err != nil {
return nil , err
}
var tagKeys [ ] string
// Parse required IN or EQ token.
if tok , pos , lit := p . scanIgnoreWhitespace ( ) ; tok == IN {
// Parse required ( token.
if tok , pos , lit = p . scanIgnoreWhitespace ( ) ; tok != LPAREN {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "(" } , pos )
}
// Parse tag key list.
if tagKeys , err = p . parseIdentList ( ) ; err != nil {
return nil , err
}
// Parse required ) token.
if tok , pos , lit = p . scanIgnoreWhitespace ( ) ; tok != RPAREN {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "(" } , pos )
}
} else if tok == EQ {
// Parse required tag key.
ident , err := p . parseIdent ( )
if err != nil {
return nil , err
}
tagKeys = append ( tagKeys , ident )
} else {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "IN" , "=" } , pos )
}
return tagKeys , nil
}
2015-01-26 03:40:50 +00:00
// parseShowUsersStatement parses a string and returns a ShowUsersStatement.
// This function assumes the "SHOW USERS" tokens have been consumed.
func ( p * Parser ) parseShowUsersStatement ( ) ( * ShowUsersStatement , error ) {
return & ShowUsersStatement { } , nil
2015-01-14 16:53:17 +00:00
}
2015-01-26 03:40:50 +00:00
// parseShowFieldKeysStatement parses a string and returns a ShowSeriesStatement.
// This function assumes the "SHOW FIELD KEYS" tokens have already been consumed.
func ( p * Parser ) parseShowFieldKeysStatement ( ) ( * ShowFieldKeysStatement , error ) {
stmt := & ShowFieldKeysStatement { }
2015-01-25 20:34:49 +00:00
var err error
2014-12-16 02:48:22 +00:00
2015-01-30 22:31:31 +00:00
// Parse optional source.
if tok , _ , _ := p . scanIgnoreWhitespace ( ) ; tok == FROM {
2015-08-27 23:23:21 +00:00
if stmt . Sources , err = p . parseSources ( stmt ) ; err != nil {
2015-01-30 22:31:31 +00:00
return nil , err
}
} else {
p . unscan ( )
2014-12-16 02:48:22 +00:00
}
// Parse sort: "ORDER BY FIELD+".
2015-01-25 20:34:49 +00:00
if stmt . SortFields , err = p . parseOrderBy ( ) ; err != nil {
2014-12-16 17:32:08 +00:00
return nil , err
2014-12-16 02:48:22 +00:00
}
2015-01-25 20:34:49 +00:00
// Parse limit: "LIMIT <n>".
2015-03-13 00:59:38 +00:00
if stmt . Limit , err = p . parseOptionalTokenAndInt ( LIMIT ) ; err != nil {
2015-01-25 20:34:49 +00:00
return nil , err
}
// Parse offset: "OFFSET <n>".
2015-03-13 00:59:38 +00:00
if stmt . Offset , err = p . parseOptionalTokenAndInt ( OFFSET ) ; err != nil {
2014-12-16 02:48:22 +00:00
return nil , err
}
return stmt , nil
}
2015-02-23 20:51:52 +00:00
// parseDropMeasurementStatement parses a string and returns a DropMeasurementStatement.
// This function assumes the "DROP MEASUREMENT" tokens have already been consumed.
func ( p * Parser ) parseDropMeasurementStatement ( ) ( * DropMeasurementStatement , error ) {
stmt := & DropMeasurementStatement { }
// Parse the name of the measurement to be dropped.
lit , err := p . parseIdent ( )
if err != nil {
return nil , err
}
stmt . Name = lit
return stmt , nil
}
2014-11-22 23:33:21 +00:00
// parseDropSeriesStatement parses a string and returns a DropSeriesStatement.
// This function assumes the "DROP SERIES" tokens have already been consumed.
func ( p * Parser ) parseDropSeriesStatement ( ) ( * DropSeriesStatement , error ) {
stmt := & DropSeriesStatement { }
2015-02-17 23:29:25 +00:00
var err error
2014-11-22 23:33:21 +00:00
2015-06-02 15:20:20 +00:00
tok , pos , lit := p . scanIgnoreWhitespace ( )
if tok == FROM {
2015-02-17 23:29:25 +00:00
// Parse source.
2015-08-27 23:23:21 +00:00
if stmt . Sources , err = p . parseSources ( stmt ) ; err != nil {
2015-02-17 23:29:25 +00:00
return nil , err
}
} else {
p . unscan ( )
2015-02-18 22:20:07 +00:00
}
// Parse condition: "WHERE EXPR".
if stmt . Condition , err = p . parseCondition ( ) ; err != nil {
return nil , err
}
2015-06-02 15:20:20 +00:00
// If they didn't provide a FROM or a WHERE, this query is invalid
if stmt . Condition == nil && stmt . Sources == nil {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "FROM" , "WHERE" } , pos )
2015-02-17 23:29:25 +00:00
}
2015-06-02 15:20:20 +00:00
2014-11-22 23:33:21 +00:00
return stmt , nil
}
2015-01-26 03:40:50 +00:00
// parseShowContinuousQueriesStatement parses a string and returns a ShowContinuousQueriesStatement.
// This function assumes the "SHOW CONTINUOUS" tokens have already been consumed.
func ( p * Parser ) parseShowContinuousQueriesStatement ( ) ( * ShowContinuousQueriesStatement , error ) {
stmt := & ShowContinuousQueriesStatement { }
2014-11-22 23:33:21 +00:00
// Expect a "QUERIES" token.
if tok , pos , lit := p . scanIgnoreWhitespace ( ) ; tok != QUERIES {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "QUERIES" } , pos )
}
2014-11-25 04:49:09 +00:00
return stmt , nil
}
2015-03-10 19:46:05 +00:00
// parseShowServersStatement parses a string and returns a ShowServersStatement.
// This function assumes the "SHOW SERVERS" tokens have already been consumed.
func ( p * Parser ) parseShowServersStatement ( ) ( * ShowServersStatement , error ) {
stmt := & ShowServersStatement { }
return stmt , nil
}
2015-05-24 07:27:02 +00:00
// parseGrantsForUserStatement parses a string and returns a ShowGrantsForUserStatement.
// This function assumes the "SHOW GRANTS" tokens have already been consumed.
func ( p * Parser ) parseGrantsForUserStatement ( ) ( * ShowGrantsForUserStatement , error ) {
stmt := & ShowGrantsForUserStatement { }
// Expect a "FOR" token.
if tok , pos , lit := p . scanIgnoreWhitespace ( ) ; tok != FOR {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "FOR" } , pos )
}
// Parse the name of the user to be displayed.
lit , err := p . parseIdent ( )
if err != nil {
return nil , err
}
stmt . Name = lit
return stmt , nil
}
2015-01-26 03:40:50 +00:00
// parseShowDatabasesStatement parses a string and returns a ShowDatabasesStatement.
// This function assumes the "SHOW DATABASE" tokens have already been consumed.
func ( p * Parser ) parseShowDatabasesStatement ( ) ( * ShowDatabasesStatement , error ) {
stmt := & ShowDatabasesStatement { }
2015-01-09 15:47:57 +00:00
return stmt , nil
}
2014-11-25 04:49:09 +00:00
// parseCreateContinuousQueriesStatement parses a string and returns a CreateContinuousQueryStatement.
// This function assumes the "CREATE CONTINUOUS" tokens have already been consumed.
func ( p * Parser ) parseCreateContinuousQueryStatement ( ) ( * CreateContinuousQueryStatement , error ) {
stmt := & CreateContinuousQueryStatement { }
// Expect a "QUERY" token.
if tok , pos , lit := p . scanIgnoreWhitespace ( ) ; tok != QUERY {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "QUERY" } , pos )
}
// Read the id of the query to create.
2015-01-19 23:12:33 +00:00
ident , err := p . parseIdent ( )
2015-01-06 21:30:27 +00:00
if err != nil {
return nil , err
2014-11-25 04:49:09 +00:00
}
2015-01-06 21:30:27 +00:00
stmt . Name = ident
2014-11-25 04:49:09 +00:00
2015-01-06 21:30:27 +00:00
// Expect an "ON" keyword.
if tok , pos , lit := p . scanIgnoreWhitespace ( ) ; tok != ON {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "ON" } , pos )
2014-11-25 04:49:09 +00:00
}
2015-01-06 21:30:27 +00:00
// Read the name of the database to create the query on.
2015-01-19 23:12:33 +00:00
if ident , err = p . parseIdent ( ) ; err != nil {
2015-01-06 21:30:27 +00:00
return nil , err
}
2015-01-09 22:50:33 +00:00
stmt . Database = ident
2015-01-06 21:30:27 +00:00
// Expect a "BEGIN SELECT" tokens.
if err := p . parseTokens ( [ ] Token { BEGIN , SELECT } ) ; err != nil {
return nil , err
2014-11-25 04:49:09 +00:00
}
// Read the select statement to be used as the source.
2015-01-06 21:30:27 +00:00
source , err := p . parseSelectStatement ( targetRequired )
2014-11-25 04:49:09 +00:00
if err != nil {
return nil , err
}
stmt . Source = source
2015-01-20 02:44:47 +00:00
// validate that the statement has a non-zero group by interval if it is aggregated
2015-03-19 23:32:25 +00:00
if ! source . IsRawQuery {
2015-01-20 02:44:47 +00:00
d , err := source . GroupByInterval ( )
if d == 0 || err != nil {
// rewind so we can output an error with some info
p . unscan ( ) // unscan the whitespace
p . unscan ( ) // unscan the last token
tok , pos , lit := p . scanIgnoreWhitespace ( )
expected := [ ] string { "GROUP BY time(...)" }
if err != nil {
expected = append ( expected , err . Error ( ) )
}
return nil , newParseError ( tokstr ( tok , lit ) , expected , pos )
}
}
2015-01-06 21:30:27 +00:00
// Expect a "END" keyword.
if tok , pos , lit := p . scanIgnoreWhitespace ( ) ; tok != END {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "END" } , pos )
2014-11-22 23:33:21 +00:00
}
return stmt , nil
}
2014-12-31 13:47:21 +00:00
// parseCreateDatabaseStatement parses a string and returns a CreateDatabaseStatement.
// This function assumes the "CREATE DATABASE" tokens have already been consumed.
func ( p * Parser ) parseCreateDatabaseStatement ( ) ( * CreateDatabaseStatement , error ) {
stmt := & CreateDatabaseStatement { }
2015-08-29 00:41:43 +00:00
// Look for "IF NOT EXISTS"
if tok , _ , _ := p . scanIgnoreWhitespace ( ) ; tok == IF {
2015-08-29 16:55:35 +00:00
if err := p . parseTokens ( [ ] Token { NOT , EXISTS } ) ; err != nil {
return nil , err
2015-08-29 00:41:43 +00:00
}
stmt . IfNotExists = true
} else {
p . unscan ( )
}
2015-01-05 03:32:49 +00:00
// Parse the name of the database to be created.
2015-01-19 23:12:33 +00:00
lit , err := p . parseIdent ( )
if err != nil {
return nil , err
2015-01-05 03:32:49 +00:00
}
stmt . Name = lit
return stmt , nil
}
// parseDropDatabaseStatement parses a string and returns a DropDatabaseStatement.
// This function assumes the DROP DATABASE tokens have already been consumed.
func ( p * Parser ) parseDropDatabaseStatement ( ) ( * DropDatabaseStatement , error ) {
stmt := & DropDatabaseStatement { }
// Parse the name of the database to be dropped.
2015-01-19 23:12:33 +00:00
lit , err := p . parseIdent ( )
if err != nil {
return nil , err
2014-12-31 13:47:21 +00:00
}
stmt . Name = lit
return stmt , nil
}
2015-01-13 21:46:07 +00:00
// parseDropRetentionPolicyStatement parses a string and returns a DropRetentionPolicyStatement.
// This function assumes the DROP RETENTION POLICY tokens have been consumed.
func ( p * Parser ) parseDropRetentionPolicyStatement ( ) ( * DropRetentionPolicyStatement , error ) {
stmt := & DropRetentionPolicyStatement { }
// Parse the policy name.
2015-01-19 23:12:33 +00:00
ident , err := p . parseIdent ( )
2015-01-13 21:46:07 +00:00
if err != nil {
return nil , err
}
stmt . Name = ident
// Consume the required ON token.
if tok , pos , lit := p . scanIgnoreWhitespace ( ) ; tok != ON {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "ON" } , pos )
}
// Parse the database name.
2015-01-19 23:12:33 +00:00
if stmt . Database , err = p . parseIdent ( ) ; err != nil {
2015-01-13 21:46:07 +00:00
return nil , err
}
return stmt , nil
}
2014-12-31 16:22:07 +00:00
// parseCreateUserStatement parses a string and returns a CreateUserStatement.
// This function assumes the "CREATE USER" tokens have already been consumed.
func ( p * Parser ) parseCreateUserStatement ( ) ( * CreateUserStatement , error ) {
stmt := & CreateUserStatement { }
// Parse name of the user to be created.
2015-01-19 23:12:33 +00:00
ident , err := p . parseIdent ( )
2015-01-09 22:50:33 +00:00
if err != nil {
return nil , err
2014-12-31 16:22:07 +00:00
}
2015-01-09 22:50:33 +00:00
stmt . Name = ident
2014-12-31 16:22:07 +00:00
// Consume "WITH PASSWORD" tokens
if err := p . parseTokens ( [ ] Token { WITH , PASSWORD } ) ; err != nil {
return nil , err
}
// Parse new user's password
2015-01-19 20:01:32 +00:00
if ident , err = p . parseString ( ) ; err != nil {
2015-01-09 22:50:33 +00:00
return nil , err
}
stmt . Password = ident
// Check for option WITH clause.
if tok , _ , _ := p . scanIgnoreWhitespace ( ) ; tok != WITH {
p . unscan ( )
return stmt , nil
}
2015-07-10 20:39:33 +00:00
// "WITH ALL PRIVILEGES" grants the new user admin privilege.
// Only admin privilege can be set on user creation.
2015-01-09 22:50:33 +00:00
if err := p . parseTokens ( [ ] Token { ALL , PRIVILEGES } ) ; err != nil {
return nil , err
2014-12-31 16:22:07 +00:00
}
2015-07-10 20:39:33 +00:00
stmt . Admin = true
2014-12-31 16:22:07 +00:00
2015-01-05 03:56:25 +00:00
return stmt , nil
}
// parseDropUserStatement parses a string and returns a DropUserStatement.
// This function assumes the DROP USER tokens have already been consumed.
func ( p * Parser ) parseDropUserStatement ( ) ( * DropUserStatement , error ) {
stmt := & DropUserStatement { }
// Parse the name of the user to be dropped.
2015-01-19 23:12:33 +00:00
lit , err := p . parseIdent ( )
if err != nil {
return nil , err
2015-01-05 03:56:25 +00:00
}
stmt . Name = lit
2014-12-31 16:22:07 +00:00
return stmt , nil
}
2014-12-31 13:47:21 +00:00
// parseRetentionPolicy parses a string and returns a retention policy name.
// This function assumes the "WITH" token has already been consumed.
func ( p * Parser ) parseRetentionPolicy ( ) ( name string , dfault bool , err error ) {
// Check for optional DEFAULT token.
tok , pos , lit := p . scanIgnoreWhitespace ( )
if tok == DEFAULT {
dfault = true
tok , pos , lit = p . scanIgnoreWhitespace ( )
}
// Check for required RETENTION token.
if tok != RETENTION {
err = newParseError ( tokstr ( tok , lit ) , [ ] string { "RETENTION" } , pos )
return
}
// Check of required POLICY token.
if tok , pos , lit = p . scanIgnoreWhitespace ( ) ; tok != POLICY {
err = newParseError ( tokstr ( tok , lit ) , [ ] string { "POLICY" } , pos )
return
}
// Parse retention policy name.
2015-01-19 23:12:33 +00:00
name , err = p . parseIdent ( )
if err != nil {
2014-12-31 13:47:21 +00:00
return
}
return
}
2015-03-12 23:07:41 +00:00
// parseShowStatsStatement parses a string and returns a ShowStatsStatement.
// This function assumes the "SHOW STATS" tokens have already been consumed.
func ( p * Parser ) parseShowStatsStatement ( ) ( * ShowStatsStatement , error ) {
stmt := & ShowStatsStatement { }
var err error
if tok , _ , _ := p . scanIgnoreWhitespace ( ) ; tok == ON {
stmt . Host , err = p . parseString ( )
} else {
p . unscan ( )
}
return stmt , err
}
2015-03-24 03:13:54 +00:00
// parseShowDiagnostics parses a string and returns a ShowDiagnosticsStatement.
func ( p * Parser ) parseShowDiagnosticsStatement ( ) ( * ShowDiagnosticsStatement , error ) {
stmt := & ShowDiagnosticsStatement { }
return stmt , nil
}
2014-11-22 23:33:21 +00:00
// parseDropContinuousQueriesStatement parses a string and returns a DropContinuousQueryStatement.
// This function assumes the "DROP CONTINUOUS" tokens have already been consumed.
func ( p * Parser ) parseDropContinuousQueryStatement ( ) ( * DropContinuousQueryStatement , error ) {
stmt := & DropContinuousQueryStatement { }
// Expect a "QUERY" token.
if tok , pos , lit := p . scanIgnoreWhitespace ( ) ; tok != QUERY {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "QUERY" } , pos )
}
// Read the id of the query to drop.
2015-03-25 00:11:26 +00:00
ident , err := p . parseIdent ( )
2015-01-19 23:12:33 +00:00
if err != nil {
return nil , err
2014-11-22 23:33:21 +00:00
}
2015-03-25 00:11:26 +00:00
stmt . Name = ident
// Expect an "ON" keyword.
if tok , pos , lit := p . scanIgnoreWhitespace ( ) ; tok != ON {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "ON" } , pos )
}
// Read the name of the database to remove the query from.
if ident , err = p . parseIdent ( ) ; err != nil {
return nil , err
}
stmt . Database = ident
2014-11-22 23:33:21 +00:00
2014-11-22 04:12:48 +00:00
return stmt , nil
}
// parseFields parses a list of one or more fields.
func ( p * Parser ) parseFields ( ) ( Fields , error ) {
var fields Fields
2014-11-25 22:43:22 +00:00
// Check for "*" (i.e., "all fields")
if tok , _ , _ := p . scanIgnoreWhitespace ( ) ; tok == MUL {
2014-11-25 23:23:10 +00:00
fields = append ( fields , & Field { & Wildcard { } , "" } )
2014-11-25 22:43:22 +00:00
return fields , nil
}
p . unscan ( )
2014-11-22 04:12:48 +00:00
for {
// Parse the field.
f , err := p . parseField ( )
if err != nil {
return nil , err
}
// Add new field.
fields = append ( fields , f )
// If there's not a comma next then stop parsing fields.
if tok , _ , _ := p . scan ( ) ; tok != COMMA {
p . unscan ( )
break
}
}
return fields , nil
}
// parseField parses a single field.
func ( p * Parser ) parseField ( ) ( * Field , error ) {
f := & Field { }
2015-08-03 18:16:07 +00:00
_ , pos , _ := p . scanIgnoreWhitespace ( )
p . unscan ( )
2014-11-22 04:12:48 +00:00
// Parse the expression first.
expr , err := p . ParseExpr ( )
if err != nil {
return nil , err
}
2015-08-03 18:16:07 +00:00
var c validateField
Walk ( & c , expr )
if c . foundInvalid {
return nil , fmt . Errorf ( "invalid operator %s in SELECT clause at line %d, char %d; operator is intended for WHERE clause" , c . badToken , pos . Line + 1 , pos . Char + 1 )
}
2014-11-22 04:12:48 +00:00
f . Expr = expr
// Parse the alias if the current and next tokens are "WS AS".
alias , err := p . parseAlias ( )
if err != nil {
return nil , err
}
f . Alias = alias
// Consume all trailing whitespace.
p . consumeWhitespace ( )
return f , nil
}
2015-08-03 18:16:07 +00:00
// validateField checks if the Expr is a valid field. We disallow all binary expression
// that return a boolean
type validateField struct {
foundInvalid bool
badToken Token
}
func ( c * validateField ) Visit ( n Node ) Visitor {
e , ok := n . ( * BinaryExpr )
if ! ok {
return c
}
switch e . Op {
case EQ , NEQ , EQREGEX ,
NEQREGEX , LT , LTE , GT , GTE ,
AND , OR :
c . foundInvalid = true
c . badToken = e . Op
return nil
}
return c
}
2014-11-22 04:12:48 +00:00
// parseAlias parses the "AS (IDENT|STRING)" alias for fields and dimensions.
func ( p * Parser ) parseAlias ( ) ( string , error ) {
// Check if the next token is "AS". If not, then unscan and exit.
if tok , _ , _ := p . scanIgnoreWhitespace ( ) ; tok != AS {
p . unscan ( )
return "" , nil
}
// Then we should have the alias identifier.
2015-01-19 23:12:33 +00:00
lit , err := p . parseIdent ( )
if err != nil {
return "" , err
2014-11-22 04:12:48 +00:00
}
return lit , nil
}
2015-03-06 13:52:25 +00:00
// parseSources parses a comma delimited list of sources.
2015-08-27 23:23:21 +00:00
func ( p * Parser ) parseSources ( parent Node ) ( Sources , error ) {
2015-03-06 13:52:25 +00:00
var sources Sources
2014-12-20 04:36:52 +00:00
for {
2015-08-27 23:23:21 +00:00
s , err := p . parseSource ( parent )
2015-03-06 13:52:25 +00:00
if err != nil {
return nil , err
2014-12-06 18:17:58 +00:00
}
2015-03-06 13:52:25 +00:00
sources = append ( sources , s )
2014-12-20 04:36:52 +00:00
2015-03-06 13:52:25 +00:00
if tok , _ , _ := p . scanIgnoreWhitespace ( ) ; tok != COMMA {
2014-12-20 04:36:52 +00:00
p . unscan ( )
break
2014-12-06 18:17:58 +00:00
}
}
2015-03-06 13:52:25 +00:00
return sources , nil
}
// peekRune returns the next rune that would be read by the scanner.
func ( p * Parser ) peekRune ( ) rune {
r , _ , _ := p . s . s . r . ReadRune ( )
if r != eof {
_ = p . s . s . r . UnreadRune ( )
2014-12-20 04:36:52 +00:00
}
2015-03-06 13:52:25 +00:00
return r
}
2015-08-27 23:23:21 +00:00
func ( p * Parser ) parseSource ( parent Node ) ( Source , error ) {
m := & Measurement { Parent : parent }
2015-03-06 13:52:25 +00:00
2015-03-28 00:40:21 +00:00
// Attempt to parse a regex.
re , err := p . parseRegex ( )
if err != nil {
return nil , err
} else if re != nil {
m . Regex = re
// Regex is always last so we're done.
return m , nil
}
2015-03-06 13:52:25 +00:00
2015-03-28 00:40:21 +00:00
// Didn't find a regex so parse segmented identifiers.
idents , err := p . parseSegmentedIdents ( )
if err != nil {
return nil , err
}
2015-03-06 13:52:25 +00:00
2015-03-28 00:40:21 +00:00
// If we already have the max allowed idents, we're done.
if len ( idents ) == 3 {
m . Database , m . RetentionPolicy , m . Name = idents [ 0 ] , idents [ 1 ] , idents [ 2 ]
return m , nil
}
// Check again for regex.
re , err = p . parseRegex ( )
if err != nil {
return nil , err
} else if re != nil {
m . Regex = re
}
2015-03-06 13:52:25 +00:00
2015-03-28 00:40:21 +00:00
// Assign identifiers to their proper locations.
switch len ( idents ) {
case 1 :
if re != nil {
m . RetentionPolicy = idents [ 0 ]
2015-03-06 13:52:25 +00:00
} else {
2015-03-28 00:40:21 +00:00
m . Name = idents [ 0 ]
}
case 2 :
if re != nil {
m . Database , m . RetentionPolicy = idents [ 0 ] , idents [ 1 ]
} else {
m . RetentionPolicy , m . Name = idents [ 0 ] , idents [ 1 ]
2015-03-06 13:52:25 +00:00
}
2014-12-20 04:36:52 +00:00
}
2015-03-28 00:40:21 +00:00
return m , nil
2014-11-22 04:12:48 +00:00
}
// parseCondition parses the "WHERE" clause of the query, if it exists.
func ( p * Parser ) parseCondition ( ) ( Expr , error ) {
// Check if the WHERE token exists.
if tok , _ , _ := p . scanIgnoreWhitespace ( ) ; tok != WHERE {
p . unscan ( )
return nil , nil
}
// Scan the identifier for the source.
expr , err := p . ParseExpr ( )
if err != nil {
return nil , err
}
return expr , nil
}
// parseDimensions parses the "GROUP BY" clause of the query, if it exists.
func ( p * Parser ) parseDimensions ( ) ( Dimensions , error ) {
// If the next token is not GROUP then exit.
if tok , _ , _ := p . scanIgnoreWhitespace ( ) ; tok != GROUP {
p . unscan ( )
return nil , nil
}
// Now the next token should be "BY".
if tok , pos , lit := p . scanIgnoreWhitespace ( ) ; tok != BY {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "BY" } , pos )
}
var dimensions Dimensions
for {
// Parse the dimension.
d , err := p . parseDimension ( )
if err != nil {
return nil , err
}
// Add new dimension.
dimensions = append ( dimensions , d )
// If there's not a comma next then stop parsing dimensions.
if tok , _ , _ := p . scan ( ) ; tok != COMMA {
p . unscan ( )
break
}
}
return dimensions , nil
}
// parseDimension parses a single dimension.
func ( p * Parser ) parseDimension ( ) ( * Dimension , error ) {
// Parse the expression first.
expr , err := p . ParseExpr ( )
if err != nil {
return nil , err
}
// Consume all trailing whitespace.
p . consumeWhitespace ( )
return & Dimension { Expr : expr } , nil
}
2015-06-28 06:54:34 +00:00
// parseFill parses the fill call and its options.
2015-03-12 01:05:31 +00:00
func ( p * Parser ) parseFill ( ) ( FillOption , interface { } , error ) {
// Parse the expression first.
expr , err := p . ParseExpr ( )
if err != nil {
p . unscan ( )
return NullFill , nil , nil
}
2015-07-09 18:24:06 +00:00
lit , ok := expr . ( * Call )
if ! ok {
2015-03-12 01:05:31 +00:00
p . unscan ( )
return NullFill , nil , nil
2015-07-09 18:24:06 +00:00
}
if strings . ToLower ( lit . Name ) != "fill" {
p . unscan ( )
return NullFill , nil , nil
}
if len ( lit . Args ) != 1 {
return NullFill , nil , errors . New ( "fill requires an argument, e.g.: 0, null, none, previous" )
}
switch lit . Args [ 0 ] . String ( ) {
case "null" :
return NullFill , nil , nil
case "none" :
return NoFill , nil , nil
case "previous" :
return PreviousFill , nil , nil
default :
num , ok := lit . Args [ 0 ] . ( * NumberLiteral )
if ! ok {
return NullFill , nil , fmt . Errorf ( "expected number argument in fill()" )
2015-03-12 01:05:31 +00:00
}
2015-07-09 18:24:06 +00:00
return NumberFill , num . Val , nil
2015-03-12 01:05:31 +00:00
}
}
2015-01-25 20:34:49 +00:00
// parseOptionalTokenAndInt parses the specified token followed
// by an int, if it exists.
2015-03-13 00:59:38 +00:00
func ( p * Parser ) parseOptionalTokenAndInt ( t Token ) ( int , error ) {
2015-01-25 20:34:49 +00:00
// Check if the token exists.
if tok , _ , _ := p . scanIgnoreWhitespace ( ) ; tok != t {
2014-11-22 04:12:48 +00:00
p . unscan ( )
return 0 , nil
}
2015-01-25 20:34:49 +00:00
// Scan the number.
2014-11-22 04:12:48 +00:00
tok , pos , lit := p . scanIgnoreWhitespace ( )
if tok != NUMBER {
return 0 , newParseError ( tokstr ( tok , lit ) , [ ] string { "number" } , pos )
}
// Return an error if the number has a fractional part.
if strings . Contains ( lit , "." ) {
2015-01-25 20:34:49 +00:00
msg := fmt . Sprintf ( "fractional parts not allowed in %s" , t . String ( ) )
return 0 , & ParseError { Message : msg , Pos : pos }
2014-11-22 04:12:48 +00:00
}
// Parse number.
2014-11-22 23:33:21 +00:00
n , _ := strconv . ParseInt ( lit , 10 , 64 )
2014-11-22 04:12:48 +00:00
2015-03-13 00:59:38 +00:00
if n < 0 {
msg := fmt . Sprintf ( "%s must be >= 0" , t . String ( ) )
2015-01-25 20:34:49 +00:00
return 0 , & ParseError { Message : msg , Pos : pos }
2014-12-15 01:43:08 +00:00
}
2014-11-22 04:12:48 +00:00
return int ( n ) , nil
}
2014-12-16 17:32:08 +00:00
// parseOrderBy parses the "ORDER BY" clause of a query, if it exists.
func ( p * Parser ) parseOrderBy ( ) ( SortFields , error ) {
// Return nil result and nil error if no ORDER token at this position.
if tok , _ , _ := p . scanIgnoreWhitespace ( ) ; tok != ORDER {
p . unscan ( )
return nil , nil
}
// Parse the required BY token.
if tok , pos , lit := p . scanIgnoreWhitespace ( ) ; tok != BY {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "BY" } , pos )
}
// Parse the ORDER BY fields.
fields , err := p . parseSortFields ( )
if err != nil {
return nil , err
}
return fields , nil
}
2015-07-21 19:07:56 +00:00
// parseSortFields parses the sort fields for an ORDER BY clause.
2014-12-15 00:54:51 +00:00
func ( p * Parser ) parseSortFields ( ) ( SortFields , error ) {
var fields SortFields
2015-07-21 19:07:56 +00:00
// If first token is ASC or DESC, all fields are sorted.
if tok , pos , lit := p . scanIgnoreWhitespace ( ) ; tok == ASC || tok == DESC {
if tok == DESC {
// Token must be ASC, until other sort orders are supported.
return nil , errors . New ( "only ORDER BY time ASC supported at this time" )
}
return append ( fields , & SortField { Ascending : ( tok == ASC ) } ) , nil
} else if tok != IDENT {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "identifier" , "ASC" , "DESC" } , pos )
}
p . unscan ( )
2014-12-15 00:54:51 +00:00
// At least one field is required.
field , err := p . parseSortField ( )
if err != nil {
return nil , err
2014-11-22 04:12:48 +00:00
}
2014-12-15 00:54:51 +00:00
fields = append ( fields , field )
2014-11-22 04:12:48 +00:00
2014-12-15 00:54:51 +00:00
// Parse additional fields.
for {
tok , _ , _ := p . scanIgnoreWhitespace ( )
2014-12-16 14:06:28 +00:00
2014-12-15 00:54:51 +00:00
if tok != COMMA {
p . unscan ( )
break
}
field , err := p . parseSortField ( )
if err != nil {
return nil , err
}
fields = append ( fields , field )
2014-11-22 04:12:48 +00:00
}
2015-07-21 19:07:56 +00:00
// First SortField must be time ASC, until other sort orders are supported.
if len ( fields ) > 1 || fields [ 0 ] . Name != "time" || ! fields [ 0 ] . Ascending {
return nil , errors . New ( "only ORDER BY time ASC supported at this time" )
}
2014-12-15 00:54:51 +00:00
return fields , nil
}
// parseSortField parses one field of an ORDER BY clause.
func ( p * Parser ) parseSortField ( ) ( * SortField , error ) {
field := & SortField { }
2015-07-21 19:07:56 +00:00
// Parse sort field name.
ident , err := p . parseIdent ( )
if err != nil {
return nil , err
}
field . Name = ident
// Check for optional ASC or DESC clause. Default is ASC.
2015-06-11 07:51:44 +00:00
tok , _ , _ := p . scanIgnoreWhitespace ( )
2015-07-21 19:07:56 +00:00
if tok != ASC && tok != DESC {
p . unscan ( )
tok = ASC
2014-11-22 04:12:48 +00:00
}
2015-07-21 19:07:56 +00:00
field . Ascending = ( tok == ASC )
2014-11-22 04:12:48 +00:00
2014-12-15 00:54:51 +00:00
return field , nil
2014-11-22 04:12:48 +00:00
}
2015-03-28 00:40:21 +00:00
// parseVarRef parses a reference to a measurement or field.
func ( p * Parser ) parseVarRef ( ) ( * VarRef , error ) {
// Parse the segments of the variable ref.
segments , err := p . parseSegmentedIdents ( )
if err != nil {
return nil , err
}
vr := & VarRef { Val : strings . Join ( segments , "." ) }
return vr , nil
}
2014-11-22 04:12:48 +00:00
// ParseExpr parses an expression.
func ( p * Parser ) ParseExpr ( ) ( Expr , error ) {
2015-03-03 02:21:37 +00:00
var err error
2015-04-15 17:25:49 +00:00
// Dummy root node.
root := & BinaryExpr { }
2015-03-03 02:21:37 +00:00
2014-11-22 04:12:48 +00:00
// Parse a non-binary expression type to start.
// This variable will always be the root of the expression tree.
2015-04-15 17:25:49 +00:00
root . RHS , err = p . parseUnaryExpr ( )
2014-11-22 04:12:48 +00:00
if err != nil {
return nil , err
}
// Loop over operations and unary exprs and build a tree based on precendence.
for {
// If the next token is NOT an operator then return the expression.
op , _ , _ := p . scanIgnoreWhitespace ( )
2014-11-22 23:33:21 +00:00
if ! op . isOperator ( ) {
2014-11-22 04:12:48 +00:00
p . unscan ( )
2015-04-15 17:25:49 +00:00
return root . RHS , nil
2014-11-22 04:12:48 +00:00
}
2015-03-03 02:21:37 +00:00
// Otherwise parse the next expression.
var rhs Expr
if IsRegexOp ( op ) {
// RHS of a regex operator must be a regular expression.
p . consumeWhitespace ( )
if rhs , err = p . parseRegex ( ) ; err != nil {
return nil , err
}
2015-07-16 20:47:48 +00:00
// parseRegex can return an empty type, but we need it to be present
if rhs . ( * RegexLiteral ) == nil {
tok , pos , lit := p . scanIgnoreWhitespace ( )
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "regex" } , pos )
}
2015-03-03 02:21:37 +00:00
} else {
if rhs , err = p . parseUnaryExpr ( ) ; err != nil {
return nil , err
}
2014-11-22 04:12:48 +00:00
}
2015-04-15 17:52:18 +00:00
// Find the right spot in the tree to add the new expression by
// descending the RHS of the expression tree until we reach the last
// BinaryExpr or a BinaryExpr whose RHS has an operator with
// precedence >= the operator being added.
2015-04-15 17:25:49 +00:00
for node := root ; ; {
r , ok := node . RHS . ( * BinaryExpr )
2015-04-15 13:28:21 +00:00
if ! ok || r . Op . Precedence ( ) >= op . Precedence ( ) {
2015-04-15 17:52:18 +00:00
// Add the new expression here and break.
2015-04-15 17:25:49 +00:00
node . RHS = & BinaryExpr { LHS : node . RHS , RHS : rhs , Op : op }
2015-04-15 13:28:21 +00:00
break
}
2015-04-15 17:25:49 +00:00
node = r
2014-11-22 04:12:48 +00:00
}
}
}
// parseUnaryExpr parses an non-binary expression.
func ( p * Parser ) parseUnaryExpr ( ) ( Expr , error ) {
2014-11-25 06:12:32 +00:00
// If the first token is a LPAREN then parse it as its own grouped expression.
if tok , _ , _ := p . scanIgnoreWhitespace ( ) ; tok == LPAREN {
expr , err := p . ParseExpr ( )
if err != nil {
return nil , err
}
// Expect an RPAREN at the end.
if tok , pos , lit := p . scanIgnoreWhitespace ( ) ; tok != RPAREN {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { ")" } , pos )
}
return & ParenExpr { Expr : expr } , nil
}
p . unscan ( )
2014-11-22 04:12:48 +00:00
// Read next token.
tok , pos , lit := p . scanIgnoreWhitespace ( )
switch tok {
case IDENT :
2014-11-25 03:43:23 +00:00
// If the next immediate token is a left parentheses, parse as function call.
// Otherwise parse as a variable reference.
if tok0 , _ , _ := p . scan ( ) ; tok0 == LPAREN {
return p . parseCall ( lit )
}
2015-03-28 00:40:21 +00:00
p . unscan ( ) // unscan the last token (wasn't an LPAREN)
p . unscan ( ) // unscan the IDENT token
// Parse it as a VarRef.
return p . parseVarRef ( )
2015-05-18 21:36:50 +00:00
case DISTINCT :
// If the next immediate token is a left parentheses, parse as function call.
// Otherwise parse as a Distinct expression.
tok0 , pos , lit := p . scan ( )
if tok0 == LPAREN {
return p . parseCall ( "distinct" )
} else if tok0 == WS {
tok1 , pos , lit := p . scanIgnoreWhitespace ( )
if tok1 != IDENT {
return nil , newParseError ( tokstr ( tok1 , lit ) , [ ] string { "identifier" } , pos )
}
return & Distinct { Val : lit } , nil
}
return nil , newParseError ( tokstr ( tok0 , lit ) , [ ] string { "(" , "identifier" } , pos )
2014-11-22 04:12:48 +00:00
case STRING :
2014-12-15 15:34:32 +00:00
// If literal looks like a date time then parse it as a time literal.
2014-12-21 17:59:36 +00:00
if isDateTimeString ( lit ) {
t , err := time . Parse ( DateTimeFormat , lit )
if err != nil {
2015-02-08 11:06:30 +00:00
// try to parse it as an RFCNano time
t , err := time . Parse ( time . RFC3339Nano , lit )
if err != nil {
return nil , & ParseError { Message : "unable to parse datetime" , Pos : pos }
}
return & TimeLiteral { Val : t } , nil
2014-12-21 17:59:36 +00:00
}
return & TimeLiteral { Val : t } , nil
} else if isDateString ( lit ) {
t , err := time . Parse ( DateFormat , lit )
2014-12-15 15:34:32 +00:00
if err != nil {
2014-12-21 17:59:36 +00:00
return nil , & ParseError { Message : "unable to parse date" , Pos : pos }
2014-12-15 15:34:32 +00:00
}
return & TimeLiteral { Val : t } , nil
}
2014-11-22 04:12:48 +00:00
return & StringLiteral { Val : lit } , nil
case NUMBER :
v , err := strconv . ParseFloat ( lit , 64 )
if err != nil {
return nil , & ParseError { Message : "unable to parse number" , Pos : pos }
}
return & NumberLiteral { Val : v } , nil
case TRUE , FALSE :
return & BooleanLiteral { Val : ( tok == TRUE ) } , nil
2015-01-05 02:50:56 +00:00
case DURATION_VAL :
2014-11-22 23:33:21 +00:00
v , _ := ParseDuration ( lit )
2014-11-22 04:12:48 +00:00
return & DurationLiteral { Val : v } , nil
2015-02-18 05:13:33 +00:00
case MUL :
return & Wildcard { } , nil
2015-03-02 16:33:51 +00:00
case REGEX :
re , err := regexp . Compile ( lit )
2015-02-13 18:25:48 +00:00
if err != nil {
2015-03-02 16:33:51 +00:00
return nil , & ParseError { Message : err . Error ( ) , Pos : pos }
2015-02-13 18:25:48 +00:00
}
2015-03-02 16:33:51 +00:00
return & RegexLiteral { Val : re } , nil
default :
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "identifier" , "string" , "number" , "bool" } , pos )
2015-02-13 18:25:48 +00:00
}
}
2015-03-03 02:21:37 +00:00
// parseRegex parses a regular expression.
2015-03-28 00:40:21 +00:00
func ( p * Parser ) parseRegex ( ) ( * RegexLiteral , error ) {
nextRune := p . peekRune ( )
if isWhitespace ( nextRune ) {
p . consumeWhitespace ( )
}
// If the next character is not a '/', then return nils.
nextRune = p . peekRune ( )
if nextRune != '/' {
return nil , nil
}
2015-03-06 13:52:25 +00:00
tok , pos , lit := p . s . ScanRegex ( )
2015-03-03 02:21:37 +00:00
if tok == BADESCAPE {
msg := fmt . Sprintf ( "bad escape: %s" , lit )
return nil , & ParseError { Message : msg , Pos : pos }
} else if tok == BADREGEX {
msg := fmt . Sprintf ( "bad regex: %s" , lit )
return nil , & ParseError { Message : msg , Pos : pos }
} else if tok != REGEX {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { "regex" } , pos )
}
re , err := regexp . Compile ( lit )
if err != nil {
return nil , & ParseError { Message : err . Error ( ) , Pos : pos }
}
return & RegexLiteral { Val : re } , nil
}
2014-11-25 03:43:23 +00:00
// parseCall parses a function call.
// This function assumes the function name and LPAREN have been consumed.
func ( p * Parser ) parseCall ( name string ) ( * Call , error ) {
2015-05-01 15:29:39 +00:00
name = strings . ToLower ( name )
2014-11-25 03:43:23 +00:00
// If there's a right paren then just return immediately.
if tok , _ , _ := p . scan ( ) ; tok == RPAREN {
return & Call { Name : name } , nil
}
p . unscan ( )
// Otherwise parse function call arguments.
var args [ ] Expr
for {
// Parse an expression argument.
arg , err := p . ParseExpr ( )
if err != nil {
return nil , err
}
args = append ( args , arg )
// If there's not a comma next then stop parsing arguments.
if tok , _ , _ := p . scan ( ) ; tok != COMMA {
p . unscan ( )
break
}
}
// There should be a right parentheses at the end.
if tok , pos , lit := p . scan ( ) ; tok != RPAREN {
return nil , newParseError ( tokstr ( tok , lit ) , [ ] string { ")" } , pos )
}
return & Call { Name : name , Args : args } , nil
}
2014-11-22 04:12:48 +00:00
// scan returns the next token from the underlying scanner.
func ( p * Parser ) scan ( ) ( tok Token , pos Pos , lit string ) { return p . s . Scan ( ) }
// scanIgnoreWhitespace scans the next non-whitespace token.
func ( p * Parser ) scanIgnoreWhitespace ( ) ( tok Token , pos Pos , lit string ) {
tok , pos , lit = p . scan ( )
if tok == WS {
tok , pos , lit = p . scan ( )
}
return
}
// consumeWhitespace scans the next token if it's whitespace.
func ( p * Parser ) consumeWhitespace ( ) {
if tok , _ , _ := p . scan ( ) ; tok != WS {
p . unscan ( )
}
}
// unscan pushes the previously read token back onto the buffer.
func ( p * Parser ) unscan ( ) { p . s . Unscan ( ) }
// ParseDuration parses a time duration from a string.
func ParseDuration ( s string ) ( time . Duration , error ) {
// Return an error if the string is blank.
if len ( s ) == 0 {
return 0 , ErrInvalidDuration
}
// If there's only character then it must be a digit (in microseconds).
if len ( s ) == 1 {
2015-02-01 18:47:48 +00:00
if n , err := strconv . ParseInt ( s , 10 , 64 ) ; err == nil {
2014-11-22 04:12:48 +00:00
return time . Duration ( n ) * time . Microsecond , nil
}
2015-02-01 18:47:48 +00:00
return 0 , ErrInvalidDuration
2014-11-22 04:12:48 +00:00
}
2014-11-25 06:43:23 +00:00
// Split string into individual runes.
a := split ( s )
2014-11-22 04:12:48 +00:00
// Extract the unit of measure.
// If the last character is a digit then parse the whole string as microseconds.
// If the last two characters are "ms" the parse as milliseconds.
// Otherwise just use the last character as the unit of measure.
var num , uom string
2014-11-25 06:43:23 +00:00
if isDigit ( rune ( a [ len ( a ) - 1 ] ) ) {
2014-11-22 04:12:48 +00:00
num , uom = s , "u"
} else if len ( s ) > 2 && s [ len ( s ) - 2 : ] == "ms" {
2014-11-25 06:43:23 +00:00
num , uom = string ( a [ : len ( a ) - 2 ] ) , "ms"
2014-11-22 04:12:48 +00:00
} else {
2014-11-25 06:43:23 +00:00
num , uom = string ( a [ : len ( a ) - 1 ] ) , string ( a [ len ( a ) - 1 : ] )
2014-11-22 04:12:48 +00:00
}
// Parse the numeric part.
n , err := strconv . ParseInt ( num , 10 , 64 )
if err != nil {
return 0 , ErrInvalidDuration
}
// Multiply by the unit of measure.
switch uom {
2014-11-25 06:43:23 +00:00
case "u" , "µ" :
2014-11-22 04:12:48 +00:00
return time . Duration ( n ) * time . Microsecond , nil
case "ms" :
return time . Duration ( n ) * time . Millisecond , nil
case "s" :
return time . Duration ( n ) * time . Second , nil
case "m" :
return time . Duration ( n ) * time . Minute , nil
case "h" :
return time . Duration ( n ) * time . Hour , nil
case "d" :
return time . Duration ( n ) * 24 * time . Hour , nil
case "w" :
return time . Duration ( n ) * 7 * 24 * time . Hour , nil
default :
return 0 , ErrInvalidDuration
}
}
2014-12-06 18:17:58 +00:00
// FormatDuration formats a duration to a string.
func FormatDuration ( d time . Duration ) string {
2014-12-11 06:32:45 +00:00
if d == 0 {
return "0s"
} else if d % ( 7 * 24 * time . Hour ) == 0 {
2014-12-06 18:17:58 +00:00
return fmt . Sprintf ( "%dw" , d / ( 7 * 24 * time . Hour ) )
} else if d % ( 24 * time . Hour ) == 0 {
return fmt . Sprintf ( "%dd" , d / ( 24 * time . Hour ) )
} else if d % time . Hour == 0 {
return fmt . Sprintf ( "%dh" , d / time . Hour )
} else if d % time . Minute == 0 {
return fmt . Sprintf ( "%dm" , d / time . Minute )
} else if d % time . Second == 0 {
return fmt . Sprintf ( "%ds" , d / time . Second )
} else if d % time . Millisecond == 0 {
return fmt . Sprintf ( "%dms" , d / time . Millisecond )
}
2015-02-01 18:47:48 +00:00
return fmt . Sprintf ( "%d" , d / time . Microsecond )
2014-12-06 18:17:58 +00:00
}
2015-01-03 03:56:26 +00:00
// parseTokens consumes an expected sequence of tokens.
func ( p * Parser ) parseTokens ( toks [ ] Token ) error {
for _ , expected := range toks {
if tok , pos , lit := p . scanIgnoreWhitespace ( ) ; tok != expected {
return newParseError ( tokstr ( tok , lit ) , [ ] string { tokens [ expected ] } , pos )
}
}
return nil
}
2015-02-01 18:47:48 +00:00
// QuoteString returns a quoted string.
2015-01-19 20:01:32 +00:00
func QuoteString ( s string ) string {
return ` ' ` + strings . NewReplacer ( "\n" , ` \n ` , ` \ ` , ` \\ ` , ` ' ` , ` \' ` ) . Replace ( s ) + ` ' `
2014-12-06 18:17:58 +00:00
}
2015-01-18 21:45:22 +00:00
// QuoteIdent returns a quoted identifier from multiple bare identifiers.
2015-03-28 00:40:21 +00:00
func QuoteIdent ( segments ... string ) string {
2015-01-19 20:01:32 +00:00
r := strings . NewReplacer ( "\n" , ` \n ` , ` \ ` , ` \\ ` , ` " ` , ` \" ` )
2015-01-18 21:45:22 +00:00
var buf bytes . Buffer
for i , segment := range segments {
2015-03-28 00:40:21 +00:00
needQuote := IdentNeedsQuotes ( segment ) ||
( ( i < len ( segments ) - 1 ) && segment != "" ) // not last segment && not ""
if needQuote {
_ = buf . WriteByte ( '"' )
}
2015-01-19 20:01:32 +00:00
_ , _ = buf . WriteString ( r . Replace ( segment ) )
2015-03-28 00:40:21 +00:00
if needQuote {
_ = buf . WriteByte ( '"' )
}
2015-01-18 21:45:22 +00:00
if i < len ( segments ) - 1 {
_ = buf . WriteByte ( '.' )
}
2014-12-06 18:17:58 +00:00
}
2015-01-18 21:45:22 +00:00
return buf . String ( )
2014-12-06 18:17:58 +00:00
}
2015-03-28 00:40:21 +00:00
// IdentNeedsQuotes returns true if the ident string given would require quotes.
func IdentNeedsQuotes ( ident string ) bool {
2015-08-05 16:40:42 +00:00
// check if this identifier is a keyword
tok := Lookup ( ident )
if tok != IDENT {
return true
}
2015-03-28 00:40:21 +00:00
for i , r := range ident {
if i == 0 && ! isIdentFirstChar ( r ) {
return true
} else if i > 0 && ! isIdentChar ( r ) {
return true
}
}
return false
}
2014-11-25 06:43:23 +00:00
// split splits a string into a slice of runes.
func split ( s string ) ( a [ ] rune ) {
for _ , ch := range s {
a = append ( a , ch )
}
return
}
2014-12-21 19:45:52 +00:00
// isDateString returns true if the string looks like a date-only time literal.
2014-12-21 17:59:36 +00:00
func isDateString ( s string ) bool { return dateStringRegexp . MatchString ( s ) }
2014-12-21 19:45:52 +00:00
// isDateTimeString returns true if the string looks like a date+time time literal.
2014-12-21 17:59:36 +00:00
func isDateTimeString ( s string ) bool { return dateTimeStringRegexp . MatchString ( s ) }
2014-12-15 15:34:32 +00:00
2014-12-21 17:59:36 +00:00
var dateStringRegexp = regexp . MustCompile ( ` ^\d { 4}-\d { 2}-\d { 2}$ ` )
2015-02-08 11:06:30 +00:00
var dateTimeStringRegexp = regexp . MustCompile ( ` ^\d { 4}-\d { 2}-\d { 2}.+ ` )
2014-12-15 15:34:32 +00:00
2014-11-22 04:12:48 +00:00
// ErrInvalidDuration is returned when parsing a malformatted duration.
var ErrInvalidDuration = errors . New ( "invalid duration" )
// ParseError represents an error that occurred during parsing.
type ParseError struct {
Message string
Found string
Expected [ ] string
Pos Pos
}
// newParseError returns a new instance of ParseError.
func newParseError ( found string , expected [ ] string , pos Pos ) * ParseError {
return & ParseError { Found : found , Expected : expected , Pos : pos }
}
// Error returns the string representation of the error.
func ( e * ParseError ) Error ( ) string {
if e . Message != "" {
return fmt . Sprintf ( "%s at line %d, char %d" , e . Message , e . Pos . Line + 1 , e . Pos . Char + 1 )
}
return fmt . Sprintf ( "found %s, expected %s at line %d, char %d" , e . Found , strings . Join ( e . Expected , ", " ) , e . Pos . Line + 1 , e . Pos . Char + 1 )
2014-11-17 22:54:35 +00:00
}