Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BIND operator broken since 7.0 #78

Open
lucafabbian opened this issue Nov 29, 2022 · 1 comment
Open

BIND operator broken since 7.0 #78

lucafabbian opened this issue Nov 29, 2022 · 1 comment
Labels
bug Something isn't working

Comments

@lucafabbian
Copy link

Describe the bug
Bind operator working wrong since 7.0

To Reproduce
Just use a query with BIND inside one of the examples (here I chose the one about using a storage based on N3.js).

'use strict'

const { Parser, Store } = require('n3')
const { HashMapDataset, Graph, PlanBuilder } = require('sparql-engine')

// Format a triple pattern according to N3 API:
// SPARQL variables must be replaced by `null` values
function formatTriplePattern (triple) {
  let subject = null
  let predicate = null
  let object = null
  if (!triple.subject.startsWith('?')) {
    subject = triple.subject
  }
  if (!triple.predicate.startsWith('?')) {
    predicate = triple.predicate
  }
  if (!triple.object.startsWith('?')) {
    object = triple.object
  }
  return { subject, predicate, object }
}

class N3Graph extends Graph {
  constructor () {
    super()
    this._store = Store()
  }

  insert (triple) {
    return new Promise((resolve, reject) => {
      try {
        this._store.addTriple(triple.subject, triple.predicate, triple.object)
        resolve()
      } catch (e) {
        reject(e)
      }
    })
  }

  delete (triple) {
    return new Promise((resolve, reject) => {
      try {
        this._store.removeTriple(triple.subject, triple.predicate, triple.object)
        resolve()
      } catch (e) {
        reject(e)
      }
    })
  }

  find (triple) {
    const { subject, predicate, object } = formatTriplePattern(triple)
    return this._store.getTriples(subject, predicate, object)
  }

  estimateCardinality (triple) {
    const { subject, predicate, object } = formatTriplePattern(triple)
    return Promise.resolve(this._store.countTriples(subject, predicate, object))
  }
}

const graph = new N3Graph()
const dataset = new HashMapDataset('http://example.org#default', graph)

// Load some RDF data into the graph
const parser = new Parser()
parser.parse(`
  @prefix foaf: <http://xmlns.com/foaf/0.1/> .
  @prefix : <http://example.org#> .
  :a foaf:name "a" .
  :b foaf:name "b" .
`).forEach(t => {
  graph._store.addTriple(t)
})

const query = `
  PREFIX foaf: <http://xmlns.com/foaf/0.1/>
  SELECT ?s ?name
  WHERE {
    BIND(<http://example.org#a> as ?s)
    ?s foaf:name ?name .
  }`

// Creates a plan builder for the RDF dataset
const builder = new PlanBuilder(dataset)

// Get an iterator to evaluate the query
const iterator = builder.build(query)

// Read results
iterator.subscribe(bindings => {
  console.log('Found solution:', bindings.toObject())
}, err => {
  console.error('error', err)
}, () => {
  console.log('Query evaluation complete!')
})

Expected behavior
On 6.0 and below, I get the expected result:

Found solution: { '?s': 'http://example.org#a', '?name': '"a"' }
Query evaluation complete!

While on 7.0 and above, I get:

Found solution: { '?s': 'http://example.org#a', '?name': '"a"' }
Found solution: { '?s': 'http://example.org#a', '?name': '"b"' }
Query evaluation complete!
@Callidon
Copy link
Owner

Hi,

Thank you for using sparql-engine 👍 It is in deed a regression: in v0.7.0, we introduced a query plan optimizer, to, optimize the execution plan regardless of the syntax of the query. However, we didn't account for the very special case your issue highlight: a BIND clause sued to feed data into the res tof the query. The plan optimizer doesn't recognize the dependency between the BIND clause and the triple patterns, and pushes the BIND evaluation after the triple pattern evaluation. This pattern is evaluated first and then the BIND overrides ?s with http://example.org#a, leading to this results.

I will look into this if there's a quick fix, thank you for sharing it!

@Callidon Callidon added the bug Something isn't working label Nov 30, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants