func (this *SimplePlanner) buildDropIndexStatementPlans(stmt *ast.DropIndexStatement, pc plan.PlanChannel, ec query.ErrorChannel) { poolName := stmt.Pool if poolName == "" { poolName = this.defaultPool } pool, err := this.site.PoolByName(poolName) if err != nil { ec <- query.NewPoolDoesNotExist(this.defaultPool) return } bucket, err := pool.BucketByName(stmt.Bucket) if err != nil { ec <- query.NewBucketDoesNotExist(stmt.Bucket) return } var lastStep plan.PlanElement lastStep = plan.NewDropIndex(pool.Name(), bucket.Name(), stmt.Name) if stmt.ExplainOnly { lastStep = plan.NewExplain(lastStep) } pc <- plan.Plan{Root: lastStep} return }
func (this *SimplePlanner) buildSelectStatementPlans(stmt *ast.SelectStatement, pc plan.PlanChannel, ec query.ErrorChannel) { var planHeads []plan.PlanElement from := stmt.GetFrom() if from == nil { // point to :system.dual from = &ast.From{Pool: system.POOL_NAME, Bucket: system.BUCKET_NAME_DUAL} } // get the pool poolName := from.Pool if poolName == "" { poolName = this.defaultPool } pool, err := this.site.PoolByName(poolName) if err != nil { ec <- query.NewPoolDoesNotExist(poolName) return } bucket, err := pool.BucketByName(from.Bucket) if err != nil { ec <- query.NewBucketDoesNotExist(from.Bucket) return } // find all docs index indexes, err := bucket.Indexes() if err != nil { ec <- query.NewError(err, fmt.Sprintf("No indexes found for bucket %v", from.Bucket)) return } var keylist []string if stmt.Keys != nil { keylist = stmt.Keys.GetKeys() } clog.To(planner.CHANNEL, "Indexes in bucket %v", indexes) if keylist == nil { for _, index := range indexes { var lastStep plan.PlanElement switch index := index.(type) { case catalog.PrimaryIndex: clog.To(planner.CHANNEL, "See primary index %v", index.Name()) // if from.Over == nil && stmt.Where == nil && stmt.GroupBy != nil && len(stmt.GroupBy) == 0 && CanFastCountBucket(stmt.Select) { // lastStep = plan.NewFastCount(pool.Name(), bucket.Name(), "", nil, nil) // } else { lastStep = plan.NewScan(pool.Name(), bucket.Name(), index.Name(), nil) // } case catalog.RangeIndex: // see if this index can be used clog.To(planner.CHANNEL, "See index %v", index.Name()) clog.To(planner.CHANNEL, "with Key %v", index.Key()) if stmt.Where != nil && from.Projection == nil { possible, ranges, _, err := CanIUseThisIndexForThisWhereClause(index, stmt.Where, stmt.From.As) if err != nil { clog.Error(err) continue } clog.To(planner.CHANNEL, "Can I use it1: %v", possible) if possible { // great, but lets check for a min optimizatin too if stmt.GroupBy != nil && len(stmt.GroupBy) == 0 { possible, minranges, _, _ := CanIUseThisIndexForThisProjectionNoWhereNoGroupClause(index, stmt.Select, stmt.From.As) if possible { for _, r := range ranges { r.Limit = minranges[0].Limit } } } scan := plan.NewScan(pool.Name(), bucket.Name(), index.Name(), ranges) // see if this index covers the query if DoesIndexCoverStatement(index, stmt) { scan.Cover = true scan.As = from.As } lastStep = scan } else { continue } } else if from.Projection == nil { // try to do a fast count if its possible doingFastCount := false // countIndex, isCountIndex := index.(catalog.CountIndex) // if isCountIndex { // fastCountIndexOnExpr := CanFastCountIndex(countIndex, stmt.From.As, stmt.Select) // if fastCountIndexOnExpr != nil && from.Over == nil && stmt.Where == nil && stmt.GroupBy != nil && len(stmt.GroupBy) == 0 { // lastStep = plan.NewFastCount(pool.Name(), bucket.Name(), countIndex.Name(), fastCountIndexOnExpr, nil) // doingFastCount = true // } // } // this works for aggregates on the whole bucket if !doingFastCount && stmt.GroupBy != nil && len(stmt.GroupBy) == 0 { possible, ranges, _, err := CanIUseThisIndexForThisProjectionNoWhereNoGroupClause(index, stmt.Select, stmt.From.As) if err != nil { clog.Error(err) continue } clog.To(planner.CHANNEL, "Can I use it2: %v", possible) if possible { lastStep = plan.NewScan(pool.Name(), bucket.Name(), index.Name(), ranges) } else { continue } } else if !doingFastCount { continue } } default: clog.To(planner.CHANNEL, "Unsupported type of index %T", index) continue } scanOp, lastStepWasScan := lastStep.(*plan.Scan) if lastStepWasScan { if !scanOp.Cover { lastStep = plan.NewFetch(lastStep, pool.Name(), bucket.Name(), from.Projection, from.As) nextFrom := from.Over for nextFrom != nil { // add document joins if nextFrom.Keys != nil { // This is a key-join lastStep = plan.NewKeyJoin(lastStep, pool.Name(), nextFrom.Bucket, nextFrom.Projection, nextFrom.Type, nextFrom.Oper, *nextFrom.Keys, nextFrom.As) } else { lastStep = plan.NewUnnest(lastStep, nextFrom.Projection, nextFrom.Type, nextFrom.As) } nextFrom = nextFrom.Over } } } planHeads = append(planHeads, lastStep) } } else if keylist != nil { // if keylist is present then we avoid a bucket scan var lastStep plan.PlanElement lastStep = plan.NewKeyScan(keylist) lastStep = plan.NewFetch(lastStep, pool.Name(), bucket.Name(), from.Projection, from.As) nextFrom := from.Over for nextFrom != nil { // add in-document joins if nextFrom.Keys != nil { lastStep = plan.NewKeyJoin(lastStep, pool.Name(), nextFrom.Bucket, nextFrom.Projection, nextFrom.Type, nextFrom.Oper, *nextFrom.Keys, nextFrom.As) } else { lastStep = plan.NewUnnest(lastStep, nextFrom.Projection, nextFrom.Type, nextFrom.As) } nextFrom = nextFrom.Over } planHeads = append(planHeads, lastStep) } if len(planHeads) == 0 { ec <- query.NewError(nil, fmt.Sprintf("No usable indexes found for bucket %v", from.Bucket)) return } // now for all the plan heads, create a full plan for _, lastStep := range planHeads { if stmt.GetWhere() != nil { ids := WhereClauseFindById(stmt.GetWhere()) fetch, ok := lastStep.(*plan.Fetch) if ids != nil && ok { fetch.ConvertToIds(ids) } else { lastStep = plan.NewFilter(lastStep, stmt.GetWhere()) } } if stmt.GetGroupBy() != nil { _, isFastCount := lastStep.(*plan.FastCount) if !isFastCount { lastStep = plan.NewGroup(lastStep, stmt.GetGroupBy(), stmt.GetAggregateReferences()) } } if stmt.GetHaving() != nil { lastStep = plan.NewFilter(lastStep, stmt.GetHaving()) } lastStep = plan.NewProjector(lastStep, stmt.GetResultExpressionList(), true) if stmt.IsDistinct() { lastStep = plan.NewEliminateDuplicates(lastStep) } if stmt.GetOrderBy() != nil { explicitAliases := stmt.GetExplicitProjectionAliases() lastStep = plan.NewOrder(lastStep, stmt.GetOrderBy(), explicitAliases) } if stmt.GetOffset() != 0 { lastStep = plan.NewOffset(lastStep, stmt.GetOffset()) } if stmt.GetLimit() >= 0 { lastStep = plan.NewLimit(lastStep, stmt.GetLimit()) } if stmt.ExplainOnly { lastStep = plan.NewExplain(lastStep) } pc <- plan.Plan{Root: lastStep} } }