func (this *builder) VisitSelect(stmt *algebra.Select) (interface{}, error) { order := stmt.Order() offset := stmt.Offset() limit := stmt.Limit() delayProjection := this.delayProjection // If there is an ORDER BY, delay the final projection if order != nil { this.order = order this.delayProjection = true } sub, err := stmt.Subresult().Accept(this) if err != nil { return nil, err } if order == nil && offset == nil && limit == nil { return sub, nil } children := make([]Operator, 0, 5) children = append(children, sub.(Operator)) if order != nil { if this.order == nil { // Disallow aggregates in ORDER BY aggs := make(map[string]algebra.Aggregate) for _, term := range order.Terms() { collectAggregates(aggs, term.Expression()) if len(aggs) > 0 { return nil, fmt.Errorf("Aggregates not available for this ORDER BY.") } } } children = append(children, NewOrder(order)) } if offset != nil { children = append(children, NewOffset(offset)) } if limit != nil { children = append(children, NewLimit(limit)) } // Perform the delayed final projection now, after the ORDER BY if this.delayProjection { children = append(children, NewParallel(NewFinalProject())) this.delayProjection = delayProjection } return NewSequence(children...), nil }
func (this *Context) EvaluateSubquery(query *algebra.Select, parent value.Value) (value.Value, error) { subresult, ok := this.subresults.get(query) if ok { return subresult.(value.Value), nil } subplan, planFound := this.subplans.get(query) if !planFound { var err error subplan, err = plan.Build(query, this.datastore, this.systemstore, this.namespace, true) if err != nil { return nil, err } // Cache plan this.subplans.set(query, subplan) } pipeline, err := Build(subplan.(plan.Operator)) if err != nil { return nil, err } // Collect subquery results collect := NewCollect() sequence := NewSequence(pipeline, collect) sequence.RunOnce(this, parent) // Await completion ok = true for ok { _, ok = <-collect.Output().ItemChannel() } results := collect.Values() // Cache results if !planFound && !query.Subresult().IsCorrelated() { this.subresults.set(query, results) } return results, nil }