You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by an...@apache.org on 2011/12/28 19:46:32 UTC
svn commit: r1225272 - in /incubator/jena/Jena2/ARQ/trunk: ./
src/main/java/com/hp/hpl/jena/sparql/lang/
src/main/java/com/hp/hpl/jena/sparql/syntax/
src/main/java/com/hp/hpl/jena/sparql/util/
src/test/java/com/hp/hpl/jena/sparql/lang/
Author: andy
Date: Wed Dec 28 18:46:31 2011
New Revision: 1225272
URL: http://svn.apache.org/viewvc?rev=1225272&view=rev
Log:
JENA-142 Scope tracking of variables.
Modified:
incubator/jena/Jena2/ARQ/trunk/ChangeLog.txt
incubator/jena/Jena2/ARQ/trunk/src/main/java/com/hp/hpl/jena/sparql/lang/SyntaxVarScope.java
incubator/jena/Jena2/ARQ/trunk/src/main/java/com/hp/hpl/jena/sparql/syntax/ElementWalker.java
incubator/jena/Jena2/ARQ/trunk/src/main/java/com/hp/hpl/jena/sparql/syntax/PatternVarsVisitor.java
incubator/jena/Jena2/ARQ/trunk/src/main/java/com/hp/hpl/jena/sparql/syntax/RecursiveElementVisitor.java
incubator/jena/Jena2/ARQ/trunk/src/main/java/com/hp/hpl/jena/sparql/util/VarUtils.java
incubator/jena/Jena2/ARQ/trunk/src/test/java/com/hp/hpl/jena/sparql/lang/TestVarScope.java
Modified: incubator/jena/Jena2/ARQ/trunk/ChangeLog.txt
URL: http://svn.apache.org/viewvc/incubator/jena/Jena2/ARQ/trunk/ChangeLog.txt?rev=1225272&r1=1225271&r2=1225272&view=diff
==============================================================================
--- incubator/jena/Jena2/ARQ/trunk/ChangeLog.txt (original)
+++ incubator/jena/Jena2/ARQ/trunk/ChangeLog.txt Wed Dec 28 18:46:31 2011
@@ -3,11 +3,16 @@ ChangeLog for ARQ
==== ARQ 2.9.1
++ SPARQL 1.1: Complete scope tracking of variables (JENA-142)
++ Faster writing of XML and JSON results formats (JENA-178)
+
+
==== ARQ 2.8.9 / 2.9.0
** Java 6 is now required for running ARQ.
-+ ARQ: Provides \-escapes for characters ~.-!$&'()*+,;=:/?#@% in local part of prefix names
-+ ARQ: Allow %xx in the local part of prefix names
++ SPARQL 1.1: Provides \-escapes for characters ~.-!$&'()*+,;=:/?#@%
+ in local part of prefix names
++ SPARQl 1.1: Allow %xx in the local part of prefix names
+ SPARQL 1.1 / RDF 1.1 : DATATYPE(literal-with-lang) is now rdf:langString, not an error.
+ DatasetFactory: perferred methods for an in-memory dataset are:
create() -- will automatically add in-memory named graphs
Modified: incubator/jena/Jena2/ARQ/trunk/src/main/java/com/hp/hpl/jena/sparql/lang/SyntaxVarScope.java
URL: http://svn.apache.org/viewvc/incubator/jena/Jena2/ARQ/trunk/src/main/java/com/hp/hpl/jena/sparql/lang/SyntaxVarScope.java?rev=1225272&r1=1225271&r2=1225272&view=diff
==============================================================================
--- incubator/jena/Jena2/ARQ/trunk/src/main/java/com/hp/hpl/jena/sparql/lang/SyntaxVarScope.java (original)
+++ incubator/jena/Jena2/ARQ/trunk/src/main/java/com/hp/hpl/jena/sparql/lang/SyntaxVarScope.java Wed Dec 28 18:46:31 2011
@@ -56,6 +56,8 @@ public class SyntaxVarScope
* SubQuery done as a separate pass.
* Combine finalization with findAndAddNamedVars/setResultVars
*/
+
+ // Weakness : EXISTS inside FILTERs?
public static void check(Query query)
{
@@ -76,12 +78,8 @@ public class SyntaxVarScope
// Check BIND by accumulating variables and making sure BIND does not attempt to reuse one
private static void checkBind(Query query)
{
- LinkedHashSet<Var> queryVars = new LinkedHashSet<Var>() ;
- BindScopeChecker visitor = new BindScopeChecker(queryVars) ;
- //PatternVars.vars(query.getQueryPattern(), visitor) ;
-
- ElementWalker.Walker walker = new ScopeWalker(visitor) ;
- ElementWalker.walk(query.getQueryPattern(), walker) ;
+ HashSet<Var> queryVars = new HashSet<Var>() ;
+ scopeVars(queryVars, query.getQueryPattern()) ;
}
// Check subquery by finding subquries and recurisively checking.
@@ -239,26 +237,16 @@ public class SyntaxVarScope
}
}
- /** Accumulate pattern variables but include some checking (BIND) as well */
- private static class BindScopeChecker extends PatternVarsVisitor
+ // Special version of walker for scoping rules.
+
+ private static void scopeVars(Collection<Var> acc, Element e)
{
- public BindScopeChecker(Set<Var> s)
- {
- super(s) ;
- }
-
- @Override
- public void visit(ElementBind el)
- {
- Var var = el.getVar() ;
-
- if ( acc.contains(var) )
- throw new QueryParseException("BIND: Variable used when already in-scope: "+var+" in "+el, -1 , -1) ;
- checkAssignment(acc, el.getExpr(), var) ;
- }
+ PatternVarsVisitor pvv = new PatternVarsVisitor(acc) ;
+ ScopeWalker sw = new ScopeWalker(pvv) ;
+ e.visit(sw) ;
}
-
- // Special version of walker for scoping rules.
+
+ // Applies scope rules and does the structure walk.
public static class ScopeWalker extends ElementWalker.Walker
{
@@ -274,21 +262,16 @@ public class SyntaxVarScope
public void visit(ElementMinus el)
{
// Don't go down the RHS of MINUS
- //if ( el.getMinusElement() != null )
- // el.getMinusElement().visit(this) ;
proc.visit(el) ;
}
- // It is a top-down walk, so on enter an element of group or UNION,
- // then the entry set is
-
// Isolate elements of UNION
@Override
public void visit(ElementUnion el)
{
- Set<Var> accState = new HashSet<Var>(pvVisitor.acc) ;
- doMultipleIndependent(accState, el.getElements()) ;
- pvVisitor.acc = accState ;
+ Collection<Var> accGroup = pvVisitor.acc ;
+ for ( Element e : el.getElements() )
+ nestedScope(accGroup, e) ;
proc.visit(el) ;
}
@@ -300,28 +283,66 @@ public class SyntaxVarScope
// FILTER end of group
// All other elements (SERVICE?) outcome is only to the overall results.
-// @Override
-// public void visit(ElementGroup el)
-// {
-// // But BIND needs to be does over end of group.
-// // Ditto FILTER tests.
-// Set<Var> accState = new HashSet<Var>(pvVisitor.acc) ;
-// doMultipleIndependent(accState, el.getElements()) ;
-// pvVisitor.acc = accState ;
-// proc.visit(el) ;
-// }
+ @Override
+ public void visit(ElementGroup el)
+ {
+ // Ther are two kinds of elements: ones that accumulate variables
+ // across the group and ones that isolate a subexpression to be joined
+ // with other and the group itself.
+ // Scoped: UNION, Group, OPTIONAL, (MINUS), SERVICE, SubSELECT
+ // Acumulating: BGPs, paths, BIND, LET
+
+ Collection<Var> accGroup = pvVisitor.acc ; // Accumulate as we go.
+
+ for ( Element e : el.getElements() )
+ {
+ if ( scoped(e) )
+ nestedScope(accGroup, e) ;
+ else
+ scopeVars(accGroup, e) ;
+ }
+ proc.visit(el) ;
+ }
+ private void nestedScope(Collection<Var> accGroup , Element e )
+ {
+ // New scope accumulator.
+ Collection<Var> x = new HashSet<Var>() ;
+ scopeVars(x, e) ;
+ accGroup.addAll(x) ;
+ }
- private void doMultipleIndependent(Set<Var> agg, List<Element> elements)
+ private static boolean scoped(Element e)
+ {
+ return e instanceof ElementGroup ||
+ e instanceof ElementUnion ||
+ e instanceof ElementOptional ||
+ e instanceof ElementService ||
+ e instanceof ElementSubQuery ;
+ }
+
+ // Inside filters.
+
+ @Override
+ public void visit(ElementBind el)
+ {
+ Var var = el.getVar() ;
+
+ if ( pvVisitor.acc.contains(var) )
+ throw new QueryParseException("BIND: Variable used when already in-scope: "+var+" in "+el, -1 , -1) ;
+ checkAssignment(pvVisitor.acc, el.getExpr(), var) ;
+ }
+
+
+
+ @Override
+ public void visit(ElementService el)
{
- // agg is empty?
- for ( Element e : elements )
+ if ( el.getServiceNode().isVariable() )
{
- pvVisitor.acc.clear() ;
- // Do subelement.
- e.visit(this) ;
- // Accumulate for final result.
- agg.addAll(pvVisitor.acc) ;
+ Var var = Var.alloc(el.getServiceNode()) ;
+ if ( ! pvVisitor.acc.contains(var) )
+ throw new QueryParseException("SERVICE: Variable not already in-scope: "+var+" in "+el, -1 , -1) ;
}
}
Modified: incubator/jena/Jena2/ARQ/trunk/src/main/java/com/hp/hpl/jena/sparql/syntax/ElementWalker.java
URL: http://svn.apache.org/viewvc/incubator/jena/Jena2/ARQ/trunk/src/main/java/com/hp/hpl/jena/sparql/syntax/ElementWalker.java?rev=1225272&r1=1225271&r2=1225272&view=diff
==============================================================================
--- incubator/jena/Jena2/ARQ/trunk/src/main/java/com/hp/hpl/jena/sparql/syntax/ElementWalker.java (original)
+++ incubator/jena/Jena2/ARQ/trunk/src/main/java/com/hp/hpl/jena/sparql/syntax/ElementWalker.java Wed Dec 28 18:46:31 2011
@@ -19,12 +19,12 @@
package com.hp.hpl.jena.sparql.syntax;
-
/** An element visitor that walks the graph pattern tree,
* applying a visitor at each Element traversed.
- * Only walks one level of the query (not subqueries -- sub SELECT, (NOT)EXISTS
- * these will need to call down themselves if it is meaningful for the visitor.
- * Bottom-up walk - apply to subelements before applying to current element. */
+ * Does not (NOT)EXISTS in filters.
+ * These will need to call down themselves if it is meaningful for the visitor.
+ * Bottom-up walk - apply to subelements before applying to current element.
+ */
public class ElementWalker
{
@@ -49,7 +49,10 @@ public class ElementWalker
static public class Walker implements ElementVisitor
{
protected ElementVisitor proc ;
- protected Walker(ElementVisitor visitor) { proc = visitor ; }
+ protected Walker(ElementVisitor visitor)
+ {
+ proc = visitor ;
+ }
@Override
public void visit(ElementTriplesBlock el)
@@ -129,22 +132,17 @@ public class ElementWalker
proc.visit(el) ;
}
- // EXISTs, NOT EXISTs are really subqueries so don't automatically walk down them.
- // NB They also occur in FILTERs via expressions.
+ // EXISTs, NOT EXISTs also occur in FILTERs via expressions.
@Override
public void visit(ElementExists el)
{
-// if ( el.getElement() != null )
-// el.getElement().visit(this) ;
proc.visit(el) ;
}
@Override
public void visit(ElementNotExists el)
{
-// if ( el.getElement() != null )
-// el.getElement().visit(this) ;
proc.visit(el) ;
}
@@ -159,10 +157,6 @@ public class ElementWalker
@Override
public void visit(ElementSubQuery el)
{
- // Only walk this level.
-// Element el2 = el.getQuery().getQueryPattern() ;
-// if ( el2 != null )
-// el2.visit(this) ;
proc.visit(el) ;
}
Modified: incubator/jena/Jena2/ARQ/trunk/src/main/java/com/hp/hpl/jena/sparql/syntax/PatternVarsVisitor.java
URL: http://svn.apache.org/viewvc/incubator/jena/Jena2/ARQ/trunk/src/main/java/com/hp/hpl/jena/sparql/syntax/PatternVarsVisitor.java?rev=1225272&r1=1225271&r2=1225272&view=diff
==============================================================================
--- incubator/jena/Jena2/ARQ/trunk/src/main/java/com/hp/hpl/jena/sparql/syntax/PatternVarsVisitor.java (original)
+++ incubator/jena/Jena2/ARQ/trunk/src/main/java/com/hp/hpl/jena/sparql/syntax/PatternVarsVisitor.java Wed Dec 28 18:46:31 2011
@@ -18,8 +18,8 @@
package com.hp.hpl.jena.sparql.syntax;
+import java.util.Collection ;
import java.util.Iterator ;
-import java.util.Set ;
import com.hp.hpl.jena.graph.Triple ;
import com.hp.hpl.jena.sparql.core.TriplePath ;
@@ -29,8 +29,8 @@ import com.hp.hpl.jena.sparql.util.VarUt
public class PatternVarsVisitor extends ElementVisitorBase
{
- public Set<Var> acc ;
- public PatternVarsVisitor(Set<Var> s) { acc = s ; }
+ public Collection<Var> acc ;
+ public PatternVarsVisitor(Collection<Var> s) { acc = s ; }
@Override
public void visit(ElementTriplesBlock el)
Modified: incubator/jena/Jena2/ARQ/trunk/src/main/java/com/hp/hpl/jena/sparql/syntax/RecursiveElementVisitor.java
URL: http://svn.apache.org/viewvc/incubator/jena/Jena2/ARQ/trunk/src/main/java/com/hp/hpl/jena/sparql/syntax/RecursiveElementVisitor.java?rev=1225272&r1=1225271&r2=1225272&view=diff
==============================================================================
--- incubator/jena/Jena2/ARQ/trunk/src/main/java/com/hp/hpl/jena/sparql/syntax/RecursiveElementVisitor.java (original)
+++ incubator/jena/Jena2/ARQ/trunk/src/main/java/com/hp/hpl/jena/sparql/syntax/RecursiveElementVisitor.java Wed Dec 28 18:46:31 2011
@@ -26,9 +26,9 @@ package com.hp.hpl.jena.sparql.syntax;
* calling points:
* <ul>
* <li>start of element</li>
- * <li>end of element</li>
* <li>start each sub element</li>
* <li>end of each sub element</li>
+ * <li>end of element</li>
* </ul>
* </p>
*
Modified: incubator/jena/Jena2/ARQ/trunk/src/main/java/com/hp/hpl/jena/sparql/util/VarUtils.java
URL: http://svn.apache.org/viewvc/incubator/jena/Jena2/ARQ/trunk/src/main/java/com/hp/hpl/jena/sparql/util/VarUtils.java?rev=1225272&r1=1225271&r2=1225272&view=diff
==============================================================================
--- incubator/jena/Jena2/ARQ/trunk/src/main/java/com/hp/hpl/jena/sparql/util/VarUtils.java (original)
+++ incubator/jena/Jena2/ARQ/trunk/src/main/java/com/hp/hpl/jena/sparql/util/VarUtils.java Wed Dec 28 18:46:31 2011
@@ -18,6 +18,7 @@
package com.hp.hpl.jena.sparql.util;
+import java.util.Collection ;
import java.util.HashSet ;
import java.util.Set ;
@@ -35,20 +36,20 @@ public class VarUtils
return x ;
}
- public static void addVarsFromTriple(Set<Var> acc, Triple t)
+ public static void addVarsFromTriple(Collection<Var> acc, Triple t)
{
addVar(acc, t.getSubject()) ;
addVar(acc, t.getPredicate()) ;
addVar(acc, t.getObject()) ;
}
- public static void addVarsFromTriplePath(Set<Var> acc, TriplePath tpath)
+ public static void addVarsFromTriplePath(Collection<Var> acc, TriplePath tpath)
{
addVar(acc, tpath.getSubject()) ;
addVar(acc, tpath.getObject()) ;
}
- public static void addVar(Set<Var> acc, Node n)
+ public static void addVar(Collection<Var> acc, Node n)
{
if ( n == null )
return ;
Modified: incubator/jena/Jena2/ARQ/trunk/src/test/java/com/hp/hpl/jena/sparql/lang/TestVarScope.java
URL: http://svn.apache.org/viewvc/incubator/jena/Jena2/ARQ/trunk/src/test/java/com/hp/hpl/jena/sparql/lang/TestVarScope.java?rev=1225272&r1=1225271&r2=1225272&view=diff
==============================================================================
--- incubator/jena/Jena2/ARQ/trunk/src/test/java/com/hp/hpl/jena/sparql/lang/TestVarScope.java (original)
+++ incubator/jena/Jena2/ARQ/trunk/src/test/java/com/hp/hpl/jena/sparql/lang/TestVarScope.java Wed Dec 28 18:46:31 2011
@@ -22,16 +22,14 @@ import org.junit.Test ;
import org.openjena.atlas.junit.BaseTest ;
import com.hp.hpl.jena.query.Query ;
-import com.hp.hpl.jena.query.QueryFactory ;
import com.hp.hpl.jena.query.QueryException ;
-import com.hp.hpl.jena.sparql.lang.SyntaxVarScope ;
+import com.hp.hpl.jena.query.QueryFactory ;
public class TestVarScope extends BaseTest
{
private static void scope(String queryStr)
{
Query query = QueryFactory.create(queryStr) ;
- SyntaxVarScope.check(query) ;
}
@Test public void scope_01() { scope("SELECT ?x { ?s ?p ?o }") ; }
@@ -62,25 +60,37 @@ public class TestVarScope extends BaseTe
@Test (expected=QueryException.class)
public void scope_21() { scope("SELECT ?o { ?x ?p ?o } GROUP BY ?x") ; }
+
+ @Test(expected=QueryException.class)
+ public void scope_22() { scope("SELECT * { ?s ?p ?o BIND(5 AS ?o) }") ; }
- @Test public void scope_22() { scope("SELECT * { ?s ?p ?o OPTIONAL{?s ?p2 ?o2} BIND(?o2+5 AS ?z) }") ; }
+ @Test public void scope_23() { scope("SELECT * { ?s ?p ?o { BIND(5 AS ?o) } }") ; }
+
+ @Test(expected=QueryException.class)
+ public void scope_24() { scope("SELECT * { { ?s ?p ?o } BIND(5 AS ?o) }") ; }
+
+ @Test public void scope_25() { scope("SELECT * { { ?s ?p ?o } { BIND(5 AS ?o) } }") ; }
+
+ @Test public void scope_26() { scope("SELECT * { ?s ?p ?o OPTIONAL{?s ?p2 ?o2} BIND(?o2+5 AS ?z) }") ; }
@Test(expected=QueryException.class)
- public void scope_23() { scope("SELECT * { ?s ?p ?o OPTIONAL{?s ?p2 ?o2} BIND(5 AS ?o2) }") ; }
+ public void scope_27() { scope("SELECT * { ?s ?p ?o OPTIONAL{?s ?p2 ?o2} BIND(5 AS ?o2) }") ; }
@Test(expected=QueryException.class)
- public void scope_24() { scope("SELECT * { ?s ?p ?o OPTIONAL{?s ?p2 ?o2} BIND(?o+5 AS ?o2) }") ; }
+ public void scope_28() { scope("SELECT * { ?s ?p ?o OPTIONAL{?s ?p2 ?o2} BIND(?o+5 AS ?o2) }") ; }
@Test(expected=QueryException.class)
- public void scope_25() { scope("SELECT * { ?s ?p ?o OPTIONAL{?s ?p2 ?o2} BIND(5 AS ?o) }") ; }
+ public void scope_29() { scope("SELECT * { ?s ?p ?o OPTIONAL{?s ?p2 ?o2} BIND(5 AS ?o) }") ; }
+ @Test(expected=QueryException.class)
+ public void scope_31() { scope("SELECT * { { ?s ?p ?o } UNION {?s ?p2 ?o2} BIND(5 AS ?o) }") ; }
// Subqueries
@Test(expected=QueryException.class)
- public void scope_30() { scope("SELECT * { SELECT (?o+1 AS ?o) { ?s ?p ?o }}") ; }
+ public void scope_50() { scope("SELECT * { SELECT (?o+1 AS ?o) { ?s ?p ?o }}") ; }
@Test
- public void scope_31()
+ public void scope_51()
{
scope("SELECT ?y { " +
"{ { SELECT (?x AS ?y) { ?s ?p ?x } } } UNION { { SELECT (?x AS ?y) { ?s ?p ?x } } }" +
@@ -88,7 +98,7 @@ public class TestVarScope extends BaseTe
}
@Test(expected=QueryException.class)
- public void scope_32()
+ public void scope_52()
{
scope("SELECT ?y { " +
"{ { SELECT (?o+1 AS ?x) (?o+1 AS ?x) { ?s ?p ?o } } UNION { ?s ?p ?x } }" +