func TestRewriteStatement(t *testing.T) { tests := []struct { stmt string s string }{ { stmt: `SHOW FIELD KEYS`, s: `SELECT fieldKey, fieldType FROM _fieldKeys`, }, { stmt: `SHOW FIELD KEYS FROM cpu`, s: `SELECT fieldKey, fieldType FROM _fieldKeys WHERE _name = 'cpu'`, }, { stmt: `SHOW FIELD KEYS FROM /c.*/`, s: `SELECT fieldKey, fieldType FROM _fieldKeys WHERE _name =~ /c.*/`, }, { stmt: `SHOW FIELD KEYS FROM mydb.myrp2.cpu`, s: `SELECT fieldKey, fieldType FROM mydb.myrp2._fieldKeys WHERE _name = 'cpu'`, }, { stmt: `SHOW FIELD KEYS FROM mydb.myrp2./c.*/`, s: `SELECT fieldKey, fieldType FROM mydb.myrp2._fieldKeys WHERE _name =~ /c.*/`, }, { stmt: `SHOW SERIES`, s: `SELECT "key" FROM _series`, }, { stmt: `SHOW SERIES FROM cpu`, s: `SELECT "key" FROM _series WHERE _name = 'cpu'`, }, { stmt: `SHOW SERIES FROM mydb.myrp1.cpu`, s: `SELECT "key" FROM mydb.myrp1._series WHERE _name = 'cpu'`, }, { stmt: `SHOW SERIES FROM mydb.myrp1./c.*/`, s: `SELECT "key" FROM mydb.myrp1._series WHERE _name =~ /c.*/`, }, { stmt: `SHOW TAG KEYS`, s: `SELECT tagKey FROM _tagKeys`, }, { stmt: `SHOW TAG KEYS FROM cpu`, s: `SELECT tagKey FROM _tagKeys WHERE _name = 'cpu'`, }, { stmt: `SHOW TAG KEYS FROM /c.*/`, s: `SELECT tagKey FROM _tagKeys WHERE _name =~ /c.*/`, }, { stmt: `SHOW TAG KEYS FROM cpu WHERE region = 'uswest'`, s: `SELECT tagKey FROM _tagKeys WHERE (_name = 'cpu') AND (region = 'uswest')`, }, { stmt: `SHOW TAG KEYS FROM mydb.myrp1.cpu`, s: `SELECT tagKey FROM mydb.myrp1._tagKeys WHERE _name = 'cpu'`, }, { stmt: `SHOW TAG KEYS FROM mydb.myrp1./c.*/`, s: `SELECT tagKey FROM mydb.myrp1._tagKeys WHERE _name =~ /c.*/`, }, { stmt: `SHOW TAG KEYS FROM mydb.myrp1.cpu WHERE region = 'uswest'`, s: `SELECT tagKey FROM mydb.myrp1._tagKeys WHERE (_name = 'cpu') AND (region = 'uswest')`, }, { stmt: `SELECT value FROM cpu`, s: `SELECT value FROM cpu`, }, } for _, test := range tests { stmt, err := influxql.ParseStatement(test.stmt) if err != nil { t.Errorf("error parsing statement: %s", err) } else { stmt, err = influxql.RewriteStatement(stmt) if err != nil { t.Errorf("error rewriting statement: %s", err) } else if s := stmt.String(); s != test.s { t.Errorf("error rendering string. expected %s, actual: %s", test.s, s) } } } }
func TestRewriteStatement(t *testing.T) { tests := []struct { stmt string s string }{ { stmt: `SHOW FIELD KEYS`, s: `SELECT fieldKey FROM _fieldKeys`, }, { stmt: `SHOW FIELD KEYS FROM cpu`, s: `SELECT fieldKey FROM _fieldKeys WHERE _name = 'cpu'`, }, { stmt: `SHOW FIELD KEYS FROM /c.*/`, s: `SELECT fieldKey FROM _fieldKeys WHERE _name =~ /c.*/`, }, { stmt: `SHOW FIELD KEYS FROM mydb.myrp2.cpu`, s: `SELECT fieldKey FROM mydb.myrp2._fieldKeys WHERE _name = 'cpu'`, }, { stmt: `SHOW FIELD KEYS FROM mydb.myrp2./c.*/`, s: `SELECT fieldKey FROM mydb.myrp2._fieldKeys WHERE _name =~ /c.*/`, }, { stmt: `SHOW MEASUREMENTS`, s: `SELECT _name AS "name" FROM _measurements`, }, { stmt: `SHOW MEASUREMENTS WITH MEASUREMENT = cpu`, s: `SELECT _name AS "name" FROM _measurements WHERE _name = 'cpu'`, }, { stmt: `SHOW MEASUREMENTS WITH MEASUREMENT =~ /c.*/`, s: `SELECT _name AS "name" FROM _measurements WHERE _name =~ /c.*/`, }, { stmt: `SHOW MEASUREMENTS WHERE region = 'uswest'`, s: `SELECT _name AS "name" FROM _measurements WHERE region = 'uswest'`, }, { stmt: `SHOW MEASUREMENTS WITH MEASUREMENT = cpu WHERE region = 'uswest'`, s: `SELECT _name AS "name" FROM _measurements WHERE (_name = 'cpu') AND (region = 'uswest')`, }, { stmt: `SHOW SERIES`, s: `SELECT "key" FROM _series`, }, { stmt: `SHOW SERIES FROM cpu`, s: `SELECT "key" FROM _series WHERE _name = 'cpu'`, }, { stmt: `SHOW SERIES FROM mydb.myrp1.cpu`, s: `SELECT "key" FROM mydb.myrp1._series WHERE _name = 'cpu'`, }, { stmt: `SHOW SERIES FROM mydb.myrp1./c.*/`, s: `SELECT "key" FROM mydb.myrp1._series WHERE _name =~ /c.*/`, }, { stmt: `SHOW TAG KEYS`, s: `SELECT tagKey FROM _tagKeys`, }, { stmt: `SHOW TAG KEYS FROM cpu`, s: `SELECT tagKey FROM _tagKeys WHERE _name = 'cpu'`, }, { stmt: `SHOW TAG KEYS FROM /c.*/`, s: `SELECT tagKey FROM _tagKeys WHERE _name =~ /c.*/`, }, { stmt: `SHOW TAG KEYS FROM cpu WHERE region = 'uswest'`, s: `SELECT tagKey FROM _tagKeys WHERE (_name = 'cpu') AND (region = 'uswest')`, }, { stmt: `SHOW TAG KEYS FROM mydb.myrp1.cpu`, s: `SELECT tagKey FROM mydb.myrp1._tagKeys WHERE _name = 'cpu'`, }, { stmt: `SHOW TAG KEYS FROM mydb.myrp1./c.*/`, s: `SELECT tagKey FROM mydb.myrp1._tagKeys WHERE _name =~ /c.*/`, }, { stmt: `SHOW TAG KEYS FROM mydb.myrp1.cpu WHERE region = 'uswest'`, s: `SELECT tagKey FROM mydb.myrp1._tagKeys WHERE (_name = 'cpu') AND (region = 'uswest')`, }, { stmt: `SHOW TAG VALUES WITH KEY = region`, s: `SELECT _tagKey AS "key", value FROM _tags WHERE _tagKey = 'region'`, }, { stmt: `SHOW TAG VALUES FROM cpu WITH KEY = region`, s: `SELECT _tagKey AS "key", value FROM _tags WHERE (_name = 'cpu') AND (_tagKey = 'region')`, }, { stmt: `SHOW TAG VALUES FROM cpu WITH KEY IN (region, host)`, s: `SELECT _tagKey AS "key", value FROM _tags WHERE (_name = 'cpu') AND (_tagKey = 'region' OR _tagKey = 'host')`, }, { stmt: `SHOW TAG VALUES FROM mydb.myrp1.cpu WITH KEY IN (region, host)`, s: `SELECT _tagKey AS "key", value FROM mydb.myrp1._tags WHERE (_name = 'cpu') AND (_tagKey = 'region' OR _tagKey = 'host')`, }, { stmt: `SELECT value FROM cpu`, s: `SELECT value FROM cpu`, }, } for _, test := range tests { stmt, err := influxql.ParseStatement(test.stmt) if err != nil { t.Errorf("error parsing statement: %s", err) } else { stmt, err = influxql.RewriteStatement(stmt) if err != nil { t.Errorf("error rewriting statement: %s", err) } else if s := stmt.String(); s != test.s { t.Errorf("error rendering string. expected %s, actual: %s", test.s, s) } } } }
func (e *QueryExecutor) executeQuery(query *influxql.Query, database string, chunkSize int, closing <-chan struct{}, results chan *influxql.Result) { defer close(results) e.statMap.Add(statQueriesActive, 1) defer func(start time.Time) { e.statMap.Add(statQueriesActive, -1) e.statMap.Add(statQueryExecutionDuration, time.Since(start).Nanoseconds()) }(time.Now()) qerr := &influxql.QueryError{} var qid uint64 if e.QueryManager != nil { var err error qid, closing, err = e.QueryManager.AttachQuery(&influxql.QueryParams{ Query: query, Database: database, Timeout: e.QueryTimeout, InterruptCh: closing, Error: qerr, }) if err != nil { results <- &influxql.Result{Err: err} return } defer e.QueryManager.KillQuery(qid) } logger := e.logger() var i int for ; i < len(query.Statements); i++ { stmt := query.Statements[i] // If a default database wasn't passed in by the caller, check the statement. defaultDB := database if defaultDB == "" { if s, ok := stmt.(influxql.HasDefaultDatabase); ok { defaultDB = s.DefaultDatabase() } } // Rewrite statements, if necessary. // This can occur on meta read statements which convert to SELECT statements. newStmt, err := influxql.RewriteStatement(stmt) if err != nil { results <- &influxql.Result{Err: err} break } stmt = newStmt // Normalize each statement. if err := e.normalizeStatement(stmt, defaultDB); err != nil { results <- &influxql.Result{Err: err} break } // Log each normalized statement. logger.Println(stmt.String()) // Select statements are handled separately so that they can be streamed. if stmt, ok := stmt.(*influxql.SelectStatement); ok { if err := e.executeSelectStatement(stmt, chunkSize, i, qid, results, closing); err != nil { if err == influxql.ErrQueryInterrupted { err = qerr.Error() } results <- &influxql.Result{StatementID: i, Err: err} break } continue } var rows models.Rows switch stmt := stmt.(type) { case *influxql.AlterRetentionPolicyStatement: err = e.executeAlterRetentionPolicyStatement(stmt) case *influxql.CreateContinuousQueryStatement: err = e.executeCreateContinuousQueryStatement(stmt) case *influxql.CreateDatabaseStatement: err = e.executeCreateDatabaseStatement(stmt) case *influxql.CreateRetentionPolicyStatement: err = e.executeCreateRetentionPolicyStatement(stmt) case *influxql.CreateSubscriptionStatement: err = e.executeCreateSubscriptionStatement(stmt) case *influxql.CreateUserStatement: err = e.executeCreateUserStatement(stmt) case *influxql.DropContinuousQueryStatement: err = e.executeDropContinuousQueryStatement(stmt) case *influxql.DropDatabaseStatement: err = e.executeDropDatabaseStatement(stmt) case *influxql.DropMeasurementStatement: err = e.executeDropMeasurementStatement(stmt, database) case *influxql.DropSeriesStatement: err = e.executeDropSeriesStatement(stmt, database) case *influxql.DropRetentionPolicyStatement: err = e.executeDropRetentionPolicyStatement(stmt) case *influxql.DropServerStatement: err = influxql.ErrInvalidQuery case *influxql.DropShardStatement: err = e.executeDropShardStatement(stmt) case *influxql.DropSubscriptionStatement: err = e.executeDropSubscriptionStatement(stmt) case *influxql.DropUserStatement: err = e.executeDropUserStatement(stmt) case *influxql.GrantStatement: err = e.executeGrantStatement(stmt) case *influxql.GrantAdminStatement: err = e.executeGrantAdminStatement(stmt) case *influxql.KillQueryStatement: err = e.executeKillQueryStatement(stmt) case *influxql.RevokeStatement: err = e.executeRevokeStatement(stmt) case *influxql.RevokeAdminStatement: err = e.executeRevokeAdminStatement(stmt) case *influxql.ShowContinuousQueriesStatement: rows, err = e.executeShowContinuousQueriesStatement(stmt) case *influxql.ShowDatabasesStatement: rows, err = e.executeShowDatabasesStatement(stmt) case *influxql.ShowDiagnosticsStatement: rows, err = e.executeShowDiagnosticsStatement(stmt) case *influxql.ShowGrantsForUserStatement: rows, err = e.executeShowGrantsForUserStatement(stmt) case *influxql.ShowQueriesStatement: rows, err = e.executeShowQueriesStatement(stmt) case *influxql.ShowRetentionPoliciesStatement: rows, err = e.executeShowRetentionPoliciesStatement(stmt) case *influxql.ShowServersStatement: // TODO: corylanou add this back for single node err = influxql.ErrInvalidQuery case *influxql.ShowShardsStatement: rows, err = e.executeShowShardsStatement(stmt) case *influxql.ShowShardGroupsStatement: rows, err = e.executeShowShardGroupsStatement(stmt) case *influxql.ShowStatsStatement: rows, err = e.executeShowStatsStatement(stmt) case *influxql.ShowSubscriptionsStatement: rows, err = e.executeShowSubscriptionsStatement(stmt) case *influxql.ShowTagValuesStatement: rows, err = e.executeShowTagValuesStatement(stmt, database) case *influxql.ShowUsersStatement: rows, err = e.executeShowUsersStatement(stmt) case *influxql.SetPasswordUserStatement: err = e.executeSetPasswordUserStatement(stmt) default: err = influxql.ErrInvalidQuery } // Send results for each statement. results <- &influxql.Result{ StatementID: i, Series: rows, Err: err, } // Stop after the first error. if err != nil { break } } // Send error results for any statements which were not executed. for ; i < len(query.Statements)-1; i++ { results <- &influxql.Result{ StatementID: i, Err: influxql.ErrNotExecuted, } } }