func (this *Context) EvaluateSubquery(query *algebra.Select, parent value.Value) (value.Value, error) { subresults := this.getSubresults() subresult, ok := subresults.get(query) if ok { return subresult.(value.Value), nil } subplans := this.getSubplans() subplan, planFound := subplans.get(query) if !planFound { var err error subplan, err = planner.Build(query, this.datastore, this.systemstore, this.namespace, true) if err != nil { return nil, err } // Cache plan subplans.set(query, subplan) } pipeline, err := Build(subplan.(plan.Operator), this) 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.ValuesOnce() // Cache results if !planFound && !query.Subresult().IsCorrelated() { subresults.set(query, results) } return results, nil }
func (this *builder) VisitSelect(stmt *algebra.Select) (interface{}, error) { // Restore previous values when exiting. VisitSelect() // can be called multiple times by set operators prevCover := this.cover prevOrder := this.order prevLimit := this.limit prevProjection := this.delayProjection defer func() { this.cover = prevCover this.order = prevOrder this.limit = prevLimit this.delayProjection = prevProjection }() order := stmt.Order() offset := stmt.Offset() limit := stmt.Limit() this.order = order if order != nil { // If there is an ORDER BY, delay the final projection this.delayProjection = true this.cover = stmt } else { this.cover = nil } if order != nil || offset != nil { this.limit = nil } else if limit != nil { this.limit = limit } sub, err := stmt.Subresult().Accept(this) if err != nil { return nil, err } if order == nil && offset == nil && limit == nil { return sub, nil } children := make([]plan.Operator, 0, 5) children = append(children, sub.(plan.Operator)) if order != nil { children = append(children, plan.NewOrder(order)) } if offset != nil { children = append(children, plan.NewOffset(offset)) } if limit != nil { children = append(children, plan.NewLimit(limit)) } // Perform the delayed final projection now, after the ORDER BY if this.delayProjection { children = append(children, plan.NewFinalProject()) } return plan.NewSequence(children...), nil }