You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by rv...@apache.org on 2013/03/25 21:33:10 UTC

svn commit: r1460878 - in /jena/trunk: jena-arq/src/main/java/com/hp/hpl/jena/sparql/algebra/OpAsQuery.java jena-arq/src/test/java/com/hp/hpl/jena/sparql/algebra/OpAsQueryTest.java jena-fuseki/src/test/java/org/apache/jena/fuseki/TestQuery.java

Author: rvesse
Date: Mon Mar 25 20:33:10 2013
New Revision: 1460878

URL: http://svn.apache.org/r1460878
Log:
Fixes and tests for JENA-422

Allows for top level BIND to round trip (albeit as a project expression but it's semantically equivalent)
Fixes the reported issue of BIND inside a SERVICE clause not being carried to the remote service

Modified:
    jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/algebra/OpAsQuery.java
    jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/algebra/OpAsQueryTest.java
    jena/trunk/jena-fuseki/src/test/java/org/apache/jena/fuseki/TestQuery.java

Modified: jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/algebra/OpAsQuery.java
URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/algebra/OpAsQuery.java?rev=1460878&r1=1460877&r2=1460878&view=diff
==============================================================================
--- jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/algebra/OpAsQuery.java (original)
+++ jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/algebra/OpAsQuery.java Mon Mar 25 20:33:10 2013
@@ -51,11 +51,16 @@ public class OpAsQuery
         //OpWalker.walk(op, v) ;
         op.visit(v) ;
         
-        List<Var> vars = v.projectVars;
+        Set<Var> vars = v.projectVars;
         query.setQueryResultStar(vars.isEmpty()); // SELECT * unless we are projecting
         Iterator<Var> iter = vars.iterator();
         for (; iter.hasNext();) {
             Var var = iter.next();
+            
+            // Depending on where the variable comes from we may already
+            // have added this as a result variable
+            if (query.getResultVars().contains(var)) continue;
+            
             if (v.varExpression.containsKey(var))
                 query.addResultVar(var, v.varExpression.get(var));
             else
@@ -76,7 +81,7 @@ public class OpAsQuery
         private Element element = null ;
         private ElementGroup currentGroup = null ;
         private Deque<ElementGroup> stack = new ArrayDeque<ElementGroup>() ;
-        private List<Var> projectVars = Collections.emptyList() ;
+        private Set<Var> projectVars = Collections.emptySet();
         private Map<Var, Expr> varExpression = new HashMap<Var, Expr>() ;
         
         public Converter(Query query)
@@ -419,7 +424,7 @@ public class OpAsQuery
         @Override
         public void visit(OpAssign opAssign)
         {
-	    opAssign.getSubOp().visit(this) ;
+            opAssign.getSubOp().visit(this) ;
             
             // Go through each var and get the assigned expression
             for ( Var v : opAssign.getVarExprList().getVars() )
@@ -432,8 +437,15 @@ public class OpAsQuery
                 
                 // If in top level we defer assignment to SELECT section
                 // This also covers the GROUP recombine
-                // NOTE: this means we can't round trip top-level BINDs
                 if (inTopLevel()) {
+                    if (!inGroupRecombine(opAssign)) {
+                        // If not wrapped over a Group then we need to ensure we add the variable
+                        // to the list or otherwise the BIND will not round trip
+                        // Note - This does mean top level BIND will manifest as a project expression
+                        //        rather than a BIND but this is semantically equivalent so is not an issue
+                        if (projectVars.isEmpty()) projectVars = new HashSet<Var>();
+                        projectVars.add(v);
+                    }
                     varExpression.put(v, tr);
                 } else {
                     Element elt = new ElementAssign(v, e) ;
@@ -458,8 +470,15 @@ public class OpAsQuery
                 
                 // If in top level we defer assignment to SELECT section
                 // This also covers the GROUP recombine
-                // NOTE: this means we can't round trip top-level BINDs
                 if (inTopLevel()) {
+                    if (!inGroupRecombine(opExtend)) {
+                        // If not wrapped over a Group then we need to ensure we add the variable
+                        // to the list or otherwise the BIND will not round trip
+                        // Note - This does mean top level BIND will manifest as a project expression
+                        //        rather than a BIND but this is semantically equivalent so is not an issue
+                        if (projectVars.isEmpty()) projectVars = new HashSet<Var>();
+                        projectVars.add(v);
+                    }
                     varExpression.put(v, tr);
                 } else {
                     Element elt = new ElementBind(v, tr) ;
@@ -488,7 +507,7 @@ public class OpAsQuery
         {
             // Defer adding result vars until the end.
             // OpGroup generates dupes otherwise
-            this.projectVars = opProject.getVars();
+            this.projectVars = new HashSet<Var>(opProject.getVars());
             opProject.getSubOp().visit(this) ;
         }
 
@@ -596,6 +615,32 @@ public class OpAsQuery
         private ElementGroup pop() { return stack.pop(); }
         private void push(ElementGroup el) { stack.push(el); }
         private boolean inTopLevel() { return stack.size() == 0; }
+        
+        private boolean inGroupRecombine(OpExtend op) {
+            Op subOp = op.getSubOp();
+            if (subOp instanceof OpExtend) {
+                return inGroupRecombine((OpExtend)subOp);
+            } else if (subOp instanceof OpAssign) {
+                return inGroupRecombine((OpAssign)subOp);
+            } else if (subOp instanceof OpGroup) {
+                return true;
+            } else {
+                return false;
+            }
+        }
+        
+        private boolean inGroupRecombine(OpAssign op) {
+            Op subOp = op.getSubOp();
+            if (subOp instanceof OpExtend) {
+                return inGroupRecombine((OpExtend)subOp);
+            } else if (subOp instanceof OpAssign) {
+                return inGroupRecombine((OpAssign)subOp);
+            } else if (subOp instanceof OpGroup) {
+                return true;
+            } else {
+                return false;
+            }
+        }
     }
     
     /**

Modified: jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/algebra/OpAsQueryTest.java
URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/algebra/OpAsQueryTest.java?rev=1460878&r1=1460877&r2=1460878&view=diff
==============================================================================
--- jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/algebra/OpAsQueryTest.java (original)
+++ jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/algebra/OpAsQueryTest.java Mon Mar 25 20:33:10 2013
@@ -52,8 +52,10 @@ public class OpAsQueryTest {
     
     @Test
     public void testDoubleCount() {
-        Object[] result = checkQuery("select (count(?s) as ?sc) (count(?p) as ?pc) { ?s ?p ?o }");
-        assertEquals(result[0], result[1]);
+        Query[] result = checkQuery("select (count(?s) as ?sc) (count(?p) as ?pc) { ?s ?p ?o }");
+        assertEquals(2, result[1].getResultVars().size());
+        assertTrue(result[1].getResultVars().contains("sc"));
+        assertTrue(result[1].getResultVars().contains("pc"));
     }
     
     /* JENA-166 */
@@ -63,18 +65,18 @@ public class OpAsQueryTest {
         assertEquals(result[0], result[1]);
     }
     
-    // The next two tests represent an loss of information
-    // I suspect the best solution is to let this pass and the other fail
     @Test
-    public void testProject() {
+    public void testProject1() {
         Object[] result = checkQuery("SELECT (?x + 1 AS ?c) {}");
         assertEquals(result[0], result[1]);
     }
     
-    // Ambiguous, don't bother
-    public void testBind() {
-        Object[] result = checkQuery("SELECT ?c { BIND(?x + 1 AS ?c) }");
-        assertEquals(result[0], result[1]);
+    @Test
+    public void testProject2() {
+        Query[] result = checkQuery("SELECT (?x + 1 AS ?c) ?d {}");
+        assertEquals(2, result[1].getResultVars().size());
+        assertTrue(result[1].getResultVars().contains("c"));
+        assertTrue(result[1].getResultVars().contains("d"));
     }
     
     // This BIND is distinguisable, however
@@ -140,11 +142,34 @@ public class OpAsQueryTest {
         assertEquals(result[0], result[1]);
     }
     
-    public Object[] checkQuery(String query) {
+    @Test
+    public void testExtend1() {
+        //Top Level BIND should now be round trippable
+        Query[] result = checkQuery("SELECT * WHERE { ?s ?p ?o . BIND(?o AS ?x) }");
+        assertNotEquals(result[0], result[1]);
+        assertTrue(result[1].getResultVars().contains("x"));
+    }
+    
+    @Test
+    public void testExtend2() {
+        //Nested BIND should always have been round trippable
+        Query[] result = checkQuery("SELECT * WHERE { GRAPH ?g { ?s ?p ?o . BIND(?o AS ?x) } }");
+        assertEquals(result[0], result[1]);
+    }
+    
+    @Test
+    public void testExtendInService() {
+        //Original test case from JENA-422
+        Query[] result = checkQuery("SELECT * WHERE { SERVICE <http://example/endpoint> { ?s ?p ?o . BIND(?o AS ?x) } }");
+        assertEquals(result[0], result[1]);
+        assertTrue(result[1].toString().contains("BIND"));
+    }
+    
+    public Query[] checkQuery(String query) {
         Query orig = QueryFactory.create(query, Syntax.syntaxSPARQL_11);
         Op toReconstruct = Algebra.compile(orig);
         Query got = OpAsQuery.asQuery(toReconstruct);
-        Object[] r = { orig, got };
+        Query[] r = { orig, got };
         return r;
     }
     
@@ -153,7 +178,7 @@ public class OpAsQueryTest {
         Op toReconstruct = Algebra.compile(orig);
         toReconstruct = Algebra.toQuadForm(toReconstruct);
         Query got = OpAsQuery.asQuery(toReconstruct);
-        Object[] r = { orig, got };
+        Query[] r = { orig, got };
         return r;
     }
 }

Modified: jena/trunk/jena-fuseki/src/test/java/org/apache/jena/fuseki/TestQuery.java
URL: http://svn.apache.org/viewvc/jena/trunk/jena-fuseki/src/test/java/org/apache/jena/fuseki/TestQuery.java?rev=1460878&r1=1460877&r2=1460878&view=diff
==============================================================================
--- jena/trunk/jena-fuseki/src/test/java/org/apache/jena/fuseki/TestQuery.java (original)
+++ jena/trunk/jena-fuseki/src/test/java/org/apache/jena/fuseki/TestQuery.java Mon Mar 25 20:33:10 2013
@@ -30,6 +30,8 @@ import org.junit.Test ;
 import com.hp.hpl.jena.query.DatasetAccessor ;
 import com.hp.hpl.jena.query.DatasetAccessorFactory ;
 import com.hp.hpl.jena.query.* ;
+import com.hp.hpl.jena.sparql.core.Var;
+import com.hp.hpl.jena.sparql.engine.binding.Binding;
 import com.hp.hpl.jena.sparql.resultset.ResultSetCompare ;
 import com.hp.hpl.jena.sparql.sse.Item ;
 import com.hp.hpl.jena.sparql.sse.SSE ;
@@ -66,6 +68,20 @@ public class TestQuery extends BaseServe
         execQuery("SELECT * {?s ?p ?o}", 1) ;
     }
     
+    @Test public void query_recursive_01()
+    {
+        String query = "SELECT * WHERE { SERVICE <" + serviceQuery + "> { ?s ?p ?o . BIND(?o AS ?x) } }";
+        QueryExecution qExec = QueryExecutionFactory.sparqlService(serviceQuery, query);
+        ResultSet rs = qExec.execSelect();
+        
+        Var x = Var.alloc("x");
+        while (rs.hasNext()) {
+            Binding b = rs.nextBinding();
+            Assert.assertNotNull(b.get(x));
+        }
+        qExec.close();
+    }
+    
     @Test public void request_id_header_01() throws IOException
     {
         String qs = Convert.encWWWForm("ASK{}") ;