package query import ( "bytes" "fmt" "io" "strings" "github.com/influxdata/influxdb/influxql" ) func (p *preparedStatement) Explain() (string, error) { // Determine the cost of all iterators created as part of this plan. ic := &explainIteratorCreator{ic: p.ic} p.ic = ic itrs, _, err := p.Select() p.ic = ic.ic if err != nil { return "", err } Iterators(itrs).Close() var buf bytes.Buffer for i, node := range ic.nodes { if i > 0 { buf.WriteString("\n") } expr := "" if node.Expr != nil { expr = node.Expr.String() } fmt.Fprintf(&buf, "EXPRESSION: %s\n", expr) if len(node.Aux) != 0 { refs := make([]string, len(node.Aux)) for i, ref := range node.Aux { refs[i] = ref.String() } fmt.Fprintf(&buf, "AUXILIARY FIELDS: %s\n", strings.Join(refs, ", ")) } fmt.Fprintf(&buf, "NUMBER OF SHARDS: %d\n", node.Cost.NumShards) fmt.Fprintf(&buf, "NUMBER OF SERIES: %d\n", node.Cost.NumSeries) fmt.Fprintf(&buf, "CACHED VALUES: %d\n", node.Cost.CachedValues) fmt.Fprintf(&buf, "NUMBER OF FILES: %d\n", node.Cost.NumFiles) fmt.Fprintf(&buf, "NUMBER OF BLOCKS: %d\n", node.Cost.BlocksRead) fmt.Fprintf(&buf, "SIZE OF BLOCKS: %d\n", node.Cost.BlockSize) } return buf.String(), nil } type planNode struct { Expr influxql.Expr Aux []influxql.VarRef Cost IteratorCost } type explainIteratorCreator struct { ic interface { IteratorCreator io.Closer } nodes []planNode } func (e *explainIteratorCreator) CreateIterator(m *influxql.Measurement, opt IteratorOptions) (Iterator, error) { cost, err := e.ic.IteratorCost(m, opt) if err != nil { return nil, err } e.nodes = append(e.nodes, planNode{ Expr: opt.Expr, Aux: opt.Aux, Cost: cost, }) return &nilFloatIterator{}, nil } func (e *explainIteratorCreator) IteratorCost(m *influxql.Measurement, opt IteratorOptions) (IteratorCost, error) { return e.ic.IteratorCost(m, opt) } func (e *explainIteratorCreator) Close() error { return e.ic.Close() }