Skip to content

Commit

Permalink
wip: fix #36. support table aliases
Browse files Browse the repository at this point in the history
  • Loading branch information
jvshahid committed Nov 18, 2013
1 parent fc4aca4 commit dbc6208
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 36 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@
## Features

- [Issue #51](https://github.com/influxdb/influxdb/issues/51). Implement first and last aggregates
- [Issue #36](https://github.com/influxdb/influxdb/issues/36). Support table aliases

## Bugfixes

Expand Down
4 changes: 2 additions & 2 deletions src/engine/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@ func (self *QueryEngine) distributeQuery(user common.User, database string, quer
// see if this is a merge query
fromClause := query.GetFromClause()
if fromClause.Type == parser.FromClauseMerge {
yield = getMergeYield(fromClause.Names[0].Name, fromClause.Names[1].Name, yield)
yield = getMergeYield(fromClause.Names[0].Name.Name, fromClause.Names[1].Name.Name, yield)
}

if fromClause.Type == parser.FromClauseInnerJoin {
yield = getJoinYield(fromClause.Names[0].Name, fromClause.Names[1].Name, yield)
yield = getJoinYield(fromClause.Names[0].Name.Name, fromClause.Names[1].Name.Name, yield)
}

return self.coordinator.DistributeQuery(user, database, query, yield)
Expand Down
18 changes: 17 additions & 1 deletion src/parser/frees.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,26 @@ free_array(array *array)
free(array->elems);
free(array);
}
void free_table_name(table_name *name)
{
free_value(name->name);
free(name->alias);
free(name);
}
void
free_table_name_array(table_name_array *array)
{
int i;
for (i = 0; i < array->size; i++)
free_table_name(array->elems[i]);
free(array->elems);
free(array);
}

void
free_from_clause(from_clause *f)
{
free_value_array(f->names);
free_table_name_array(f->names);
free(f);
}

Expand Down
38 changes: 36 additions & 2 deletions src/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,14 @@ const (
FromClauseInnerJoin FromClauseType = C.FROM_INNER_JOIN
)

type TableName struct {
Name *Value
Alias string
}

type FromClause struct {
Type FromClauseType
Names []*Value
Names []*TableName
}

type Expression struct {
Expand Down Expand Up @@ -213,8 +218,37 @@ func GetValue(value *C.value) (*Value, error) {
return v, err
}

func GetTableName(name *C.table_name) (*TableName, error) {
value, err := GetValue(name.name)
if err != nil {
return nil, err
}

table := &TableName{Name: value}
if name.alias != nil {
table.Alias = C.GoString(name.alias)
}

return table, nil
}

func GetTableNameArray(array *C.table_name_array) ([]*TableName, error) {
var names []*C.table_name
setupSlice((*reflect.SliceHeader)((unsafe.Pointer(&names))), unsafe.Pointer(array.elems), array.size)

tableNamesSlice := make([]*TableName, 0, array.size)
for _, name := range names {
tableName, err := GetTableName(name)
if err != nil {
return nil, err
}
tableNamesSlice = append(tableNamesSlice, tableName)
}
return tableNamesSlice, nil
}

func GetFromClause(fromClause *C.from_clause) (*FromClause, error) {
arr, err := GetValueArray(fromClause.names)
arr, err := GetTableNameArray(fromClause.names)
if err != nil {
return nil, err
}
Expand Down
22 changes: 11 additions & 11 deletions src/parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func (self *QueryParserSuite) TestSimpleFromClause(c *C) {
fromClause := q.GetFromClause()
c.Assert(fromClause.Type, Equals, FromClauseArray)
c.Assert(fromClause.Names, HasLen, 1)
c.Assert(fromClause.Names[0].Name, Equals, "t")
c.Assert(fromClause.Names[0].Name.Name, Equals, "t")
}

func (self *QueryParserSuite) TestParseFromWithMergedTable(c *C) {
Expand All @@ -69,8 +69,8 @@ func (self *QueryParserSuite) TestParseFromWithMergedTable(c *C) {
fromClause := q.GetFromClause()
c.Assert(fromClause.Type, Equals, FromClauseMerge)
c.Assert(fromClause.Names, HasLen, 2)
c.Assert(fromClause.Names[0].Name, Equals, "newsletter.signups")
c.Assert(fromClause.Names[1].Name, Equals, "user.signups")
c.Assert(fromClause.Names[0].Name.Name, Equals, "newsletter.signups")
c.Assert(fromClause.Names[1].Name.Name, Equals, "user.signups")
}

func (self *QueryParserSuite) TestMultipleAggregateFunctions(c *C) {
Expand All @@ -88,8 +88,8 @@ func (self *QueryParserSuite) TestParseFromWithJoinedTable(c *C) {
fromClause := q.GetFromClause()
c.Assert(fromClause.Type, Equals, FromClauseInnerJoin)
c.Assert(fromClause.Names, HasLen, 2)
c.Assert(fromClause.Names[0].Name, Equals, "newsletter.signups")
c.Assert(fromClause.Names[1].Name, Equals, "user.signups")
c.Assert(fromClause.Names[0].Name.Name, Equals, "newsletter.signups")
c.Assert(fromClause.Names[1].Name.Name, Equals, "user.signups")
}

func (self *QueryParserSuite) TestParseSelectWithInsensitiveRegexTables(c *C) {
Expand All @@ -99,9 +99,9 @@ func (self *QueryParserSuite) TestParseSelectWithInsensitiveRegexTables(c *C) {
fromClause := q.GetFromClause()
c.Assert(fromClause.Type, Equals, FromClauseArray)
c.Assert(fromClause.Names, HasLen, 1)
c.Assert(fromClause.Names[0].Name, Equals, "users.*")
c.Assert(fromClause.Names[0].Type, Equals, ValueRegex)
c.Assert(fromClause.Names[0].IsCaseInsensitive, Equals, true)
c.Assert(fromClause.Names[0].Name.Name, Equals, "users.*")
c.Assert(fromClause.Names[0].Name.Type, Equals, ValueRegex)
c.Assert(fromClause.Names[0].Name.IsCaseInsensitive, Equals, true)
}

func (self *QueryParserSuite) TestParseSelectWithRegexTables(c *C) {
Expand All @@ -111,9 +111,9 @@ func (self *QueryParserSuite) TestParseSelectWithRegexTables(c *C) {
fromClause := q.GetFromClause()
c.Assert(fromClause.Type, Equals, FromClauseArray)
c.Assert(fromClause.Names, HasLen, 1)
c.Assert(fromClause.Names[0].Name, Equals, "users.*")
c.Assert(fromClause.Names[0].Type, Equals, ValueRegex)
c.Assert(fromClause.Names[0].IsCaseInsensitive, Equals, false)
c.Assert(fromClause.Names[0].Name.Name, Equals, "users.*")
c.Assert(fromClause.Names[0].Name.Type, Equals, ValueRegex)
c.Assert(fromClause.Names[0].Name.IsCaseInsensitive, Equals, false)
}

func (self *QueryParserSuite) TestMergeFromClause(c *C) {
Expand Down
1 change: 1 addition & 0 deletions src/parser/query.lex
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ static int yycolumn = 1;
"join" { return JOIN; }
"from" { return FROM; }
"where" { return WHERE; }
"as" { return AS; }
"select" { return SELECT; }
"limit" { return LIMIT; }
"order" { return ORDER; }
Expand Down
64 changes: 49 additions & 15 deletions src/parser/query.yacc
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,9 @@ value *create_value(char *name, int type, char is_case_insensitive, value_array
%lex-param {void *scanner}

// define types of tokens (terminals)
%token SELECT FROM WHERE EQUAL GROUP BY LIMIT ORDER ASC DESC MERGE INNER JOIN
%token <string> STRING_VALUE INT_VALUE FLOAT_VALUE TABLE_NAME SIMPLE_NAME REGEX_OP NEGATION_REGEX_OP REGEX_STRING INSENSITIVE_REGEX_STRING DURATION
%token SELECT FROM WHERE EQUAL GROUP BY LIMIT ORDER ASC DESC MERGE INNER JOIN AS
%token <string> STRING_VALUE INT_VALUE FLOAT_VALUE TABLE_NAME SIMPLE_NAME REGEX_OP
%token <string> NEGATION_REGEX_OP REGEX_STRING INSENSITIVE_REGEX_STRING DURATION

// define the precedence of these operators
%left OR
Expand All @@ -74,7 +75,7 @@ value *create_value(char *name, int type, char is_case_insensitive, value_array
%type <from_clause> FROM_CLAUSE
%type <condition> WHERE_CLAUSE
%type <value_array> COLUMN_NAMES
%type <string> BOOL_OPERATION
%type <string> BOOL_OPERATION ALIAS_CLAUSE
%type <condition> CONDITION
%type <bool_expression> BOOL_EXPRESSION
%type <value_array> VALUES
Expand Down Expand Up @@ -213,36 +214,69 @@ GROUP_BY_CLAUSE:
COLUMN_NAMES:
VALUES

ALIAS_CLAUSE:
AS SIMPLE_TABLE_VALUE
{
$$ = $2->name;
free($2);
}
|
{
$$ = NULL;
}

FROM_CLAUSE:
FROM TABLE_VALUE
{
$$ = malloc(sizeof(from_clause));
$$->names = malloc(sizeof(value_array));
$$->names->elems = malloc(sizeof(value*));
$$->names = malloc(sizeof(table_name_array));
$$->names->elems = malloc(sizeof(table_name*));
$$->names->size = 1;
$$->names->elems[0] = $2;
$$->names->elems[0] = malloc(sizeof(table_name));
$$->names->elems[0]->name = $2;
$$->names->elems[0]->alias = NULL;
$$->from_clause_type = FROM_ARRAY;
}
|
FROM SIMPLE_TABLE_VALUE MERGE SIMPLE_TABLE_VALUE
FROM SIMPLE_TABLE_VALUE ALIAS_CLAUSE
{
$$ = malloc(sizeof(from_clause));
$$->names = malloc(sizeof(value_array));
$$->names->elems = malloc(2 * sizeof(value*));
$$->names = malloc(sizeof(table_name_array));
$$->names->elems = malloc(sizeof(table_name*));
$$->names->size = 1;
$$->names->elems[0] = malloc(sizeof(table_name));
$$->names->elems[0]->name = $2;
$$->names->elems[0]->alias = $3;
$$->from_clause_type = FROM_ARRAY;
}
|
FROM SIMPLE_TABLE_VALUE ALIAS_CLAUSE MERGE SIMPLE_TABLE_VALUE ALIAS_CLAUSE
{
$$ = malloc(sizeof(from_clause));
$$->names = malloc(sizeof(table_name_array));
$$->names->elems = malloc(2 * sizeof(table_name*));
$$->names->size = 2;
$$->names->elems[0] = $2;
$$->names->elems[1] = $4;
$$->names->elems[0] = malloc(sizeof(table_name));
$$->names->elems[0]->name = $2;
$$->names->elems[0]->alias = $3;
$$->names->elems[1] = malloc(sizeof(table_name));
$$->names->elems[1]->name = $5;
$$->names->elems[1]->alias = $6;
$$->from_clause_type = FROM_MERGE;
}
|
FROM SIMPLE_TABLE_VALUE INNER JOIN SIMPLE_TABLE_VALUE
FROM SIMPLE_TABLE_VALUE ALIAS_CLAUSE INNER JOIN SIMPLE_TABLE_VALUE ALIAS_CLAUSE
{
$$ = malloc(sizeof(from_clause));
$$->names = malloc(sizeof(value_array));
$$->names = malloc(sizeof(table_name_array));
$$->names->elems = malloc(2 * sizeof(value*));
$$->names->size = 2;
$$->names->elems[0] = $2;
$$->names->elems[1] = $5;
$$->names->elems[0] = malloc(sizeof(table_name));
$$->names->elems[0]->name = $2;
$$->names->elems[0]->alias = $3;
$$->names->elems[1] = malloc(sizeof(table_name));
$$->names->elems[1]->name = $6;
$$->names->elems[1]->alias = $7;
$$->from_clause_type = FROM_INNER_JOIN;
}

Expand Down
3 changes: 2 additions & 1 deletion src/parser/query_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ func (self *Query) GetReferencedColumns() map[*Value][]string {
notPrefixedColumns = uniq(notPrefixedColumns)

returnedMapping := make(map[*Value][]string)
for _, value := range self.GetFromClause().Names {
for _, tableName := range self.GetFromClause().Names {
value := tableName.Name
if _, ok := value.GetCompiledRegex(); ok {
// this is a regex table, cannot be referenced, only unreferenced
// columns will be attached to regex table names
Expand Down
17 changes: 13 additions & 4 deletions src/parser/query_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,25 @@ typedef struct {
char *err;
} error;

typedef struct {
value *name;
char *alias;
} table_name;

typedef struct {
size_t size;
table_name **elems;
} table_name_array;

typedef struct {
enum {
FROM_ARRAY,
FROM_MERGE,
FROM_INNER_JOIN
} from_clause_type;
// in case of merge or join, it's guaranteed
// that the names array will have two table
// names only and they aren't regex.
value_array *names;
// in case of merge or join, it's guaranteed that the names array
// will have two table names only and they aren't regex.
table_name_array *names;
} from_clause;

typedef struct {
Expand Down

0 comments on commit dbc6208

Please sign in to comment.