Author: andy
Date: Sat Jul 19 20:29:30 2014
New Revision: 1611957

URL: http://svn.apache.org/r1611957
Log:
JENA-734 : Don't move expressions involving unstable functions.

Modified:
    
jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/algebra/optimize/TransformFilterPlacement.java
    jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/expr/Expr.java
    jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/expr/ExprLib.java
    
jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/expr/ExprVisitorFunction.java
    
jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/expr/ExprWalker.java
    
jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/algebra/optimize/TestTransformFilterPlacement.java

Modified: 
jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/algebra/optimize/TransformFilterPlacement.java
URL: 
http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/algebra/optimize/TransformFilterPlacement.java?rev=1611957&r1=1611956&r2=1611957&view=diff
==============================================================================
--- 
jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/algebra/optimize/TransformFilterPlacement.java
 (original)
+++ 
jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/algebra/optimize/TransformFilterPlacement.java
 Sat Jul 19 20:29:30 2014
@@ -31,8 +31,7 @@ import com.hp.hpl.jena.sparql.algebra.Tr
 import com.hp.hpl.jena.sparql.algebra.op.* ;
 import com.hp.hpl.jena.sparql.core.BasicPattern ;
 import com.hp.hpl.jena.sparql.core.Var ;
-import com.hp.hpl.jena.sparql.expr.Expr ;
-import com.hp.hpl.jena.sparql.expr.ExprList ;
+import com.hp.hpl.jena.sparql.expr.* ;
 import com.hp.hpl.jena.sparql.util.VarUtils ;
 
 /**
@@ -100,11 +99,41 @@ public class TransformFilterPlacement ex
     @Override
     public Op transform(OpFilter opFilter, Op x) {
         ExprList exprs = opFilter.getExprs() ;
+        
+        // Extract any expressions with "nasty" cases (RAND, UUID, STRUUID and 
BNODE)
+        // which are not true functions (they return a different value every 
call so
+        // number of calls matters.  NOW is safe (returns a fixed time point 
for the whole
+        // query.
+        
+        // Phase one - check to see if work needed. 
+        ExprList exprs2 = null ;
+        for ( Expr expr : exprs ) {
+            if ( ! ExprLib.isStable(expr) ) {
+                if ( exprs2 == null )
+                    exprs2 = new ExprList() ;
+                exprs2.add(expr) ;
+            }
+        }
+        
+        // Phase 2 - if needed, split.
+        if ( exprs2 != null ) {
+            ExprList exprs1 = new ExprList() ;
+            for ( Expr expr : exprs ) {
+                // We are assuming fixup is rare. 
+                if ( ExprLib.isStable(expr) )
+                    exprs1.add(expr) ;
+            }
+            exprs = exprs1 ;
+        }
+        
         Placement placement = transform(exprs, x) ;
         if ( placement == null )  
             // Didn't do anything.
             return super.transform(opFilter, x) ;
         Op op = buildFilter(placement) ;
+        if ( exprs2 != null )
+            // Add back the non-deterministic expressions
+            op = OpFilter.filter(exprs2, op );
         return op ;
     }
 

Modified: 
jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/expr/Expr.java
URL: 
http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/expr/Expr.java?rev=1611957&r1=1611956&r2=1611957&view=diff
==============================================================================
--- jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/expr/Expr.java 
(original)
+++ jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/expr/Expr.java Sat 
Jul 19 20:29:30 2014
@@ -46,16 +46,11 @@ public interface Expr
      */ 
     public boolean isSatisfied(Binding binding, FunctionEnv execCxt) ;
   
-    /** Variables used by this expression - excludes variables scoped to 
(NOT)EXISTS*/
+    /** Variables used by this expression - excludes variables scoped to 
(NOT)EXISTS */
     public Set<Var>  getVarsMentioned() ;
-    /** Variables used by this expression - excludes variables scoped to 
(NOT)EXISTS*/
+    /** Variables used by this expression - excludes variables scoped to 
(NOT)EXISTS */
     public void varsMentioned(Collection<Var> acc) ;
     
