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 2015/09/08 19:10:45 UTC

[13/20] jena git commit: JENA-1023: Left join tests

JENA-1023: Left join tests


Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/56ea4f90
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/56ea4f90
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/56ea4f90

Branch: refs/heads/master
Commit: 56ea4f905391fa795c5cfdb651f83d91623337fa
Parents: 6da3c8d
Author: Andy Seaborne <an...@apache.org>
Authored: Tue Sep 8 14:19:35 2015 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Tue Sep 8 18:08:56 2015 +0100

----------------------------------------------------------------------
 .../engine/join/AbstractTestInnerJoin.java      | 124 ++--------
 .../sparql/engine/join/AbstractTestJoin.java    | 231 +++++++++++++++++--
 .../engine/join/AbstractTestLeftJoin.java       | 153 +++---------
 .../apache/jena/sparql/engine/join/TS_Join.java |   5 +
 .../jena/sparql/engine/join/TestHashJoin.java   |   3 +-
 .../sparql/engine/join/TestJoinNestedLoop.java  |   5 +-
 .../engine/join/TestJoinNestedLoopSimple.java   |   5 +-
 .../jena/sparql/engine/join/TestJoinSimple.java |   3 +-
 .../engine/join/TestLeftJoinNestedLoop.java     |  35 +++
 .../join/TestLeftJoinNestedLoopSimple.java      |  35 +++
 .../sparql/engine/join/TestLeftJoinSimple.java  |   6 +-
 11 files changed, 348 insertions(+), 257 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/56ea4f90/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/AbstractTestInnerJoin.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/AbstractTestInnerJoin.java b/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/AbstractTestInnerJoin.java
index f5a1bdc..0242d4a 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/AbstractTestInnerJoin.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/AbstractTestInnerJoin.java
@@ -19,123 +19,29 @@
 package org.apache.jena.sparql.engine.join;
 
 import org.apache.jena.sparql.algebra.Table ;
