diff --git a/CHANGELOG.md b/CHANGELOG.md index b8f64e6a5c3..077f857a6e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - [#2596](https://github.com/influxdb/influxdb/pull/2596): RC30: `panic: runtime error: index out of range` when insert data points. - [#2592](https://github.com/influxdb/influxdb/pull/2592): Should return an error if user attempts to group by a field. - [#2499](https://github.com/influxdb/influxdb/pull/2499): Issuing a select query with tag as a values causes panic. +- [#2612](https://github.com/influxdb/influxdb/pull/2612): Query planner should validate distinct is passed a field. ## PRs - [#2569](https://github.com/influxdb/influxdb/pull/2569): Add derivative functions diff --git a/cmd/influxd/server_integration_test.go b/cmd/influxd/server_integration_test.go index 4784efce3bf..1be64732aa2 100644 --- a/cmd/influxd/server_integration_test.go +++ b/cmd/influxd/server_integration_test.go @@ -705,29 +705,59 @@ func runTestsData(t *testing.T, testName string, nodes Cluster, database, retent }, { reset: true, - name: "distincts", + name: "distinct as call", write: `{"database" : "%DB%", "retentionPolicy" : "%RP%", "points": [ - {"name": "cpu", "time": "2000-01-01T00:00:00Z", "fields": {"value": 30}}, - {"name": "cpu", "time": "2000-01-01T00:00:10Z", "fields": {"value": 20}}, - {"name": "cpu", "time": "2000-01-01T00:00:20Z", "fields": {"value": 30}}, - {"name": "cpu", "time": "2000-01-01T00:00:30Z", "fields": {"value": 100}} + {"name": "cpu", "time": "2000-01-01T00:00:00Z", "tags": {"host": "server01"}, "fields": {"value": 30}}, + {"name": "cpu", "time": "2000-01-01T00:00:10Z", "tags": {"host": "server02"}, "fields": {"value": 20}}, + {"name": "cpu", "time": "2000-01-01T00:00:20Z", "tags": {"host": "server03"}, "fields": {"value": 30}}, + {"name": "cpu", "time": "2000-01-01T00:00:30Z", "tags": {"host": "server03"}, "fields": {"value": 100}} ]}`, query: `SELECT distinct(value) FROM cpu`, queryDb: "%DB%", expected: `{"results":[{"series":[{"name":"cpu","columns":["time","distinct"],"values":[["1970-01-01T00:00:00Z",[20,30,100]]]}]}]}`, }, { - name: "distincts alt syntax", + name: "distinct alt syntax", query: `SELECT distinct value FROM cpu`, queryDb: "%DB%", expected: `{"results":[{"series":[{"name":"cpu","columns":["time","distinct"],"values":[["1970-01-01T00:00:00Z",[20,30,100]]]}]}]}`, }, + { + name: "distinct select tag", + query: `SELECT distinct(host) FROM cpu`, + queryDb: "%DB%", + expected: `{"results":[{"error":"host isn't a field on measurement cpu; to query the unique values for a tag use SHOW TAG VALUES FROM cpu WITH KEY = \"host\""}]}`, + }, + { + name: "distinct alt select tag", + query: `SELECT distinct host FROM cpu`, + queryDb: "%DB%", + expected: `{"results":[{"error":"host isn't a field on measurement cpu; to query the unique values for a tag use SHOW TAG VALUES FROM cpu WITH KEY = \"host\""}]}`, + }, { name: "count distinct", query: `SELECT count(distinct value) FROM cpu`, queryDb: "%DB%", expected: `{"results":[{"series":[{"name":"cpu","columns":["time","count"],"values":[["1970-01-01T00:00:00Z",3]]}]}]}`, }, + { + name: "count distinct as call", + query: `SELECT count(distinct(value)) FROM cpu`, + queryDb: "%DB%", + expected: `{"results":[{"series":[{"name":"cpu","columns":["time","count"],"values":[["1970-01-01T00:00:00Z",3]]}]}]}`, + }, + { + name: "count distinct select tag", + query: `SELECT count(distinct host) FROM cpu`, + queryDb: "%DB%", + expected: `{"results":[{"error":"host isn't a field on measurement cpu"}]}`, + }, + { + name: "count distinct as call select tag", + query: `SELECT count(distinct(host)) FROM cpu`, + queryDb: "%DB%", + expected: `{"results":[{"error":"host isn't a field on measurement cpu"}]}`, + }, { reset: true, name: "aggregations", diff --git a/tx.go b/tx.go index 16c679f7f4b..4ce365daeac 100644 --- a/tx.go +++ b/tx.go @@ -374,6 +374,8 @@ func (l *LocalMapper) Begin(c *influxql.Call, startingTime int64, chunkSize int) l.chunkSize = chunkSize l.tmin = startingTime + var isDistinct bool + // determine if this is a raw data query with a single field, multiple fields, or an aggregate var fieldName string if c == nil { // its a raw data query @@ -404,12 +406,17 @@ func (l *LocalMapper) Begin(c *influxql.Call, startingTime int64, chunkSize int) default: return fmt.Errorf("aggregate call didn't contain a field %s", c.String()) } + + isDistinct = c.Name == "distinct" } // set up the field info if a specific field was set for this mapper if fieldName != "" { f := l.decoder.FieldByName(fieldName) if f == nil { + if isDistinct { + return fmt.Errorf("%s isn't a field on measurement %s; to query the unique values for a tag use SHOW TAG VALUES FROM %s WITH KEY = %q", fieldName, l.job.MeasurementName, l.job.MeasurementName, fieldName) + } return fmt.Errorf("%s isn't a field on measurement %s", fieldName, l.job.MeasurementName) } l.fieldID = f.ID