Merge pull request #3505 from influxdb/cherry-pick-739fe73

Fix aggregate queries and time precision on where clauses.
pull/3508/head
dgnorton 2015-07-29 16:18:46 -04:00
commit 401f1b2843
5 changed files with 42 additions and 35 deletions

View File

@ -710,12 +710,19 @@ func TestServer_Query_Count(t *testing.T) {
test := NewTest("db0", "rp0")
test.write = `cpu,host=server01 value=1.0 ` + strconv.FormatInt(now.UnixNano(), 10)
hour_ago := now.Add(-time.Hour).UTC()
test.addQueries([]*Query{
&Query{
name: "selecting count(value) should succeed",
command: `SELECT count(value) FROM db0.rp0.cpu`,
exp: `{"results":[{"series":[{"name":"cpu","columns":["time","count"],"values":[["1970-01-01T00:00:00Z",1]]}]}]}`,
},
&Query{
name: "selecting count(value) with where time should return result",
command: fmt.Sprintf(`SELECT count(value) FROM db0.rp0.cpu WHERE time >= '%s'`, hour_ago.Format(time.RFC3339Nano)),
exp: fmt.Sprintf(`{"results":[{"series":[{"name":"cpu","columns":["time","count"],"values":[["%s",1]]}]}]}`, hour_ago.Format(time.RFC3339Nano)),
},
&Query{
name: "selecting count(*) should error",
command: `SELECT count(*) FROM db0.rp0.cpu`,

View File

@ -2225,7 +2225,7 @@ type TimeLiteral struct {
// String returns a string representation of the literal.
func (l *TimeLiteral) String() string {
return `'` + l.Val.UTC().Format(DateTimeFormat) + `'`
return `'` + l.Val.UTC().Format(time.RFC3339Nano) + `'`
}
// DurationLiteral represents a duration literal.
@ -2358,11 +2358,11 @@ func TimeRange(expr Expr) (min, max time.Time) {
}
// Update the min/max depending on the operator.
// The GT & LT update the value by +/- 1µs not make them "not equal".
// The GT & LT update the value by +/- 1ns not make them "not equal".
switch op {
case GT:
if min.IsZero() || value.After(min) {
min = value.Add(time.Microsecond)
min = value.Add(time.Nanosecond)
}
case GTE:
if min.IsZero() || value.After(min) {
@ -2370,7 +2370,7 @@ func TimeRange(expr Expr) (min, max time.Time) {
}
case LT:
if max.IsZero() || value.Before(max) {
max = value.Add(-time.Microsecond)
max = value.Add(-time.Nanosecond)
}
case LTE:
if max.IsZero() || value.Before(max) {

View File

@ -132,8 +132,8 @@ func TestSelectStatement_SetTimeRange(t *testing.T) {
if min != start {
t.Fatalf("start time wasn't set properly.\n exp: %s\n got: %s", start, min)
}
// the end range is actually one microsecond before the given one since end is exclusive
end = end.Add(-time.Microsecond)
// the end range is actually one nanosecond before the given one since end is exclusive
end = end.Add(-time.Nanosecond)
if max != end {
t.Fatalf("end time wasn't set properly.\n exp: %s\n got: %s", end, max)
}
@ -165,8 +165,8 @@ func TestSelectStatement_SetTimeRange(t *testing.T) {
if min != start {
t.Fatalf("start time wasn't set properly.\n exp: %s\n got: %s", start, min)
}
// the end range is actually one microsecond before the given one since end is exclusive
end = end.Add(-time.Microsecond)
// the end range is actually one nanosecond before the given one since end is exclusive
end = end.Add(-time.Nanosecond)
if max != end {
t.Fatalf("end time wasn't set properly.\n exp: %s\n got: %s", end, max)
}
@ -189,8 +189,8 @@ func TestSelectStatement_SetTimeRange(t *testing.T) {
if min != start {
t.Fatalf("start time wasn't set properly.\n exp: %s\n got: %s", start, min)
}
// the end range is actually one microsecond before the given one since end is exclusive
end = end.Add(-time.Microsecond)
// the end range is actually one nanosecond before the given one since end is exclusive
end = end.Add(-time.Nanosecond)
if max != end {
t.Fatalf("end time wasn't set properly.\n exp: %s\n got: %s", end, max)
}
@ -472,45 +472,45 @@ func TestTimeRange(t *testing.T) {
min, max string
}{
// LHS VarRef
{expr: `time > '2000-01-01 00:00:00'`, min: `2000-01-01 00:00:00.000001`, max: `0001-01-01 00:00:00`},
{expr: `time >= '2000-01-01 00:00:00'`, min: `2000-01-01 00:00:00`, max: `0001-01-01 00:00:00`},
{expr: `time < '2000-01-01 00:00:00'`, min: `0001-01-01 00:00:00`, max: `1999-12-31 23:59:59.999999`},
{expr: `time <= '2000-01-01 00:00:00'`, min: `0001-01-01 00:00:00`, max: `2000-01-01 00:00:00`},
{expr: `time > '2000-01-01 00:00:00'`, min: `2000-01-01T00:00:00.000000001Z`, max: `0001-01-01T00:00:00Z`},
{expr: `time >= '2000-01-01 00:00:00'`, min: `2000-01-01T00:00:00Z`, max: `0001-01-01T00:00:00Z`},
{expr: `time < '2000-01-01 00:00:00'`, min: `0001-01-01T00:00:00Z`, max: `1999-12-31T23:59:59.999999999Z`},
{expr: `time <= '2000-01-01 00:00:00'`, min: `0001-01-01T00:00:00Z`, max: `2000-01-01T00:00:00Z`},
// RHS VarRef
{expr: `'2000-01-01 00:00:00' > time`, min: `0001-01-01 00:00:00`, max: `1999-12-31 23:59:59.999999`},
{expr: `'2000-01-01 00:00:00' >= time`, min: `0001-01-01 00:00:00`, max: `2000-01-01 00:00:00`},
{expr: `'2000-01-01 00:00:00' < time`, min: `2000-01-01 00:00:00.000001`, max: `0001-01-01 00:00:00`},
{expr: `'2000-01-01 00:00:00' <= time`, min: `2000-01-01 00:00:00`, max: `0001-01-01 00:00:00`},
{expr: `'2000-01-01 00:00:00' > time`, min: `0001-01-01T00:00:00Z`, max: `1999-12-31T23:59:59.999999999Z`},
{expr: `'2000-01-01 00:00:00' >= time`, min: `0001-01-01T00:00:00Z`, max: `2000-01-01T00:00:00Z`},
{expr: `'2000-01-01 00:00:00' < time`, min: `2000-01-01T00:00:00.000000001Z`, max: `0001-01-01T00:00:00Z`},
{expr: `'2000-01-01 00:00:00' <= time`, min: `2000-01-01T00:00:00Z`, max: `0001-01-01T00:00:00Z`},
// Equality
{expr: `time = '2000-01-01 00:00:00'`, min: `2000-01-01 00:00:00`, max: `2000-01-01 00:00:00`},
{expr: `time = '2000-01-01 00:00:00'`, min: `2000-01-01T00:00:00Z`, max: `2000-01-01T00:00:00Z`},
// Multiple time expressions.
{expr: `time >= '2000-01-01 00:00:00' AND time < '2000-01-02 00:00:00'`, min: `2000-01-01 00:00:00`, max: `2000-01-01 23:59:59.999999`},
{expr: `time >= '2000-01-01 00:00:00' AND time < '2000-01-02 00:00:00'`, min: `2000-01-01T00:00:00Z`, max: `2000-01-01T23:59:59.999999999Z`},
// Min/max crossover
{expr: `time >= '2000-01-01 00:00:00' AND time <= '1999-01-01 00:00:00'`, min: `2000-01-01 00:00:00`, max: `1999-01-01 00:00:00`},
{expr: `time >= '2000-01-01 00:00:00' AND time <= '1999-01-01 00:00:00'`, min: `2000-01-01T00:00:00Z`, max: `1999-01-01T00:00:00Z`},
// Absolute time
{expr: `time = 1388534400s`, min: `2014-01-01 00:00:00`, max: `2014-01-01 00:00:00`},
{expr: `time = 1388534400s`, min: `2014-01-01T00:00:00Z`, max: `2014-01-01T00:00:00Z`},
// Non-comparative expressions.
{expr: `time`, min: `0001-01-01 00:00:00`, max: `0001-01-01 00:00:00`},
{expr: `time + 2`, min: `0001-01-01 00:00:00`, max: `0001-01-01 00:00:00`},
{expr: `time - '2000-01-01 00:00:00'`, min: `0001-01-01 00:00:00`, max: `0001-01-01 00:00:00`},
{expr: `time AND '2000-01-01 00:00:00'`, min: `0001-01-01 00:00:00`, max: `0001-01-01 00:00:00`},
{expr: `time`, min: `0001-01-01T00:00:00Z`, max: `0001-01-01T00:00:00Z`},
{expr: `time + 2`, min: `0001-01-01T00:00:00Z`, max: `0001-01-01T00:00:00Z`},
{expr: `time - '2000-01-01 00:00:00'`, min: `0001-01-01T00:00:00Z`, max: `0001-01-01T00:00:00Z`},
{expr: `time AND '2000-01-01 00:00:00'`, min: `0001-01-01T00:00:00Z`, max: `0001-01-01T00:00:00Z`},
} {
// Extract time range.
expr := MustParseExpr(tt.expr)
min, max := influxql.TimeRange(expr)
// Compare with expected min/max.
if min := min.Format(influxql.DateTimeFormat); tt.min != min {
if min := min.Format(time.RFC3339Nano); tt.min != min {
t.Errorf("%d. %s: unexpected min:\n\nexp=%s\n\ngot=%s\n\n", i, tt.expr, tt.min, min)
continue
}
if max := max.Format(influxql.DateTimeFormat); tt.max != max {
if max := max.Format(time.RFC3339Nano); tt.max != max {
t.Errorf("%d. %s: unexpected max:\n\nexp=%s\n\ngot=%s\n\n", i, tt.expr, tt.max, max)
continue
}
@ -694,9 +694,9 @@ func TestReduce(t *testing.T) {
{in: `true + false`, out: `true + false`},
// Time literals.
{in: `now() + 2h`, out: `'2000-01-01 02:00:00'`, data: map[string]interface{}{"now()": now}},
{in: `now() / 2h`, out: `'2000-01-01 00:00:00' / 2h`, data: map[string]interface{}{"now()": now}},
{in: `4µ + now()`, out: `'2000-01-01 00:00:00.000004'`, data: map[string]interface{}{"now()": now}},
{in: `now() + 2h`, out: `'2000-01-01T02:00:00Z'`, data: map[string]interface{}{"now()": now}},
{in: `now() / 2h`, out: `'2000-01-01T00:00:00Z' / 2h`, data: map[string]interface{}{"now()": now}},
{in: `4µ + now()`, out: `'2000-01-01T00:00:00.000004Z'`, data: map[string]interface{}{"now()": now}},
{in: `now() = now()`, out: `true`, data: map[string]interface{}{"now()": now}},
{in: `now() <> now()`, out: `false`, data: map[string]interface{}{"now()": now}},
{in: `now() < now() + 1h`, out: `true`, data: map[string]interface{}{"now()": now}},
@ -704,7 +704,7 @@ func TestReduce(t *testing.T) {
{in: `now() >= now() - 1h`, out: `true`, data: map[string]interface{}{"now()": now}},
{in: `now() > now() - 1h`, out: `true`, data: map[string]interface{}{"now()": now}},
{in: `now() - (now() - 60s)`, out: `1m`, data: map[string]interface{}{"now()": now}},
{in: `now() AND now()`, out: `'2000-01-01 00:00:00' AND '2000-01-01 00:00:00'`, data: map[string]interface{}{"now()": now}},
{in: `now() AND now()`, out: `'2000-01-01T00:00:00Z' AND '2000-01-01T00:00:00Z'`, data: map[string]interface{}{"now()": now}},
{in: `now()`, out: `now()`},
// Duration literals.

View File

@ -141,7 +141,7 @@ func (lm *LocalMapper) Open() error {
// Ensure that the start time for the results is on the start of the window.
lm.queryTMinWindow = lm.queryTMin
if lm.intervalSize > 0 {
if lm.intervalSize > 0 && lm.numIntervals > 1 {
lm.queryTMinWindow = lm.queryTMinWindow / lm.intervalSize * lm.intervalSize
}
}

View File

@ -372,13 +372,13 @@ func TestShardMapper_WriteAndSingleMapperAggregateQuery(t *testing.T) {
{
stmt: fmt.Sprintf(`SELECT sum(value) FROM cpu WHERE time > '%s'`, pt1time.Format(influxql.DateTimeFormat)),
expected: []string{
`{"name":"cpu","values":[{"value":[60]}]}`,
`{"name":"cpu","values":[{"time":10000000001,"value":[60]}]}`,
`null`},
},
{
stmt: fmt.Sprintf(`SELECT sum(value) FROM cpu WHERE time > '%s'`, pt2time.Format(influxql.DateTimeFormat)),
expected: []string{
`{"name":"cpu","values":[{"value":[null]}]}`,
`{"name":"cpu","values":[{"time":20000000001,"value":[null]}]}`,
`null`},
},
}