1100 lines
39 KiB
Go
1100 lines
39 KiB
Go
package parser
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"testing"
|
|
"time"
|
|
|
|
. "launchpad.net/gocheck"
|
|
)
|
|
|
|
// Hook up gocheck into the gotest runner.
|
|
func Test(t *testing.T) {
|
|
TestingT(t)
|
|
}
|
|
|
|
type QueryParserSuite struct{}
|
|
|
|
var _ = Suite(&QueryParserSuite{})
|
|
|
|
func ToValueArray(strings ...string) (values []*Value) {
|
|
for _, str := range strings {
|
|
values = append(values, &Value{str, "", ValueSimpleName, nil, nil, false})
|
|
}
|
|
return
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestInvalidFromClause(c *C) {
|
|
query := "select value from .t"
|
|
_, err := ParseSelectQuery(query)
|
|
|
|
c.Assert(err, ErrorMatches, ".*\\$undefined.*")
|
|
}
|
|
|
|
// Make sure that GetQueryStringWithTimeCondition() works for regex
|
|
// merge queries.
|
|
func (self *QueryParserSuite) TestMergeMultipleRegex(c *C) {
|
|
query := "select * from merge(/.*foo.*/, /.*bar.*/)"
|
|
_, err := ParseQuery(query)
|
|
c.Assert(err, NotNil)
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseMergeGetString(c *C) {
|
|
f := func(r *regexp.Regexp) []string {
|
|
return []string{"foobar"}
|
|
}
|
|
|
|
query := "select * from merge(/.*foo.*/)"
|
|
qs, err := ParseQuery(query)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(qs, HasLen, 1)
|
|
RewriteMergeQuery(qs[0].SelectQuery, f)
|
|
actualQs, err := ParseQuery(qs[0].GetQueryStringWithTimeCondition())
|
|
c.Assert(err, IsNil)
|
|
c.Assert(actualQs, HasLen, 1)
|
|
RewriteMergeQuery(actualQs[0].SelectQuery, f)
|
|
actualQs[0].SelectQuery.startTimeSpecified = false
|
|
c.Assert(actualQs[0].SelectQuery, DeepEquals, qs[0].SelectQuery)
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestInvalidExplainQueries(c *C) {
|
|
query := "explain select foo, baz group by time(1d)"
|
|
_, err := ParseQuery(query)
|
|
|
|
c.Assert(err, NotNil)
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestExplainQueries(c *C) {
|
|
query := "explain select foo, bar from baz group by time(1d)"
|
|
queries, err := ParseQuery(query)
|
|
|
|
c.Assert(err, IsNil)
|
|
c.Assert(queries, HasLen, 1)
|
|
c.Assert(queries[0].SelectQuery, NotNil)
|
|
c.Assert(queries[0].SelectQuery.IsExplainQuery(), Equals, true)
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseBasicSelectQuery(c *C) {
|
|
for _, query := range []string{
|
|
"select value from t where c = '5';",
|
|
// semicolon is optional
|
|
"select value from t where c = '5'",
|
|
} {
|
|
q, err := ParseSelectQuery(query)
|
|
c.Assert(err, IsNil)
|
|
|
|
c.Assert(q.GetColumnNames(), DeepEquals, ToValueArray("value"))
|
|
w := q.GetWhereCondition()
|
|
|
|
boolExpression, ok := w.GetBoolExpression()
|
|
c.Assert(ok, Equals, true)
|
|
|
|
leftValue := boolExpression.Elems[0]
|
|
rightValue := boolExpression.Elems[1]
|
|
|
|
c.Assert(leftValue.Name, Equals, "c")
|
|
c.Assert(boolExpression.Name, Equals, "=")
|
|
c.Assert(rightValue.Name, Equals, "5")
|
|
}
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestGetQueryStringWithDoubleQuotes(c *C) {
|
|
q := `select dashboard from "grafana.dashboard_VWx0cmFNUg=="`
|
|
query, err := ParseQuery(q)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(query, HasLen, 1)
|
|
actualQ := query[0].GetQueryStringWithTimeCondition()
|
|
actualQuery, err := ParseQuery(actualQ)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(actualQuery, HasLen, 1)
|
|
query[0].SelectQuery.startTimeSpecified = false
|
|
actualQuery[0].SelectQuery.startTimeSpecified = false
|
|
c.Assert(actualQuery, DeepEquals, query)
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestGetQueryString(c *C) {
|
|
for _, query := range []string{
|
|
"select value from t",
|
|
"select value from /.*foo.*/",
|
|
"select value from /.*foo.*/i",
|
|
"select value from t where c = '5'",
|
|
"select value from t where c = '5' limit 1",
|
|
"select value from t where c = '5' limit 1 order asc",
|
|
"select a.value, b.value from foo as a inner join bar as b where c = '5' limit 1 order asc",
|
|
"select count(value) from t group by time(1h)",
|
|
"select count(value) from t group by time(1h) into value.hourly",
|
|
"select count(value), host from t group by time(1h), host into value.hourly.[:host]",
|
|
"select count(value), host from t group by time(1h), host where time > now() - 1h into value.hourly.[:host]",
|
|
"select count(value), host from t group by time(1h), host into value.hourly.[:host] backfill(F)",
|
|
"select count(value), host from t group by time(1h), host where time > now() - 1h into value.hourly.[:host] backfill(true)",
|
|
"select count(value) from t, host into value.hourly.[:host] backfill(1)",
|
|
"delete from foo",
|
|
} {
|
|
fmt.Printf("testing %s\n", query)
|
|
expectedQuery, err := ParseQuery(query)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(expectedQuery, HasLen, 1)
|
|
queryString := expectedQuery[0].GetQueryStringWithTimeCondition()
|
|
fmt.Printf("query string: %s\n", queryString)
|
|
actualQuery, err := ParseQuery(queryString)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(actualQuery, HasLen, 1)
|
|
if expectedQuery[0].DeleteQuery != nil {
|
|
expectedQuery[0].DeleteQuery.startTimeSpecified = false
|
|
actualQuery[0].DeleteQuery.startTimeSpecified = false
|
|
} else if expectedQuery[0].SelectQuery != nil {
|
|
expectedQuery[0].SelectQuery.startTimeSpecified = false
|
|
actualQuery[0].SelectQuery.startTimeSpecified = false
|
|
}
|
|
|
|
c.Assert(actualQuery[0], DeepEquals, expectedQuery[0])
|
|
}
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseDeleteQueryWithEndTime(c *C) {
|
|
query := "delete from foo where time < 1389040522000000u"
|
|
queries, err := ParseQuery(query)
|
|
c.Assert(err, IsNil)
|
|
|
|
c.Assert(queries, HasLen, 1)
|
|
|
|
_q := queries[0]
|
|
|
|
c.Assert(_q.DeleteQuery, NotNil)
|
|
|
|
q := _q.DeleteQuery
|
|
|
|
c.Assert(q.GetEndTime(), Equals, time.Unix(1389040522, 0).UTC())
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseSelectQueryWithDotInColumnName(c *C) {
|
|
query := "select patient.first.name from foo"
|
|
queries, err := ParseQuery(query)
|
|
c.Assert(err, IsNil)
|
|
|
|
c.Assert(queries, HasLen, 1)
|
|
|
|
_q := queries[0]
|
|
|
|
c.Assert(_q.SelectQuery, NotNil)
|
|
|
|
q := _q.SelectQuery
|
|
|
|
for _, columns := range q.GetReferencedColumns() {
|
|
c.Assert(columns, DeepEquals, []string{"patient.first.name"})
|
|
}
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseDropSeries(c *C) {
|
|
query := "drop series foobar"
|
|
queries, err := ParseQuery(query)
|
|
c.Assert(err, IsNil)
|
|
|
|
c.Assert(queries, HasLen, 1)
|
|
|
|
_q := queries[0]
|
|
|
|
c.Assert(_q.DropSeriesQuery, NotNil)
|
|
|
|
q := _q.DropSeriesQuery
|
|
|
|
c.Assert(q.GetTableName(), Equals, "foobar")
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestGetQueryStringForContinuousQuery(c *C) {
|
|
base := time.Now().Truncate(time.Minute)
|
|
start := base.UTC()
|
|
end := base.Add(time.Minute).UTC()
|
|
|
|
inputQuery := "select count(c1) from s1 group by time(1m) into d1;"
|
|
|
|
queries, err := ParseQuery(inputQuery)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(queries, HasLen, 1)
|
|
|
|
query := queries[0]
|
|
c.Assert(query.SelectQuery, NotNil)
|
|
|
|
selectQuery := query.SelectQuery
|
|
|
|
// try to parse the query with the time condition
|
|
queries, err = ParseQuery(selectQuery.GetQueryStringWithTimesAndNoIntoClause(start, end))
|
|
c.Assert(err, IsNil)
|
|
|
|
query = queries[0]
|
|
c.Assert(query.SelectQuery, NotNil)
|
|
|
|
selectQuery = query.SelectQuery
|
|
c.Assert(selectQuery.GetStartTime().Round(time.Second), Equals, start)
|
|
c.Assert(selectQuery.GetEndTime(), Equals, end)
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseDeleteQuery(c *C) {
|
|
query := "delete from foo where time > '2012-08-13' and time < '2013-08-13'"
|
|
queries, err := ParseQuery(query)
|
|
c.Assert(err, IsNil)
|
|
|
|
c.Assert(queries, HasLen, 1)
|
|
|
|
_q := queries[0]
|
|
|
|
c.Assert(_q.DeleteQuery, NotNil)
|
|
|
|
q := _q.DeleteQuery
|
|
|
|
startTime, _ := time.Parse("2006-01-02", "2012-08-13")
|
|
endTime, _ := time.Parse("2006-01-02", "2013-08-13")
|
|
c.Assert(q.GetStartTime(), Equals, startTime)
|
|
c.Assert(q.GetEndTime(), Equals, endTime)
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestInvalidWhereClause(c *C) {
|
|
_, err := ParseQuery("delete from foo where 1;")
|
|
c.Assert(err, NotNil)
|
|
|
|
_, err = ParseQuery("select * from foo where is_uppercase(name);")
|
|
c.Assert(err, IsNil)
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseWithUnderscore(c *C) {
|
|
queryString := "select _value, time, sequence_number from foo"
|
|
query, err := ParseSelectQuery(queryString)
|
|
c.Assert(err, IsNil)
|
|
|
|
for table, columns := range query.GetReferencedColumns() {
|
|
c.Assert(table.Name, Equals, "foo")
|
|
c.Assert(columns, DeepEquals, []string{"_value"})
|
|
}
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestSimpleFromClause(c *C) {
|
|
q, err := ParseSelectQuery("select value from t;")
|
|
c.Assert(err, IsNil)
|
|
|
|
fromClause := q.GetFromClause()
|
|
c.Assert(fromClause.Type, Equals, FromClauseArray)
|
|
c.Assert(fromClause.Names, HasLen, 1)
|
|
c.Assert(fromClause.Names[0].Name.Name, Equals, "t")
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseFromWithMergedTable(c *C) {
|
|
q, err := ParseSelectQuery("select count(*) from newsletter.signups merge user.signups where time>now()-1d;")
|
|
c.Assert(err, IsNil)
|
|
fromClause := q.GetFromClause()
|
|
c.Assert(fromClause.Type, Equals, FromClauseMerge)
|
|
c.Assert(fromClause.Names, HasLen, 2)
|
|
c.Assert(fromClause.Names[0].Name.Name, Equals, "newsletter.signups")
|
|
c.Assert(fromClause.Names[1].Name.Name, Equals, "user.signups")
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseFromWithMergeRegex(c *C) {
|
|
q, err := ParseSelectQuery("select count(*) from merge(/.*/) where time>now()-1d;")
|
|
c.Assert(err, IsNil)
|
|
fromClause := q.GetFromClause()
|
|
c.Assert(fromClause.Type, Equals, FromClauseMergeRegex)
|
|
c.Assert(fromClause.Regex, NotNil)
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestMultipleAggregateFunctions(c *C) {
|
|
q, err := ParseSelectQuery("select first(bar), last(bar) from foo")
|
|
c.Assert(err, IsNil)
|
|
columns := q.GetColumnNames()
|
|
c.Assert(columns, HasLen, 2)
|
|
c.Assert(columns[0].Name, Equals, "first")
|
|
c.Assert(columns[1].Name, Equals, "last")
|
|
c.Assert(q.HasAggregates(), Equals, true)
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseFromWithJoinedTable(c *C) {
|
|
q, err := ParseSelectQuery("select max(newsletter.signups.value, user.signups.value) from newsletter.signups inner join user.signups where time>now()-1d;")
|
|
c.Assert(err, IsNil)
|
|
fromClause := q.GetFromClause()
|
|
c.Assert(fromClause.Type, Equals, FromClauseInnerJoin)
|
|
c.Assert(fromClause.Names, HasLen, 2)
|
|
c.Assert(fromClause.Names[0].Name.Name, Equals, "newsletter.signups")
|
|
c.Assert(fromClause.Names[1].Name.Name, Equals, "user.signups")
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestIncompleteRegex(c *C) {
|
|
_, err := ParseQuery("list series /")
|
|
c.Assert(err, NotNil)
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseListSeries(c *C) {
|
|
queries, err := ParseQuery("list series")
|
|
c.Assert(err, IsNil)
|
|
c.Assert(queries, HasLen, 1)
|
|
c.Assert(queries[0].IsListQuery(), Equals, true)
|
|
listSeriesQuery := queries[0].GetListSeriesQuery()
|
|
c.Assert(listSeriesQuery, NotNil)
|
|
c.Assert(listSeriesQuery.HasRegex(), Equals, false)
|
|
c.Assert(listSeriesQuery.IncludeSpaces, Equals, false)
|
|
|
|
// test the case sensitive and case insensitive list series
|
|
for i := 0; i < 2; i++ {
|
|
query := "list series /^foo.*/"
|
|
if i == 1 {
|
|
query += "i"
|
|
}
|
|
queries, err = ParseQuery(query)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(queries, HasLen, 1)
|
|
c.Assert(queries[0].IsListSeriesQuery(), Equals, true)
|
|
listSeriesQuery = queries[0].GetListSeriesQuery()
|
|
c.Assert(listSeriesQuery, NotNil)
|
|
c.Assert(listSeriesQuery.HasRegex(), Equals, true)
|
|
var regularExpression *regexp.Regexp
|
|
if i == 1 {
|
|
regularExpression, _ = regexp.Compile("(?i)^foo.*")
|
|
} else {
|
|
regularExpression, _ = regexp.Compile("^foo.*")
|
|
}
|
|
c.Assert(listSeriesQuery.GetRegex(), DeepEquals, regularExpression)
|
|
c.Assert(listSeriesQuery.IncludeSpaces, Equals, false)
|
|
}
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseListSeriesInludeSpaces(c *C) {
|
|
queries, err := ParseQuery("list series include spaces")
|
|
c.Assert(err, IsNil)
|
|
c.Assert(queries, HasLen, 1)
|
|
c.Assert(queries[0].IsListQuery(), Equals, true)
|
|
listSeriesQuery := queries[0].GetListSeriesQuery()
|
|
c.Assert(listSeriesQuery, NotNil)
|
|
c.Assert(listSeriesQuery.HasRegex(), Equals, false)
|
|
c.Assert(listSeriesQuery.IncludeSpaces, Equals, true)
|
|
|
|
queries, err = ParseQuery("list series /foo.*/ include spaces")
|
|
c.Assert(err, IsNil)
|
|
c.Assert(queries, HasLen, 1)
|
|
c.Assert(queries[0].IsListQuery(), Equals, true)
|
|
listSeriesQuery = queries[0].GetListSeriesQuery()
|
|
c.Assert(listSeriesQuery, NotNil)
|
|
c.Assert(listSeriesQuery.HasRegex(), Equals, true)
|
|
c.Assert(listSeriesQuery.IncludeSpaces, Equals, true)
|
|
regularExpression, _ := regexp.Compile("foo.*")
|
|
c.Assert(listSeriesQuery.GetRegex(), DeepEquals, regularExpression)
|
|
}
|
|
|
|
// issue #267
|
|
func (self *QueryParserSuite) TestParseSelectWithWeirdCharacters(c *C) {
|
|
q, err := ParseSelectQuery("select a from \"/blah ( ) ; : ! @ # $ \n \t,foo\\\"=bar/baz\"")
|
|
c.Assert(err, IsNil)
|
|
c.Assert(q.GetFromClause().Names[0].Name.Name, Equals, "/blah ( ) ; : ! @ # $ \n \t,foo\"=bar/baz")
|
|
c.Assert(q.GetColumnNames(), HasLen, 1)
|
|
}
|
|
|
|
// issue #150
|
|
func (self *QueryParserSuite) TestParseSelectWithDivisionThatLooksLikeRegex(c *C) {
|
|
q, err := ParseSelectQuery("select a/2, b/2 from x")
|
|
c.Assert(err, IsNil)
|
|
c.Assert(q.GetFromClause().Names[0].Name.Name, Equals, "x")
|
|
c.Assert(q.GetColumnNames(), HasLen, 2)
|
|
}
|
|
|
|
// issue #150
|
|
func (self *QueryParserSuite) TestParseSelectWithSlashesInRegex(c *C) {
|
|
q, err := ParseSelectQuery("select * from foo where x =~ /users\\/login/")
|
|
c.Assert(err, IsNil)
|
|
whereCondition := q.GetWhereCondition()
|
|
boolExpression, _ := whereCondition.GetBoolExpression()
|
|
fmt.Printf("value: %v\n", boolExpression.Elems[1])
|
|
c.Assert(boolExpression.Elems[1].Name, Equals, "users/login")
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseSelectWithRegexNegation(c *C) {
|
|
q, err := ParseSelectQuery("select * from foo where x !~ /users\\/login/")
|
|
c.Assert(err, IsNil)
|
|
whereCondition := q.GetWhereCondition()
|
|
boolExpression, _ := whereCondition.GetBoolExpression()
|
|
fmt.Printf("value: %v\n", boolExpression.Elems[1])
|
|
c.Assert(boolExpression.Elems[1].Name, Equals, "users/login")
|
|
}
|
|
|
|
// issue #150
|
|
func (self *QueryParserSuite) TestParseSelectWithTwoRegexThatLooksLikeSingleRegex(c *C) {
|
|
q, err := ParseSelectQuery("select * from /.*/ where x =~ /.*/")
|
|
c.Assert(err, IsNil)
|
|
fromClause := q.GetFromClause()
|
|
c.Assert(fromClause.Names[0].Name.Name, Equals, ".*")
|
|
whereCondition := q.GetWhereCondition()
|
|
boolExpression, _ := whereCondition.GetBoolExpression()
|
|
c.Assert(boolExpression.Elems[1].Name, Equals, ".*")
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseSelectWithInsensitiveRegexTables(c *C) {
|
|
q, err := ParseSelectQuery("select email from /users.*/i where time>now()-2d;")
|
|
c.Assert(err, IsNil)
|
|
|
|
fromClause := q.GetFromClause()
|
|
c.Assert(fromClause.Type, Equals, FromClauseArray)
|
|
c.Assert(fromClause.Names, HasLen, 1)
|
|
regex, ok := fromClause.Names[0].Name.GetCompiledRegex()
|
|
c.Assert(ok, Equals, true)
|
|
c.Assert(regex.MatchString("USERSFOOBAR"), Equals, true)
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseSelectWithRegexTables(c *C) {
|
|
q, err := ParseSelectQuery("select email from /users.*/ where time>now()-2d;")
|
|
c.Assert(err, IsNil)
|
|
|
|
fromClause := q.GetFromClause()
|
|
c.Assert(fromClause.Type, Equals, FromClauseArray)
|
|
c.Assert(fromClause.Names, HasLen, 1)
|
|
regex, ok := fromClause.Names[0].Name.GetCompiledRegex()
|
|
c.Assert(ok, Equals, true)
|
|
c.Assert(regex.MatchString("USERSFOOBAR"), Equals, false)
|
|
c.Assert(regex.MatchString("usersfoobar"), Equals, true)
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseSelectWithMultipleTables(c *C) {
|
|
q, err := ParseSelectQuery("select email from first_series, second_series, third_series where time>now()-2d;")
|
|
c.Assert(err, IsNil)
|
|
|
|
fromClause := q.GetFromClause()
|
|
c.Assert(fromClause.Type, Equals, FromClauseArray)
|
|
c.Assert(fromClause.Names, HasLen, 3)
|
|
c.Assert(fromClause.Names[0].Name.Name, Equals, "first_series")
|
|
c.Assert(fromClause.Names[1].Name.Name, Equals, "second_series")
|
|
c.Assert(fromClause.Names[2].Name.Name, Equals, "third_series")
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestMergeFromClause(c *C) {
|
|
q, err := ParseSelectQuery("select value from t1 merge t2 where c = '5';")
|
|
c.Assert(err, IsNil)
|
|
|
|
c.Assert(q.GetColumnNames(), DeepEquals, ToValueArray("value"))
|
|
w := q.GetWhereCondition()
|
|
|
|
boolExpression, ok := w.GetBoolExpression()
|
|
c.Assert(ok, Equals, true)
|
|
|
|
leftValue := boolExpression.Elems[0]
|
|
rightValue := boolExpression.Elems[1]
|
|
|
|
c.Assert(leftValue.Name, Equals, "c")
|
|
c.Assert(boolExpression.Name, Equals, "=")
|
|
c.Assert(rightValue.Name, Equals, "5")
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseSelectWithoutWhereClause(c *C) {
|
|
q, err := ParseSelectQuery("select value, time from t;")
|
|
c.Assert(err, IsNil)
|
|
c.Assert(q.GetColumnNames(), DeepEquals, ToValueArray("value", "time"))
|
|
c.Assert(q.GetWhereCondition(), IsNil)
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseSelectWithUpperCase(c *C) {
|
|
q, err := ParseSelectQuery("SELECT VALUE, TIME FROM t WHERE C = '5';")
|
|
c.Assert(err, IsNil)
|
|
c.Assert(q.GetColumnNames(), DeepEquals, ToValueArray("VALUE", "TIME"))
|
|
w := q.GetWhereCondition()
|
|
|
|
boolExpression, ok := w.GetBoolExpression()
|
|
c.Assert(ok, Equals, true)
|
|
leftValue := boolExpression.Elems[0]
|
|
rightValue := boolExpression.Elems[1]
|
|
|
|
c.Assert(leftValue.Name, Equals, "C")
|
|
c.Assert(rightValue.Name, Equals, "5")
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseSelectWithMultipleColumns(c *C) {
|
|
q, err := ParseSelectQuery("select value, time from t;")
|
|
|
|
c.Assert(err, IsNil)
|
|
columns := q.GetColumnNames()
|
|
c.Assert(columns, HasLen, 2)
|
|
c.Assert(columns[0].Name, Equals, "value")
|
|
c.Assert(columns[1].Name, Equals, "time")
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseSelectWithInequality(c *C) {
|
|
q, err := ParseSelectQuery("select value, time from t where c < 5;")
|
|
c.Assert(err, IsNil)
|
|
w := q.GetWhereCondition()
|
|
|
|
boolExpression, ok := w.GetBoolExpression()
|
|
c.Assert(ok, Equals, true)
|
|
leftValue := boolExpression.Elems[0]
|
|
rightValue := boolExpression.Elems[1]
|
|
|
|
c.Assert(leftValue.Name, Equals, "c")
|
|
c.Assert(boolExpression.Name, Equals, "<")
|
|
c.Assert(rightValue.Name, Equals, "5")
|
|
}
|
|
|
|
// issue #355
|
|
func (self *QueryParserSuite) TestErrorWithTimeSuffix(c *C) {
|
|
q := `SELECT * FROM foo where time < now() - '1f'`
|
|
_, err := ParseSelectQuery(q)
|
|
c.Assert(err, ErrorMatches, ".*1f.*")
|
|
}
|
|
|
|
// issue #331
|
|
func (self *QueryParserSuite) TestTimeWithNegativeEndTime(c *C) {
|
|
q := `SELECT * FROM foo where time < -1s`
|
|
query, err := ParseSelectQuery(q)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(query.GetEndTime(), Equals, time.Unix(-1, 0).UTC())
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestMillisecondTimeDuration(c *C) {
|
|
now := time.Now().Add(-10 * time.Millisecond).UTC()
|
|
q, err := ParseSelectQuery(`select * from foo where time < now() - 10ms`)
|
|
c.Assert(err, IsNil)
|
|
// millisecond is too short, probably the above two statements will
|
|
// take ~5 ms to run
|
|
c.Assert(q.GetEndTime().Truncate(5*time.Millisecond), Equals, now.Truncate(5*time.Millisecond))
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseSelectWithTimeCondition(c *C) {
|
|
queries := map[string]time.Time{
|
|
"select value, time from t where time > now() - 1d and time < now() - 1m;": time.Now().Add(-time.Minute).Round(time.Minute).UTC(),
|
|
"select value, time from t where time > now() - 1d and time < now() - 1y;": time.Now().Add(-365 * 24 * time.Hour).Round(time.Minute).UTC(),
|
|
"select value, time from t where time > now() - 1d and time < now();": time.Now().Round(time.Minute).UTC(),
|
|
}
|
|
for query, expected := range queries {
|
|
fmt.Printf("Running %s\n", query)
|
|
|
|
q, err := ParseSelectQuery(query)
|
|
c.Assert(err, IsNil)
|
|
|
|
c.Assert(q.GetStartTime().Round(time.Minute), Equals, time.Now().Add(-24*time.Hour).Round(time.Minute).UTC())
|
|
c.Assert(q.GetEndTime().Round(time.Minute).UTC(), Equals, expected)
|
|
|
|
// note: the time condition will be removed
|
|
c.Assert(q.GetWhereCondition(), IsNil)
|
|
}
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseSelectWithPartialTimeString(c *C) {
|
|
for actual, expected := range map[string]string{
|
|
"2013-08-15": "2013-08-15 00:00:00",
|
|
"2013-08-15 7": "2013-08-15 07:00:00",
|
|
"2013-08-15 7:04": "2013-08-15 07:04:00",
|
|
"2013-08-15 15": "2013-08-15 15:00:00",
|
|
"2013-08-15 15:14": "2013-08-15 15:14:00",
|
|
"2013-08-15 15:14:26": "2013-08-15 15:14:26",
|
|
} {
|
|
t, err := time.Parse("2006-01-02 15:04:05", expected)
|
|
c.Assert(err, IsNil)
|
|
q, err := ParseSelectQuery(fmt.Sprintf("select value, time from t where time > '%s';", actual))
|
|
c.Assert(err, IsNil)
|
|
|
|
// note: the time condition will be removed
|
|
c.Assert(q.GetWhereCondition(), IsNil)
|
|
|
|
startTime := q.GetStartTime()
|
|
c.Assert(startTime, Equals, t)
|
|
}
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseSelectWithTimeString(c *C) {
|
|
t, err := time.Parse("2006-01-02 15:04:05", "2013-08-12 23:32:01.232")
|
|
c.Assert(err, IsNil)
|
|
q, err := ParseSelectQuery("select value, time from t where time > '2013-08-12 23:32:01.232';")
|
|
c.Assert(err, IsNil)
|
|
|
|
// note: the time condition will be removed
|
|
c.Assert(q.GetWhereCondition(), IsNil)
|
|
|
|
startTime := q.GetStartTime()
|
|
c.Assert(startTime, Equals, t)
|
|
|
|
milliseconds := startTime.Sub(startTime.Round(time.Second)).Nanoseconds() / 1000000
|
|
c.Assert(milliseconds, Equals, int64(232))
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseSelectWithAnd(c *C) {
|
|
q, err := ParseSelectQuery("select value from cpu.idle where value > exp() * 2 and value < exp() * 3;")
|
|
c.Assert(err, IsNil)
|
|
|
|
w := q.GetWhereCondition()
|
|
c.Assert(w.Operation, Equals, "AND")
|
|
|
|
// leftBoolExpression = 'value > exp() * 2'
|
|
leftWhereCondition, ok := w.GetLeftWhereCondition()
|
|
c.Assert(ok, Equals, true)
|
|
leftBoolExpression, ok := leftWhereCondition.GetBoolExpression()
|
|
c.Assert(ok, Equals, true)
|
|
// rightBoolExpression = 'value > exp() * 3'
|
|
rightBoolExpression, ok := w.Right.GetBoolExpression()
|
|
c.Assert(ok, Equals, true)
|
|
|
|
c.Assert(leftBoolExpression.Elems[0], DeepEquals, &Value{"value", "", ValueSimpleName, nil, nil, false})
|
|
value := leftBoolExpression.Elems[1].Elems[0]
|
|
c.Assert(value, DeepEquals, &Value{"exp", "", ValueFunctionCall, nil, nil, false})
|
|
value = leftBoolExpression.Elems[1].Elems[1]
|
|
c.Assert(value, DeepEquals, &Value{"2", "", ValueInt, nil, nil, false})
|
|
c.Assert(leftBoolExpression.Name, Equals, ">")
|
|
|
|
c.Assert(rightBoolExpression.Elems[0], DeepEquals, &Value{"value", "", ValueSimpleName, nil, nil, false})
|
|
value = rightBoolExpression.Elems[1].Elems[0]
|
|
c.Assert(value, DeepEquals, &Value{"exp", "", ValueFunctionCall, nil, nil, false})
|
|
value = rightBoolExpression.Elems[1].Elems[1]
|
|
c.Assert(value, DeepEquals, &Value{"3", "", ValueInt, nil, nil, false})
|
|
c.Assert(rightBoolExpression.Name, Equals, "<")
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseSelectWithGroupBy(c *C) {
|
|
q, err := ParseSelectQuery("select count(*) from users.events group by user_email,time(1h) where time>now()-1d;")
|
|
c.Assert(err, IsNil)
|
|
|
|
c.Assert(q.GetColumnNames(), HasLen, 1)
|
|
|
|
column := q.GetColumnNames()[0]
|
|
c.Assert(column.IsFunctionCall(), Equals, true)
|
|
c.Assert(column.Name, Equals, "count")
|
|
c.Assert(column.Elems, HasLen, 1)
|
|
c.Assert(column.Elems[0].IsFunctionCall(), Equals, false)
|
|
c.Assert(column.Elems[0].Name, Equals, "*")
|
|
|
|
groupBy := q.GetGroupByClause()
|
|
c.Assert(groupBy.FillWithZero, Equals, false)
|
|
c.Assert(groupBy.Elems, HasLen, 2)
|
|
c.Assert(groupBy.Elems[0].IsFunctionCall(), Equals, false)
|
|
c.Assert(groupBy.Elems[0].Name, Equals, "user_email")
|
|
c.Assert(groupBy.Elems[1].IsFunctionCall(), Equals, true)
|
|
c.Assert(groupBy.Elems[1].Name, Equals, "time")
|
|
c.Assert(groupBy.Elems[1].Elems, HasLen, 1)
|
|
c.Assert(groupBy.Elems[1].Elems[0].Name, Equals, "1h")
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseSelectWithGroupByFillWithZero(c *C) {
|
|
q, err := ParseSelectQuery("select count(*) from users.events group by user_email,time(1h) fill(0) where time>now()-1d;")
|
|
c.Assert(err, IsNil)
|
|
|
|
c.Assert(q.GetColumnNames(), HasLen, 1)
|
|
|
|
column := q.GetColumnNames()[0]
|
|
c.Assert(column.IsFunctionCall(), Equals, true)
|
|
c.Assert(column.Name, Equals, "count")
|
|
c.Assert(column.Elems, HasLen, 1)
|
|
c.Assert(column.Elems[0].IsFunctionCall(), Equals, false)
|
|
c.Assert(column.Elems[0].Name, Equals, "*")
|
|
|
|
groupBy := q.GetGroupByClause()
|
|
c.Assert(groupBy.FillWithZero, Equals, true)
|
|
c.Assert(groupBy.FillValue.Name, Equals, "0")
|
|
c.Assert(groupBy.Elems, HasLen, 2)
|
|
c.Assert(groupBy.Elems[0].IsFunctionCall(), Equals, false)
|
|
c.Assert(groupBy.Elems[0].Name, Equals, "user_email")
|
|
c.Assert(groupBy.Elems[1].IsFunctionCall(), Equals, true)
|
|
c.Assert(groupBy.Elems[1].Name, Equals, "time")
|
|
c.Assert(groupBy.Elems[1].Elems, HasLen, 1)
|
|
c.Assert(groupBy.Elems[1].Elems[0].Name, Equals, "1h")
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseSelectWithGroupByWithInvalidFunctions(c *C) {
|
|
for _, query := range []string{
|
|
"select count(*) from users.events group by user_email,time(1h) foobar(0) where time>now()-1d;",
|
|
} {
|
|
_, err := ParseSelectQuery(query)
|
|
c.Assert(err, NotNil)
|
|
}
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseFromWithNestedFunctions(c *C) {
|
|
q, err := ParseSelectQuery("select top(10, count(*)) from users.events;")
|
|
c.Assert(err, IsNil)
|
|
c.Assert(q.GetColumnNames(), HasLen, 1)
|
|
column := q.GetColumnNames()[0]
|
|
c.Assert(column.IsFunctionCall(), Equals, true)
|
|
c.Assert(column.Name, Equals, "top")
|
|
c.Assert(column.Elems, HasLen, 2)
|
|
c.Assert(column.Elems[0].IsFunctionCall(), Equals, false)
|
|
c.Assert(column.Elems[0].Name, Equals, "10")
|
|
c.Assert(column.Elems[1].IsFunctionCall(), Equals, true)
|
|
c.Assert(column.Elems[1].Name, Equals, "count")
|
|
c.Assert(column.Elems[1].Elems, HasLen, 1)
|
|
c.Assert(column.Elems[1].Elems[0].IsFunctionCall(), Equals, false)
|
|
c.Assert(column.Elems[1].Elems[0].Name, Equals, "*")
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseWhereClausePrecedence(c *C) {
|
|
q, err := ParseSelectQuery("select value from cpu.idle where value > 90 and other_value > 10.0 or value > 80 and other_value > 20;")
|
|
c.Assert(err, IsNil)
|
|
|
|
whereCondition := q.GetWhereCondition()
|
|
|
|
c.Assert(whereCondition.Operation, Equals, "OR")
|
|
leftCondition, ok := whereCondition.Left.(*WhereCondition)
|
|
c.Assert(ok, Equals, true)
|
|
c.Assert(leftCondition.Operation, Equals, "AND")
|
|
|
|
condition, ok := leftCondition.GetLeftWhereCondition()
|
|
c.Assert(ok, Equals, true)
|
|
leftExpression, ok := condition.GetBoolExpression()
|
|
c.Assert(ok, Equals, true)
|
|
c.Assert(leftExpression.Name, Equals, ">")
|
|
c.Assert(leftExpression.Elems[0], DeepEquals, &Value{"value", "", ValueSimpleName, nil, nil, false})
|
|
c.Assert(leftExpression.Elems[1], DeepEquals, &Value{"90", "", ValueInt, nil, nil, false})
|
|
|
|
rightExpression, ok := leftCondition.Right.GetBoolExpression()
|
|
c.Assert(ok, Equals, true)
|
|
c.Assert(rightExpression.Name, Equals, ">")
|
|
c.Assert(rightExpression.Elems[0], DeepEquals, &Value{"other_value", "", ValueSimpleName, nil, nil, false})
|
|
c.Assert(rightExpression.Elems[1], DeepEquals, &Value{"10.0", "", ValueFloat, nil, nil, false})
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseWhereClauseParentheses(c *C) {
|
|
q, err := ParseSelectQuery("select value from cpu.idle where value > 90 and (other_value > 10 or value > 80) and other_value > 20;")
|
|
c.Assert(err, IsNil)
|
|
|
|
whereCondition := q.GetWhereCondition()
|
|
|
|
first := whereCondition.Left.(*WhereCondition).Left.(*WhereCondition).Left.(*Value)
|
|
second := whereCondition.Left.(*WhereCondition).Right
|
|
third := whereCondition.Right.Left.(*Value)
|
|
|
|
c.Assert(first.Name, Equals, ">")
|
|
c.Assert(second.Operation, Equals, "OR")
|
|
c.Assert(third.Name, Equals, ">")
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseSelectWithInvalidLimit(c *C) {
|
|
_, err := ParseSelectQuery("select value from t limit;")
|
|
c.Assert(err, NotNil)
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseSelectWithOrderByAndLimit(c *C) {
|
|
q, err := ParseSelectQuery("select value from t order asc limit 10;")
|
|
c.Assert(err, IsNil)
|
|
c.Assert(q.Limit, Equals, 10)
|
|
c.Assert(q.Ascending, Equals, true)
|
|
|
|
q, err = ParseSelectQuery("select value from t order desc;")
|
|
c.Assert(err, IsNil)
|
|
c.Assert(q.Ascending, Equals, false)
|
|
|
|
q, err = ParseSelectQuery("select value from t limit 20;")
|
|
c.Assert(err, IsNil)
|
|
c.Assert(q.Limit, Equals, 20)
|
|
// descending is the default
|
|
c.Assert(q.Ascending, Equals, false)
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseFromWithNestedFunctions2(c *C) {
|
|
q, err := ParseSelectQuery("select count(distinct(email)) from user.events where time>now()-1d group by time(15m);")
|
|
c.Assert(err, IsNil)
|
|
c.Assert(q.GetColumnNames(), HasLen, 1)
|
|
column := q.GetColumnNames()[0]
|
|
c.Assert(column.IsFunctionCall(), Equals, true)
|
|
c.Assert(column.Name, Equals, "count")
|
|
c.Assert(column.Elems, HasLen, 1)
|
|
c.Assert(column.Elems[0].IsFunctionCall(), Equals, true)
|
|
c.Assert(column.Elems[0].Name, Equals, "distinct")
|
|
c.Assert(column.Elems[0].Elems, HasLen, 1)
|
|
c.Assert(column.Elems[0].Elems[0].Name, Equals, "email")
|
|
|
|
c.Assert(q.GetGroupByClause().Elems, HasLen, 1)
|
|
c.Assert(q.GetGroupByClause().Elems[0], DeepEquals, &Value{
|
|
Name: "time",
|
|
Alias: "",
|
|
Type: ValueFunctionCall,
|
|
Elems: []*Value{{"15m", "", ValueDuration, nil, nil, false}},
|
|
})
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseWithColumnAlias(c *C) {
|
|
q, err := ParseSelectQuery("select count(email) as email_count from user.events")
|
|
c.Assert(err, IsNil)
|
|
c.Assert(q.GetColumnNames(), HasLen, 1)
|
|
column := q.GetColumnNames()[0]
|
|
c.Assert(column.IsFunctionCall(), Equals, true)
|
|
c.Assert(column.Name, Equals, "count")
|
|
c.Assert(column.Elems, HasLen, 1)
|
|
c.Assert(column.Alias, Equals, "email_count")
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseSelectWithInvalidRegex(c *C) {
|
|
_, err := ParseSelectQuery("select email from users.events where email =~ /[/i and time>now()-2d;")
|
|
c.Assert(err, ErrorMatches, ".*missing closing.*")
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseSelectWithRegexCondition(c *C) {
|
|
q, err := ParseSelectQuery("select email from users.events where email =~ /gmail\\.com/i and time>now()-2d;")
|
|
c.Assert(err, IsNil)
|
|
w := q.GetWhereCondition()
|
|
|
|
// note: conditions that involve time are removed after the query is parsed
|
|
regexExpression, _ := w.GetBoolExpression()
|
|
c.Assert(regexExpression.Elems[0], DeepEquals, &Value{"email", "", ValueSimpleName, nil, nil, false})
|
|
c.Assert(regexExpression.Name, Equals, "=~")
|
|
expr := regexExpression.Elems[1]
|
|
c.Assert(expr.Type, Equals, ValueRegex)
|
|
c.Assert(expr.Name, Equals, "gmail\\.com")
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestErrorLocation(c *C) {
|
|
_, err := ParseSelectQuery("select -1 * value from cpu.idle")
|
|
c.Assert(err, IsNil)
|
|
_, err = ParseSelectQuery("select -1 * value group by")
|
|
c.Assert(err, ErrorMatches, ".*0:18 0:23.*")
|
|
c.Assert(err, FitsTypeOf, &QueryError{})
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestQueryWithArithmeticColumns(c *C) {
|
|
q, err := ParseSelectQuery("select -1 * value from cpu.idle")
|
|
c.Assert(err, IsNil)
|
|
c.Assert(q.ColumnNames, HasLen, 1)
|
|
c.Assert(int(q.ColumnNames[0].Type), Equals, ValueExpression)
|
|
c.Assert(q.ColumnNames[0].Name, Equals, "*")
|
|
c.Assert(q.ColumnNames[0].Elems[0].Name, Equals, "-1")
|
|
c.Assert(q.ColumnNames[0].Elems[1].Name, Equals, "value")
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseSelectWithComplexArithmeticOperations(c *C) {
|
|
q, err := ParseSelectQuery("select value from cpu.idle where .30 < value * 1 / 3 ;")
|
|
c.Assert(err, IsNil)
|
|
|
|
boolExpression, ok := q.GetWhereCondition().GetBoolExpression()
|
|
c.Assert(ok, Equals, true)
|
|
|
|
c.Assert(boolExpression.Elems[0], DeepEquals, &Value{".30", "", ValueFloat, nil, nil, false})
|
|
|
|
// value * 1 / 3
|
|
rightExpression := boolExpression.Elems[1]
|
|
|
|
// value * 1
|
|
left := rightExpression.Elems[0]
|
|
c.Assert(left.Name, Equals, "*")
|
|
value := left.Elems[0]
|
|
c.Assert(value.Name, Equals, "value")
|
|
one := left.Elems[1]
|
|
c.Assert(one.Name, Equals, "1")
|
|
|
|
// '3'
|
|
c.Assert(rightExpression.Name, Equals, "/")
|
|
value = rightExpression.Elems[1]
|
|
c.Assert(value.Name, Equals, "3")
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestTimeConditionWithFloats(c *C) {
|
|
var startTime int64 = 13853965
|
|
for _, query := range []string{
|
|
fmt.Sprintf("select * from foo where time > %d000000000.0", startTime),
|
|
fmt.Sprintf("select * from foo where time > %ds", startTime),
|
|
fmt.Sprintf("select * from foo where time > %d.0s", startTime),
|
|
} {
|
|
q, err := ParseSelectQuery(query)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(q.GetStartTime(), Equals, time.Unix(startTime, 0).UTC())
|
|
}
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestQueryWithInCondition(c *C) {
|
|
query := "select * from foo where bar in ('baz', 'bazz')"
|
|
q, err := ParseSelectQuery(query)
|
|
c.Assert(err, IsNil)
|
|
condition := q.GetWhereCondition()
|
|
expr, ok := condition.GetBoolExpression()
|
|
c.Assert(ok, Equals, true)
|
|
c.Assert(expr.Name, Equals, "in")
|
|
left := expr.Elems[0]
|
|
right := expr.Elems[1:]
|
|
c.Assert(left.Name, Equals, "bar")
|
|
c.Assert(right, HasLen, 2)
|
|
c.Assert(right[0].Name, Equals, "baz")
|
|
c.Assert(right[1].Name, Equals, "bazz")
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseSinglePointQuery(c *C) {
|
|
q, err := ParseSelectQuery("select value from foo where time = 999 and sequence_number = 1;")
|
|
c.Assert(err, IsNil)
|
|
|
|
w := q.GetWhereCondition()
|
|
c.Assert(w.Operation, Equals, "AND")
|
|
|
|
// leftBoolExpression = 'time = 999'
|
|
leftWhereCondition, ok := w.GetLeftWhereCondition()
|
|
c.Assert(ok, Equals, true)
|
|
leftBoolExpression, ok := leftWhereCondition.GetBoolExpression()
|
|
c.Assert(ok, Equals, true)
|
|
|
|
// rightBoolExpression = 'sequence_number = 1'
|
|
rightBoolExpression, ok := w.Right.GetBoolExpression()
|
|
c.Assert(ok, Equals, true)
|
|
|
|
c.Assert(leftBoolExpression.Elems[0], DeepEquals, &Value{"time", "", ValueSimpleName, nil, nil, false})
|
|
value := leftBoolExpression.Elems[1]
|
|
c.Assert(value, DeepEquals, &Value{"999", "", ValueInt, nil, nil, false})
|
|
c.Assert(leftBoolExpression.Name, Equals, "=")
|
|
|
|
c.Assert(rightBoolExpression.Elems[0], DeepEquals, &Value{"sequence_number", "", ValueSimpleName, nil, nil, false})
|
|
value = rightBoolExpression.Elems[1]
|
|
c.Assert(value, DeepEquals, &Value{"1", "", ValueInt, nil, nil, false})
|
|
c.Assert(rightBoolExpression.Name, Equals, "=")
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestSinglePointGetQueryString(c *C) {
|
|
qs := "select value from \"foo\" where (time = 999) AND (sequence_number = 1)"
|
|
q, err := ParseSelectQuery(qs)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(q.GetQueryString(), Equals, qs)
|
|
c.Assert(q.GetQueryStringWithTimeCondition(), Equals, qs)
|
|
}
|
|
|
|
// TODO: test reversed order of time and sequence_number
|
|
func (self *QueryParserSuite) TestIsSinglePointQuery(c *C) {
|
|
query := "select * from foo where time = 123 and sequence_number = 99"
|
|
q, err := ParseSelectQuery(query)
|
|
c.Assert(err, IsNil)
|
|
result := q.IsSinglePointQuery()
|
|
c.Assert(result, Equals, true)
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseContinuousQueryCreation(c *C) {
|
|
q := getContinuousQuery("select * from foo into bar;", c)
|
|
c.Assert(q.IsValidContinuousQuery(), Equals, true)
|
|
clause := q.GetIntoClause()
|
|
c.Assert(clause.Target, DeepEquals, &Value{"bar", "", ValueSimpleName, nil, nil, false})
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseRecursiveContinuousQueries(c *C) {
|
|
query := `select * from /^stats\\..*/ into bar;`
|
|
q, err := ParseSelectQuery(query)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(q.IsNonRecursiveContinuousQuery(), Equals, true)
|
|
|
|
query = `select * from /^stats\\..*/ group by time(5m) into rollups.:series_name.5m;`
|
|
q, err = ParseSelectQuery(query)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(q.IsNonRecursiveContinuousQuery(), Equals, true)
|
|
|
|
query = `select * from /.*stats$/ group by time(5m) into :series_name.5m;`
|
|
q, err = ParseSelectQuery(query)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(q.IsNonRecursiveContinuousQuery(), Equals, true)
|
|
|
|
query = `select * from /.*/ into :series_name.foo;`
|
|
q, err = ParseSelectQuery(query)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(q.IsNonRecursiveContinuousQuery(), Equals, false)
|
|
|
|
query = `select * from /^stats\..*/ into :series_name.foo;`
|
|
q, err = ParseSelectQuery(query)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(q.IsNonRecursiveContinuousQuery(), Equals, false)
|
|
|
|
query = `select * from /stats$/ into foo.:series_name;`
|
|
q, err = ParseSelectQuery(query)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(q.IsNonRecursiveContinuousQuery(), Equals, false)
|
|
}
|
|
|
|
func getContinuousQuery(q string, c *C) *SelectQuery {
|
|
queries, err := ParseQuery(q)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(queries, HasLen, 1)
|
|
query := queries[0]
|
|
c.Assert(query.IsContinuousQuery(), Equals, true)
|
|
return query.SelectQuery
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseInterpolatedContinuousQueryCreation(c *C) {
|
|
q := getContinuousQuery("select * from foo into bar.[c4];", c)
|
|
clause := q.GetIntoClause()
|
|
c.Assert(clause.Target, DeepEquals, &Value{"bar.[c4]", "", ValueIntoName, nil, nil, false})
|
|
|
|
q = getContinuousQuery("select * from foo into [c5].bar.[c4];", c)
|
|
clause = q.GetIntoClause()
|
|
c.Assert(clause.Target, DeepEquals, &Value{"[c5].bar.[c4]", "", ValueIntoName, nil, nil, false})
|
|
|
|
q = getContinuousQuery("select average(c4), count(c5) from s3 group by time(1h) into [average].[count];", c)
|
|
clause = q.GetIntoClause()
|
|
c.Assert(clause.Target, DeepEquals, &Value{"[average].[count]", "", ValueIntoName, nil, nil, false})
|
|
|
|
q = getContinuousQuery("select * from foo into :series_name.foo;", c)
|
|
clause = q.GetIntoClause()
|
|
c.Assert(clause.Target, DeepEquals, &Value{":series_name.foo", "", ValueIntoName, nil, nil, false})
|
|
|
|
_, err := ParseQuery("select * from foo into ]bar")
|
|
c.Assert(err, NotNil)
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseContinuousQueryDeletion(c *C) {
|
|
query := "drop continuous query 1;"
|
|
queries, err := ParseQuery(query)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(queries, HasLen, 1)
|
|
c.Assert(queries[0].DropQuery, NotNil)
|
|
c.Assert(queries[0].DropQuery.Id, Equals, 1)
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestParseContinuousQueryList(c *C) {
|
|
query := "list continuous queries;"
|
|
queries, err := ParseQuery(query)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(queries, HasLen, 1)
|
|
c.Assert(queries[0].IsListQuery(), Equals, true)
|
|
c.Assert(queries[0].IsListContinuousQueriesQuery(), Equals, true)
|
|
}
|
|
|
|
// For issue #768
|
|
func (self *QueryParserSuite) TestMinusWithoutSpace(c *C) {
|
|
query := "select val1-val0 from foo;"
|
|
q, err := ParseSelectQuery(query)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(q.GetColumnNames(), HasLen, 1)
|
|
column := q.GetColumnNames()[0]
|
|
c.Assert(column.Type, Equals, ValueType(ValueExpression))
|
|
c.Assert(column.Elems[0].Name, Equals, "val1")
|
|
c.Assert(column.Elems[1].Name, Equals, "val0")
|
|
c.Assert(column.Name, Equals, "-")
|
|
}
|
|
|
|
// For issue #466 - allow all characters in column names - https://github.com/influxdb/influxdb/issues/267
|
|
func (self *QueryParserSuite) TestParseColumnWithPeriodOrDash(c *C) {
|
|
query := "select count(\"column-a.foo\") as \"count-column-a.foo\" from seriesA;"
|
|
q, err := ParseSelectQuery(query)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(q.GetColumnNames(), HasLen, 1)
|
|
column := q.GetColumnNames()[0]
|
|
c.Assert(column.Name, Equals, "count")
|
|
c.Assert(column.Elems, HasLen, 1)
|
|
c.Assert(column.Elems[0].Name, Equals, "column-a.foo")
|
|
c.Assert(column.Alias, Equals, "count-column-a.foo")
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestQueryErrorShouldHaveQueryString(c *C) {
|
|
query := "select ! from foo;"
|
|
_, err := ParseSelectQuery(query)
|
|
e, _ := err.(*QueryError)
|
|
c.Assert(e, NotNil)
|
|
c.Assert(e.queryString, Equals, query)
|
|
}
|
|
|
|
// For issue #496 - parentheses value should support alias https://github.com/influxdb/influxdb/issues/496
|
|
func (self *QueryParserSuite) TestQueryParenthesesValueShouldSupportAlias(c *C) {
|
|
query := "select (1 + 2) as arithmetic_result from foo;"
|
|
q, err := ParseSelectQuery(query)
|
|
|
|
c.Assert(err, IsNil)
|
|
c.Assert(q.GetColumnNames(), HasLen, 1)
|
|
column := q.GetColumnNames()[0]
|
|
c.Assert(column.Elems, HasLen, 2)
|
|
c.Assert(column.Alias, Equals, "arithmetic_result")
|
|
}
|
|
|
|
func (self *QueryParserSuite) TestQueryParenthesesValueShouldSupportAliases(c *C) {
|
|
query := "select (1 + 2) as arithmetic_result, (3 + 4) as arithmetic_result2 from foo;"
|
|
q, err := ParseSelectQuery(query)
|
|
|
|
c.Assert(err, IsNil)
|
|
c.Assert(q.GetColumnNames(), HasLen, 2)
|
|
column := q.GetColumnNames()[0]
|
|
c.Assert(column.Elems, HasLen, 2)
|
|
c.Assert(column.Alias, Equals, "arithmetic_result")
|
|
|
|
column2 := q.GetColumnNames()[1]
|
|
c.Assert(column2.Elems, HasLen, 2)
|
|
c.Assert(column2.Alias, Equals, "arithmetic_result2")
|
|
}
|
|
|
|
// TODO:
|
|
// insert into user.events.count.per_day select count(*) from user.events where time<forever group by time(1d)
|
|
// insert into :series_name.percentiles.95 select percentile(95,value) from stats.* where time<forever group by time(1d)
|