func NewQueryEngine(next Processor, query *parser.SelectQuery, shards []uint32) (Processor, error) { limit := query.Limit var engine Processor = NewPassthroughEngineWithLimit(next, 1, limit) var err error if query.HasAggregates() { engine, err = NewAggregatorEngine(query, engine) } else if query.ContainsArithmeticOperators() { engine, err = NewArithmeticEngine(query, engine) } fromClause := query.GetFromClause() switch fromClause.Type { case parser.FromClauseInnerJoin: engine = NewJoinEngine(shards, query, engine) case parser.FromClauseMerge: tables := make([]string, len(fromClause.Names)) for i, name := range fromClause.Names { tables[i] = name.Name.Name } engine = NewMergeEngine(shards, query.Ascending, engine) case parser.FromClauseMergeRegex: // At this point the regex should be expanded to the list of // tables that will be queries panic("QueryEngine cannot be called with merge function") } if err != nil { return nil, err } return engine, nil }
func Filter(query *parser.SelectQuery, series *protocol.Series) (*protocol.Series, error) { if query.GetWhereCondition() == nil { return series, nil } columns := map[string]struct{}{} if query.GetFromClause().Type == parser.FromClauseInnerJoin { outer: for t, cs := range query.GetResultColumns() { for _, c := range cs { // if this is a wildcard select, then drop all columns and // just use '*' if c == "*" { columns = make(map[string]struct{}, 1) columns[c] = struct{}{} break outer } columns[t.Name+"."+c] = struct{}{} } } } else { for _, cs := range query.GetResultColumns() { for _, c := range cs { columns[c] = struct{}{} } } } points := series.Points series.Points = nil for _, point := range points { ok, err := matches(query.GetWhereCondition(), series.Fields, point) if err != nil { return nil, err } if ok { filterColumns(columns, series.Fields, point) series.Points = append(series.Points, point) } } if _, ok := columns["*"]; !ok { newFields := []string{} for _, f := range series.Fields { if _, ok := columns[f]; !ok { continue } newFields = append(newFields, f) } series.Fields = newFields } return series, nil }
func getJoinYield(query *parser.SelectQuery, yield func(*protocol.Series) error) func(*protocol.Series) error { var lastPoint1 *protocol.Point var lastFields1 []string var lastPoint2 *protocol.Point var lastFields2 []string table1 := query.GetFromClause().Names[0].GetAlias() table2 := query.GetFromClause().Names[1].GetAlias() name := table1 + "_join_" + table2 return mergeYield(table1, table2, false, query.Ascending, func(s *protocol.Series) error { if *s.Name == table1 { lastPoint1 = s.Points[len(s.Points)-1] if lastFields1 == nil { for _, f := range s.Fields { lastFields1 = append(lastFields1, table1+"."+f) } } } if *s.Name == table2 { lastPoint2 = s.Points[len(s.Points)-1] if lastFields2 == nil { for _, f := range s.Fields { lastFields2 = append(lastFields2, table2+"."+f) } } } if lastPoint1 == nil || lastPoint2 == nil { return nil } newSeries := &protocol.Series{ Name: &name, Fields: append(lastFields1, lastFields2...), Points: []*protocol.Point{ { Values: append(lastPoint1.Values, lastPoint2.Values...), Timestamp: lastPoint2.Timestamp, }, }, } lastPoint1 = nil lastPoint2 = nil filteredSeries, _ := Filter(query, newSeries) if len(filteredSeries.Points) > 0 { return yield(newSeries) } return nil }) }
// distribute query and possibly do the merge/join before yielding the points func (self *QueryEngine) distributeQuery(query *parser.SelectQuery, yield func(*protocol.Series) error) error { // see if this is a merge query fromClause := query.GetFromClause() if fromClause.Type == parser.FromClauseMerge { yield = getMergeYield(fromClause.Names[0].Name.Name, fromClause.Names[1].Name.Name, query.Ascending, yield) } if fromClause.Type == parser.FromClauseInnerJoin { yield = getJoinYield(query, yield) } self.yield = yield return nil }
func NewJoinEngine(query *parser.SelectQuery, next Processor) Processor { table1 := query.GetFromClause().Names[0].GetAlias() table2 := query.GetFromClause().Names[1].GetAlias() name := table1 + "_join_" + table2 joinEngine := &JoinEngine{ next: next, name: name, table1: table1, table2: table2, query: query, } mergeEngine := NewCommonMergeEngine(table1, table2, false, query.Ascending, joinEngine) return mergeEngine }
// Create and return a new JoinEngine given the shards that will be // processed and the query func NewJoinEngine(shards []uint32, query *parser.SelectQuery, next Processor) Processor { tableNames := query.GetFromClause().Names name := query.GetFromClause().GetString() log4go.Debug("NewJoinEngine: shards=%v, query=%s, next=%s, tableNames=%v, name=%s", shards, query.GetQueryString(), next.Name(), tableNames, name) joinEngine := &JoinEngine{ next: next, name: name, tablesState: make([]joinEngineState, len(tableNames)), tableIdx: make(map[string]int, len(tableNames)), query: query, pts: 0, } for i, tn := range tableNames { alias := tn.GetAlias() joinEngine.tablesState[i] = joinEngineState{} joinEngine.tableIdx[alias] = i } mergeEngine := NewCommonMergeEngine(shards, false, query.Ascending, joinEngine) return mergeEngine }
func NewQueryEngine(next Processor, query *parser.SelectQuery) (Processor, error) { limit := query.Limit var engine Processor = NewPassthroughEngineWithLimit(next, 1, limit) var err error if query.HasAggregates() { engine, err = NewAggregatorEngine(query, engine) } else if query.ContainsArithmeticOperators() { engine, err = NewArithmeticEngine(query, engine) } fromClause := query.GetFromClause() if fromClause.Type == parser.FromClauseMerge { engine = NewMergeEngine(fromClause.Names[0].Name.Name, fromClause.Names[1].Name.Name, query.Ascending, engine) } else if fromClause.Type == parser.FromClauseInnerJoin { engine = NewJoinEngine(query, engine) } if err != nil { return nil, err } return engine, nil }