func (this *builder) VisitDelete(stmt *algebra.Delete) (interface{}, error) { this.cover = stmt this.where = stmt.Where() ksref := stmt.KeyspaceRef() keyspace, err := this.getNameKeyspace(ksref.Namespace(), ksref.Keyspace()) if err != nil { return nil, err } err = this.beginMutate(keyspace, ksref, stmt.Keys(), stmt.Indexes(), stmt.Limit()) if err != nil { return nil, err } subChildren := this.subChildren subChildren = append(subChildren, plan.NewSendDelete(keyspace, ksref.Alias(), stmt.Limit())) if stmt.Returning() != nil { subChildren = append(subChildren, plan.NewInitialProject(stmt.Returning()), plan.NewFinalProject()) } parallel := plan.NewParallel(plan.NewSequence(subChildren...), this.maxParallelism) this.children = append(this.children, parallel) if stmt.Limit() != nil { this.children = append(this.children, plan.NewLimit(stmt.Limit())) } if stmt.Returning() == nil { this.children = append(this.children, plan.NewDiscard()) } return plan.NewSequence(this.children...), nil }
func (this *builder) visitGroup(group *algebra.Group, aggs map[string]algebra.Aggregate) { aggn := make(sort.StringSlice, 0, len(aggs)) for n, _ := range aggs { aggn = append(aggn, n) } aggn.Sort() aggv := make(algebra.Aggregates, len(aggs)) for i, n := range aggn { aggv[i] = aggs[n] } this.subChildren = append(this.subChildren, plan.NewInitialGroup(group.By(), aggv)) this.children = append(this.children, plan.NewParallel(plan.NewSequence(this.subChildren...), this.maxParallelism)) this.children = append(this.children, plan.NewIntermediateGroup(group.By(), aggv)) this.children = append(this.children, plan.NewFinalGroup(group.By(), aggv)) this.subChildren = make([]plan.Operator, 0, 8) letting := group.Letting() if letting != nil { this.subChildren = append(this.subChildren, plan.NewLet(letting)) } having := group.Having() if having != nil { this.subChildren = append(this.subChildren, plan.NewFilter(having)) } }
func Build(stmt algebra.Statement, datastore, systemstore datastore.Datastore, namespace string, subquery bool) (plan.Operator, error) { builder := newBuilder(datastore, systemstore, namespace, subquery) o, err := stmt.Accept(builder) if err != nil { return nil, err } op := o.(plan.Operator) _, is_prepared := o.(*plan.Prepared) if !subquery && !is_prepared { privs, er := stmt.Privileges() if er != nil { return nil, er } if len(privs) > 0 { op = plan.NewAuthorize(privs, op) } return plan.NewSequence(op, plan.NewStream()), nil } else { return op, nil } }
func (this *builder) VisitUpsert(stmt *algebra.Upsert) (interface{}, error) { ksref := stmt.KeyspaceRef() ksref.SetDefaultNamespace(this.namespace) keyspace, err := this.getNameKeyspace(ksref.Namespace(), ksref.Keyspace()) if err != nil { return nil, err } children := make([]plan.Operator, 0, 4) if stmt.Values() != nil { children = append(children, plan.NewValueScan(stmt.Values())) this.maxParallelism = util.MaxInt(1, len(stmt.Values())) } else if stmt.Select() != nil { sel, err := stmt.Select().Accept(this) if err != nil { return nil, err } children = append(children, sel.(plan.Operator)) } else { return nil, fmt.Errorf("UPSERT missing both VALUES and SELECT.") } subChildren := make([]plan.Operator, 0, 4) subChildren = append(subChildren, plan.NewSendUpsert(keyspace, ksref.Alias(), stmt.Key(), stmt.Value())) if stmt.Returning() != nil { subChildren = append(subChildren, plan.NewInitialProject(stmt.Returning()), plan.NewFinalProject()) } else { subChildren = append(subChildren, plan.NewDiscard()) } parallel := plan.NewParallel(plan.NewSequence(subChildren...), this.maxParallelism) children = append(children, parallel) return plan.NewSequence(children...), nil }
func (this *builder) VisitUnion(node *algebra.Union) (interface{}, error) { // Inject DISTINCT into both terms distinct := this.distinct this.distinct = true defer func() { this.distinct = distinct }() this.order = nil // Disable aggregates from ORDER BY this.delayProjection = false // Disable ORDER BY non-projected expressions this.limit = nil first, err := node.First().Accept(this) if err != nil { return nil, err } second, err := node.Second().Accept(this) if err != nil { return nil, err } this.maxParallelism = 0 unionAll := plan.NewUnionAll(first.(plan.Operator), second.(plan.Operator)) return plan.NewSequence(unionAll, plan.NewDistinct()), nil }
func (this *builder) VisitSubselect(node *algebra.Subselect) (interface{}, error) { prevCover := this.cover prevCorrelated := this.correlated defer func() { this.cover = prevCover this.correlated = prevCorrelated }() this.correlated = node.IsCorrelated() if this.cover == nil { this.cover = node } aggs, err := allAggregates(node, this.order) if err != nil { return nil, err } this.where = node.Where() group := node.Group() if group == nil && len(aggs) > 0 { group = algebra.NewGroup(nil, nil, nil) this.where = constrainAggregate(this.where, aggs) } this.children = make([]plan.Operator, 0, 16) // top-level children, executed sequentially this.subChildren = make([]plan.Operator, 0, 16) // sub-children, executed across data-parallel streams err = this.visitFrom(node, group) if err != nil { return nil, err } if this.coveringScan != nil { coverer := expression.NewCoverer(this.coveringScan.Covers()) err = this.cover.MapExpressions(coverer) if err != nil { return nil, err } if this.where != nil { this.where, err = coverer.Map(this.where) if err != nil { return nil, err } } } if node.Let() != nil { this.subChildren = append(this.subChildren, plan.NewLet(node.Let())) } if node.Where() != nil { this.subChildren = append(this.subChildren, plan.NewFilter(node.Where())) } if group != nil { this.visitGroup(group, aggs) } projection := node.Projection() this.subChildren = append(this.subChildren, plan.NewInitialProject(projection)) // Initial DISTINCT (parallel) if projection.Distinct() || this.distinct { this.subChildren = append(this.subChildren, plan.NewDistinct()) } if !this.delayProjection { // Perform the final projection if there is no subsequent ORDER BY this.subChildren = append(this.subChildren, plan.NewFinalProject()) } // Parallelize the subChildren this.children = append(this.children, plan.NewParallel(plan.NewSequence(this.subChildren...), this.maxParallelism)) // Final DISTINCT (serial) if projection.Distinct() || this.distinct { this.children = append(this.children, plan.NewDistinct()) } // Serialize the top-level children return plan.NewSequence(this.children...), 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 }
func (this *builder) VisitMerge(stmt *algebra.Merge) (interface{}, error) { children := make([]plan.Operator, 0, 8) subChildren := make([]plan.Operator, 0, 8) source := stmt.Source() if source.Select() != nil { sel, err := source.Select().Accept(this) if err != nil { return nil, err } children = append(children, sel.(plan.Operator)) } else { if source.From() == nil { return nil, fmt.Errorf("MERGE missing source.") } _, err := source.From().Accept(this) if err != nil { return nil, err } // Update local operator slices with results of building From: children = append(children, this.children...) subChildren = append(subChildren, this.subChildren...) } if source.As() != "" { subChildren = append(subChildren, plan.NewAlias(source.As())) } ksref := stmt.KeyspaceRef() ksref.SetDefaultNamespace(this.namespace) keyspace, err := this.getNameKeyspace(ksref.Namespace(), ksref.Keyspace()) if err != nil { return nil, err } actions := stmt.Actions() var update, delete, insert plan.Operator if actions.Update() != nil { act := actions.Update() ops := make([]plan.Operator, 0, 5) if act.Where() != nil { ops = append(ops, plan.NewFilter(act.Where())) } ops = append(ops, plan.NewClone(ksref.Alias())) if act.Set() != nil { ops = append(ops, plan.NewSet(act.Set())) } if act.Unset() != nil { ops = append(ops, plan.NewUnset(act.Unset())) } ops = append(ops, plan.NewSendUpdate(keyspace, ksref.Alias(), stmt.Limit())) update = plan.NewSequence(ops...) } if actions.Delete() != nil { act := actions.Delete() ops := make([]plan.Operator, 0, 4) if act.Where() != nil { ops = append(ops, plan.NewFilter(act.Where())) } ops = append(ops, plan.NewSendDelete(keyspace, ksref.Alias(), stmt.Limit())) delete = plan.NewSequence(ops...) } if actions.Insert() != nil { act := actions.Insert() ops := make([]plan.Operator, 0, 4) if act.Where() != nil { ops = append(ops, plan.NewFilter(act.Where())) } ops = append(ops, plan.NewSendInsert(keyspace, ksref.Alias(), stmt.Key(), act.Value(), stmt.Limit())) insert = plan.NewSequence(ops...) } merge := plan.NewMerge(keyspace, ksref, stmt.Key(), update, delete, insert) subChildren = append(subChildren, merge) if stmt.Returning() != nil { subChildren = append(subChildren, plan.NewInitialProject(stmt.Returning()), plan.NewFinalProject()) } parallel := plan.NewParallel(plan.NewSequence(subChildren...), this.maxParallelism) children = append(children, parallel) if stmt.Limit() != nil { children = append(children, plan.NewLimit(stmt.Limit())) } if stmt.Returning() == nil { children = append(children, plan.NewDiscard()) } return plan.NewSequence(children...), nil }