-    /** Return true iff this constraint is implemened by something in the expr 
package
-     * and hence is fully integrated or compatible with the visitors.
-     * @return boolean
-     */
-
     /** Evaluate this expression against the binding
      * @param binding 
      * @param env

Modified: 
jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/expr/ExprLib.java
URL: 
http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/expr/ExprLib.java?rev=1611957&r1=1611956&r2=1611957&view=diff
==============================================================================
--- jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/expr/ExprLib.java 
(original)
+++ jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/expr/ExprLib.java 
Sat Jul 19 20:29:30 2014
@@ -124,5 +124,39 @@ public class ExprLib
         throw new ARQInternalErrorException() ;
     }
     
+    /** Some "functions" are non-deterministic (unstable) - 
+     * calling them with the same arguments 
+     * does not yields the same answer each time.
+     * Therefore how and when they are called
+     * matters.
+     * 
+     * Functions: RAND, UUID, StrUUID, BNode
+     * 
+     * NOW() is safe.
+     */
+    public static boolean isStable(Expr expr) {
+        try {
+            ExprWalker.walk(exprVisitorCheckForNonFunctions, expr) ;
+            return true ;
+        } catch ( ExprUnstable ex ) {
+            return false ;
+        }
+    }
+
+    private static ExprVisitor exprVisitorCheckForNonFunctions = new 
ExprVisitorBase() { 
+        @Override
+        public void visit(ExprFunction0 func) {
+            if ( func instanceof E_Random ||
+                func instanceof E_UUID ||
+                func instanceof E_StrUUID)
+                throw new ExprUnstable() ; 
+        }
+        @Override
+        public void visit(ExprFunctionN func) {
+            if (func instanceof E_BNode )
+                throw new ExprUnstable() ;
+        }
+    } ;
     
+    private static class ExprUnstable extends ExprException {}
 }

Modified: 
jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/expr/ExprVisitorFunction.java
URL: 
http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/expr/ExprVisitorFunction.java?rev=1611957&r1=1611956&r2=1611957&view=diff
==============================================================================
--- 
jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/expr/ExprVisitorFunction.java
 (original)
+++ 
jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/expr/ExprVisitorFunction.java
 Sat Jul 19 20:29:30 2014
@@ -18,7 +18,7 @@
 
 package com.hp.hpl.jena.sparql.expr;
 
-/** Convert all visit calls on the expressions in a call to a generic visit 
operation for expession functions */
+/** Convert all visit calls on the expressions in a call to a generic visit 
operation for expression functions */
 public abstract class ExprVisitorFunction implements ExprVisitor 
 {
     @Override

Modified: 
jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/expr/ExprWalker.java
URL: 
http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/expr/ExprWalker.java?rev=1611957&r1=1611956&r2=1611957&view=diff
==============================================================================
--- 
jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/expr/ExprWalker.java 
(original)
+++ 
jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/expr/ExprWalker.java 
Sat Jul 19 20:29:30 2014
@@ -17,9 +17,8 @@
  */
 
 package com.hp.hpl.jena.sparql.expr;
-// Walk the expression tree, bottom up.
-// NOT FINISHED
-public class ExprWalker //implements ExprVisitor 
+/** Walk the expression tree, bottom up */
+public class ExprWalker 
 {
     ExprVisitor visitor ;
     

Modified: 
jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/algebra/optimize/TestTransformFilterPlacement.java
URL: 
http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/algebra/optimize/TestTransformFilterPlacement.java?rev=1611957&r1=1611956&r2=1611957&view=diff
==============================================================================
--- 
jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/algebra/optimize/TestTransformFilterPlacement.java
 (original)
+++ 
jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/algebra/optimize/TestTransformFilterPlacement.java
 Sat Jul 19 20:29:30 2014
@@ -71,8 +71,8 @@ public class TestTransformFilterPlacemen
     
 
     @Test public void place_bgp_06() {
-        test("(filter (isURI ?g) (quadpattern (?g ?s ?p ?o) ))",
-             null) ;
+        testNoChange("(filter (isURI ?g) (quadpattern (?g ?s ?p ?o) ))") ;
+
     }
 
     @Test public void place_bgp_06a() {
@@ -154,15 +154,15 @@ public class TestTransformFilterPlacemen
 
     @Test public void place_no_match_01() {
         // Unbound
-        test("(filter (= ?x ?unbound) (bgp (?s ?p ?x)))", null) ;
+        testNoChange("(filter (= ?x ?unbound) (bgp (?s ?p ?x)))") ;
     }
 
     @Test public void place_no_match_02() {
-        test("(filter (= ?x ?unbound) (bgp (?s ?p ?x) (?s ?p ?x)))", null) ;
+        testNoChange("(filter (= ?x ?unbound) (bgp (?s ?p ?x) (?s ?p ?x)))") ;
     }
 
     @Test public void place_no_match_03() {
-        test("(filter (= ?x ?unbound) (bgp (?s ?p ?x) (?s1 ?p1 ?XX)))", null) ;
+        testNoChange("(filter (= ?x ?unbound) (bgp (?s ?p ?x) (?s1 ?p1 
?XX)))") ;
     }
 
     @Test public void place_sequence_01() {
@@ -210,13 +210,11 @@ public class TestTransformFilterPlacemen
     }
 
     @Test public void place_sequence_07() {
-        test("(filter (= ?A 123) (sequence (bgp (?s ?p ?x)) (bgp (?s ?p ?z)) 
))",
-             null) ;
+        testNoChange("(filter (= ?A 123) (sequence (bgp (?s ?p ?x)) (bgp (?s 
?p ?z)) ))") ;
     }
 
     @Test public void place_sequence_08() {
-        test("(sequence (bgp (?s ?p ?x)) (filter (= ?z 123) (bgp (?s ?p ?z))) 
)",
-             null) ;
+        testNoChange("(sequence (bgp (?s ?p ?x)) (filter (= ?z 123) (bgp (?s 
?p ?z))) )") ;
     }
     
     @Test public void place_sequence_09() {
@@ -314,8 +312,7 @@ public class TestTransformFilterPlacemen
     }
 
     @Test public void place_project_02() {
-        test("(filter (= ?x 123) (project (?s) (bgp (?s ?p ?x)) ))",
-             null) ;
+        testNoChange("(filter (= ?x 123) (project (?s) (bgp (?s ?p ?x)) ))") ;
     }
     
     @Test public void place_project_03() {
@@ -597,12 +594,69 @@ public class TestTransformFilterPlacemen
              ) ; 
         test( in, out ) ;
     }
