func shouldIgnoreTriple(t *triple.Triple, cls *semantic.GraphClause) (bool, error) {
	if cls.PID != "" {
		if string(t.Predicate().ID()) != cls.PID {
			return true, nil
		}
		if cls.PTemporal && cls.PAnchorBinding == "" {
			if t.Predicate().Type() != predicate.Temporal {
				return true, nil
			}
			ta, err := t.Predicate().TimeAnchor()
			if err != nil {
				return true, fmt.Errorf("failed to retrieve time anchor from time predicate in triple %s with error %v", t, err)
			}
			if cls.PLowerBound != nil && cls.PLowerBound.After(*ta) {
				return true, nil
			}
			if cls.PUpperBound != nil && cls.PUpperBound.Before(*ta) {
				return true, nil
			}
		}
	}
	if cls.OID != "" {
		if p, err := t.Object().Predicate(); err == nil {
			if string(p.ID()) != cls.OID {
				return true, nil
			}
			if cls.OTemporal && cls.OAnchorBinding == "" {
				if p.Type() != predicate.Temporal {
					return true, nil
				}
				ta, err := p.TimeAnchor()
				if err != nil {
					return true, fmt.Errorf("failed to retrieve time anchor from time predicate in triple %s with error %v", t, err)
				}
				if cls.OLowerBound != nil && cls.OLowerBound.After(*ta) {
					return true, nil
				}
				if cls.OUpperBound != nil && cls.OUpperBound.Before(*ta) {
					return true, nil
				}
			}
		}
	}
	return false, nil
}
shouldIgnoreTriple indicates if the given triple should be ignored in addTriples.
package planner
import (
	"context"
	"fmt"
	"io"
	"reflect"
	"sync"
	"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/node"
	"github.com/google/badwolf/triple/predicate"
)
type skippableError struct {
	situation string
	err       error
}
func (e *skippableError) Error() string {
	return e.situation + ": " + e.err.Error()
}
var _ error = (*skippableError)(nil)
func updateTimeBounds(lo *storage.LookupOptions, cls *semantic.GraphClause) *storage.LookupOptions {
	nlo := &storage.LookupOptions{
		MaxElements:   lo.MaxElements,
		LowerAnchor:   lo.LowerAnchor,
		UpperAnchor:   lo.UpperAnchor,
		FilterOptions: lo.FilterOptions,
	}
	if cls.PLowerBound != nil {
		if lo.LowerAnchor == nil || (lo.LowerAnchor != nil && cls.PLowerBound.After(*lo.LowerAnchor)) {
			nlo.LowerAnchor = cls.PLowerBound
		}
	}
	if cls.PUpperBound != nil {
		if lo.UpperAnchor == nil || (lo.UpperAnchor != nil && cls.PUpperBound.Before(*lo.UpperAnchor)) {
			nlo.UpperAnchor = cls.PUpperBound
		}
	}
	return nlo
}
func updateTimeBoundsForRow(lo *storage.LookupOptions, cls *semantic.GraphClause, r table.Row) (*storage.LookupOptions, error) {
	lo = updateTimeBounds(lo, cls)
	if cls.PLowerBoundAlias != "" {
		v, ok := r[cls.PLowerBoundAlias]
		if ok && v.T == nil {
			return nil, fmt.Errorf("invalid time anchor value %v for bound %s", v, cls.PLowerBoundAlias)
		}
		if lo.LowerAnchor == nil || (lo.LowerAnchor != nil && v.T.After(*lo.LowerAnchor)) {
			lo.LowerAnchor = v.T
		}
	}
	if cls.PUpperBoundAlias != "" {
		v, ok := r[cls.PUpperBoundAlias]
		if ok && v.T == nil {
			return nil, fmt.Errorf("invalid time anchor value %v for bound %s", v, cls.PUpperBoundAlias)
		}
		if lo.UpperAnchor == nil || (lo.UpperAnchor != nil && v.T.After(*lo.UpperAnchor)) {
			lo.UpperAnchor = v.T
		}
	}
	nlo := updateTimeBounds(lo, cls)
	return nlo, nil
}
func simpleExist(ctx context.Context, gs []storage.Graph, cls *semantic.GraphClause, t *triple.Triple, w io.Writer) (bool, *table.Table, error) {
	unfeasible := true
	tbl, err := table.New(cls.Bindings())
	if err != nil {
		return true, nil, err
	}
	for _, g := range gs {
		gID := g.ID(ctx)
		tracer.V(2).Trace(w, func() *tracer.Arguments {
			return &tracer.Arguments{
				Msgs: []string{fmt.Sprintf("g.Exist(%v), graph: %s", t, gID)},
			}
		})
		b, err := g.Exist(ctx, t)
		if err != nil {
			return true, nil, err
		}
		if b {
			unfeasible = false
			ts := make(chan *triple.Triple, 1)
			ts <- t
			close(ts)
			if err := addTriples(ts, cls, tbl, w); err != nil {
				return true, nil, err
			}
		}
	}
	return unfeasible, tbl, nil
}
func simpleFetch(ctx context.Context, gs []storage.Graph, cls *semantic.GraphClause, lo *storage.LookupOptions, stmLimit int64, chanSize int, w io.Writer) (*table.Table, error) {
	s, p, o := cls.S, cls.P, cls.O
	lo = updateTimeBounds(lo, cls)
	loStr := lo.String()
	tbl, err := table.New(cls.Bindings())
	if err != nil {
		return nil, err
	}
	if s != nil && p != nil && o != nil {
		t, err := triple.New(s, p, o)
		if err != nil {
			return nil, err
		}
		for _, g := range gs {
			gID := g.ID(ctx)
			tracer.V(2).Trace(w, func() *tracer.Arguments {
				return &tracer.Arguments{
					Msgs: []string{fmt.Sprintf("g.Exist(%v), graph: %s", t, gID)},
				}
			})
			b, err := g.Exist(ctx, t)
			if err != nil {
				return nil, err
			}
			if b {
				ts := make(chan *triple.Triple, 1)
				ts <- t
				close(ts)
				if err := addTriples(ts, cls, tbl, w); err != nil {
					return nil, err
				}
			}
		}
		return tbl, nil
	}
	if s != nil && p != nil && o == nil {
		for _, g := range gs {
			gID := g.ID(ctx)
			var (
				oErr error
				aErr error
				lErr error
				wg   sync.WaitGroup
			)
			tracer.V(2).Trace(w, func() *tracer.Arguments {
				return &tracer.Arguments{
					Msgs: []string{fmt.Sprintf("g.Objects(%v, %v, %s), graph: %s", s, p, loStr, gID)},
				}
			})
			wg.Add(2)
			os := make(chan *triple.Object, chanSize)
			go func() {
				defer wg.Done()
				oErr = g.Objects(ctx, s, p, lo, os)
			}()
			ts := make(chan *triple.Triple, chanSize)
			go func() {
				defer wg.Done()
				aErr = addTriples(ts, cls, tbl, w)
			}()
			for o := range os {
				if lErr != nil {
					continue
				}
				t, err := triple.New(s, p, o)
				if err != nil {
					lErr = err
					continue
				}
				ts <- t
			}
			close(ts)
			wg.Wait()
			if oErr != nil {
				return nil, oErr
			}
			if aErr != nil {
				return nil, aErr
			}
			if lErr != nil {
				return nil, lErr
			}
		}
		return tbl, nil
	}
	if s != nil && p == nil && o != nil {
		for _, g := range gs {
			gID := g.ID(ctx)
			var (
				pErr error
				aErr error
				lErr error
				wg   sync.WaitGroup
			)
			tracer.V(2).Trace(w, func() *tracer.Arguments {
				return &tracer.Arguments{
					Msgs: []string{fmt.Sprintf("g.PredicatesForSubjectAndObject(%v, %v, %s), graph: %s", s, o, loStr, gID)},
				}
			})
			wg.Add(2)
			ps := make(chan *predicate.Predicate, chanSize)
			go func() {
				defer wg.Done()
				pErr = g.PredicatesForSubjectAndObject(ctx, s, o, lo, ps)
			}()
			ts := make(chan *triple.Triple, chanSize)
			go func() {
				defer wg.Done()
				aErr = addTriples(ts, cls, tbl, w)
			}()
			for p := range ps {
				if lErr != nil {
					continue
				}
				t, err := triple.New(s, p, o)
				if err != nil {
					lErr = err
					continue
				}
				ts <- t
			}
			close(ts)
			wg.Wait()
			if pErr != nil {
				return nil, pErr
			}
			if aErr != nil {
				return nil, aErr
			}
			if lErr != nil {
				return nil, lErr
			}
		}
		return tbl, nil
	}
	if s == nil && p != nil && o != nil {
		for _, g := range gs {
			gID := g.ID(ctx)
			var (
				pErr error
				aErr error
				lErr error
				wg   sync.WaitGroup
			)
			tracer.V(2).Trace(w, func() *tracer.Arguments {
				return &tracer.Arguments{
					Msgs: []string{fmt.Sprintf("g.Subjects(%v, %v, %s), graph: %s", p, o, loStr, gID)},
				}
			})
			wg.Add(2)
			ss := make(chan *node.Node, chanSize)
			go func() {
				defer wg.Done()
				pErr = g.Subjects(ctx, p, o, lo, ss)
			}()
			ts := make(chan *triple.Triple, chanSize)
			go func() {
				defer wg.Done()
				aErr = addTriples(ts, cls, tbl, w)
			}()
			for s := range ss {
				if lErr != nil {
					continue
				}
				t, err := triple.New(s, p, o)
				if err != nil {
					lErr = err
					continue
				}
				ts <- t
			}
			close(ts)
			wg.Wait()
			if pErr != nil {
				return nil, pErr
			}
			if aErr != nil {
				return nil, aErr
			}
			if lErr != nil {
				return nil, lErr
			}
		}
		return tbl, nil
	}
	if s != nil && p == nil && o == nil {
		for _, g := range gs {
			gID := g.ID(ctx)
			var (
				tErr error
				aErr error
				wg   sync.WaitGroup
			)
			tracer.V(2).Trace(w, func() *tracer.Arguments {
				return &tracer.Arguments{
					Msgs: []string{fmt.Sprintf("g.TriplesForSubject(%v, %s), graph: %s", s, loStr, gID)},
				}
			})
			ts := make(chan *triple.Triple, chanSize)
			wg.Add(1)
			go func() {
				defer wg.Done()
				tErr = g.TriplesForSubject(ctx, s, lo, ts)
			}()
			aErr = addTriples(ts, cls, tbl, w)
			wg.Wait()
			if tErr != nil {
				return nil, tErr
			}
			if aErr != nil {
				return nil, aErr
			}
		}
		return tbl, nil
	}
	if s == nil && p != nil && o == nil {
		for _, g := range gs {
			gID := g.ID(ctx)
			var (
				tErr error
				aErr error
				wg   sync.WaitGroup
			)
			tracer.V(2).Trace(w, func() *tracer.Arguments {
				return &tracer.Arguments{
					Msgs: []string{fmt.Sprintf("g.TriplesForPredicate(%v, %s), graph: %s", p, loStr, gID)},
				}
			})
			ts := make(chan *triple.Triple, chanSize)
			wg.Add(1)
			go func() {
				defer wg.Done()
				tErr = g.TriplesForPredicate(ctx, p, lo, ts)
			}()
			aErr = addTriples(ts, cls, tbl, w)
			wg.Wait()
			if tErr != nil {
				return nil, tErr
			}
			if aErr != nil {
				return nil, aErr
			}
		}
		return tbl, nil
	}
	if s == nil && p == nil && o != nil {
		for _, g := range gs {
			gID := g.ID(ctx)
			var (
				tErr error
				wg   sync.WaitGroup
			)
			tracer.V(2).Trace(w, func() *tracer.Arguments {
				return &tracer.Arguments{
					Msgs: []string{fmt.Sprintf("g.TriplesForObject(%v, %s), graph: %s", o, loStr, gID)},
				}
			})
			ts := make(chan *triple.Triple, chanSize)
			wg.Add(1)
			go func() {
				defer wg.Done()
				tErr = g.TriplesForObject(ctx, o, lo, ts)
			}()
			aErr := addTriples(ts, cls, tbl, w)
			wg.Wait()
			if tErr != nil {
				return nil, tErr
			}
			if aErr != nil {
				return nil, aErr
			}
		}
		return tbl, nil
	}
	if s == nil && p == nil && o == nil {
		for _, g := range gs {
			gID := g.ID(ctx)
			var (
				tErr error
				aErr error
				wg   sync.WaitGroup
			)
			tracer.V(2).Trace(w, func() *tracer.Arguments {
				return &tracer.Arguments{
					Msgs: []string{fmt.Sprintf("g.Triples(%s), graph: %s", loStr, gID)},
				}
			})
			ts := make(chan *triple.Triple, chanSize)
			wg.Add(1)
			go func() {
				defer wg.Done()
				nlo := *lo
				if stmLimit > 0 {
					nlo.MaxElements = int(stmLimit)
				}
				tErr = g.Triples(ctx, &nlo, ts)
			}()
			aErr = addTriples(ts, cls, tbl, w)
			wg.Wait()
			if tErr != nil {
				return nil, tErr
			}
			if aErr != nil {
				return nil, aErr
			}
		}
		return tbl, nil
	}
	return nil, fmt.Errorf("planner.simpleFetch could not recognize request in clause %v", cls)
}