func (s *Store) CreateMapper(shardID uint64, stmt influxql.Statement, chunkSize int) (Mapper, error) { shard := s.Shard(shardID) switch stmt := stmt.(type) { case *influxql.SelectStatement: if (stmt.IsRawQuery && !stmt.HasDistinct()) || stmt.IsSimpleDerivative() { m := NewRawMapper(shard, stmt) m.ChunkSize = chunkSize return m, nil } return NewAggregateMapper(shard, stmt), nil case *influxql.ShowMeasurementsStatement: m := NewShowMeasurementsMapper(shard, stmt) m.ChunkSize = chunkSize return m, nil case *influxql.ShowTagKeysStatement: return NewShowTagKeysMapper(shard, stmt, chunkSize), nil default: return nil, fmt.Errorf("can't create mapper for statement type: %T", stmt) } }
// ExecuteQuery executes an InfluxQL query against the server. // It sends results down the passed in chan and closes it when done. It will close the chan // on the first statement that throws an error. func (q *QueryExecutor) ExecuteQuery(query *influxql.Query, database string, chunkSize int) (<-chan *influxql.Result, error) { // Execute each statement. Keep the iterator external so we can // track how many of the statements were executed results := make(chan *influxql.Result) go func() { var i int var stmt influxql.Statement for i, stmt = range query.Statements { // If a default database wasn't passed in by the caller, check the statement. // Some types of statements have an associated default database, even if it // is not explicitly included. defaultDB := database if defaultDB == "" { if s, ok := stmt.(influxql.HasDefaultDatabase); ok { defaultDB = s.DefaultDatabase() } } // Normalize each statement. if err := q.normalizeStatement(stmt, defaultDB); err != nil { results <- &influxql.Result{Err: err} break } // Log each normalized statement. if q.QueryLogEnabled { q.Logger.Println(stmt.String()) } var res *influxql.Result switch stmt := stmt.(type) { case *influxql.SelectStatement: if err := q.executeStatement(i, stmt, database, results, chunkSize); err != nil { results <- &influxql.Result{Err: err} break } case *influxql.DropSeriesStatement: // TODO: handle this in a cluster res = q.executeDropSeriesStatement(stmt, database) case *influxql.ShowSeriesStatement: res = q.executeShowSeriesStatement(stmt, database) case *influxql.DropMeasurementStatement: // TODO: handle this in a cluster res = q.executeDropMeasurementStatement(stmt, database) case *influxql.ShowMeasurementsStatement: if err := q.executeStatement(i, stmt, database, results, chunkSize); err != nil { results <- &influxql.Result{Err: err} break } case *influxql.ShowTagKeysStatement: if err := q.executeStatement(i, stmt, database, results, chunkSize); err != nil { results <- &influxql.Result{Err: err} break } case *influxql.ShowTagValuesStatement: res = q.executeShowTagValuesStatement(stmt, database) case *influxql.ShowFieldKeysStatement: res = q.executeShowFieldKeysStatement(stmt, database) case *influxql.DeleteStatement: res = &influxql.Result{Err: ErrInvalidQuery} case *influxql.DropDatabaseStatement: // TODO: handle this in a cluster res = q.executeDropDatabaseStatement(stmt) case *influxql.ShowStatsStatement, *influxql.ShowDiagnosticsStatement: // Send monitor-related queries to the monitor service. res = q.MonitorStatementExecutor.ExecuteStatement(stmt) default: // Delegate all other meta statements to a separate executor. They don't hit tsdb storage. res = q.MetaStatementExecutor.ExecuteStatement(stmt) } if res != nil { // set the StatementID for the handler on the other side to combine results res.StatementID = i // If an error occurs then stop processing remaining statements. results <- res if res.Err != nil { break } } } // if there was an error send results that the remaining statements weren't executed for ; i < len(query.Statements)-1; i++ { results <- &influxql.Result{Err: ErrNotExecuted} } close(results) }() return results, nil }