+    
+    @Test public void nondeterministic_functions_01() {
+        testNoChange("(filter (= ?x (rand)) (bgp (?s ?p ?x) (?s1 ?p1 ?x)))") ;
+    }
         
+    @Test public void nondeterministic_functions_02() {
+        testNoChange("(filter (= ?x (bnode)) (bgp (?s ?p ?x) (?s1 ?p1 ?x)))") ;
+    }
+
+    @Test public void nondeterministic_functions_03() {
+        testNoChange("(filter (= ?x (struuid)) (bgp (?s ?p ?x) (?s1 ?p1 
?x)))") ;
+    }
+
+    @Test public void nondeterministic_functions_04() {
+        testNoChange("(filter (= ?x (uuid)) (bgp (?s ?p ?x) (?s1 ?p1 ?x)))") ;
+    }
+
+    // NOW() is safe.
+    @Test public void nondeterministic_functions_05() {
+        test("(filter (= ?x (now)) (bgp (?s ?p ?x) (?s1 ?p1 ?x)))",
+             "(sequence  (filter (= ?x (now)) (bgp (?s ?p ?x) ))  (bgp (?s1 
?p1 ?x)) )") ;
+    }
+
+    @Test public void nondeterministic_functions_06() {
+        String in = StrUtils.strjoinNL
+            ("(filter ( (!= ?x ?s) (= ?x (rand)) )"
+            ,"   (bgp (?s ?p ?x) (?s1 ?p1 ?x))"
+            ,")") ;
+        String out = StrUtils.strjoinNL
+            ("(filter (= ?x (rand)) "
+            ,"  (sequence"
+            ,"     (filter (!= ?x ?s) (bgp (?s ?p ?x)))"
+            ,"     (bgp (?s1 ?p1 ?x))"
+            ,"))"
+            ) ;
+        test(in,out) ;
+    }
+
+    @Test public void nondeterministic_functions_07() {
+        String in = StrUtils.strjoinNL
+            ("(filter ( (!= ?x ?s) (|| ?x (rand)) )"
+            ,"   (bgp (?s ?p ?x) (?s1 ?p1 ?x))"
+            ,")") ;
+        String out = StrUtils.strjoinNL
+            ("(filter (|| ?x (rand)) "
+            ,"  (sequence"
+            ,"     (filter (!= ?x ?s) (bgp (?s ?p ?x)))"
+            ,"     (bgp (?s1 ?p1 ?x))"
+            ,"))"
+            ) ;
+        test(in,out) ;
+    }
+
+    
+    public static void testNoChange(String input) {
+        test(input, null) ;
+    }
+
     public static void test(String input, String output) {
         test$(input, output, true) ;
     }
 
-    public static void testNoBGP(String input , String output ) {
+    public static void testNoBGP(String input , String output) {
         test$(input, output, false) ;
     }
         


Reply via email to