diff --git a/handler_test.go b/handler_test.go index 34d9114bfc..cb6fb506d3 100644 --- a/handler_test.go +++ b/handler_test.go @@ -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) diff --git a/influxql/ast.go b/influxql/ast.go index 2af5540d2d..1a4eaa739f 100644 --- a/influxql/ast.go +++ b/influxql/ast.go @@ -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 { diff --git a/influxql/ast_test.go b/influxql/ast_test.go index 3180843dee..c99eb39584 100644 --- a/influxql/ast_test.go +++ b/influxql/ast_test.go @@ -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) diff --git a/influxql/engine_test.go b/influxql/engine_test.go index 4c40d8e896..a32c47acfc 100644 --- a/influxql/engine_test.go +++ b/influxql/engine_test.go @@ -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. diff --git a/influxql/parser.go b/influxql/parser.go index 445cdae78e..5c511296d6 100644 --- a/influxql/parser.go +++ b/influxql/parser.go @@ -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('.') } diff --git a/influxql/parser_test.go b/influxql/parser_test.go index dccf01541c..3535778454 100644 --- a/influxql/parser_test.go +++ b/influxql/parser_test.go @@ -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) } } diff --git a/influxql/scanner.go b/influxql/scanner.go index 49858c1ff0..221d203c3a 100644 --- a/influxql/scanner.go +++ b/influxql/scanner.go @@ -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() diff --git a/influxql/scanner_test.go b/influxql/scanner_test.go index 8d60db597d..e69a05a699 100644 --- a/influxql/scanner_test.go +++ b/influxql/scanner_test.go @@ -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. diff --git a/server.go b/server.go index b47974f431..43f80b29ad 100644 --- a/server.go +++ b/server.go @@ -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:]}) } } }