Merge pull request #290 from influxdb/fix-69-column-aliasing

Fix #69 column aliasing
pull/292/head
Paul Dix 2014-03-03 14:55:26 -05:00
commit 2409047bb3
8 changed files with 188 additions and 34 deletions

View File

@ -44,6 +44,14 @@ func init() {
registeredAggregators["last"] = NewLastAggregator
}
// used in testing to get a list of all aggregators
func GetRegisteredAggregators() (names []string) {
for n, _ := range registeredAggregators {
names = append(names, n)
}
return
}
type AbstractAggregator struct {
Aggregator
value *parser.Value
@ -103,6 +111,7 @@ type StandardDeviationAggregator struct {
AbstractAggregator
running map[string]map[interface{}]*StandardDeviationRunning
defaultValue *protocol.FieldValue
alias string
}
func (self *StandardDeviationAggregator) AggregatePoint(series string, group interface{}, p *protocol.Point) error {
@ -140,6 +149,10 @@ func (self *StandardDeviationAggregator) AggregatePoint(series string, group int
}
func (self *StandardDeviationAggregator) ColumnNames() []string {
if self.alias != "" {
return []string{self.alias}
}
return []string{"stddev"}
}
@ -196,6 +209,7 @@ func NewStandardDeviationAggregator(q *parser.SelectQuery, v *parser.Value, defa
},
running: make(map[string]map[interface{}]*StandardDeviationRunning),
defaultValue: value,
alias: v.Alias,
}, nil
}
@ -208,6 +222,7 @@ type DerivativeAggregator struct {
firstValues map[string]map[interface{}]*protocol.Point
lastValues map[string]map[interface{}]*protocol.Point
defaultValue *protocol.FieldValue
alias string
}
func (self *DerivativeAggregator) AggregatePoint(series string, group interface{}, p *protocol.Point) error {
@ -253,6 +268,9 @@ func (self *DerivativeAggregator) AggregatePoint(series string, group interface{
}
func (self *DerivativeAggregator) ColumnNames() []string {
if self.alias != "" {
return []string{self.alias}
}
return []string{"derivative"}
}
@ -299,6 +317,7 @@ func NewDerivativeAggregator(q *parser.SelectQuery, v *parser.Value, defaultValu
firstValues: make(map[string]map[interface{}]*protocol.Point),
lastValues: make(map[string]map[interface{}]*protocol.Point),
defaultValue: wrappedDefaultValue,
alias: v.Alias,
}, nil
}
@ -308,8 +327,9 @@ func NewDerivativeAggregator(q *parser.SelectQuery, v *parser.Value, defaultValu
type HistogramAggregator struct {
AbstractAggregator
bucketSize float64
histograms map[string]map[interface{}]map[int]int
bucketSize float64
histograms map[string]map[interface{}]map[int]int
columnNames []string
}
func (self *HistogramAggregator) AggregatePoint(series string, group interface{}, p *protocol.Point) error {
@ -344,7 +364,7 @@ func (self *HistogramAggregator) AggregatePoint(series string, group interface{}
}
func (self *HistogramAggregator) ColumnNames() []string {
return []string{"bucket_start", "count"}
return self.columnNames
}
func (self *HistogramAggregator) GetValues(series string, group interface{}) [][]*protocol.FieldValue {
@ -391,12 +411,19 @@ func NewHistogramAggregator(q *parser.SelectQuery, v *parser.Value, defaultValue
}
}
columnNames := []string{"bucket_start", "count"}
if v.Alias != "" {
columnNames[0] = fmt.Sprintf("%s_bucket_start", v.Alias)
columnNames[1] = fmt.Sprintf("%s_count", v.Alias)
}
return &HistogramAggregator{
AbstractAggregator: AbstractAggregator{
value: v.Elems[0],
},
bucketSize: bucketSize,
histograms: make(map[string]map[interface{}]map[int]int),
bucketSize: bucketSize,
histograms: make(map[string]map[interface{}]map[int]int),
columnNames: columnNames,
}, nil
}
@ -407,6 +434,7 @@ func NewHistogramAggregator(q *parser.SelectQuery, v *parser.Value, defaultValue
type CountAggregator struct {
defaultValue *protocol.FieldValue
counts map[string]map[interface{}]int32
alias string
}
func (self *CountAggregator) AggregatePoint(series string, group interface{}, p *protocol.Point) error {
@ -420,6 +448,9 @@ func (self *CountAggregator) AggregatePoint(series string, group interface{}, p
}
func (self *CountAggregator) ColumnNames() []string {
if self.alias != "" {
return []string{self.alias}
}
return []string{"count"}
}
@ -464,10 +495,10 @@ func NewCountAggregator(q *parser.SelectQuery, v *parser.Value, defaultValue *pa
if err != nil {
return nil, err
}
return NewCompositeAggregator(&CountAggregator{wrappedDefaultValue, make(map[string]map[interface{}]int32)}, inner)
return NewCompositeAggregator(&CountAggregator{wrappedDefaultValue, make(map[string]map[interface{}]int32), v.Alias}, inner)
}
return &CountAggregator{wrappedDefaultValue, make(map[string]map[interface{}]int32)}, nil
return &CountAggregator{wrappedDefaultValue, make(map[string]map[interface{}]int32), v.Alias}, nil
}
//
@ -537,6 +568,7 @@ type MeanAggregator struct {
means map[string]map[interface{}]float64
counts map[string]map[interface{}]int
defaultValue *protocol.FieldValue
alias string
}
func (self *MeanAggregator) AggregatePoint(series string, group interface{}, p *protocol.Point) error {
@ -574,6 +606,9 @@ func (self *MeanAggregator) AggregatePoint(series string, group interface{}, p *
}
func (self *MeanAggregator) ColumnNames() []string {
if self.alias != "" {
return []string{self.alias}
}
return []string{"mean"}
}
@ -608,6 +643,7 @@ func NewMeanAggregator(_ *parser.SelectQuery, value *parser.Value, defaultValue
means: make(map[string]map[interface{}]float64),
counts: make(map[string]map[interface{}]int),
defaultValue: wrappedDefaultValue,
alias: value.Alias,
}, nil
}
@ -621,15 +657,22 @@ func NewMedianAggregator(_ *parser.SelectQuery, value *parser.Value, defaultValu
return nil, err
}
return &PercentileAggregator{
functionName := "median"
if value.Alias != "" {
functionName = value.Alias
}
aggregator := &PercentileAggregator{
AbstractAggregator: AbstractAggregator{
value: value.Elems[0],
},
functionName: "median",
functionName: functionName,
percentile: 50.0,
float_values: make(map[string]map[interface{}][]float64),
defaultValue: wrappedDefaultValue,
}, nil
alias: value.Alias,
}
return aggregator, nil
}
//
@ -642,6 +685,7 @@ type PercentileAggregator struct {
percentile float64
float_values map[string]map[interface{}][]float64
defaultValue *protocol.FieldValue
alias string
}
func (self *PercentileAggregator) AggregatePoint(series string, group interface{}, p *protocol.Point) error {
@ -671,6 +715,9 @@ func (self *PercentileAggregator) AggregatePoint(series string, group interface{
}
func (self *PercentileAggregator) ColumnNames() []string {
if self.alias != "" {
return []string{self.alias}
}
return []string{self.functionName}
}
@ -708,11 +755,16 @@ func NewPercentileAggregator(_ *parser.SelectQuery, value *parser.Value, default
return nil, err
}
functionName := "percentile"
if value.Alias != "" {
functionName = value.Alias
}
return &PercentileAggregator{
AbstractAggregator: AbstractAggregator{
value: value.Elems[0],
},
functionName: "percentile",
functionName: functionName,
percentile: percentile,
float_values: make(map[string]map[interface{}][]float64),
defaultValue: wrappedDefaultValue,
@ -727,6 +779,7 @@ type ModeAggregator struct {
AbstractAggregator
counts map[string]map[interface{}]map[float64]int
defaultValue *protocol.FieldValue
alias string
}
func (self *ModeAggregator) AggregatePoint(series string, group interface{}, p *protocol.Point) error {
@ -764,6 +817,9 @@ func (self *ModeAggregator) AggregatePoint(series string, group interface{}, p *
}
func (self *ModeAggregator) ColumnNames() []string {
if self.alias != "" {
return []string{self.alias}
}
return []string{"mode"}
}
@ -815,6 +871,7 @@ func NewModeAggregator(_ *parser.SelectQuery, value *parser.Value, defaultValue
},
counts: make(map[string]map[interface{}]map[float64]int),
defaultValue: wrappedDefaultValue,
alias: value.Alias,
}, nil
}
@ -826,6 +883,7 @@ type DistinctAggregator struct {
AbstractAggregator
counts map[string]map[interface{}]map[interface{}]int
defaultValue *protocol.FieldValue
alias string
}
func (self *DistinctAggregator) AggregatePoint(series string, group interface{}, p *protocol.Point) error {
@ -867,6 +925,9 @@ func (self *DistinctAggregator) AggregatePoint(series string, group interface{},
}
func (self *DistinctAggregator) ColumnNames() []string {
if self.alias != "" {
return []string{self.alias}
}
return []string{"distinct"}
}
@ -907,6 +968,7 @@ func NewDistinctAggregator(_ *parser.SelectQuery, value *parser.Value, defaultVa
},
counts: make(map[string]map[interface{}]map[interface{}]int),
defaultValue: wrappedDefaultValue,
alias: value.Alias,
}, nil
}
@ -964,6 +1026,10 @@ func NewCumulativeArithmeticAggregator(name string, value *parser.Value, initial
return nil, err
}
if value.Alias != "" {
name = value.Alias
}
return &CumulativeArithmeticAggregator{
AbstractAggregator: AbstractAggregator{
value: value.Elems[0],
@ -1065,6 +1131,10 @@ func NewFirstOrLastAggregator(name string, v *parser.Value, isFirst bool, defaul
return nil, err
}
if v.Alias != "" {
name = v.Alias
}
return &FirstOrLastAggregator{
AbstractAggregator: AbstractAggregator{
value: v.Elems[0],

View File

@ -5,6 +5,7 @@ import (
"checkers"
. "common"
"encoding/json"
"engine"
"flag"
"fmt"
"io/ioutil"
@ -626,6 +627,39 @@ func (self *IntegrationSuite) TestCountWithGroupBy(c *C) {
c.Assert(data[0].Points[1][1], Equals, 20.0)
}
func (self *IntegrationSuite) TestCountWithAlias(c *C) {
for i := 0; i < 5; i++ {
err := self.server.WriteData(fmt.Sprintf(`
[
{
"name": "test_aliasing",
"columns": ["cpu", "host"],
"points": [[%d, "hosta"], [%d, "hostb"]]
}
]
`, 60+i*10, 70+i*10))
c.Assert(err, IsNil)
}
for _, name := range engine.GetRegisteredAggregators() {
query := fmt.Sprintf("select %s(cpu) as some_alias from test_aliasing", name)
if name == "percentile" {
query = "select percentile(cpu, 90) as some_alias from test_aliasing"
}
fmt.Printf("query: %s\n", query)
bs, err := self.server.RunQuery(query, "m")
c.Assert(err, IsNil)
data := []*SerializedSeries{}
err = json.Unmarshal(bs, &data)
c.Assert(data, HasLen, 1)
c.Assert(data[0].Name, Equals, "test_aliasing")
if name == "histogram" {
c.Assert(data[0].Columns, DeepEquals, []string{"time", "some_alias_bucket_start", "some_alias_count"})
continue
}
c.Assert(data[0].Columns, DeepEquals, []string{"time", "some_alias"})
}
}
// test for issue #30
func (self *IntegrationSuite) TestHttpPostWithTime(c *C) {
now := time.Now().Add(-10 * 24 * time.Hour)

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);