diff --git a/CHANGELOG.md b/CHANGELOG.md index 042f2ad84a..1f55ce0546 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - [#7285](https://github.com/influxdata/influxdb/issues/7285): Correctly use password-type field in Admin UI. Thanks @dandv! - [#2792](https://github.com/influxdata/influxdb/issues/2792): Exceeding max retention policy duration gives incorrect error message - [#7226](https://github.com/influxdata/influxdb/issues/7226): Fix database locked up when deleting shards +- [#7315](https://github.com/influxdata/influxdb/issues/7315): Prevent users from manually using system queries since incorrect use would result in a panic. ## v1.0.0 [2016-09-07] diff --git a/influxql/ast.go b/influxql/ast.go index c2c6432225..8992091176 100644 --- a/influxql/ast.go +++ b/influxql/ast.go @@ -409,7 +409,6 @@ func IsSystemName(name string) bool { case "_fieldKeys", "_measurements", "_series", - "_tagKey", "_tagKeys", "_tags": return true diff --git a/influxql/query_executor.go b/influxql/query_executor.go index bc9d3ebe94..f3205f0c07 100644 --- a/influxql/query_executor.go +++ b/influxql/query_executor.go @@ -199,6 +199,7 @@ func (e *QueryExecutor) executeQuery(query *Query, opt ExecutionOptions, closing } var i int +LOOP: for ; i < len(query.Statements); i++ { ctx.StatementID = i stmt := query.Statements[i] @@ -211,6 +212,36 @@ func (e *QueryExecutor) executeQuery(query *Query, opt ExecutionOptions, closing } } + // Do not let queries manually use the system measurements. If we find + // one, return an error. This prevents a person from using the + // measurement incorrectly and causing a panic. + if stmt, ok := stmt.(*SelectStatement); ok { + for _, s := range stmt.Sources { + switch s := s.(type) { + case *Measurement: + if IsSystemName(s.Name) { + command := "the appropriate meta command" + switch s.Name { + case "_fieldKeys": + command = "SHOW FIELD KEYS" + case "_measurements": + command = "SHOW MEASUREMENTS" + case "_series": + command = "SHOW SERIES" + case "_tagKeys": + command = "SHOW TAG KEYS" + case "_tags": + command = "SHOW TAG VALUES" + } + results <- &Result{ + Err: fmt.Errorf("unable to use system source '%s': use %s instead", s.Name, command), + } + break LOOP + } + } + } + } + // Rewrite statements, if necessary. // This can occur on meta read statements which convert to SELECT statements. newStmt, err := RewriteStatement(stmt) diff --git a/influxql/query_executor_test.go b/influxql/query_executor_test.go index 6deda3e699..3d11c8232b 100644 --- a/influxql/query_executor_test.go +++ b/influxql/query_executor_test.go @@ -283,6 +283,56 @@ func TestQueryExecutor_Panic(t *testing.T) { } } +func TestQueryExecutor_InvalidSource(t *testing.T) { + e := NewQueryExecutor() + e.StatementExecutor = &StatementExecutor{ + ExecuteStatementFn: func(stmt influxql.Statement, ctx influxql.ExecutionContext) error { + return errors.New("statement executed unexpectedly") + }, + } + + for i, tt := range []struct { + q string + err string + }{ + { + q: `SELECT fieldKey, fieldType FROM _fieldKeys`, + err: `unable to use system source '_fieldKeys': use SHOW FIELD KEYS instead`, + }, + { + q: `SELECT "name" FROM _measurements`, + err: `unable to use system source '_measurements': use SHOW MEASUREMENTS instead`, + }, + { + q: `SELECT "key" FROM _series`, + err: `unable to use system source '_series': use SHOW SERIES instead`, + }, + { + q: `SELECT tagKey FROM _tagKeys`, + err: `unable to use system source '_tagKeys': use SHOW TAG KEYS instead`, + }, + { + q: `SELECT "key", value FROM _tags`, + err: `unable to use system source '_tags': use SHOW TAG VALUES instead`, + }, + } { + q, err := influxql.ParseQuery(tt.q) + if err != nil { + t.Errorf("%d. unable to parse: %s", i, tt.q) + continue + } + + results := e.ExecuteQuery(q, influxql.ExecutionOptions{}, nil) + result := <-results + if len(result.Series) != 0 { + t.Errorf("%d. expected %d rows, got %d", 0, i, len(result.Series)) + } + if result.Err == nil || result.Err.Error() != tt.err { + t.Errorf("%d. unexpected error: %s", i, result.Err) + } + } +} + func discardOutput(results <-chan *influxql.Result) { for range results { // Read all results and discard.