// newQueryPlan returns a new query plan ready to be excecuted. func newQueryPlan(store storage.Store, stm *semantic.Statement) (*queryPlan, error) { bs := []string{} for _, b := range stm.Bindings() { bs = append(bs, b) } t, err := table.New([]string{}) if err != nil { return nil, err } var gs []storage.Graph for _, g := range stm.Graphs() { ng, err := store.Graph(g) if err != nil { return nil, err } gs = append(gs, ng) } return &queryPlan{ stm: stm, store: store, bndgs: bs, grfs: gs, grfsNames: stm.Graphs(), cls: stm.SortedGraphPatternClauses(), tbl: t, }, nil }
// Execute queries the indicated graphs. func (p *queryPlan) Execute(ctx context.Context) (*table.Table, error) { // Retrieve the data. lo := p.stm.GlobalLookupOptions() if err := p.processGraphPattern(ctx, lo); err != nil { return nil, err } if err := p.projectAndGroupBy(); err != nil { return nil, err } p.orderBy() err := p.having() if err != nil { return nil, err } p.limit() if p.tbl.NumRows() == 0 { // Correct the bindings. t, err := table.New(p.stm.OutputBindings()) if err != nil { return nil, err } p.tbl = t } return p.tbl, nil }
func TestAddTriples(t *testing.T) { testBindings := []string{"?s", "?p", "?o"} cls := &semantic.GraphClause{ SBinding: "?s", PBinding: "?p", OBinding: "?o", } g, err := getTestStore(t).Graph("?test") if err != nil { t.Fatal(err) } ts, err := g.Triples() if err != nil { t.Fatal(err) } tbl, err := table.New([]string{}) if err != nil { t.Fatal(err) } if err := addTriples(ts, cls, tbl); err != nil { t.Errorf("addTriple failed with errorf %v", err) } if got, want := tbl.NumRows(), len(testTextTriples); got != want { t.Errorf("addTriples returned the wrong number of rows; got %d, want %d", got, want) } for _, r := range tbl.Rows() { if got, want := len(r), len(testBindings); got != want { t.Errorf("addTriples returned row %v with the incorrect number of bindings; got %d, want %d", r, got, want) } } }
// Execute deletes the provided data into the indicated graphs. func (p *deletePlan) Excecute() (*table.Table, error) { t, err := table.New([]string{}) if err != nil { return nil, err } return t, update(p.stm, p.store, func(g storage.Graph, d []*triple.Triple) error { return g.RemoveTriples(d) }) }
// Execute inserts the provided data into the indicated graphs. 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, p.store, func(g storage.Graph, d []*triple.Triple) error { return g.AddTriples(ctx, d) }) }
// 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) (*table.Table, error) { tbl, err := table.New(cls.Bindings()) if err != nil { return nil, err } if cls.S != nil && cls.P != nil && cls.O != nil { // Fully qualified triple. // TODO(xllora): Implement. return nil, nil } if cls.S != nil && cls.P != nil && cls.O == nil { // SP request. // TODO(xllora): Implement. return nil, nil } if cls.S != nil && cls.P == nil && cls.O != nil { // SO request. // TODO(xllora): Implement. return nil, nil } if cls.S == nil && cls.P != nil && cls.O != nil { // PO request. // TODO(xllora): Implement. return nil, nil } if cls.S != nil && cls.P == nil && cls.O == nil { // S request. // TODO(xllora): Implement. return nil, nil } if cls.S == nil && cls.P != nil && cls.O == nil { // P request. // TODO(xllora): Implement. return nil, nil } if cls.S == nil && cls.P == nil && cls.O != nil { // O request. // TODO(xllora): Implement. return nil, nil } if cls.S == nil && cls.P == nil && cls.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) }
// OutputTable returns the expected result table for the must result table // provided by the story. func (a *Assertion) OutputTable(bo []string) (*table.Table, error) { // Return the already computed output table. if a.table != nil { return a.table, nil } // Compute the output table. var ( first bool mBdngs map[string]bool data []table.Row bs []string ) mBdngs, first = make(map[string]bool), true for _, row := range a.MustReturn { nr := table.Row{} for k, v := range row { _, ok := mBdngs[k] if first && !ok { bs = append(bs, k) } if !first && !ok { return nil, fmt.Errorf("unknow binding %q; available ones are %v", k, mBdngs) } mBdngs[k], nr[k] = true, inferCell(v) } data = append(data, nr) first = false } if first { // No data was provided. This will create the empty table with the right // bindings. bs = bo } // Build the table. if len(bo) != len(bs) { return nil, fmt.Errorf("incompatible bindings; got %v, want %v", bs, bo) } for _, b := range bo { if _, ok := mBdngs[b]; !first && !ok { return nil, fmt.Errorf("missing binding %q; want bining in %v", b, bo) } } t, err := table.New(bo) if err != nil { return nil, err } for _, r := range data { t.AddRow(r) } return t, nil }
// Execute drops the indicated graphs. func (p *dropPlan) Excecute() (*table.Table, error) { t, err := table.New([]string{}) if err != nil { return nil, err } errs := []string{} for _, g := range p.stm.Graphs() { if err := p.store.DeleteGraph(g); err != nil { errs = append(errs, err.Error()) } } if len(errs) > 0 { return nil, errors.New(strings.Join(errs, "; ")) } return t, nil }
// Execute creates the indicated graphs. func (p *createPlan) Execute(ctx context.Context) (*table.Table, error) { t, err := table.New([]string{}) if err != nil { return nil, err } errs := []string{} for _, g := range p.stm.Graphs() { if _, err := p.store.NewGraph(ctx, g); err != nil { errs = append(errs, err.Error()) } } if len(errs) > 0 { return nil, errors.New(strings.Join(errs, "; ")) } return t, nil }
func TestDataAccessAddTriples(t *testing.T) { ctx := context.Background() testBindings := []string{"?s", "?p", "?o"} cls := &semantic.GraphClause{ SBinding: "?s", PBinding: "?p", OBinding: "?o", } g, err := getTestStore(t, testImmutatbleTriples).Graph(ctx, "?test") if err != nil { t.Fatal(err) } tbl, err := table.New([]string{}) if err != nil { t.Fatal(err) } var wg sync.WaitGroup wg.Add(2) ts := make(chan *triple.Triple) go func() { defer wg.Done() if err := g.Triples(ctx, ts); err != nil { t.Fatal(err) } }() go func() { defer wg.Done() if err := addTriples(ts, cls, tbl); err != nil { t.Errorf("addTriple failed with errorf %v", err) } }() wg.Wait() if got, want := tbl.NumRows(), len(testImmutatbleTriples); got != want { t.Errorf("addTriples returned the wrong number of rows; got %d, want %d", got, want) } for _, r := range tbl.Rows() { if got, want := len(r), len(testBindings); got != want { t.Errorf("addTriples returned row %v with the incorrect number of bindings; got %d, want %d", r, got, want) } } }
// simpleExist returns true if the triple exist. Return the unfeasible state, // the table and the error if present. func simpleExist(gs []storage.Graph, cls *semantic.GraphClause, t *triple.Triple) (bool, *table.Table, error) { unfeasible := true tbl, err := table.New(cls.Bindings()) if err != nil { return true, nil, err } for _, g := range gs { b, err := g.Exist(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); err != nil { return true, nil, err } } } return unfeasible, tbl, nil }
// 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) }
// 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) }