Example #1
0
func TestDataAccessUnfeasibleSimpleExist(t *testing.T) {
	ctx := context.Background()
	g, err := getTestStore(t, testImmutatbleTriples).Graph(ctx, "?test")
	if err != nil {
		t.Fatal(err)
	}
	unknown, err := node.Parse("/unknown<unknown>")
	if err != nil {
		t.Fatal(err)
	}
	tt := getTestTriples(t, testImmutatbleTriples)
	s, p, o := unknown, tt[0].Predicate(), tt[0].Object()
	clsNotOK := &semantic.GraphClause{
		S: s,
		P: p,
		O: o,
	}
	tplNotOK, err := triple.New(s, p, o)
	if err != nil {
		t.Fatal(err)
	}
	unfeasible, tbl, err := simpleExist(ctx, []storage.Graph{g}, clsNotOK, tplNotOK)
	if err != nil {
		t.Errorf("simpleExist should have not failed with error %v", err)
	}
	if !unfeasible {
		t.Error(errors.New("simpleExist should have return an unfeasible table instead"))
	}
	if got, want := tbl.NumRows(), 0; got != want {
		t.Errorf("simpleExist failed to return the right number of rows: got %d, want %d", got, want)
	}
}
Example #2
0
// dataAccumulator creates a element hook that tracks fully formed triples and
// adds them to the Statement when fully formed.
func dataAccumulator(b literal.Builder) ElementHook {
	var (
		hook ElementHook
		s    *node.Node
		p    *predicate.Predicate
		o    *triple.Object
	)

	hook = func(st *Statement, ce ConsumedElement) (ElementHook, error) {
		if ce.IsSymbol() {
			return hook, nil
		}
		tkn := ce.Token()
		if tkn.Type != lexer.ItemNode && tkn.Type != lexer.ItemPredicate && tkn.Type != lexer.ItemLiteral {
			return hook, nil
		}
		if s == nil {
			if tkn.Type != lexer.ItemNode {
				return nil, fmt.Errorf("hook.DataAccumulator requires a node to create a subject, got %v instead", tkn)
			}
			tmp, err := node.Parse(tkn.Text)
			if err != nil {
				return nil, err
			}
			s = tmp
			return hook, nil
		}
		if p == nil {
			if tkn.Type != lexer.ItemPredicate {
				return nil, fmt.Errorf("hook.DataAccumulator requires a predicate to create a predicate, got %v instead", tkn)
			}
			tmp, err := predicate.Parse(tkn.Text)
			if err != nil {
				return nil, err
			}
			p = tmp
			return hook, nil
		}
		if o == nil {
			tmp, err := triple.ParseObject(tkn.Text, b)
			if err != nil {
				return nil, err
			}
			o = tmp
			trpl, err := triple.New(s, p, o)
			if err != nil {
				return nil, err
			}
			st.AddData(trpl)
			s, p, o = nil, nil, nil
			return hook, nil
		}
		return nil, fmt.Errorf("hook.DataAccumulator has failed to flush the triple %s, %s, %s", s, p, o)
	}
	return hook
}
Example #3
0
// newTriple creates new triple using the provided node IDs.
func (r *randomGraph) newTriple(i, j int) (*triple.Triple, error) {
	s, err := r.newNode(i)
	if err != nil {
		return nil, err
	}
	o, err := r.newNode(j)
	if err != nil {
		return nil, err
	}
	return triple.New(s, r.predicate, triple.NewNodeObject(o))
}
Example #4
0
// processClause retrieves the triples for the provided triple given the
// information available.
func (p *queryPlan) processClause(ctx context.Context, cls *semantic.GraphClause, lo *storage.LookupOptions) (bool, error) {
	// This method decides how to process the clause based on the current
	// list of bindings solved and data available.
	if cls.Specificity() == 3 {
		t, err := triple.New(cls.S, cls.P, cls.O)
		if err != nil {
			return false, err
		}
		b, tbl, err := simpleExist(ctx, p.grfs, cls, t)
		if err != nil {
			return false, err
		}
		if err := p.tbl.AppendTable(tbl); err != nil {
			return b, err
		}
		return b, nil
	}
	exist, total := 0, 0
	for _, b := range cls.Bindings() {
		total++
		if p.tbl.HasBinding(b) {
			exist++
		}
	}
	if exist == 0 {
		// Data is new.
		tbl, err := simpleFetch(ctx, p.grfs, cls, lo, p.chanSize)
		if err != nil {
			return false, err
		}
		if len(p.tbl.Bindings()) > 0 {
			return false, p.tbl.DotProduct(tbl)
		}
		return false, p.tbl.AppendTable(tbl)
	}
	if exist > 0 && exist < total {
		// Data is partially bound, retrieve data either extends the row with the
		// new bindings or filters it out if now new bindings are available.
		return false, p.specifyClauseWithTable(ctx, cls, lo)
	}
	if exist > 0 && exist == total {
		// Since all bindings in the clause are already solved, the clause becomes a
		// fully specified triple. If the triple does not exist the row will be
		// deleted.
		return false, p.filterOnExistence(ctx, cls, lo)
	}
	// Something is wrong with the code.
	return false, fmt.Errorf("queryPlan.processClause(%v) should have never failed to resolve the clause", cls)
}
Example #5
0
// simpleFetch returns a table containing the data specified by the graph
// clause by querying the provided stora. Will return an error if it had poblems
// retrieveing the data.
func simpleFetch(gs []storage.Graph, cls *semantic.GraphClause, lo *storage.LookupOptions) (*table.Table, error) {
	s, p, o := cls.S, cls.P, cls.O
	lo = updateTimeBounds(lo, cls)
	tbl, err := table.New(cls.Bindings())
	if err != nil {
		return nil, err
	}
	if s != nil && p != nil && o != nil {
		// Fully qualified triple.
		t, err := triple.New(s, p, o)
		if err != nil {
			return nil, err
		}
		for _, g := range gs {
			b, err := g.Exist(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); err != nil {
					return nil, err
				}
			}
		}
		return tbl, nil
	}
	if s != nil && p != nil && o == nil {
		// SP request.
		for _, g := range gs {
			os, err := g.Objects(s, p, lo)
			if err != nil {
				return nil, err
			}
			var ros []*triple.Object
			for o := range os {
				ros = append(ros, o)
			}
			ts := make(chan *triple.Triple, len(ros))
			for _, o := range ros {
				t, err := triple.New(s, p, o)
				if err != nil {
					return nil, err
				}
				ts <- t
			}
			close(ts)
			if err := addTriples(ts, cls, tbl); err != nil {
				return nil, err
			}
		}
		return tbl, nil
	}
	if s != nil && p == nil && o != nil {
		// SO request.
		for _, g := range gs {
			ps, err := g.PredicatesForSubjectAndObject(s, o, lo)
			if err != nil {
				return nil, err
			}
			var rps []*predicate.Predicate
			for p := range ps {
				rps = append(rps, p)
			}
			ts := make(chan *triple.Triple, len(rps))
			for _, p := range rps {
				t, err := triple.New(s, p, o)
				if err != nil {
					return nil, err
				}
				ts <- t
			}
			close(ts)
			if err := addTriples(ts, cls, tbl); err != nil {
				return nil, err
			}
		}
		return tbl, nil
	}
	if s == nil && p != nil && o != nil {
		// PO request.
		for _, g := range gs {
			ss, err := g.Subjects(p, o, lo)
			if err != nil {
				return nil, err
			}
			var rss []*node.Node
			for s := range ss {
				rss = append(rss, s)
			}
			ts := make(chan *triple.Triple, len(rss))
			for _, s := range rss {
				t, err := triple.New(s, p, o)
				if err != nil {
					return nil, err
				}
				ts <- t
			}
			close(ts)
			if err := addTriples(ts, cls, tbl); err != nil {
				return nil, err
			}
		}
		return tbl, nil
	}
	if s != nil && p == nil && o == nil {
		// S request.
		for _, g := range gs {
			ts, err := g.TriplesForSubject(s, lo)
			if err != nil {
				return nil, err
			}
			if err := addTriples(ts, cls, tbl); err != nil {
				return nil, err
			}
		}
		return tbl, nil
	}
	if s == nil && p != nil && o == nil {
		// P request.
		for _, g := range gs {
			ts, err := g.TriplesForPredicate(p, lo)
			if err != nil {
				return nil, err
			}
			if err := addTriples(ts, cls, tbl); err != nil {
				return nil, err
			}
		}
		return tbl, nil
	}
	if s == nil && p == nil && o != nil {
		// O request.
		for _, g := range gs {
			ts, err := g.TriplesForObject(o, lo)
			if err != nil {
				return nil, err
			}
			if err := addTriples(ts, cls, tbl); err != nil {
				return nil, err
			}
		}
		return tbl, nil
	}
	if s == nil && p == nil && o == nil {
		// Full data request.
		for _, g := range gs {
			ts, err := g.Triples()
			if err != nil {
				return nil, err
			}
			if err := addTriples(ts, cls, tbl); err != nil {
				return nil, err
			}
		}
		return tbl, nil
	}

	return nil, fmt.Errorf("planner.simpleFetch could not recognize request in clause %v", cls)
}
Example #6
0
// filterOnExistance removes rows based on the existance of the fully qualified
// triple after the biding of the clause.
func (p *queryPlan) filterOnExistance(cls *semantic.GraphClause, lo *storage.LookupOptions) error {
	for idx, r := range p.tbl.Rows() {
		sbj, prd, obj := cls.S, cls.P, cls.O
		// Attempt to rebind the subject.
		if sbj == nil && p.tbl.HasBinding(cls.SBinding) {
			v, ok := r[cls.SBinding]
			if !ok {
				return fmt.Errorf("row %+v misses binding %q", r, cls.SBinding)
			}
			if v.N == nil {
				return fmt.Errorf("binding %q requires a node, got %+v instead", cls.SBinding, v)
			}
			sbj = v.N
		}
		if sbj == nil && p.tbl.HasBinding(cls.SAlias) {
			v, ok := r[cls.SAlias]
			if !ok {
				return fmt.Errorf("row %+v misses binding %q", r, cls.SAlias)
			}
			if v.N == nil {
				return fmt.Errorf("binding %q requires a node, got %+v instead", cls.SAlias, v)
			}
			sbj = v.N
		}
		// Attempt to rebind the predicate.
		if prd == nil && p.tbl.HasBinding(cls.PBinding) {
			v, ok := r[cls.PBinding]
			if !ok {
				return fmt.Errorf("row %+v misses binding %q", r, cls.PBinding)
			}
			if v.P == nil {
				return fmt.Errorf("binding %q requires a predicate, got %+v instead", cls.PBinding, v)
			}
			prd = v.P
		}
		if prd == nil && p.tbl.HasBinding(cls.PAlias) {
			v, ok := r[cls.PAlias]
			if !ok {
				return fmt.Errorf("row %+v misses binding %q", r, cls.SAlias)
			}
			if v.N == nil {
				return fmt.Errorf("binding %q requires a predicate, got %+v instead", cls.SAlias, v)
			}
			prd = v.P
		}
		// Attempt to rebind the object.
		if obj == nil && p.tbl.HasBinding(cls.PBinding) {
			v, ok := r[cls.OBinding]
			if !ok {
				return fmt.Errorf("row %+v misses binding %q", r, cls.OBinding)
			}
			if v.P == nil {
				return fmt.Errorf("binding %q requires a object, got %+v instead", cls.OBinding, v)
			}
			co, err := cellToObject(v)
			if err != nil {
				return err
			}
			obj = co
		}
		if obj == nil && p.tbl.HasBinding(cls.OAlias) {
			v, ok := r[cls.OAlias]
			if !ok {
				return fmt.Errorf("row %+v misses binding %q", r, cls.OAlias)
			}
			if v.N == nil {
				return fmt.Errorf("binding %q requires a object, got %+v instead", cls.OAlias, v)
			}
			co, err := cellToObject(v)
			if err != nil {
				return err
			}
			obj = co
		}
		// Attempt to filter.
		if sbj == nil || prd == nil || obj == nil {
			return fmt.Errorf("failed to fully specify clause %v for row %+v", cls, r)
		}
		for _, g := range p.stm.Graphs() {
			t, err := triple.New(sbj, prd, obj)
			if err != nil {
				return err
			}
			gph, err := p.store.Graph(g)
			if err != nil {
				return err
			}
			b, err := gph.Exist(t)
			if err != nil {
				return err
			}
			if b {
				p.tbl.DeleteRow(idx)
			}
		}
	}
	return nil
}
Example #7
0
// newTriple creates a new triple given the parent and the descendant as an object.
func (t *treeGenerator) newTriple(parent, descendant *node.Node) (*triple.Triple, error) {
	return triple.New(parent, t.predicate, triple.NewNodeObject(descendant))
}
Example #8
0
// simpleFetch returns a table containing the data specified by the graph
// clause by querying the provided stora. Will return an error if it had poblems
// retrieveing the data.
func simpleFetch(ctx context.Context, gs []storage.Graph, cls *semantic.GraphClause, lo *storage.LookupOptions, chanSize int) (*table.Table, error) {
	s, p, o := cls.S, cls.P, cls.O
	lo = updateTimeBounds(lo, cls)
	tbl, err := table.New(cls.Bindings())
	if err != nil {
		return nil, err
	}
	if s != nil && p != nil && o != nil {
		// Fully qualified triple.
		t, err := triple.New(s, p, o)
		if err != nil {
			return nil, err
		}
		for _, g := range gs {
			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); err != nil {
					return nil, err
				}
			}
		}
		return tbl, nil
	}
	if s != nil && p != nil && o == nil {
		// SP request.
		for _, g := range gs {
			var (
				oErr error
				aErr error
				lErr error
				wg   sync.WaitGroup
			)
			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)
			}()
			for o := range os {
				if lErr != nil {
					// Drain the channel to avoid leaking goroutines.
					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 {
		// SO request.
		for _, g := range gs {
			var (
				pErr error
				aErr error
				lErr error
				wg   sync.WaitGroup
			)
			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)
			}()
			for p := range ps {
				if lErr != nil {
					// Drain the channel to avoid leaking goroutines.
					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 {
		// PO request.
		for _, g := range gs {
			var (
				pErr error
				aErr error
				lErr error
				wg   sync.WaitGroup
			)
			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)
			}()
			for s := range ss {
				if lErr != nil {
					// Drain the channel to avoid leaking goroutines.
					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 {
		// S request.
		for _, g := range gs {
			var (
				tErr error
				aErr error
				wg   sync.WaitGroup
			)
			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)
			wg.Wait()
			if tErr != nil {
				return nil, tErr
			}
			if aErr != nil {
				return nil, aErr
			}
		}
		return tbl, nil
	}
	if s == nil && p != nil && o == nil {
		// P request.
		for _, g := range gs {
			var (
				tErr error
				aErr error
				wg   sync.WaitGroup
			)
			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)
			wg.Wait()
			if tErr != nil {
				return nil, tErr
			}
			if aErr != nil {
				return nil, aErr
			}
		}
		return tbl, nil
	}
	if s == nil && p == nil && o != nil {
		// O request.
		for _, g := range gs {
			var (
				tErr error
				wg   sync.WaitGroup
			)
			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)
			wg.Wait()
			if tErr != nil {
				return nil, tErr
			}
			if aErr != nil {
				return nil, aErr
			}
		}
		return tbl, nil
	}
	if s == nil && p == nil && o == nil {
		// Full data request.
		for _, g := range gs {
			var (
				tErr error
				aErr error
				wg   sync.WaitGroup
			)
			ts := make(chan *triple.Triple, chanSize)
			wg.Add(1)
			go func() {
				defer wg.Done()
				tErr = g.Triples(ctx, ts)
			}()
			aErr = addTriples(ts, cls, tbl)
			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)
}