func (this *builder) buildSecondaryScan(secondaries map[datastore.Index]*indexEntry, node *algebra.KeyspaceTerm, limit expression.Expression) (plan.Operator, error) { if this.cover != nil { scan, err := this.buildCoveringScan(secondaries, node, limit) if scan != nil || err != nil { return scan, err } } scans := make([]plan.Operator, 0, len(secondaries)) var op plan.Operator for index, entry := range secondaries { op = plan.NewIndexScan(index, node, entry.spans, false, limit, nil) if len(entry.spans) > 1 { // Use UnionScan to de-dup multiple spans op = plan.NewUnionScan(op) } else { // Use UnionScan to de-dup array index scans for _, sk := range entry.sargKeys { if isArray, _ := sk.IsArrayIndexKey(); isArray { op = plan.NewUnionScan(op) break } } } scans = append(scans, op) } if len(scans) > 1 { return plan.NewIntersectScan(scans...), nil } else { return scans[0], nil } }
func (this *builder) buildCoveringScan(secondaries map[datastore.Index]*indexEntry, node *algebra.KeyspaceTerm, limit expression.Expression) (plan.Operator, error) { if this.cover == nil { return nil, nil } alias := node.Alias() exprs := this.cover.Expressions() id := expression.NewField( expression.NewMeta(expression.NewIdentifier(node.Alias())), expression.NewFieldName("id", false)) outer: for index, entry := range secondaries { keys := entry.keys if !index.IsPrimary() { // Matches execution.spanScan.RunOnce() keys = append(keys, id) } // Use the first available covering index for _, expr := range exprs { if !expr.CoveredBy(alias, keys) { continue outer } } covers := make(expression.Covers, 0, len(keys)) for _, key := range keys { covers = append(covers, expression.NewCover(key)) } scan := plan.NewIndexScan(index, node, entry.spans, false, limit, covers) this.coveringScan = scan if len(entry.spans) > 1 { // Use UnionScan to de-dup multiple spans return plan.NewUnionScan(scan), nil } return scan, nil } return nil, nil }