// Plan creates an execution plan for the given SelectStatement and returns an Executor. func (q *QueryExecutor) plan(stmt *influxql.SelectStatement, chunkSize int) (Executor, error) { shards := map[uint64]meta.ShardInfo{} // Shards requiring mappers. // Replace instances of "now()" with the current time, and check the resultant times. stmt.Condition = influxql.Reduce(stmt.Condition, &influxql.NowValuer{Now: time.Now().UTC()}) tmin, tmax := influxql.TimeRange(stmt.Condition) if tmax.IsZero() { tmax = time.Now() } if tmin.IsZero() { tmin = time.Unix(0, 0) } for _, src := range stmt.Sources { mm, ok := src.(*influxql.Measurement) if !ok { return nil, fmt.Errorf("invalid source type: %#v", src) } // Build the set of target shards. Using shard IDs as keys ensures each shard ID // occurs only once. shardGroups, err := q.MetaStore.ShardGroupsByTimeRange(mm.Database, mm.RetentionPolicy, tmin, tmax) if err != nil { return nil, err } for _, g := range shardGroups { for _, sh := range g.Shards { shards[sh.ID] = sh } } } // Build the Mappers, one per shard. mappers := []Mapper{} for _, sh := range shards { m, err := q.ShardMapper.CreateMapper(sh, stmt.String(), chunkSize) if err != nil { return nil, err } if m == nil { // No data for this shard, skip it. continue } mappers = append(mappers, m) } var executor Executor if len(mappers) > 0 { // All Mapper are of same type, so check first to determine correct Executor type. if _, ok := mappers[0].(*RawMapper); ok { executor = NewRawExecutor(stmt, mappers, chunkSize) } else { executor = NewAggregateExecutor(stmt, mappers) } } else { // With no mappers, the Executor type doesn't matter. executor = NewRawExecutor(stmt, nil, chunkSize) } return executor, nil }