예제 #1
0
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
}
예제 #2
0
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
}