add support for function calls aliasing in the parser

pull/290/head
John Shahid 2014-03-03 13:05:02 -05:00
parent a3c3c79582
commit 5bb5161c8d
6 changed files with 73 additions and 23 deletions

View File

@ -60,6 +60,7 @@ void
free_value(value *value)
{
free(value->name);
if (value->alias) free(value->alias);
if (value->args) free_value_array(value->args);
free(value);
}

View File

@ -39,6 +39,7 @@ const (
type Value struct {
Name string
Alias string
Type ValueType
Elems []*Value
compiledRegex *regexp.Regexp
@ -385,6 +386,9 @@ func GetValue(value *C.value) (*Value, error) {
v.compiledRegex, err = regexp.Compile(v.Name)
}
}
if value.alias != nil {
v.Alias = C.GoString(value.alias)
}
return v, err
}

View File

@ -19,7 +19,7 @@ var _ = Suite(&QueryParserSuite{})
func ToValueArray(strings ...string) (values []*Value) {
for _, str := range strings {
values = append(values, &Value{str, ValueSimpleName, nil, nil})
values = append(values, &Value{str, "", ValueSimpleName, nil, nil})
}
return
}
@ -463,18 +463,18 @@ func (self *QueryParserSuite) TestParseSelectWithAnd(c *C) {
rightBoolExpression, ok := w.Right.GetBoolExpression()
c.Assert(ok, Equals, true)
c.Assert(leftBoolExpression.Elems[0], DeepEquals, &Value{"value", ValueSimpleName, nil, nil})
c.Assert(leftBoolExpression.Elems[0], DeepEquals, &Value{"value", "", ValueSimpleName, nil, nil})
value := leftBoolExpression.Elems[1].Elems[0]
c.Assert(value, DeepEquals, &Value{"exp", ValueFunctionCall, nil, nil})
c.Assert(value, DeepEquals, &Value{"exp", "", ValueFunctionCall, nil, nil})
value = leftBoolExpression.Elems[1].Elems[1]
c.Assert(value, DeepEquals, &Value{"2", ValueInt, nil, nil})
c.Assert(value, DeepEquals, &Value{"2", "", ValueInt, nil, nil})
c.Assert(leftBoolExpression.Name, Equals, ">")
c.Assert(rightBoolExpression.Elems[0], DeepEquals, &Value{"value", ValueSimpleName, nil, nil})
c.Assert(rightBoolExpression.Elems[0], DeepEquals, &Value{"value", "", ValueSimpleName, nil, nil})
value = rightBoolExpression.Elems[1].Elems[0]
c.Assert(value, DeepEquals, &Value{"exp", ValueFunctionCall, nil, nil})
c.Assert(value, DeepEquals, &Value{"exp", "", ValueFunctionCall, nil, nil})
value = rightBoolExpression.Elems[1].Elems[1]
c.Assert(value, DeepEquals, &Value{"3", ValueInt, nil, nil})
c.Assert(value, DeepEquals, &Value{"3", "", ValueInt, nil, nil})
c.Assert(rightBoolExpression.Name, Equals, "<")
}
@ -568,14 +568,14 @@ func (self *QueryParserSuite) TestParseWhereClausePrecedence(c *C) {
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})
c.Assert(leftExpression.Elems[1], DeepEquals, &Value{"90", ValueInt, nil, nil})
c.Assert(leftExpression.Elems[0], DeepEquals, &Value{"value", "", ValueSimpleName, nil, nil})
c.Assert(leftExpression.Elems[1], DeepEquals, &Value{"90", "", ValueInt, nil, nil})
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})
c.Assert(rightExpression.Elems[1], DeepEquals, &Value{"10.0", ValueFloat, nil, nil})
c.Assert(rightExpression.Elems[0], DeepEquals, &Value{"other_value", "", ValueSimpleName, nil, nil})
c.Assert(rightExpression.Elems[1], DeepEquals, &Value{"10.0", "", ValueFloat, nil, nil})
}
func (self *QueryParserSuite) TestParseWhereClauseParentheses(c *C) {
@ -631,11 +631,23 @@ func (self *QueryParserSuite) TestParseFromWithNestedFunctions2(c *C) {
c.Assert(q.GetGroupByClause().Elems, HasLen, 1)
c.Assert(q.GetGroupByClause().Elems[0], DeepEquals, &Value{
Name: "time",
Alias: "",
Type: ValueFunctionCall,
Elems: []*Value{&Value{"15m", ValueDuration, nil, nil}},
Elems: []*Value{&Value{"15m", "", ValueDuration, nil, nil}},
})
}
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.*")
@ -648,7 +660,7 @@ func (self *QueryParserSuite) TestParseSelectWithRegexCondition(c *C) {
// 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})
c.Assert(regexExpression.Elems[0], DeepEquals, &Value{"email", "", ValueSimpleName, nil, nil})
c.Assert(regexExpression.Name, Equals, "=~")
expr := regexExpression.Elems[1]
c.Assert(expr.Type, Equals, ValueRegex)
@ -662,7 +674,7 @@ func (self *QueryParserSuite) TestParseSelectWithComplexArithmeticOperations(c *
boolExpression, ok := q.GetWhereCondition().GetBoolExpression()
c.Assert(ok, Equals, true)
c.Assert(boolExpression.Elems[0], DeepEquals, &Value{".30", ValueFloat, nil, nil})
c.Assert(boolExpression.Elems[0], DeepEquals, &Value{".30", "", ValueFloat, nil, nil})
// value * 1 / 3
rightExpression := boolExpression.Elems[1]
@ -727,14 +739,14 @@ func (self *QueryParserSuite) TestParseSinglePointQuery(c *C) {
rightBoolExpression, ok := w.Right.GetBoolExpression()
c.Assert(ok, Equals, true)
c.Assert(leftBoolExpression.Elems[0], DeepEquals, &Value{"time", ValueSimpleName, nil, nil})
c.Assert(leftBoolExpression.Elems[0], DeepEquals, &Value{"time", "", ValueSimpleName, nil, nil})
value := leftBoolExpression.Elems[1]
c.Assert(value, DeepEquals, &Value{"999", ValueInt, nil, nil})
c.Assert(value, DeepEquals, &Value{"999", "", ValueInt, nil, nil})
c.Assert(leftBoolExpression.Name, Equals, "=")
c.Assert(rightBoolExpression.Elems[0], DeepEquals, &Value{"sequence_number", ValueSimpleName, nil, nil})
c.Assert(rightBoolExpression.Elems[0], DeepEquals, &Value{"sequence_number", "", ValueSimpleName, nil, nil})
value = rightBoolExpression.Elems[1]
c.Assert(value, DeepEquals, &Value{"1", ValueInt, nil, nil})
c.Assert(value, DeepEquals, &Value{"1", "", ValueInt, nil, nil})
c.Assert(rightBoolExpression.Name, Equals, "=")
}
@ -754,7 +766,7 @@ func (self *QueryParserSuite) TestParseContinuousQueryCreation(c *C) {
c.Assert(q.IsContinuousQuery(), Equals, true)
c.Assert(q.IsValidContinuousQuery(), Equals, true)
clause := q.GetIntoClause()
c.Assert(clause.Target, DeepEquals, &Value{"bar", ValueSimpleName, nil, nil})
c.Assert(clause.Target, DeepEquals, &Value{"bar", "", ValueSimpleName, nil, nil})
}
func (self *QueryParserSuite) TestParseInterpolatedContinuousQueryCreation(c *C) {
@ -763,28 +775,28 @@ func (self *QueryParserSuite) TestParseInterpolatedContinuousQueryCreation(c *C)
c.Assert(err, IsNil)
c.Assert(q.IsContinuousQuery(), Equals, true)
clause := q.GetIntoClause()
c.Assert(clause.Target, DeepEquals, &Value{"bar.[c4]", ValueIntoName, nil, nil})
c.Assert(clause.Target, DeepEquals, &Value{"bar.[c4]", "", ValueIntoName, nil, nil})
query = "select * from foo into [c5].bar.[c4];"
q, err = ParseSelectQuery(query)
c.Assert(err, IsNil)
c.Assert(q.IsContinuousQuery(), Equals, true)
clause = q.GetIntoClause()
c.Assert(clause.Target, DeepEquals, &Value{"[c5].bar.[c4]", ValueIntoName, nil, nil})
c.Assert(clause.Target, DeepEquals, &Value{"[c5].bar.[c4]", "", ValueIntoName, nil, nil})
query = "select average(c4), count(c5) from s3 group by time(1h) into [average].[count];"
q, err = ParseSelectQuery(query)
c.Assert(err, IsNil)
c.Assert(q.IsContinuousQuery(), Equals, true)
clause = q.GetIntoClause()
c.Assert(clause.Target, DeepEquals, &Value{"[average].[count]", ValueIntoName, nil, nil})
c.Assert(clause.Target, DeepEquals, &Value{"[average].[count]", "", ValueIntoName, nil, nil})
query = "select * from foo into :series_name.foo;"
q, err = ParseSelectQuery(query)
c.Assert(err, IsNil)
c.Assert(q.IsContinuousQuery(), Equals, true)
clause = q.GetIntoClause()
c.Assert(clause.Target, DeepEquals, &Value{":series_name.foo", ValueIntoName, nil, nil})
c.Assert(clause.Target, DeepEquals, &Value{":series_name.foo", "", ValueIntoName, nil, nil})
query = "select * from foo into ]bar"
q, err = ParseSelectQuery(query)

View File

@ -13,12 +13,14 @@ value *create_value(char *name, int type, char is_case_insensitive, value_array
v->value_type = type;
v->is_case_insensitive = is_case_insensitive;
v->args = args;
v->alias = NULL;
return v;
}
value *create_expression_value(char *operator, size_t size, ...) {
value *v = malloc(sizeof(value));
v->name = operator;
v->alias = NULL;
v->value_type = VALUE_EXPRESSION;
v->is_case_insensitive = FALSE;
v->args = malloc(sizeof(value_array));
@ -418,20 +420,46 @@ VALUE:
}
|
DURATION_VALUE
{
$$ = $1;
$$->alias = NULL;
}
|
SIMPLE_NAME_VALUE
{
$$ = $1;
$$->alias = NULL;
}
|
WILDCARD
{
$$ = $1;
$$->alias = NULL;
}
|
TABLE_NAME_VALUE
{
$$ = $1;
$$->alias = NULL;
}
|
FUNCTION_CALL
{
$$ = $1;
$$->alias = NULL;
}
|
'(' VALUE ')'
{
$$ = $2;
}
|
FUNCTION_CALL AS SIMPLE_NAME
{
$$ = $1;
$$->alias = $3;
}
|
VALUE '*' VALUE { $$ = create_expression_value(strdup("*"), 2, $1, $3); }
|
VALUE '/' VALUE { $$ = create_expression_value(strdup("/"), 2, $1, $3); }

View File

@ -32,6 +32,7 @@ typedef struct value_t {
VALUE_FUNCTION_CALL,
VALUE_EXPRESSION
} value_type;
char *alias;
char is_case_insensitive;
value_array *args;
} value;

View File

@ -12,6 +12,10 @@ int main(int argc, char **argv) {
q = parse_query("select count(*) from users.events group_by user_email,time(1h) where time >> now()-1d;");
close_query(&q);
// test freeing alias
q = parse_query("select count(bar) as the_count from users.events group_by user_email,time(1h);");
close_query(&q);
// test freeing where conditions
q = parse_query("select value from t where c == 5 and b == 6;");
close_query(&q);