-import org.apache.jena.sparql.core.Var ;
-import org.apache.jena.sparql.engine.join.JoinKey ;
+import org.apache.jena.sparql.expr.ExprList ;
 import org.junit.Test ;
 
 /** Tests for inner/equi joins */ 
 public abstract class AbstractTestInnerJoin extends AbstractTestJoin {
     
     @Override
-    protected void executeTest(JoinKey joinKey, Table left, Table right, Table expectedResults) {
-        executeTestJoin("1", joinKey, left, right, expectedResults) ;
-        executeTestJoin("2", joinKey, right, left, expectedResults) ;
+    protected void executeTest(JoinKey joinKey, Table left, Table right, ExprList conditions, Table expectedResults) {
+        if ( conditions != null )
+            fail("Conditions on inner join are meaningless (currently)") ;
+        // No conditions.
+        // Commutative.
+        executeTestJoin("1", joinKey, left, right, null, expectedResults) ;
+        executeTestJoin("2", joinKey, right, left, null, expectedResults) ;
     }
     
-    static Var var_a = Var.alloc("a") ; 
-    static Var var_b = Var.alloc("b") ; 
-    static Var var_c = Var.alloc("c") ; 
-    static Var var_d = Var.alloc("d") ; 
-
-    static Table table0() { return parseTableInt("(table)") ; } 
-
-    // Table of one row and no colums.
-    static Table table1() { 
-        return parseTableInt("(table (row))") ; }
-
-    static Table tableD1() { 
-        return parseTableInt("(table", 
-                             "   (row (?a 1) (?b 2))",
-                             "   (row (?a 1) (?b 3))",
-                             "   (row (?a 1) (?b 2))",
-            ")") ;
-    }
-
-    static Table tableD2() { 
-        return parseTableInt("(table", 
-                             "   (row (?a 0) (?d 8))",
-                             "   (row (?a 1) (?c 9))",
-            ")") ;
-    }
-
-    static Table tableD3() {
-        return parseTableInt("(table", 
-                             "   (row (?a 1) (?c 9) (?b 2))",
-                             "   (row (?a 1) (?c 9) (?b 3))",
-                             "   (row (?a 1) (?c 9) (?b 2))",
-            ")") ;
-    }
-
-    static Table tableD4() {
-        return parseTableInt("(table", 
-                             "   (row (?a 1) (?b 2))",
-                             "   (row (?a 1) (?b 3))",
-                             "   (row (?a 4) (?b 4))",
-                             "   (row (?a 4) (?b 5))",
-            ")") ;
-    }
-
-    static Table tableD5() {
-        return parseTableInt("(table", 
-                             "   (row (?a 4) (?c 4))",
-                             "   (row (?a 4) (?c 5))",
-                             "   (row (?a 6) (?c 5))",
-            ")") ;
-    }
-
-    static Table tableD6() {
-        return parseTableInt("(table", 
-                             "   (row (?a 1) (?c 2))",
-                             "   (row (?a 1) (?c 3))",
-                             "   (row (?a 4) (?c 4))",
-                             "   (row (?a 4) (?c 5))",
-            ")") ;
-    }
-
-    static Table tableD4x5() {
-        return parseTableInt("(table", 
-                             "   (row (?a 4) (?c 4) (?b 4))",
-                             "   (row (?a 4) (?c 4) (?b 5))",
-                             "   (row (?a 4) (?c 5) (?b 4))",
-                             "   (row (?a 4) (?c 5) (?b 5))",
-            ")") ;
-    }
-
-    static Table tableD4x6() {
-        return parseTableInt("(table", 
-                             "   (row (?a 1) (?c 2) (?b 2))",
-                             "   (row (?a 1) (?c 2) (?b 3))",
-                             "   (row (?a 1) (?c 3) (?b 2))",
-                             "   (row (?a 1) (?c 3) (?b 3))",
-                             "   (row (?a 4) (?c 4) (?b 4))",
-                             "   (row (?a 4) (?c 4) (?b 5))",
-                             "   (row (?a 4) (?c 5) (?b 4))",
-                             "   (row (?a 4) (?c 5) (?b 5))",
-            ")") ;
-    }
-
-    // Disjoint.
-    static Table tableD8() {
-        return parseTableInt("(table",
-                             "  (row (?x 10))",
-                             "  (row (?z 11))",
-            ")") ; 
-    }
-
-    // Table8 crossproduct table2
-    static Table tableD8x2() {
-        return parseTableInt("(table",
-                             "  (row (?a 0) (?d 8) (?z 11))",
-                             "  (row (?a 0) (?d 8) (?x 10))",
-                             "  (row (?a 1) (?c 9) (?z 11))",
-                             "  (row (?a 1) (?c 9) (?x 10))",
-            ")") ;
-    }
-
-    @Test public void join_00()  { testJoin("a", table0(), table0(), table0()) ; }
-    @Test public void join_00a() { testJoin("a", table1(), table0(), table0()) ; }
-    @Test public void join_00b() { testJoin("a", tableD1(), table1(), tableD1()) ; }
-    @Test public void join_00c() { testJoin("z", tableD1(), table1(), tableD1()) ; }
+    @Test public void join_basic_1()    { testJoin("a", table0(), table0(), table0()) ; }
+    @Test public void join_basic_2()    { testJoin("a", table1(), table0(), table0()) ; }
+    @Test public void join_basic_3()    { testJoin("a", tableD1(), table1(), tableD1()) ; }
+    @Test public void join_basic_4()    { testJoin("z", tableD1(), table1(), tableD1()) ; }
+    
+    @Test public void join_basic_5() { testJoin("a", table0(), table1(), table0()) ; }
+    @Test public void join_basic_6() { testJoin("a", table1(), table0(), table0()) ; }
 
     @Test public void join_01() { testJoin("a", table0(), tableD2(), table0()) ; }
     @Test public void join_02() { testJoin("a", tableD1(), table0(), table0()) ; }

http://git-wip-us.apache.org/repos/asf/jena/blob/56ea4f90/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/AbstractTestJoin.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/AbstractTestJoin.java b/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/AbstractTestJoin.java
index b48c66b..2ed9647 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/AbstractTestJoin.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/AbstractTestJoin.java
@@ -29,19 +29,205 @@ import org.apache.jena.sparql.algebra.TableFactory ;
 import org.apache.jena.sparql.core.Var ;
 import org.apache.jena.sparql.engine.QueryIterator ;
 import org.apache.jena.sparql.engine.binding.Binding ;
-import org.apache.jena.sparql.engine.join.JoinKey ;
+import org.apache.jena.sparql.expr.ExprList ;
 import org.apache.jena.sparql.resultset.ResultSetCompare ;
 import org.apache.jena.sparql.sse.SSE ;
 import org.junit.Assert ;
 
 /** Tests for inner/equi joins */ 
 public abstract class AbstractTestJoin extends Assert {
+
+    protected static Table table0() { return parseTableInt("(table)") ; } 
+
+    // Table of one row and no colums.
+    protected static Table table1() { 
+        return parseTableInt("(table (row))") ; }
+
+    protected static Table tableD1() { 
+        return parseTableInt("(table", 
+                             "   (row (?a 1) (?b 2))",
+                             "   (row (?a 1) (?b 3))",
+                             "   (row (?a 1) (?b 2))",
+            ")") ;
+    }
+
+    protected static Table tableD2() { 
+        return parseTableInt("(table", 
+                             "   (row (?a 0) (?d 8))",
+                             "   (row (?a 1) (?c 9))",
+            ")") ;
+    }
+
+    protected static Table tableD3() {
+        return parseTableInt("(table",
+                             "   (row (?a 1) (?c 9) (?b 2))",
+                             "   (row (?a 1) (?c 9) (?b 3))",
+                             "   (row (?a 1) (?c 9) (?b 2))",
+            ")") ;
+    }
+
+    protected static Table tableD3_LJ() {
+        return parseTableInt("(table", 
+                             "   (row (?d 8) (?a 0))",
+                             "   (row (?a 1) (?c 9) (?b 2))",
+                             "   (row (?a 1) (?c 9) (?b 3))",
+                             "   (row (?a 1) (?c 9) (?b 2))",
+                             
+            ")") ;
+    }
+
+    protected static Table tableD4() {
+        return parseTableInt("(table", 
+                             "   (row (?a 1) (?b 2))",
+                             "   (row (?a 1) (?b 3))",
+                             "   (row (?a 4) (?b 4))",
+                             "   (row (?a 4) (?b 5))",
+            ")") ;
+    }
+
+    protected static Table tableD5() {
+        return parseTableInt("(table", 
+                             "   (row (?a 4) (?c 4))",
+                             "   (row (?a 4) (?c 5))",
+                             "   (row (?a 6) (?c 5))",
+            ")") ;
+    }
+
+    protected static Table tableD6() {
+        return parseTableInt("(table", 
+                             "   (row (?a 1) (?c 2))",
+                             "   (row (?a 1) (?c 3))",
+                             "   (row (?a 4) (?c 4))",
+                             "   (row (?a 4) (?c 5))",
+            ")") ;
+    }
+
+    protected static Table tableD4x5() {
+        return parseTableInt("(table", 
+                             "   (row (?a 4) (?c 4) (?b 4))",
+                             "   (row (?a 4) (?c 4) (?b 5))",
+                             "   (row (?a 4) (?c 5) (?b 4))",
+                             "   (row (?a 4) (?c 5) (?b 5))",
+            ")") ;
+    }
+
+    protected static Table tableD4x5_LJ() {
+        return parseTableInt("(table",
+                             "   (row (?a 4) (?c 4) (?b 4))",
+                             "   (row (?a 4) (?c 4) (?b 5))",
+                             "   (row (?a 4) (?c 5) (?b 4))",
+                             "   (row (?a 4) (?c 5) (?b 5))",
+                             "   (row (?b 2) (?a 1))",
+                             "   (row (?b 3) (?a 1))",
+            ")") ;
+    }
+
+    protected static Table tableD5x4_LJ() {
+        return parseTableInt("(table", 
+                             "   (row (?a 4) (?c 4) (?b 4))",
+                             "   (row (?a 4) (?c 4) (?b 5))",
+                             "   (row (?a 4) (?c 5) (?b 4))",
+                             "   (row (?a 4) (?c 5) (?b 5))",
+                             "   (row (?a 6) (?c 5))",
+            ")") ;
+    }
+
+    protected static Table tableD4x6() {
+        return parseTableInt("(table", 
+                             "   (row (?a 1) (?c 2) (?b 2))",
+                             "   (row (?a 1) (?c 2) (?b 3))",
+                             "   (row (?a 1) (?c 3) (?b 2))",
+                             "   (row (?a 1) (?c 3) (?b 3))",
+                             "   (row (?a 4) (?c 4) (?b 4))",
+                             "   (row (?a 4) (?c 4) (?b 5))",
+                             "   (row (?a 4) (?c 5) (?b 4))",
+                             "   (row (?a 4) (?c 5) (?b 5))",
+            ")") ;
+    }
+
+    // Disjoint.
+    protected static Table tableD8() {
+        return parseTableInt("(table",
+                             "  (row (?x 10))",
+                             "  (row (?z 11))",
+            ")") ; 
+    }
+
+    // Table8 crossproduct table2
+    protected static Table tableD8x2() {
+        return parseTableInt("(table",
+                             "  (row (?a 0) (?d 8) (?z 11))",
+                             "  (row (?a 0) (?d 8) (?x 10))",
+                             "  (row (?a 1) (?c 9) (?z 11))",
+                             "  (row (?a 1) (?c 9) (?x 10))",
+            ")") ;
+    }
+    
+    // Left join data tables.
+    protected static Table tableL1() {
+        return parseTableInt("(table",
+                             "  (row (?a 0) (?d 8))",
+                             "  (row (?a 3) (?d 9))",
+            ")") ;
+    }
+
+    protected static Table tableL2() {
+        return parseTableInt("(table",
+                             "  (row (?a 0) (?z 11))",
+                             "  (row (?a 1) (?c 9) (?z 11))",
+            ")") ;
+    }
+
+    // L3 := L1 leftjoin L2 
+    protected static Table table1LJ2() {
+        return parseTableInt("(table",
+                             "  (row (?a 0) (?d 8) (?z 11))",
+                             "  (row (?a 3) (?d 9))",
+            ")") ;
+    }
+    
+    protected static Table tableL4() {
+        return parseTableInt("(table",
+                             "  (row (?a 0) (?z 11))",
+                             "  (row (?a 0) (?z 12))",
+                             "  (row               (?r 99))",
+                             "  (row        (?c 9) (?z 11))",
+            ")") ;
+    }
+
+    protected static Table tableL5() {
+        return parseTableInt("(table",
+                             "  (row (?a 0) (?d 8))",
+                             "  (row (?a 1) (?c 9) (?z 11))",
+            ")") ;
+    }
+
+    // L3 := L1 leftjoin L2 
+    protected static Table table4LJ5() {
+        return parseTableInt("(table",
+                             "  (row (?a 0) (?d 8) (?z 11))",
+                             "  (row (?a 0) (?d 8) (?z 12))",
+                             
+                             "  (row (?a 0) (?d 8) (?r 99))",
+                             "  (row (?a 1) (?c 9) (?z 11) (?r 99))",
+                             
+                             "  (row (?a 0) (?d 8) (?c 9) (?z 11))",
+                             "  (row (?a 1) (?c 9) (?z 11))",
+            ")") ;
+    }
+    
+    // Code
+
     protected static Table parseTableInt(String... strings) {
         String x = StrUtils.strjoinNL(strings) ;
         return SSE.parseTable(x) ;
     }
 
     protected void testJoin(String var, Table left, Table right, Table tableOut) {
+        testJoin(var, left, right, null, tableOut); 
+    }
+    
+    protected void testJoin(String var, Table left, Table right, ExprList conditions, Table tableOut) {
         JoinKey joinKey ;
         if ( var != null ) {
             if ( var.startsWith("?") )
@@ -53,38 +239,49 @@ public abstract class AbstractTestJoin extends Assert {
             joinKey = new JoinKey.Builder().build() ;
         }
 
-        executeTest(joinKey, left, right, tableOut) ;
+        executeTest(joinKey, left, right, null, tableOut) ;
     }
 
-    protected abstract void executeTest(JoinKey joinKey, Table left, Table right, Table expectedResults) ;
-    
+    // Any kind of join (choose by abstract join() operation).
+    protected abstract void executeTest(JoinKey joinKey, Table left, Table right, ExprList conditions, Table expectedResults) ;
     
     private List<Binding> toList(Table table) {
         return Iter.toList(table.rows()) ;
     }
 
-    protected void executeTestJoin(String num, JoinKey joinKey, Table left, Table right, Table expectedResults) {
-        Table x1 = joinMaterialize(joinKey, left, right) ;
-        assertNotNull("Null table from join ("+num+")", x1) ;
-        check("Results not equal ("+num+")", joinKey, left, right, expectedResults, x1) ;
+    protected void executeTestJoin(String msg, JoinKey joinKey, Table left, Table right, ExprList conditions, Table expectedResults) {
+        Table x1 = joinMaterialize(joinKey, left, right, conditions) ;
+        assertNotNull("Null table from join ("+msg+")", x1) ;
+        if ( false ) {
+            System.out.println("Test :    "+msg) ;
+            System.out.println("Joinkey:  "+joinKey) ;
+            System.out.println("Left:     \n"+left) ;
+            System.out.println("Right:    \n"+right) ;
+            System.out.println("Expected: \n"+expectedResults) ;
+            System.out.println("Actual:   \n"+x1) ;
+            System.out.println() ;
+        }
+        
+        check("Results not equal ("+msg+")", joinKey, left, right, expectedResults, x1) ;
     }
 
-    private Table joinMaterialize(JoinKey joinKey, Table left, Table right) {
-        QueryIterator qIter = join(joinKey, left , right) ;
+    private Table joinMaterialize(JoinKey joinKey, Table left, Table right, ExprList conditions) {
+        QueryIterator qIter = join(joinKey, left , right, null) ;
         return TableFactory.create(qIter) ;
     }
 
-    public abstract QueryIterator join(JoinKey joinKey , Table left , Table right) ;
+    public abstract QueryIterator join(JoinKey joinKey, Table left , Table right, ExprList conditions) ;
 
     private static void check(String msg, JoinKey joinKey, Table left, Table right, Table expected, Table actual) {
         boolean b = equalTables(expected, actual) ;
         if ( ! b ) {
-            System.out.println("Joinkey:  "+joinKey) ;
-            System.out.println("Left:     \n"+left) ;
-            System.out.println("Right:    \n"+right) ;
-            System.out.println("Expected: \n"+expected) ;
-            System.out.println("Actual:   \n"+actual) ;
-            System.out.println() ;
+            System.out.flush() ;
+            System.err.println("Joinkey:  "+joinKey) ;
+            System.err.println("Left:     \n"+left) ;
+            System.err.println("Right:    \n"+right) ;
+            System.err.println("Expected: \n"+expected) ;
+            System.err.println("Actual:   \n"+actual) ;
+            System.err.println() ;
         }
 
         assertTrue(msg, b) ;

http://git-wip-us.apache.org/repos/asf/jena/blob/56ea4f90/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/AbstractTestLeftJoin.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/AbstractTestLeftJoin.java b/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/AbstractTestLeftJoin.java
index 57756ff..2786bed 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/AbstractTestLeftJoin.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/AbstractTestLeftJoin.java
@@ -19,146 +19,55 @@
 package org.apache.jena.sparql.engine.join;
 
 import org.apache.jena.sparql.algebra.Table ;
-import org.apache.jena.sparql.core.Var ;
-import org.apache.jena.sparql.engine.join.JoinKey ;
+import org.apache.jena.sparql.expr.ExprList ;
 import org.junit.Test ;
 
 public abstract class AbstractTestLeftJoin extends AbstractTestJoin {
-    @Override
-    protected void executeTest(JoinKey joinKey, Table left, Table right, Table expectedResults) {
-        executeTestJoin("LJ", joinKey, left, right, expectedResults) ;
-    }
     
-    static Var var_a = Var.alloc("a") ; 
-    static Var var_b = Var.alloc("b") ; 
-    static Var var_c = Var.alloc("c") ; 
-    static Var var_d = Var.alloc("d") ; 
-
-    static Table table0() { return parseTableInt("(table)") ; } 
-
-    // Table of one row and no colums.
-    static Table table1() { 
-        return parseTableInt("(table (row))") ; }
-
-    static Table tableD1() { 
-        return parseTableInt("(table", 
-                             "   (row (?a 1) (?b 2))",
-                             "   (row (?a 1) (?b 3))",
-                             "   (row (?a 1) (?b 2))",
-            ")") ;
-    }
-
-    static Table tableD2() { 
-        return parseTableInt("(table", 
-                             "   (row (?a 0) (?d 8))",
-                             "   (row (?a 1) (?c 9))",
-            ")") ;
-    }
-
-    static Table tableD3() {
-        return parseTableInt("(table", 
-                             "   (row (?a 1) (?c 9) (?b 2))",
-                             "   (row (?a 1) (?c 9) (?b 3))",
-                             "   (row (?a 1) (?c 9) (?b 2))",
-            ")") ;
-    }
-
-    static Table tableD4() {
-        return parseTableInt("(table", 
-                             "   (row (?a 1) (?b 2))",
-                             "   (row (?a 1) (?b 3))",
-                             "   (row (?a 4) (?b 4))",
-                             "   (row (?a 4) (?b 5))",
-            ")") ;
-    }
-
-    static Table tableD5() {
-        return parseTableInt("(table", 
-                             "   (row (?a 4) (?c 4))",
-                             "   (row (?a 4) (?c 5))",
-                             "   (row (?a 6) (?c 5))",
-            ")") ;
-    }
-
-    static Table tableD6() {
-        return parseTableInt("(table", 
-                             "   (row (?a 1) (?c 2))",
-                             "   (row (?a 1) (?c 3))",
-                             "   (row (?a 4) (?c 4))",
-                             "   (row (?a 4) (?c 5))",
-            ")") ;
-    }
-
-    static Table tableD4x5() {
-        return parseTableInt("(table", 
-                             "   (row (?a 4) (?c 4) (?b 4))",
-                             "   (row (?a 4) (?c 4) (?b 5))",
-                             "   (row (?a 4) (?c 5) (?b 4))",
-                             "   (row (?a 4) (?c 5) (?b 5))",
-            ")") ;
-    }
-
-    static Table tableD4x6() {
-        return parseTableInt("(table", 
-                             "   (row (?a 1) (?c 2) (?b 2))",
-                             "   (row (?a 1) (?c 2) (?b 3))",
-                             "   (row (?a 1) (?c 3) (?b 2))",
-                             "   (row (?a 1) (?c 3) (?b 3))",
-                             "   (row (?a 4) (?c 4) (?b 4))",
-                             "   (row (?a 4) (?c 4) (?b 5))",
-                             "   (row (?a 4) (?c 5) (?b 4))",
-                             "   (row (?a 4) (?c 5) (?b 5))",
-            ")") ;
-    }
-
-    // Disjoint.
-    static Table tableD8() {
-        return parseTableInt("(table",
-                             "  (row (?x 10))",
-                             "  (row (?z 11))",
-            ")") ; 
-    }
-
-    // Table8 crossproduct table2
-    static Table tableD8x2() {
-        return parseTableInt("(table",
-                             "  (row (?a 0) (?d 8) (?z 11))",
-                             "  (row (?a 0) (?d 8) (?x 10))",
-                             "  (row (?a 1) (?c 9) (?z 11))",
-                             "  (row (?a 1) (?c 9) (?x 10))",
-            ")") ;
+    @Override
+    protected void executeTest(JoinKey joinKey, Table left, Table right, ExprList conditions, Table expectedResults) {
+        executeTestJoin("LJ", joinKey, left, right, conditions, expectedResults) ;
     }
 
     // XXX And conditions.
     
-    @Test public void leftjoin_00()  { testJoin("a", table0(), table0(), table0()) ; }
-    @Test public void leftjoin_00a() { testJoin("a", table1(), table0(), table0()) ; }
-    @Test public void leftjoin_00b() { testJoin("a", tableD1(), table1(), tableD1()) ; }
-    @Test public void leftjoin_00c() { testJoin("z", tableD1(), table1(), tableD1()) ; }
+    @Test public void leftjoin_basic_1()    { testJoin("a", table0(), table0(), table0()) ; }
+    @Test public void leftjoin_basic_2()    { testJoin("a", table1(), table0(), table1()) ; }
+    @Test public void leftjoin_basic_3()    { testJoin("a", tableD1(), table1(), tableD1()) ; }
+    @Test public void leftjoin_basic_4()    { testJoin("z", tableD1(), table1(), tableD1()) ; }
+    
+    @Test public void leftjoin_01()         { testJoin("a", tableL1(), tableL2(), table1LJ2()) ; }
+    @Test public void leftjoin_02()         { testJoin("a", tableL4(), tableL5(), table4LJ5()) ; }
+    
+    @Test public void leftjoin_03()         { testJoin("z", tableL1(), tableL2(), table1LJ2()) ; }
+    @Test public void leftjoin_04()         { testJoin("z", tableL4(), tableL5(), table4LJ5()) ; }
+    
+    @Test public void leftjoin_J01()        { testJoin("a", tableD1(), table1(), tableD1()) ; }
+    @Test public void leftjoin_J01a()       { testJoin("z", tableD1(), table1(), tableD1()) ; }
 
-    @Test public void leftjoin_01() { testJoin("a", table0(), tableD2(), table0()) ; }
-    @Test public void leftjoin_02() { testJoin("a", tableD1(), table0(), tableD1()) ; }
-    @Test public void leftjoin_03() { testJoin("a", tableD1(), tableD2(), tableD3()) ; }
+    @Test public void leftjoin_J02()        { testJoin("a", tableD1(), table0(), tableD1()) ; }
+    @Test public void leftjoin_J03()        { testJoin("a", tableD1(), tableD2(), tableD3()) ; }
 
     // Identity.
-    @Test public void leftjoin_04() { testJoin("a", tableD2(), table1(), tableD2()) ; }
-    @Test public void leftjoin_05() { testJoin("a", table1(), tableD2(), tableD2()) ; }
+    @Test public void leftjoin_J04()        { testJoin("a", tableD2(), table1(), tableD2()) ; }
+    @Test public void leftjoin_J05()        { testJoin("a", table1(), tableD2(), tableD2()) ; }
     // Identity, keymiss
-    @Test public void leftjoin_06() { testJoin("z", table1(), tableD2(), tableD2()) ; }
-    @Test public void leftjoin_07() { testJoin("z", tableD2(), table1(), tableD2()) ; }
+    @Test public void leftjoin_J06()        { testJoin("z", table1(), tableD2(), tableD2()) ; }
+    @Test public void leftjoin_J07()        { testJoin("z", tableD2(), table1(), tableD2()) ; }
 
-    @Test public void leftjoin_08() { testJoin("a", tableD4(), tableD5(), tableD4x5()) ; }
-    @Test public void leftjoin_09() { testJoin("a", tableD5(), tableD4(), tableD4x5()) ; }
+    @Test public void leftjoin_J08()        { testJoin("a", tableD4(), tableD5(), tableD4x5_LJ()) ; }
+    @Test public void leftjoin_J09()        { testJoin("a", tableD5(), tableD4(), tableD5x4_LJ()) ; }
 
-    @Test public void leftjoin_10() { testJoin("a", tableD4(), tableD6(), tableD4x6()) ; }
-    @Test public void leftjoin_11() { testJoin("a", tableD6(), tableD4(), tableD4x6()) ; }
+    @Test public void leftjoin_J10()        { testJoin("a", tableD4(), tableD6(), tableD4x6()) ; }
+    @Test public void leftjoin_J11()        { testJoin("a", tableD6(), tableD4(), tableD4x6()) ; }
 
     // Not the right join key - should still work albeit less efficiently.
-    @Test public void leftjoin_12() { testJoin("z", tableD1(), tableD2(), tableD3()) ; }
-    @Test public void leftjoin_13() { testJoin("z", tableD2(), tableD1(), tableD3()) ; }
+    @Test public void leftjoin_J12()        { testJoin("z", tableD1(), tableD2(), tableD3()) ; }
+    @Test public void leftjoin_J13()        { testJoin("z", tableD2(), tableD1(), tableD3_LJ()) ; }
 
     // No key.
-    @Test public void leftjoin_14() { testJoin(null, tableD1(), tableD2(), tableD3()) ; }
+    
+    @Test public void leftjoin_14()         { testJoin(null, tableD1(), tableD2(), tableD3()) ; }
 
 
     // Disjoint tables.

http://git-wip-us.apache.org/repos/asf/jena/blob/56ea4f90/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TS_Join.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TS_Join.java b/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TS_Join.java
index 69b5fb4..bd00872 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TS_Join.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TS_Join.java
@@ -28,6 +28,11 @@ import org.junit.runners.Suite.SuiteClasses ;
     , TestJoinNestedLoopSimple.class    // Real simple materializing version.
     , TestJoinNestedLoop.class
     , TestHashJoin.class
+    
+    , TestLeftJoinSimple.class
+    , TestLeftJoinNestedLoopSimple.class    // Real simple materializing version.
+    , TestLeftJoinNestedLoop.class
+    //, TestLeftHashJoin.class
 })
 
 public class TS_Join { }

http://git-wip-us.apache.org/repos/asf/jena/blob/56ea4f90/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestHashJoin.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestHashJoin.java b/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestHashJoin.java
index 4a4bd6f..6aa9eaa 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestHashJoin.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestHashJoin.java
@@ -26,11 +26,12 @@ import org.apache.jena.sparql.engine.binding.Binding ;
 import org.apache.jena.sparql.engine.iterator.QueryIterPlainWrapper ;
 import org.apache.jena.sparql.engine.join.Join ;
 import org.apache.jena.sparql.engine.join.JoinKey ;
+import org.apache.jena.sparql.expr.ExprList ;
 
 public class TestHashJoin extends AbstractTestInnerJoin {
 
     @Override
-    public QueryIterator join(JoinKey joinKey, Table left, Table right) {
+    public QueryIterator join(JoinKey joinKey, Table left, Table right, ExprList conditions) {
         Iterator<Binding> data = Join.hashJoin(joinKey, left.iterator(null), right.iterator(null), null) ;
         QueryIterator qIter = new QueryIterPlainWrapper(data) ;
         return qIter ;

http://git-wip-us.apache.org/repos/asf/jena/blob/56ea4f90/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestJoinNestedLoop.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestJoinNestedLoop.java b/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestJoinNestedLoop.java
index c844ea2..31530a4 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestJoinNestedLoop.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestJoinNestedLoop.java
@@ -22,12 +22,13 @@ import org.apache.jena.sparql.algebra.Table ;
 import org.apache.jena.sparql.engine.QueryIterator ;
 import org.apache.jena.sparql.engine.join.Join ;
 import org.apache.jena.sparql.engine.join.JoinKey ;
+import org.apache.jena.sparql.expr.ExprList ;
 
 public class TestJoinNestedLoop extends AbstractTestInnerJoin {
 
     @Override
-    public QueryIterator join(JoinKey joinKey, Table left, Table right) {
-        return Join.innerLoopJoin(left.iterator(null), right.iterator(null), null) ;
+    public QueryIterator join(JoinKey joinKey, Table left, Table right, ExprList conditions) {
+        return Join.nestedLoopJoin(left.iterator(null), right.iterator(null), null) ;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/jena/blob/56ea4f90/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestJoinNestedLoopSimple.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestJoinNestedLoopSimple.java b/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestJoinNestedLoopSimple.java
index 0d9db54..64206cb 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestJoinNestedLoopSimple.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestJoinNestedLoopSimple.java
@@ -22,12 +22,13 @@ import org.apache.jena.sparql.algebra.Table ;
 import org.apache.jena.sparql.engine.QueryIterator ;
 import org.apache.jena.sparql.engine.join.Join ;
 import org.apache.jena.sparql.engine.join.JoinKey ;
+import org.apache.jena.sparql.expr.ExprList ;
 
 public class TestJoinNestedLoopSimple extends AbstractTestInnerJoin {
 
     @Override
-    public QueryIterator join(JoinKey joinKey, Table left, Table right) {
-        return Join.innerLoopJoinBasic(left.iterator(null), right.iterator(null), null) ;
+    public QueryIterator join(JoinKey joinKey, Table left, Table right, ExprList conditions) {
+        return Join.nestedLoopJoinBasic(left.iterator(null), right.iterator(null), null) ;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/jena/blob/56ea4f90/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestJoinSimple.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestJoinSimple.java b/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestJoinSimple.java
index d091168..f89fa87 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestJoinSimple.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestJoinSimple.java
@@ -22,11 +22,12 @@ import org.apache.jena.sparql.algebra.Table ;
 import org.apache.jena.sparql.engine.QueryIterator ;
 import org.apache.jena.sparql.engine.join.JoinKey ;
 import org.apache.jena.sparql.engine.ref.TableJoin ;
+import org.apache.jena.sparql.expr.ExprList ;
 
 public class TestJoinSimple extends AbstractTestInnerJoin {
 
     @Override
-    public QueryIterator join(JoinKey joinKey, Table left, Table right) {
+    public QueryIterator join(JoinKey joinKey, Table left, Table right, ExprList conditions) {
         return TableJoin.join(left.iterator(null), right, null, null) ;
     }
 

http://git-wip-us.apache.org/repos/asf/jena/blob/56ea4f90/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestLeftJoinNestedLoop.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestLeftJoinNestedLoop.java b/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestLeftJoinNestedLoop.java
new file mode 100644
index 0000000..a5053a7
--- /dev/null
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestLeftJoinNestedLoop.java
@@ -0,0 +1,35 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.sparql.engine.join;
+
+import org.apache.jena.sparql.algebra.Table ;
+import org.apache.jena.sparql.engine.QueryIterator ;
+import org.apache.jena.sparql.engine.join.Join ;
+import org.apache.jena.sparql.engine.join.JoinKey ;
+import org.apache.jena.sparql.expr.ExprList ;
+
+public class TestLeftJoinNestedLoop extends AbstractTestLeftJoin {
+
+    @Override
+    public QueryIterator join(JoinKey joinKey, Table left, Table right, ExprList conditions) {
+        return Join.nestedLoopLeftJoin(left.iterator(null), right.iterator(null), conditions, null) ;
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/jena/blob/56ea4f90/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestLeftJoinNestedLoopSimple.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestLeftJoinNestedLoopSimple.java b/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestLeftJoinNestedLoopSimple.java
new file mode 100644
index 0000000..44d2d7d
--- /dev/null
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestLeftJoinNestedLoopSimple.java
@@ -0,0 +1,35 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.sparql.engine.join;
+
+import org.apache.jena.sparql.algebra.Table ;
+import org.apache.jena.sparql.engine.QueryIterator ;
+import org.apache.jena.sparql.engine.join.Join ;
+import org.apache.jena.sparql.engine.join.JoinKey ;
+import org.apache.jena.sparql.expr.ExprList ;
+
+public class TestLeftJoinNestedLoopSimple extends AbstractTestLeftJoin {
+
+    @Override
+    public QueryIterator join(JoinKey joinKey, Table left, Table right, ExprList conditions) {
+        return Join.nestedLoopLeftJoinBasic(left.iterator(null), right.iterator(null), conditions,null) ;
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/jena/blob/56ea4f90/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestLeftJoinSimple.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestLeftJoinSimple.java b/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestLeftJoinSimple.java
index 041dfe5..f9fc763 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestLeftJoinSimple.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/TestLeftJoinSimple.java
@@ -22,13 +22,13 @@ import org.apache.jena.sparql.algebra.Table ;
 import org.apache.jena.sparql.engine.QueryIterator ;
 import org.apache.jena.sparql.engine.join.JoinKey ;
 import org.apache.jena.sparql.engine.ref.TableJoin ;
+import org.apache.jena.sparql.expr.ExprList ;
 
 public class TestLeftJoinSimple extends AbstractTestLeftJoin {
 
     @Override
-    public QueryIterator join(JoinKey joinKey, Table left, Table right) {
-        return TableJoin.leftJoin(left.iterator(null), right, null, null) ;
+    public QueryIterator join(JoinKey joinKey, Table left, Table right, ExprList conditions) {
+        return TableJoin.leftJoin(left.iterator(null), right, conditions, null) ;
     }
-
 }