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 } }" +