Merge pull request #1334 from influxdb/ident-scan
Ident scanning, single quote stringspull/1337/head
commit
8a2b078a10
|
@ -367,7 +367,7 @@ func TestHandler_CreateUser(t *testing.T) {
|
|||
s := NewHTTPServer(srvr)
|
||||
defer s.Close()
|
||||
|
||||
query := map[string]string{"q": `CREATE USER testuser WITH PASSWORD "1337"`}
|
||||
query := map[string]string{"q": `CREATE USER testuser WITH PASSWORD '1337'`}
|
||||
status, body := MustHTTP("GET", s.URL+`/query`, query, nil, "")
|
||||
if status != http.StatusOK {
|
||||
t.Fatalf("unexpected status: %d", status)
|
||||
|
|
|
@ -641,9 +641,6 @@ func MatchSource(src Source, name string) string {
|
|||
|
||||
// Target represents a target (destination) policy, measurment, and DB.
|
||||
type Target struct {
|
||||
// Retention policy to write into.
|
||||
RetentionPolicy string
|
||||
|
||||
// Measurement to write into.
|
||||
Measurement string
|
||||
|
||||
|
@ -655,12 +652,6 @@ type Target struct {
|
|||
func (t *Target) String() string {
|
||||
var buf bytes.Buffer
|
||||
_, _ = buf.WriteString("INTO ")
|
||||
|
||||
if t.RetentionPolicy != "" {
|
||||
_, _ = buf.WriteString(t.RetentionPolicy)
|
||||
_, _ = buf.WriteString(".")
|
||||
}
|
||||
|
||||
_, _ = buf.WriteString(t.Measurement)
|
||||
|
||||
if t.Database != "" {
|
||||
|
@ -1146,7 +1137,7 @@ type StringLiteral struct {
|
|||
}
|
||||
|
||||
// String returns a string representation of the literal.
|
||||
func (l *StringLiteral) String() string { return Quote(l.Val) }
|
||||
func (l *StringLiteral) String() string { return QuoteString(l.Val) }
|
||||
|
||||
// TimeLiteral represents a point-in-time literal.
|
||||
type TimeLiteral struct {
|
||||
|
|
|
@ -53,23 +53,23 @@ func TestSelectStatement_Substatement(t *testing.T) {
|
|||
|
||||
// 3. Join with condition
|
||||
{
|
||||
stmt: `SELECT sum(aa.value) + sum(bb.value) FROM join(aa, bb) WHERE aa.host = "servera" AND bb.host = "serverb"`,
|
||||
stmt: `SELECT sum(aa.value) + sum(bb.value) FROM join(aa, bb) WHERE aa.host = 'servera' AND bb.host = 'serverb'`,
|
||||
expr: &influxql.VarRef{Val: "bb.value"},
|
||||
sub: `SELECT bb.value FROM bb WHERE bb.host = "serverb"`,
|
||||
sub: `SELECT bb.value FROM bb WHERE bb.host = 'serverb'`,
|
||||
},
|
||||
|
||||
// 4. Join with complex condition
|
||||
{
|
||||
stmt: `SELECT sum(aa.value) + sum(bb.value) FROM join(aa, bb) WHERE aa.host = "servera" AND (bb.host = "serverb" OR bb.host = "serverc") AND 1 = 2`,
|
||||
stmt: `SELECT sum(aa.value) + sum(bb.value) FROM join(aa, bb) WHERE aa.host = 'servera' AND (bb.host = 'serverb' OR bb.host = 'serverc') AND 1 = 2`,
|
||||
expr: &influxql.VarRef{Val: "bb.value"},
|
||||
sub: `SELECT bb.value FROM bb WHERE (bb.host = "serverb" OR bb.host = "serverc") AND 1.000 = 2.000`,
|
||||
sub: `SELECT bb.value FROM bb WHERE (bb.host = 'serverb' OR bb.host = 'serverc') AND 1.000 = 2.000`,
|
||||
},
|
||||
|
||||
// 5. 4 with different condition order
|
||||
{
|
||||
stmt: `SELECT sum(aa.value) + sum(bb.value) FROM join(aa, bb) WHERE ((bb.host = "serverb" OR bb.host = "serverc") AND aa.host = "servera") AND 1 = 2`,
|
||||
stmt: `SELECT sum(aa.value) + sum(bb.value) FROM join(aa, bb) WHERE ((bb.host = 'serverb' OR bb.host = 'serverc') AND aa.host = 'servera') AND 1 = 2`,
|
||||
expr: &influxql.VarRef{Val: "bb.value"},
|
||||
sub: `SELECT bb.value FROM bb WHERE ((bb.host = "serverb" OR bb.host = "serverc")) AND 1.000 = 2.000`,
|
||||
sub: `SELECT bb.value FROM bb WHERE ((bb.host = 'serverb' OR bb.host = 'serverc')) AND 1.000 = 2.000`,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -146,7 +146,7 @@ func TestFold(t *testing.T) {
|
|||
{`60m + 50`, `1h + 50.000`},
|
||||
|
||||
// String literals.
|
||||
{`"foo" + 'bar'`, `"foobar"`},
|
||||
{`'foo' + 'bar'`, `'foobar'`},
|
||||
} {
|
||||
// Fold expression.
|
||||
now := mustParseTime("2000-01-01T00:00:00Z")
|
||||
|
@ -175,25 +175,25 @@ func TestTimeRange(t *testing.T) {
|
|||
min, max string
|
||||
}{
|
||||
// LHS VarRef
|
||||
{expr: `time > "2000-01-01 00:00:00"`, min: `2000-01-01 00:00:00.000001`, max: `0001-01-01 00:00:00`},
|
||||
{expr: `time >= "2000-01-01 00:00:00"`, min: `2000-01-01 00:00:00`, max: `0001-01-01 00:00:00`},
|
||||
{expr: `time < "2000-01-01 00:00:00"`, min: `0001-01-01 00:00:00`, max: `1999-12-31 23:59:59.999999`},
|
||||
{expr: `time <= "2000-01-01 00:00:00"`, min: `0001-01-01 00:00:00`, max: `2000-01-01 00:00:00`},
|
||||
{expr: `time > '2000-01-01 00:00:00'`, min: `2000-01-01 00:00:00.000001`, max: `0001-01-01 00:00:00`},
|
||||
{expr: `time >= '2000-01-01 00:00:00'`, min: `2000-01-01 00:00:00`, max: `0001-01-01 00:00:00`},
|
||||
{expr: `time < '2000-01-01 00:00:00'`, min: `0001-01-01 00:00:00`, max: `1999-12-31 23:59:59.999999`},
|
||||
{expr: `time <= '2000-01-01 00:00:00'`, min: `0001-01-01 00:00:00`, max: `2000-01-01 00:00:00`},
|
||||
|
||||
// RHS VarRef
|
||||
{expr: `"2000-01-01 00:00:00" > time`, min: `0001-01-01 00:00:00`, max: `1999-12-31 23:59:59.999999`},
|
||||
{expr: `"2000-01-01 00:00:00" >= time`, min: `0001-01-01 00:00:00`, max: `2000-01-01 00:00:00`},
|
||||
{expr: `"2000-01-01 00:00:00" < time`, min: `2000-01-01 00:00:00.000001`, max: `0001-01-01 00:00:00`},
|
||||
{expr: `"2000-01-01 00:00:00" <= time`, min: `2000-01-01 00:00:00`, max: `0001-01-01 00:00:00`},
|
||||
{expr: `'2000-01-01 00:00:00' > time`, min: `0001-01-01 00:00:00`, max: `1999-12-31 23:59:59.999999`},
|
||||
{expr: `'2000-01-01 00:00:00' >= time`, min: `0001-01-01 00:00:00`, max: `2000-01-01 00:00:00`},
|
||||
{expr: `'2000-01-01 00:00:00' < time`, min: `2000-01-01 00:00:00.000001`, max: `0001-01-01 00:00:00`},
|
||||
{expr: `'2000-01-01 00:00:00' <= time`, min: `2000-01-01 00:00:00`, max: `0001-01-01 00:00:00`},
|
||||
|
||||
// Equality
|
||||
{expr: `time = "2000-01-01 00:00:00"`, min: `2000-01-01 00:00:00`, max: `2000-01-01 00:00:00`},
|
||||
{expr: `time = '2000-01-01 00:00:00'`, min: `2000-01-01 00:00:00`, max: `2000-01-01 00:00:00`},
|
||||
|
||||
// Multiple time expressions.
|
||||
{expr: `time >= "2000-01-01 00:00:00" AND time < "2000-01-02 00:00:00"`, min: `2000-01-01 00:00:00`, max: `2000-01-01 23:59:59.999999`},
|
||||
{expr: `time >= '2000-01-01 00:00:00' AND time < '2000-01-02 00:00:00'`, min: `2000-01-01 00:00:00`, max: `2000-01-01 23:59:59.999999`},
|
||||
|
||||
// Min/max crossover
|
||||
{expr: `time >= "2000-01-01 00:00:00" AND time <= "1999-01-01 00:00:00"`, min: `2000-01-01 00:00:00`, max: `1999-01-01 00:00:00`},
|
||||
{expr: `time >= '2000-01-01 00:00:00' AND time <= '1999-01-01 00:00:00'`, min: `2000-01-01 00:00:00`, max: `1999-01-01 00:00:00`},
|
||||
|
||||
// Absolute time
|
||||
{expr: `time = 1388534400s`, min: `2014-01-01 00:00:00`, max: `2014-01-01 00:00:00`},
|
||||
|
@ -201,8 +201,8 @@ func TestTimeRange(t *testing.T) {
|
|||
// Non-comparative expressions.
|
||||
{expr: `time`, min: `0001-01-01 00:00:00`, max: `0001-01-01 00:00:00`},
|
||||
{expr: `time + 2`, min: `0001-01-01 00:00:00`, max: `0001-01-01 00:00:00`},
|
||||
{expr: `time - "2000-01-01 00:00:00"`, min: `0001-01-01 00:00:00`, max: `0001-01-01 00:00:00`},
|
||||
{expr: `time AND "2000-01-01 00:00:00"`, min: `0001-01-01 00:00:00`, max: `0001-01-01 00:00:00`},
|
||||
{expr: `time - '2000-01-01 00:00:00'`, min: `0001-01-01 00:00:00`, max: `0001-01-01 00:00:00`},
|
||||
{expr: `time AND '2000-01-01 00:00:00'`, min: `0001-01-01 00:00:00`, max: `0001-01-01 00:00:00`},
|
||||
} {
|
||||
// Extract time range.
|
||||
expr := MustParseExpr(tt.expr)
|
||||
|
|
|
@ -198,9 +198,9 @@ func TestPlanner_Plan_Join(t *testing.T) {
|
|||
|
||||
// Query must join the series and sum the values.
|
||||
rs := db.MustPlanAndExecute(`
|
||||
SELECT sum(cpu.0.value) + sum(cpu.1.value) AS "sum"
|
||||
SELECT sum(cpu.0.value) + sum(cpu.1.value) AS sum
|
||||
FROM JOIN(cpu.0, cpu.1)
|
||||
WHERE time >= "2000-01-01 00:00:00" AND time < "2000-01-01 00:01:00"
|
||||
WHERE time >= '2000-01-01 00:00:00' AND time < '2000-01-01 00:01:00'
|
||||
GROUP BY time(10s)`)
|
||||
|
||||
// Expected resultset.
|
||||
|
|
|
@ -192,7 +192,7 @@ func (p *Parser) parseCreateRetentionPolicyStatement() (*CreateRetentionPolicySt
|
|||
stmt := &CreateRetentionPolicyStatement{}
|
||||
|
||||
// Parse the retention policy name.
|
||||
ident, err := p.parseIdentifier()
|
||||
ident, err := p.parseIdent()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -204,7 +204,7 @@ func (p *Parser) parseCreateRetentionPolicyStatement() (*CreateRetentionPolicySt
|
|||
}
|
||||
|
||||
// Parse the database name.
|
||||
ident, err = p.parseIdentifier()
|
||||
ident, err = p.parseIdent()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -251,7 +251,7 @@ func (p *Parser) parseAlterRetentionPolicyStatement() (*AlterRetentionPolicyStat
|
|||
stmt := &AlterRetentionPolicyStatement{}
|
||||
|
||||
// Parse the retention policy name.
|
||||
ident, err := p.parseIdentifier()
|
||||
ident, err := p.parseIdent()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -263,7 +263,7 @@ func (p *Parser) parseAlterRetentionPolicyStatement() (*AlterRetentionPolicyStat
|
|||
}
|
||||
|
||||
// Parse the database name.
|
||||
ident, err = p.parseIdentifier()
|
||||
ident, err = p.parseIdent()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -342,15 +342,24 @@ func (p *Parser) parseDuration() (time.Duration, error) {
|
|||
return d, nil
|
||||
}
|
||||
|
||||
// parserIdentifier parses a string and returns an identifier.
|
||||
func (p *Parser) parseIdentifier() (string, error) {
|
||||
// parserIdent parses an identifier.
|
||||
func (p *Parser) parseIdent() (string, error) {
|
||||
tok, pos, lit := p.scanIgnoreWhitespace()
|
||||
if tok != IDENT && tok != STRING {
|
||||
if tok != IDENT {
|
||||
return "", newParseError(tokstr(tok, lit), []string{"identifier"}, pos)
|
||||
}
|
||||
return lit, nil
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// parseRevokeStatement parses a string and returns a revoke statement.
|
||||
// This function assumes the REVOKE token has already been consumend.
|
||||
func (p *Parser) parseRevokeStatement() (*RevokeStatement, error) {
|
||||
|
@ -367,9 +376,9 @@ func (p *Parser) parseRevokeStatement() (*RevokeStatement, error) {
|
|||
tok, pos, lit := p.scanIgnoreWhitespace()
|
||||
if tok == ON {
|
||||
// Parse the name of the thing we're granting a privilege to use.
|
||||
tok, pos, lit = p.scanIgnoreWhitespace()
|
||||
if tok != IDENT && tok != STRING {
|
||||
return nil, newParseError(tokstr(tok, lit), []string{"identifier", "string"}, pos)
|
||||
lit, err := p.parseIdent()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stmt.On = lit
|
||||
|
||||
|
@ -386,9 +395,9 @@ func (p *Parser) parseRevokeStatement() (*RevokeStatement, error) {
|
|||
}
|
||||
|
||||
// Parse the name of the user we're granting the privilege to.
|
||||
tok, pos, lit = p.scanIgnoreWhitespace()
|
||||
if tok != IDENT && tok != STRING {
|
||||
return nil, newParseError(tokstr(tok, lit), []string{"identifier", "string"}, pos)
|
||||
lit, err = p.parseIdent()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stmt.User = lit
|
||||
|
||||
|
@ -411,9 +420,9 @@ func (p *Parser) parseGrantStatement() (*GrantStatement, error) {
|
|||
tok, pos, lit := p.scanIgnoreWhitespace()
|
||||
if tok == ON {
|
||||
// Parse the name of the thing we're granting a privilege to use.
|
||||
tok, pos, lit = p.scanIgnoreWhitespace()
|
||||
if tok != IDENT && tok != STRING {
|
||||
return nil, newParseError(tokstr(tok, lit), []string{"identifier", "string"}, pos)
|
||||
lit, err := p.parseIdent()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stmt.On = lit
|
||||
|
||||
|
@ -430,9 +439,9 @@ func (p *Parser) parseGrantStatement() (*GrantStatement, error) {
|
|||
}
|
||||
|
||||
// Parse the name of the user we're granting the privilege to.
|
||||
tok, pos, lit = p.scanIgnoreWhitespace()
|
||||
if tok != IDENT && tok != STRING {
|
||||
return nil, newParseError(tokstr(tok, lit), []string{"identifier", "string"}, pos)
|
||||
lit, err = p.parseIdent()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stmt.User = lit
|
||||
|
||||
|
@ -538,27 +547,12 @@ func (p *Parser) parseTarget(tr targetRequirement) (*Target, error) {
|
|||
}
|
||||
|
||||
// Parse identifier. Could be policy or measurement name.
|
||||
ident, err := p.parseIdentifier()
|
||||
ident, err := p.parseIdent()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
target := &Target{}
|
||||
|
||||
tok, _, _ := p.scanIgnoreWhitespace()
|
||||
if tok == DOT {
|
||||
// Previous identifier was retention policy name.
|
||||
target.RetentionPolicy = ident
|
||||
|
||||
// Parse required measurement.
|
||||
ident, err = p.parseIdentifier()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
p.unscan()
|
||||
}
|
||||
|
||||
target.Measurement = ident
|
||||
|
||||
// Parse optional ON.
|
||||
|
@ -568,7 +562,7 @@ func (p *Parser) parseTarget(tr targetRequirement) (*Target, error) {
|
|||
}
|
||||
|
||||
// Found an ON token so parse required identifier.
|
||||
if ident, err = p.parseIdentifier(); err != nil {
|
||||
if ident, err = p.parseIdent(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
target.Database = ident
|
||||
|
@ -664,7 +658,7 @@ func (p *Parser) parseListMeasurementsStatement() (*ListMeasurementsStatement, e
|
|||
func (p *Parser) parseListRetentionPoliciesStatement() (*ListRetentionPoliciesStatement, error) {
|
||||
stmt := &ListRetentionPoliciesStatement{}
|
||||
|
||||
ident, err := p.parseIdentifier()
|
||||
ident, err := p.parseIdent()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -841,9 +835,9 @@ func (p *Parser) parseDropSeriesStatement() (*DropSeriesStatement, error) {
|
|||
stmt := &DropSeriesStatement{}
|
||||
|
||||
// Read the name of the series to drop.
|
||||
tok, pos, lit := p.scanIgnoreWhitespace()
|
||||
if tok != IDENT && tok != STRING {
|
||||
return nil, newParseError(tokstr(tok, lit), []string{"identifier", "string"}, pos)
|
||||
lit, err := p.parseIdent()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stmt.Name = lit
|
||||
|
||||
|
@ -881,7 +875,7 @@ func (p *Parser) parseCreateContinuousQueryStatement() (*CreateContinuousQuerySt
|
|||
}
|
||||
|
||||
// Read the id of the query to create.
|
||||
ident, err := p.parseIdentifier()
|
||||
ident, err := p.parseIdent()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -893,7 +887,7 @@ func (p *Parser) parseCreateContinuousQueryStatement() (*CreateContinuousQuerySt
|
|||
}
|
||||
|
||||
// Read the name of the database to create the query on.
|
||||
if ident, err = p.parseIdentifier(); err != nil {
|
||||
if ident, err = p.parseIdent(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stmt.Database = ident
|
||||
|
@ -924,9 +918,9 @@ func (p *Parser) parseCreateDatabaseStatement() (*CreateDatabaseStatement, error
|
|||
stmt := &CreateDatabaseStatement{}
|
||||
|
||||
// Parse the name of the database to be created.
|
||||
tok, pos, lit := p.scanIgnoreWhitespace()
|
||||
if tok != IDENT && tok != STRING {
|
||||
return nil, newParseError(tokstr(tok, lit), []string{"identifier"}, pos)
|
||||
lit, err := p.parseIdent()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stmt.Name = lit
|
||||
|
||||
|
@ -939,9 +933,9 @@ func (p *Parser) parseDropDatabaseStatement() (*DropDatabaseStatement, error) {
|
|||
stmt := &DropDatabaseStatement{}
|
||||
|
||||
// Parse the name of the database to be dropped.
|
||||
tok, pos, lit := p.scanIgnoreWhitespace()
|
||||
if tok != IDENT && tok != STRING {
|
||||
return nil, newParseError(tokstr(tok, lit), []string{"identifier"}, pos)
|
||||
lit, err := p.parseIdent()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stmt.Name = lit
|
||||
|
||||
|
@ -954,7 +948,7 @@ func (p *Parser) parseDropRetentionPolicyStatement() (*DropRetentionPolicyStatem
|
|||
stmt := &DropRetentionPolicyStatement{}
|
||||
|
||||
// Parse the policy name.
|
||||
ident, err := p.parseIdentifier()
|
||||
ident, err := p.parseIdent()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -966,7 +960,7 @@ func (p *Parser) parseDropRetentionPolicyStatement() (*DropRetentionPolicyStatem
|
|||
}
|
||||
|
||||
// Parse the database name.
|
||||
if stmt.Database, err = p.parseIdentifier(); err != nil {
|
||||
if stmt.Database, err = p.parseIdent(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -979,7 +973,7 @@ func (p *Parser) parseCreateUserStatement() (*CreateUserStatement, error) {
|
|||
stmt := &CreateUserStatement{}
|
||||
|
||||
// Parse name of the user to be created.
|
||||
ident, err := p.parseIdentifier()
|
||||
ident, err := p.parseIdent()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -991,7 +985,7 @@ func (p *Parser) parseCreateUserStatement() (*CreateUserStatement, error) {
|
|||
}
|
||||
|
||||
// Parse new user's password
|
||||
if ident, err = p.parseIdentifier(); err != nil {
|
||||
if ident, err = p.parseString(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stmt.Password = ident
|
||||
|
@ -1018,9 +1012,9 @@ func (p *Parser) parseDropUserStatement() (*DropUserStatement, error) {
|
|||
stmt := &DropUserStatement{}
|
||||
|
||||
// Parse the name of the user to be dropped.
|
||||
tok, pos, lit := p.scanIgnoreWhitespace()
|
||||
if tok != IDENT && tok != STRING {
|
||||
return nil, newParseError(tokstr(tok, lit), []string{"identifier"}, pos)
|
||||
lit, err := p.parseIdent()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stmt.Name = lit
|
||||
|
||||
|
@ -1050,9 +1044,8 @@ func (p *Parser) parseRetentionPolicy() (name string, dfault bool, err error) {
|
|||
}
|
||||
|
||||
// Parse retention policy name.
|
||||
tok, pos, name = p.scanIgnoreWhitespace()
|
||||
if tok != IDENT && tok != STRING {
|
||||
err = newParseError(tokstr(tok, name), []string{"identifier"}, pos)
|
||||
name, err = p.parseIdent()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -1070,9 +1063,9 @@ func (p *Parser) parseDropContinuousQueryStatement() (*DropContinuousQueryStatem
|
|||
}
|
||||
|
||||
// Read the id of the query to drop.
|
||||
tok, pos, lit := p.scanIgnoreWhitespace()
|
||||
if tok != IDENT && tok != STRING {
|
||||
return nil, newParseError(tokstr(tok, lit), []string{"identifier", "string"}, pos)
|
||||
lit, err := p.parseIdent()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stmt.Name = lit
|
||||
|
||||
|
@ -1142,9 +1135,9 @@ func (p *Parser) parseAlias() (string, error) {
|
|||
}
|
||||
|
||||
// Then we should have the alias identifier.
|
||||
tok, pos, lit := p.scanIgnoreWhitespace()
|
||||
if tok != IDENT && tok != STRING {
|
||||
return "", newParseError(tokstr(tok, lit), []string{"identifier", "string"}, pos)
|
||||
lit, err := p.parseIdent()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return lit, nil
|
||||
}
|
||||
|
@ -1153,8 +1146,8 @@ func (p *Parser) parseAlias() (string, error) {
|
|||
func (p *Parser) parseSource() (Source, error) {
|
||||
// The first token can either be the series name or a join/merge call.
|
||||
tok, pos, lit := p.scanIgnoreWhitespace()
|
||||
if tok != IDENT && tok != STRING {
|
||||
return nil, newParseError(tokstr(tok, lit), []string{"identifier", "string"}, pos)
|
||||
if tok != IDENT {
|
||||
return nil, newParseError(tokstr(tok, lit), []string{"identifier"}, pos)
|
||||
}
|
||||
|
||||
// If the token is a string or the next token is not an LPAREN then return a measurement.
|
||||
|
@ -1174,7 +1167,7 @@ func (p *Parser) parseSource() (Source, error) {
|
|||
for {
|
||||
// Scan the measurement name.
|
||||
tok, pos, lit := p.scanIgnoreWhitespace()
|
||||
if tok != IDENT && tok != STRING {
|
||||
if tok != IDENT {
|
||||
return nil, newParseError(tokstr(tok, lit), []string{"measurement name"}, pos)
|
||||
}
|
||||
measurements = append(measurements, &Measurement{Name: lit})
|
||||
|
@ -1614,15 +1607,19 @@ func (p *Parser) parseTokens(toks []Token) error {
|
|||
}
|
||||
|
||||
// Quote returns a quoted string.
|
||||
func Quote(s string) string {
|
||||
return `"` + strings.NewReplacer("\n", `\n`, `\`, `\\`, `"`, `\"`).Replace(s) + `"`
|
||||
func QuoteString(s string) string {
|
||||
return `'` + strings.NewReplacer("\n", `\n`, `\`, `\\`, `'`, `\'`).Replace(s) + `'`
|
||||
}
|
||||
|
||||
// QuoteIdent returns a quoted identifier from multiple bare identifiers.
|
||||
func QuoteIdent(segments []string) string {
|
||||
r := strings.NewReplacer("\n", `\n`, `\`, `\\`, `"`, `\"`)
|
||||
|
||||
var buf bytes.Buffer
|
||||
for i, segment := range segments {
|
||||
_, _ = buf.WriteString(Quote(segment))
|
||||
_ = buf.WriteByte('"')
|
||||
_, _ = buf.WriteString(r.Replace(segment))
|
||||
_ = buf.WriteByte('"')
|
||||
if i < len(segments)-1 {
|
||||
_ = buf.WriteByte('.')
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ func TestParser_ParseStatement(t *testing.T) {
|
|||
Source: &influxql.Join{
|
||||
Measurements: []*influxql.Measurement{
|
||||
{Name: "aa"},
|
||||
{Name: "bb"},
|
||||
{Name: `"bb"`},
|
||||
{Name: "cc"},
|
||||
},
|
||||
},
|
||||
|
@ -320,8 +320,7 @@ func TestParser_ParseStatement(t *testing.T) {
|
|||
Source: &influxql.SelectStatement{
|
||||
Fields: []*influxql.Field{&influxql.Field{Expr: &influxql.Call{Name: "count"}}},
|
||||
Target: &influxql.Target{
|
||||
RetentionPolicy: "1h.policy1",
|
||||
Measurement: "cpu.load",
|
||||
Measurement: `"1h.policy1"."cpu.load"`,
|
||||
},
|
||||
Source: &influxql.Measurement{Name: "myseries"},
|
||||
},
|
||||
|
@ -338,7 +337,7 @@ func TestParser_ParseStatement(t *testing.T) {
|
|||
|
||||
// CREATE USER statement
|
||||
{
|
||||
s: `CREATE USER testuser WITH PASSWORD pwd1337`,
|
||||
s: `CREATE USER testuser WITH PASSWORD 'pwd1337'`,
|
||||
stmt: &influxql.CreateUserStatement{
|
||||
Name: "testuser",
|
||||
Password: "pwd1337",
|
||||
|
@ -347,7 +346,7 @@ func TestParser_ParseStatement(t *testing.T) {
|
|||
|
||||
// CREATE USER ... WITH ALL PRIVILEGES
|
||||
{
|
||||
s: `CREATE USER testuser WITH PASSWORD pwd1337 WITH ALL PRIVILEGES`,
|
||||
s: `CREATE USER testuser WITH PASSWORD 'pwd1337' WITH ALL PRIVILEGES`,
|
||||
stmt: &influxql.CreateUserStatement{
|
||||
Name: "testuser",
|
||||
Password: "pwd1337",
|
||||
|
@ -371,8 +370,8 @@ func TestParser_ParseStatement(t *testing.T) {
|
|||
{
|
||||
s: `DROP RETENTION POLICY "1h.cpu" ON mydb`,
|
||||
stmt: &influxql.DropRetentionPolicyStatement{
|
||||
Name: "1h.cpu",
|
||||
Database: "mydb",
|
||||
Name: `"1h.cpu"`,
|
||||
Database: `mydb`,
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -546,46 +545,46 @@ func TestParser_ParseStatement(t *testing.T) {
|
|||
{s: `SELECT field1 FROM myseries ORDER`, err: `found EOF, expected BY at line 1, char 35`},
|
||||
{s: `SELECT field1 FROM myseries ORDER BY /`, err: `found /, expected identifier, ASC, or DESC at line 1, char 38`},
|
||||
{s: `SELECT field1 FROM myseries ORDER BY 1`, err: `found 1, expected identifier, ASC, or DESC at line 1, char 38`},
|
||||
{s: `SELECT field1 AS`, err: `found EOF, expected identifier, string at line 1, char 18`},
|
||||
{s: `SELECT field1 FROM 12`, err: `found 12, expected identifier, string at line 1, char 20`},
|
||||
{s: `SELECT field1 AS`, err: `found EOF, expected identifier at line 1, char 18`},
|
||||
{s: `SELECT field1 FROM 12`, err: `found 12, expected identifier at line 1, char 20`},
|
||||
{s: `SELECT field1 FROM myseries GROUP BY *`, err: `found *, expected identifier, string, number, bool at line 1, char 38`},
|
||||
{s: `SELECT 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 FROM myseries`, err: `unable to parse number at line 1, char 8`},
|
||||
{s: `SELECT 10.5h FROM myseries`, err: `found h, expected FROM at line 1, char 12`},
|
||||
{s: `DELETE`, err: `found EOF, expected FROM at line 1, char 8`},
|
||||
{s: `DELETE FROM`, err: `found EOF, expected identifier, string at line 1, char 13`},
|
||||
{s: `DELETE FROM`, err: `found EOF, expected identifier at line 1, char 13`},
|
||||
{s: `DELETE FROM myseries WHERE`, err: `found EOF, expected identifier, string, number, bool at line 1, char 28`},
|
||||
{s: `DROP SERIES`, err: `found EOF, expected identifier, string at line 1, char 13`},
|
||||
{s: `DROP SERIES`, err: `found EOF, expected identifier at line 1, char 13`},
|
||||
{s: `LIST CONTINUOUS`, err: `found EOF, expected QUERIES at line 1, char 17`},
|
||||
{s: `LIST RETENTION`, err: `found EOF, expected POLICIES at line 1, char 16`},
|
||||
{s: `LIST RETENTION POLICIES`, err: `found EOF, expected identifier at line 1, char 25`},
|
||||
{s: `LIST FOO`, err: `found FOO, expected SERIES, CONTINUOUS, MEASUREMENTS, TAG, FIELD, RETENTION at line 1, char 6`},
|
||||
{s: `DROP CONTINUOUS`, err: `found EOF, expected QUERY at line 1, char 17`},
|
||||
{s: `DROP CONTINUOUS QUERY`, err: `found EOF, expected identifier, string at line 1, char 23`},
|
||||
{s: `DROP CONTINUOUS QUERY`, err: `found EOF, expected identifier at line 1, char 23`},
|
||||
{s: `DROP FOO`, err: `found FOO, expected SERIES, CONTINUOUS at line 1, char 6`},
|
||||
{s: `DROP DATABASE`, err: `found EOF, expected identifier at line 1, char 15`},
|
||||
{s: `DROP RETENTION`, err: `found EOF, expected POLICY at line 1, char 16`},
|
||||
{s: `DROP RETENTION POLICY`, err: `found EOF, expected identifier at line 1, char 23`},
|
||||
{s: `DROP RETENTION POLICY "1h.cpu"`, err: `found EOF, expected ON at line 1, char 31`},
|
||||
{s: `DROP RETENTION POLICY "1h.cpu"`, err: `found EOF, expected ON at line 1, char 32`},
|
||||
{s: `DROP RETENTION POLICY "1h.cpu" ON`, err: `found EOF, expected identifier at line 1, char 35`},
|
||||
{s: `DROP USER`, err: `found EOF, expected identifier at line 1, char 11`},
|
||||
{s: `CREATE USER testuser`, err: `found EOF, expected WITH at line 1, char 22`},
|
||||
{s: `CREATE USER testuser WITH`, err: `found EOF, expected PASSWORD at line 1, char 27`},
|
||||
{s: `CREATE USER testuser WITH PASSWORD`, err: `found EOF, expected identifier at line 1, char 36`},
|
||||
{s: `CREATE USER testuser WITH PASSWORD "pwd" WITH`, err: `found EOF, expected ALL at line 1, char 47`},
|
||||
{s: `CREATE USER testuser WITH PASSWORD "pwd" WITH ALL`, err: `found EOF, expected PRIVILEGES at line 1, char 51`},
|
||||
{s: `CREATE USER testuser WITH PASSWORD`, err: `found EOF, expected string at line 1, char 36`},
|
||||
{s: `CREATE USER testuser WITH PASSWORD 'pwd' WITH`, err: `found EOF, expected ALL at line 1, char 47`},
|
||||
{s: `CREATE USER testuser WITH PASSWORD 'pwd' WITH ALL`, err: `found EOF, expected PRIVILEGES at line 1, char 51`},
|
||||
{s: `GRANT`, err: `found EOF, expected READ, WRITE, ALL [PRIVILEGES] at line 1, char 7`},
|
||||
{s: `GRANT BOGUS`, err: `found BOGUS, expected READ, WRITE, ALL [PRIVILEGES] at line 1, char 7`},
|
||||
{s: `GRANT READ`, err: `found EOF, expected ON at line 1, char 12`},
|
||||
{s: `GRANT READ TO jdoe`, err: `found TO, expected ON at line 1, char 12`},
|
||||
{s: `GRANT READ ON`, err: `found EOF, expected identifier, string at line 1, char 15`},
|
||||
{s: `GRANT READ ON`, err: `found EOF, expected identifier at line 1, char 15`},
|
||||
{s: `GRANT READ ON testdb`, err: `found EOF, expected TO at line 1, char 22`},
|
||||
{s: `GRANT READ ON testdb TO`, err: `found EOF, expected identifier, string at line 1, char 25`}, {s: `GRANT`, err: `found EOF, expected READ, WRITE, ALL [PRIVILEGES] at line 1, char 7`},
|
||||
{s: `GRANT READ ON testdb TO`, err: `found EOF, expected identifier at line 1, char 25`}, {s: `GRANT`, err: `found EOF, expected READ, WRITE, ALL [PRIVILEGES] at line 1, char 7`},
|
||||
{s: `REVOKE BOGUS`, err: `found BOGUS, expected READ, WRITE, ALL [PRIVILEGES] at line 1, char 8`},
|
||||
{s: `REVOKE READ`, err: `found EOF, expected ON at line 1, char 13`},
|
||||
{s: `REVOKE READ TO jdoe`, err: `found TO, expected ON at line 1, char 13`},
|
||||
{s: `REVOKE READ ON`, err: `found EOF, expected identifier, string at line 1, char 16`},
|
||||
{s: `REVOKE READ ON`, err: `found EOF, expected identifier at line 1, char 16`},
|
||||
{s: `REVOKE READ ON testdb`, err: `found EOF, expected FROM at line 1, char 23`},
|
||||
{s: `REVOKE READ ON testdb FROM`, err: `found EOF, expected identifier, string at line 1, char 28`},
|
||||
{s: `REVOKE READ ON testdb FROM`, err: `found EOF, expected identifier at line 1, char 28`},
|
||||
{s: `CREATE RETENTION`, err: `found EOF, expected POLICY at line 1, char 18`},
|
||||
{s: `CREATE RETENTION POLICY`, err: `found EOF, expected identifier at line 1, char 25`},
|
||||
{s: `CREATE RETENTION POLICY policy1`, err: `found EOF, expected ON at line 1, char 33`},
|
||||
|
@ -612,10 +611,6 @@ func TestParser_ParseStatement(t *testing.T) {
|
|||
t.Errorf("%d. %q: error mismatch:\n exp=%s\n got=%s\n\n", i, tt.s, tt.err, err)
|
||||
} else if tt.err == "" && !reflect.DeepEqual(tt.stmt, stmt) {
|
||||
t.Errorf("%d. %q\n\nstmt mismatch:\n\nexp=%#v\n\ngot=%#v\n\n", i, tt.s, tt.stmt, stmt)
|
||||
exp := tt.stmt.(*influxql.CreateContinuousQueryStatement).Source.Target
|
||||
got := stmt.(*influxql.CreateContinuousQueryStatement).Source.Target
|
||||
t.Errorf("exp.String() = %#v\n", *exp)
|
||||
t.Errorf("got.String() = %#v\n", *got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -629,14 +624,14 @@ func TestParser_ParseExpr(t *testing.T) {
|
|||
}{
|
||||
// Primitives
|
||||
{s: `100`, expr: &influxql.NumberLiteral{Val: 100}},
|
||||
{s: `"foo bar"`, expr: &influxql.StringLiteral{Val: "foo bar"}},
|
||||
{s: `'foo bar'`, expr: &influxql.StringLiteral{Val: "foo bar"}},
|
||||
{s: `true`, expr: &influxql.BooleanLiteral{Val: true}},
|
||||
{s: `false`, expr: &influxql.BooleanLiteral{Val: false}},
|
||||
{s: `my_ident`, expr: &influxql.VarRef{Val: "my_ident"}},
|
||||
{s: `"2000-01-01 00:00:00"`, expr: &influxql.TimeLiteral{Val: mustParseTime("2000-01-01T00:00:00Z")}},
|
||||
{s: `"2000-01-32 00:00:00"`, err: `unable to parse datetime at line 1, char 1`},
|
||||
{s: `"2000-01-01"`, expr: &influxql.TimeLiteral{Val: mustParseTime("2000-01-01T00:00:00Z")}},
|
||||
{s: `"2000-01-99"`, err: `unable to parse date at line 1, char 1`},
|
||||
{s: `'2000-01-01 00:00:00'`, expr: &influxql.TimeLiteral{Val: mustParseTime("2000-01-01T00:00:00Z")}},
|
||||
{s: `'2000-01-32 00:00:00'`, err: `unable to parse datetime at line 1, char 1`},
|
||||
{s: `'2000-01-01'`, expr: &influxql.TimeLiteral{Val: mustParseTime("2000-01-01T00:00:00Z")}},
|
||||
{s: `'2000-01-99'`, err: `unable to parse date at line 1, char 1`},
|
||||
|
||||
// Simple binary expression
|
||||
{
|
||||
|
@ -831,13 +826,13 @@ func TestQuote(t *testing.T) {
|
|||
in string
|
||||
out string
|
||||
}{
|
||||
{``, `""`},
|
||||
{`foo`, `"foo"`},
|
||||
{"foo\nbar", `"foo\nbar"`},
|
||||
{`foo bar\\`, `"foo bar\\\\"`},
|
||||
{`"foo"`, `"\"foo\""`},
|
||||
{``, `''`},
|
||||
{`foo`, `'foo'`},
|
||||
{"foo\nbar", `'foo\nbar'`},
|
||||
{`foo bar\\`, `'foo bar\\\\'`},
|
||||
{`'foo'`, `'\'foo\''`},
|
||||
} {
|
||||
if out := influxql.Quote(tt.in); tt.out != out {
|
||||
if out := influxql.QuoteString(tt.in); tt.out != out {
|
||||
t.Errorf("%d. %s: mismatch: %s != %s", i, tt.in, tt.out, out)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,7 +42,10 @@ func (s *Scanner) Scan() (tok Token, pos Pos, lit string) {
|
|||
switch ch0 {
|
||||
case eof:
|
||||
return EOF, pos, ""
|
||||
case '"', '\'':
|
||||
case '"':
|
||||
s.r.unread()
|
||||
return s.scanIdent()
|
||||
case '\'':
|
||||
return s.scanString()
|
||||
case '.':
|
||||
ch1, _ := s.r.read()
|
||||
|
@ -123,11 +126,12 @@ func (s *Scanner) scanIdent() (tok Token, pos Pos, lit string) {
|
|||
} else if ch == '.' {
|
||||
buf.WriteRune(ch)
|
||||
} else if ch == '"' {
|
||||
s.r.unread()
|
||||
if tok0, pos0, lit0 := s.scanString(); tok == BADSTRING || tok == BADESCAPE {
|
||||
return tok0, pos0, lit0
|
||||
} else {
|
||||
buf.WriteString(lit0)
|
||||
_ = buf.WriteByte('"')
|
||||
_, _ = buf.WriteString(lit0)
|
||||
_ = buf.WriteByte('"')
|
||||
}
|
||||
} else if isIdentChar(ch) {
|
||||
s.r.unread()
|
||||
|
|
|
@ -59,17 +59,18 @@ func TestScanner_Scan(t *testing.T) {
|
|||
// Identifiers
|
||||
{s: `foo`, tok: influxql.IDENT, lit: `foo`},
|
||||
{s: `Zx12_3U_-`, tok: influxql.IDENT, lit: `Zx12_3U_`},
|
||||
{s: `"foo".bar`, tok: influxql.IDENT, lit: `"foo".bar`},
|
||||
|
||||
{s: `true`, tok: influxql.TRUE},
|
||||
{s: `false`, tok: influxql.FALSE},
|
||||
|
||||
// Strings
|
||||
{s: `"testing 123!"`, tok: influxql.STRING, lit: `testing 123!`},
|
||||
{s: `"foo\nbar"`, tok: influxql.STRING, lit: "foo\nbar"},
|
||||
{s: `"foo\\bar"`, tok: influxql.STRING, lit: "foo\\bar"},
|
||||
{s: `"test`, tok: influxql.BADSTRING, lit: `test`},
|
||||
{s: "\"test\nfoo", tok: influxql.BADSTRING, lit: `test`},
|
||||
{s: `"test\g"`, tok: influxql.BADESCAPE, lit: `\g`, pos: influxql.Pos{Line: 0, Char: 6}},
|
||||
{s: `'testing 123!'`, tok: influxql.STRING, lit: `testing 123!`},
|
||||
{s: `'foo\nbar'`, tok: influxql.STRING, lit: "foo\nbar"},
|
||||
{s: `'foo\\bar'`, tok: influxql.STRING, lit: "foo\\bar"},
|
||||
{s: `'test`, tok: influxql.BADSTRING, lit: `test`},
|
||||
{s: "'test\nfoo", tok: influxql.BADSTRING, lit: `test`},
|
||||
{s: `'test\g'`, tok: influxql.BADESCAPE, lit: `\g`, pos: influxql.Pos{Line: 0, Char: 6}},
|
||||
|
||||
// Numbers
|
||||
{s: `100`, tok: influxql.NUMBER, lit: `100`},
|
||||
|
@ -192,7 +193,7 @@ func TestScanner_Scan_Multi(t *testing.T) {
|
|||
}
|
||||
|
||||
// Create a scanner.
|
||||
v := `SELECT value from myseries WHERE a = "b"`
|
||||
v := `SELECT value from myseries WHERE a = 'b'`
|
||||
s := influxql.NewScanner(strings.NewReader(v))
|
||||
|
||||
// Continually scan until we reach the end.
|
||||
|
|
|
@ -1752,7 +1752,7 @@ func (s *Server) normalizeStatement(stmt influxql.Statement, defaultDatabase str
|
|||
case *influxql.VarRef:
|
||||
for k, v := range prefixes {
|
||||
if strings.HasPrefix(n.Val, k+".") {
|
||||
n.Val = v + "." + influxql.Quote(n.Val[len(k)+1:])
|
||||
n.Val = v + "." + influxql.QuoteIdent([]string{n.Val[len(k)+1:]})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue