func newQueryPlan(ctx context.Context, store storage.Store, stm *semantic.Statement, chanSize int, w io.Writer) (*queryPlan, error) {
	bs := []string{}
	for _, b := range stm.Bindings() {
		bs = append(bs, b)
	}
	t, err := table.New([]string{})
	if err != nil {
		return nil, err
	}
	return &queryPlan{
		stm:       stm,
		store:     store,
		bndgs:     bs,
		grfsNames: stm.InputGraphNames(),
		clauses:   stm.GraphPatternClauses(),
		filters:   stm.FilterClauses(),
		tbl:       t,
		chanSize:  chanSize,
		tracer:    w,
	}, nil
}
newQueryPlan returns a new query plan ready to be executed.
package planner
import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"io"
	"reflect"
	"strconv"
	"strings"
	"sync"
	"time"
	"github.com/google/badwolf/bql/lexer"
	"github.com/google/badwolf/bql/planner/filter"
	"github.com/google/badwolf/bql/planner/tracer"
	"github.com/google/badwolf/bql/semantic"
	"github.com/google/badwolf/bql/table"
	"github.com/google/badwolf/storage"
	"github.com/google/badwolf/triple"
	"github.com/google/badwolf/triple/literal"
	"github.com/google/badwolf/triple/predicate"
	"golang.org/x/sync/errgroup"
)
type Executor interface {
	Execute(ctx context.Context) (*table.Table, error)
	String(ctx context.Context) string
	Type() string
}
type createPlan struct {
	stm    *semantic.Statement
	store  storage.Store
	tracer io.Writer
}
func (p *createPlan) Type() string {
	return "CREATE"
}
func (p *createPlan) Execute(ctx context.Context) (*table.Table, error) {
	t, err := table.New([]string{})
	if err != nil {
		return nil, err
	}
	errs := []string{}
	for _, gName := range p.stm.GraphNames() {
		gNameCopy := gName  
		tracer.V(2).Trace(p.tracer, func() *tracer.Arguments {
			return &tracer.Arguments{
				Msgs: []string{fmt.Sprintf("Creating new graph %q", gNameCopy)},
			}
		})
		if _, err := p.store.NewGraph(ctx, gName); err != nil {
			errs = append(errs, err.Error())
		}
	}
	if len(errs) > 0 {
		return nil, errors.New(strings.Join(errs, "; "))
	}
	return t, nil
}
func (p *createPlan) String(ctx context.Context) string {
	return fmt.Sprintf("CREATE plan:\n\nstore(%q).NewGraph(_, %v)", p.store.Name(nil), p.stm.Graphs())
}
type dropPlan struct {
	stm    *semantic.Statement
	store  storage.Store
	tracer io.Writer
}
func (p *dropPlan) Type() string {
	return "DROP"
}
func (p *dropPlan) Execute(ctx context.Context) (*table.Table, error) {
	t, err := table.New([]string{})
	if err != nil {
		return nil, err
	}
	errs := []string{}
	for _, gName := range p.stm.GraphNames() {
		gNameCopy := gName  
		tracer.V(2).Trace(p.tracer, func() *tracer.Arguments {
			return &tracer.Arguments{
				Msgs: []string{fmt.Sprintf("Deleting graph %q", gNameCopy)},
			}
		})
		if err := p.store.DeleteGraph(ctx, gName); err != nil {
			errs = append(errs, err.Error())
		}
	}
	if len(errs) > 0 {
		return nil, errors.New(strings.Join(errs, "; "))
	}
	return t, nil
}
func (p *dropPlan) String(ctx context.Context) string {
	return fmt.Sprintf("DROP plan:\n\nstore(%q).DeleteGraph(_, %v)", p.store.Name(nil), p.stm.Graphs())
}
type insertPlan struct {
	stm    *semantic.Statement
	store  storage.Store
	tracer io.Writer
}
func (p *insertPlan) Type() string {
	return "INSERT"
}
type updater func(storage.Graph, []*triple.Triple) error
func update(ctx context.Context, ts []*triple.Triple, gbs []string, store storage.Store, f updater) error {
	var (
		mu   sync.Mutex
		wg   sync.WaitGroup
		errs []string
	)
	appendError := func(err error) {
		mu.Lock()
		defer mu.Unlock()
		errs = append(errs, err.Error())
	}
	for _, graphBinding := range gbs {
		wg.Add(1)
		go func(graph string) {
			defer wg.Done()
			g, err := store.Graph(ctx, graph)
			if err != nil {
				appendError(err)
				return
			}
			err = f(g, ts)
			if err != nil {
				appendError(err)
			}
		}(graphBinding)
	}
	wg.Wait()
	if len(errs) > 0 {
		return errors.New(strings.Join(errs, "; "))
	}
	return nil
}
func (p *insertPlan) Execute(ctx context.Context) (*table.Table, error) {
	t, err := table.New([]string{})
	if err != nil {
		return nil, err
	}
	return t, update(ctx, p.stm.Data(), p.stm.OutputGraphNames(), p.store, func(g storage.Graph, d []*triple.Triple) error {
		gID := g.ID(ctx)
		nTrpls := len(d)
		tracer.V(2).Trace(p.tracer, func() *tracer.Arguments {
			return &tracer.Arguments{
				Msgs: []string{fmt.Sprintf("Inserting %d triples to graph %q", nTrpls, gID)},
			}
		})
		return g.AddTriples(ctx, d)
	})
}
func (p *insertPlan) String(ctx context.Context) string {
	b := bytes.NewBufferString("INSERT plan:\n\n")
	for _, g := range p.stm.OutputGraphs() {
		b.WriteString(fmt.Sprintf("store(%q).Graph(%q).AddTriples(_, data)\n", p.store.Name(nil), g))
	}
	b.WriteString("where data:\n")
	for _, t := range p.stm.Data() {
		b.WriteString("\t")
		b.WriteString(t.String())
		b.WriteString("\n")
	}
	return b.String()
}
type deletePlan struct {
	stm    *semantic.Statement
	store  storage.Store
	tracer io.Writer
}
func (p *deletePlan) Type() string {
	return "DELETE"
}
func (p *deletePlan) Execute(ctx context.Context) (*table.Table, error) {
	t, err := table.New([]string{})
	if err != nil {
		return nil, err
	}
	return t, update(ctx, p.stm.Data(), p.stm.InputGraphNames(), p.store, func(g storage.Graph, d []*triple.Triple) error {
		gID := g.ID(ctx)
		nTrpls := len(d)
		tracer.V(2).Trace(p.tracer, func() *tracer.Arguments {
			return &tracer.Arguments{
				Msgs: []string{fmt.Sprintf("Removing %d triples from graph %q", nTrpls, gID)},
			}
		})
		return g.RemoveTriples(ctx, d)
	})
}
func (p *deletePlan) String(ctx context.Context) string {
	b := bytes.NewBufferString("DELETE plan:\n\n")
	for _, g := range p.stm.InputGraphs() {
		b.WriteString(fmt.Sprintf("store(%q).Graph(%q).RemoveTriples(_, data)\n", p.store.Name(nil), g))
	}
	b.WriteString("where data:\n")
	for _, t := range p.stm.Data() {
		b.WriteString("\t")
		b.WriteString(t.String())
		b.WriteString("\n")
	}
	return b.String()
}
type queryPlan struct {
	stm   *semantic.Statement
	store storage.Store
	bndgs     []string
	grfsNames []string
	grfs      []storage.Graph
	clauses   []*semantic.GraphClause
	filters   []*semantic.FilterClause
	tbl       *table.Table
	chanSize  int
	tracer    io.Writer
}
func (p *queryPlan) Type() string {
	return "SELECT"
}