From 5bb5161c8d1690bc3ca5a6bd458cbc0b94b72147 Mon Sep 17 00:00:00 2001
From: John Shahid <jvshahid@gmail.com>
Date: Mon, 3 Mar 2014 13:05:02 -0500
Subject: [PATCH] add support for function calls aliasing in the parser

---
 src/parser/frees.c              |  1 +
 src/parser/parser.go            |  4 +++
 src/parser/parser_test.go       | 58 ++++++++++++++++++++-------------
 src/parser/query.yacc           | 28 ++++++++++++++++
 src/parser/query_types.h        |  1 +
 src/parser/test_memory_leaks.sh |  4 +++
 6 files changed, 73 insertions(+), 23 deletions(-)

diff --git a/src/parser/frees.c b/src/parser/frees.c
index 62b02e3962..582b5e8e1a 100644
--- a/src/parser/frees.c
+++ b/src/parser/frees.c
@@ -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);
 }
diff --git a/src/parser/parser.go b/src/parser/parser.go
index edc9eac153..a694178813 100644
--- a/src/parser/parser.go
+++ b/src/parser/parser.go
@@ -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
 }
 
diff --git a/src/parser/parser_test.go b/src/parser/parser_test.go
index 342ed06191..e9112d7dfb 100644
--- a/src/parser/parser_test.go
+++ b/src/parser/parser_test.go
@@ -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)
diff --git a/src/parser/query.yacc b/src/parser/query.yacc
index 24e3f51a4b..f894fbc83c 100644
--- a/src/parser/query.yacc
+++ b/src/parser/query.yacc
@@ -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); }
diff --git a/src/parser/query_types.h b/src/parser/query_types.h
index b11898b1c3..c9d5c4775a 100644
--- a/src/parser/query_types.h
+++ b/src/parser/query_types.h
@@ -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;
diff --git a/src/parser/test_memory_leaks.sh b/src/parser/test_memory_leaks.sh
index 356f0d5e2e..b25c7aff64 100755
--- a/src/parser/test_memory_leaks.sh
+++ b/src/parser/test_memory_leaks.sh
@@ -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);