Merge branch 'master' of
https://git-wip-us.apache.org/repos/asf/empire-db.git
diff --git a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/RecordTag.java b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/RecordTag.java
index 78d1920..0d8052f 100644
--- a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/RecordTag.java
+++ b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/RecordTag.java
@@ -18,7 +18,6 @@
  */

 package org.apache.empire.jsf2.components;

 

-import javax.faces.component.NamingContainer;

 import javax.faces.component.UIComponentBase;

 

 import org.apache.empire.commons.ObjectUtils;

diff --git a/empire-db/src/main/java/org/apache/empire/db/DBCommand.java b/empire-db/src/main/java/org/apache/empire/db/DBCommand.java
index 9284a1b..f3eff01 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBCommand.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBCommand.java
@@ -34,8 +34,10 @@
 import org.apache.empire.data.DataType;
 import org.apache.empire.db.expr.compare.DBCompareColExpr;
 import org.apache.empire.db.expr.compare.DBCompareExpr;
+import org.apache.empire.db.expr.join.DBColumnJoinExpr;
+import org.apache.empire.db.expr.join.DBCompareJoinExpr;
+import org.apache.empire.db.expr.join.DBCrossJoinExpr;
 import org.apache.empire.db.expr.join.DBJoinExpr;
-import org.apache.empire.db.expr.join.DBJoinExprEx;
 import org.apache.empire.db.expr.set.DBSetExpr;
 import org.apache.empire.exceptions.InternalException;
 import org.apache.empire.exceptions.MiscellaneousErrorException;
@@ -473,6 +475,19 @@
         }
         joins.add(join);
     }
+    
+    /**
+     * Adds a cross join for two tables or views 
+     * @param left the left RowSet
+     * @param right the right RowSet
+     * @return the join expression
+     */
+    public DBCrossJoinExpr join(DBRowSet left, DBRowSet right)
+    {
+        DBCrossJoinExpr join = new DBCrossJoinExpr(left, right);
+        join(join);
+        return join;
+    }
 
     /**
      * Adds a join based on two columns to the list of join expressions.
@@ -483,9 +498,9 @@
      * 
      * @return the join expression 
      */
-    public DBJoinExpr join(DBColumnExpr left, DBColumnExpr right, DBJoinType joinType)
+    public DBColumnJoinExpr join(DBColumnExpr left, DBColumnExpr right, DBJoinType joinType)
     {
-        DBJoinExpr join = new DBJoinExpr(left, right, joinType); 
+        DBColumnJoinExpr join = new DBColumnJoinExpr(left, right, joinType); 
         join(join);
         return join;
     }
@@ -498,7 +513,7 @@
      * 
      * @return the join expresion 
      */
-    public DBJoinExpr join(DBColumnExpr left, DBColumn right)
+    public DBColumnJoinExpr join(DBColumnExpr left, DBColumn right)
     {
         return join(left, right, DBJoinType.INNER);
     }
@@ -512,9 +527,9 @@
      * 
      * @return the join expresion 
      */
-    public DBJoinExpr join(DBRowSet rowset, DBCompareExpr cmp, DBJoinType joinType)
+    public DBCompareJoinExpr join(DBRowSet rowset, DBCompareExpr cmp, DBJoinType joinType)
     {
-        DBJoinExpr join = new DBJoinExprEx(rowset, cmp, joinType); 
+        DBCompareJoinExpr join = new DBCompareJoinExpr(rowset, cmp, joinType); 
         join(join);
         return join;
     }
@@ -527,7 +542,7 @@
      * 
      * @return the join expresion 
      */
-    public DBJoinExpr join(DBRowSet rowset, DBCompareExpr cmp)
+    public DBCompareJoinExpr join(DBRowSet rowset, DBCompareExpr cmp)
     {
         return join(rowset, cmp, DBJoinType.INNER);
     }
@@ -1163,21 +1178,21 @@
                  DBJoinExpr join = joins.get(i);
                  if (i<1)
                  {   // Add Join Tables
-                     joinTables.add(join.getLeft() .getUpdateColumn().getRowSet());
-                     joinTables.add(join.getRight().getUpdateColumn().getRowSet());
+                     joinTables.add(join.getLeftTable());
+                     joinTables.add(join.getRightTable());
                      // Remove from List
-                     tables.remove(join.getLeft() .getUpdateColumn().getRowSet());
-                     tables.remove(join.getRight().getUpdateColumn().getRowSet());
+                     tables.remove(join.getLeftTable());
+                     tables.remove(join.getRightTable());
                      // Context
                      context = CTX_NAME|CTX_VALUE;
                  }
                  else
                  {   // Extend the join                    
-                     if ( joinTables.contains(join.getRight().getUpdateColumn().getRowSet()))
+                     if ( joinTables.contains(join.getRightTable()))
                           join.reverse();
                      // Add Right Table     
-                     joinTables.add(join.getRight().getUpdateColumn().getRowSet());
-                     tables .remove(join.getRight().getUpdateColumn().getRowSet());
+                     joinTables.add(join.getRightTable());
+                     tables .remove(join.getRightTable());
                      // Context
                      context = CTX_VALUE;
                      buf.append( "\t" );
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBJoinType.java b/empire-db/src/main/java/org/apache/empire/db/DBJoinType.java
index 2315ebf..3f1f949 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBJoinType.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBJoinType.java
@@ -39,7 +39,12 @@
     /**
      * SQL Right join
      */
-    RIGHT;  //   = 1
+    RIGHT,  //   = 1
+    
+    /**
+     * SQL Cross join
+     */
+    CROSS;
     
     public static DBJoinType reversed(DBJoinType type)
     {
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBQuery.java b/empire-db/src/main/java/org/apache/empire/db/DBQuery.java
index db0dbe6..ff3fa52 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBQuery.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBQuery.java
@@ -28,7 +28,6 @@
 import org.apache.empire.commons.Options;
 import org.apache.empire.commons.StringUtils;
 import org.apache.empire.data.DataType;
-import org.apache.empire.db.DBCmdParam;
 import org.apache.empire.db.exceptions.InvalidKeyException;
 import org.apache.empire.db.exceptions.NoPrimaryKeyException;
 import org.apache.empire.db.exceptions.QueryNoResultException;
@@ -37,6 +36,7 @@
 import org.apache.empire.db.exceptions.RecordUpdateInvalidException;
 import org.apache.empire.db.expr.compare.DBCompareColExpr;
 import org.apache.empire.db.expr.compare.DBCompareExpr;
+import org.apache.empire.db.expr.join.DBColumnJoinExpr;
 import org.apache.empire.db.expr.join.DBJoinExpr;
 import org.apache.empire.exceptions.InvalidArgumentException;
 import org.apache.empire.exceptions.ItemNotFoundException;
@@ -539,7 +539,10 @@
             // Evaluate Joins
             for (i = 0; cmd.joins != null && i < cmd.joins.size(); i++)
             {
-                DBJoinExpr join = cmd.joins.get(i);
+                DBJoinExpr jex = cmd.joins.get(i);
+                if (!(jex instanceof DBColumnJoinExpr))
+                    continue;
+                DBColumnJoinExpr join = (DBColumnJoinExpr)jex;
                 DBColumn left  = join.getLeft() .getUpdateColumn();
                 DBColumn right = join.getRight().getUpdateColumn();
                 if (left.getRowSet()==table && table.isKeyColumn(left))
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBReader.java b/empire-db/src/main/java/org/apache/empire/db/DBReader.java
index 91f5902..484c316 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBReader.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBReader.java
@@ -899,8 +899,8 @@
         // check the joins
         for (DBJoinExpr j : joins)
         {
-            DBRowSet rsl = j.getLeft().getUpdateColumn().getRowSet();
-            DBRowSet rsr = j.getRight().getUpdateColumn().getRowSet();
+            DBRowSet rsl = j.getLeftTable();
+            DBRowSet rsr = j.getRightTable();
             if (rsl instanceof DBQuery)
             {   // the left join is a query
                 subQueryParams = addSubQueryParams((DBQuery)rsl, subQueryParams);
diff --git a/empire-db/src/main/java/org/apache/empire/db/expr/join/DBColumnJoinExpr.java b/empire-db/src/main/java/org/apache/empire/db/expr/join/DBColumnJoinExpr.java
new file mode 100644
index 0000000..db3f4ef
--- /dev/null
+++ b/empire-db/src/main/java/org/apache/empire/db/expr/join/DBColumnJoinExpr.java
@@ -0,0 +1,267 @@
+/*

+ * 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.empire.db.expr.join;

+

+import java.util.HashSet;

+import java.util.Set;

+

+import org.apache.empire.db.DBColumn;

+import org.apache.empire.db.DBColumnExpr;

+import org.apache.empire.db.DBDatabase;

+import org.apache.empire.db.DBJoinType;

+import org.apache.empire.db.DBRowSet;

+import org.apache.empire.db.expr.compare.DBCompareExpr;

+

+public class DBColumnJoinExpr extends DBJoinExpr

+{

+    private final static long serialVersionUID = 1L;

+  

+    protected DBColumnExpr  left;

+    protected DBColumnExpr  right;

+

+    // Additional

+    public DBCompareExpr compExpr = null;

+

+    /**

+     * Constructs a new DBJoinExpr object initialize this object with

+     * the left and right column and the data type of the join

+     * expression.

+     * 

+     * @param left left value

+     * @param right right value

+     * @param type data type (JOIN_INNER, JOIN_LEFT or JOIN_RIGHT)

+     */

+    public DBColumnJoinExpr(DBColumnExpr left, DBColumnExpr right, DBJoinType type)

+    {

+        super(type);

+        this.left = left;

+        this.right = right;

+    }

+

+    /**

+     * Returns the current DBDatabase object.

+     * 

+     * @return the current DBDatabase object

+     */

+    @Override

+    public DBDatabase getDatabase()

+    {

+        return left.getDatabase();

+    }

+

+    /**

+     * returns the left join expression

+     */

+    public DBColumnExpr getLeft()

+    {

+        return left;

+    }

+

+    /**

+     * returns the right join expression

+     */

+    public DBColumnExpr getRight()

+    {

+        return right;

+    }

+    

+    @Override

+    public DBRowSet getLeftTable()

+    {

+        return left.getUpdateColumn().getRowSet();

+    }

+    

+    /**

+     * returns the RowSet on the right of the join

+     */

+    @Override

+    public DBRowSet getRightTable()

+    {

+        return right.getUpdateColumn().getRowSet();

+    }

+    

+    /**

+     * returns true if this join is using the given table or view or false otherwise

+     */

+    @Override

+    public boolean isJoinOn(DBRowSet rowset)

+    {

+        if (rowset==null)

+            return false;

+        DBColumn l = (left !=null ? left .getUpdateColumn() : null);

+        DBColumn r = (right!=null ? right.getUpdateColumn() : null);

+        DBRowSet rsl = (l!=null ? l.getRowSet() : null);

+        DBRowSet rsr = (r!=null ? r.getRowSet() : null);

+        return rowset.equals(rsl) || rowset.equals(rsr);

+    }

+    

+    /**

+     * returns true if this join is using the given column or false otherwise

+     */

+    @Override

+    public boolean isJoinOn(DBColumn column)

+    {

+        if (column==null)

+            return false;

+        // Check Update Columns

+        if (column.equals(left.getUpdateColumn()) ||

+            column.equals(right.getUpdateColumn()))

+            return true;

+        if (compExpr!=null)

+        {   // Check expression

+            HashSet<DBColumn> set = new HashSet<DBColumn>();

+            compExpr.addReferencedColumns(set);

+            return set.contains(column);

+        }

+        // not found

+        return false;

+    }

+

+    /**

+     * Returns the left table name if the data type= JOIN_LEFT and returns

+     * the right table if the data type= JOIN_RIGHT. If the

+     * data type = JOIN_INNER the return value is null.

+     * 

+     * @return the current DBDatabase object

+     */

+    @Override

+    public DBRowSet getOuterTable()

+    {

+        switch(type)

+        {

+            case LEFT:  return right.getUpdateColumn().getRowSet();

+            case RIGHT: return left .getUpdateColumn().getRowSet();

+            default:    return null; // no outer table!

+        }

+    }

+

+    /**

+     * This function swaps the left and the right statements of the join expression.

+     */

+    @Override

+    public void reverse()

+    { // Swap Type of Join

+        DBColumnExpr swap = left;

+        left = right;

+        right = swap;

+        type = DBJoinType.reversed(type); // (type * -1);

+    }

+

+    /**

+     * Returns any additional constraints to the join

+     * @return a compare expression containing additional constraints or null 

+     */

+    public DBCompareExpr getWhere()

+    {

+        return compExpr;

+    }

+

+    /**

+     * This function adds an additional constraint to the join.

+     * 

+     * @param expr the compare expression

+     */

+    public void where(DBCompareExpr expr)

+    { // Set Compare Expression

+        compExpr = expr;

+    }

+

+    /**

+     * This function adds an additional constraint to the join.

+     * 

+     * @param c1 the first column

+     * @param c2 the second column

+     * 

+     * @return the object itself

+     */

+    public DBJoinExpr and(DBColumnExpr c1, DBColumnExpr c2)

+    {   // Set Compare Expression

+        if (compExpr==null)

+            compExpr = c1.is(c2);

+        else

+            compExpr = compExpr.and(c1.is(c2));

+        return this;

+    }

+

+    /**

+     * @see org.apache.empire.db.DBExpr#addReferencedColumns(Set)

+     */

+    @Override

+    public void addReferencedColumns(Set<DBColumn> list)

+    {

+        left.addReferencedColumns(list);

+        right.addReferencedColumns(list);

+        // Compare Expression

+        if (compExpr != null)

+            compExpr.addReferencedColumns(list);

+    }

+

+    /** Not allowed, this operation have to be done in the DBCommand object. */

+    @Override

+    public void addSQL(StringBuilder buf, long context)

+    {

+        if ((context & CTX_NAME) != 0)

+            left.getUpdateColumn().getRowSet().addSQL(buf, CTX_DEFAULT | CTX_ALIAS);

+        if ((context & CTX_VALUE) != 0)

+        { // Join Type

+            switch(type)

+            {

+                case LEFT:  buf.append(" LEFT JOIN ");break;

+                case INNER: buf.append(" INNER JOIN ");break;

+                case RIGHT: buf.append(" RIGHT JOIN ");break;

+                default:    buf.append(" JOIN "); // should not come here!

+            }

+            right.getUpdateColumn().getRowSet().addSQL(buf, CTX_DEFAULT | CTX_ALIAS);

+            // compare equal

+            buf.append(" ON ");

+            right.addSQL(buf, CTX_DEFAULT);

+            buf.append(" = ");

+            left.addSQL(buf, CTX_DEFAULT);

+            // Compare Expression

+            if (compExpr != null)

+            {

+                buf.append(" AND ");

+                compExpr.addSQL(buf, CTX_DEFAULT);

+            }

+        }

+    }

+

+    /**

+     * Compares two DBJoinExpr objects.

+     * 

+     * @param obj other DBJoinExpr object

+     * @return true if the other DBJoinExpr object is equal to this object

+     */

+    @Override

+    public boolean equals(Object obj)

+    {

+        if (!(obj instanceof DBColumnJoinExpr))

+            return super.equals(obj);

+        // object

+        DBColumnJoinExpr other = (DBColumnJoinExpr) obj;

+        if (left.equals(other.left) && right.equals(other.right) && type == other.type)

+            return true;

+        // reversed

+        if (left.equals(other.right) && right.equals(other.left) && type == DBJoinType.reversed(other.type))

+            return true;

+        // not equal

+        return false;

+    }

+

+}

diff --git a/empire-db/src/main/java/org/apache/empire/db/expr/join/DBJoinExprEx.java b/empire-db/src/main/java/org/apache/empire/db/expr/join/DBCompareJoinExpr.java
similarity index 95%
rename from empire-db/src/main/java/org/apache/empire/db/expr/join/DBJoinExprEx.java
rename to empire-db/src/main/java/org/apache/empire/db/expr/join/DBCompareJoinExpr.java
index 639dd47..029b04a 100644
--- a/empire-db/src/main/java/org/apache/empire/db/expr/join/DBJoinExprEx.java
+++ b/empire-db/src/main/java/org/apache/empire/db/expr/join/DBCompareJoinExpr.java
@@ -36,10 +36,10 @@
  * <P>
  *
  */
-public class DBJoinExprEx extends DBJoinExpr
+public class DBCompareJoinExpr extends DBColumnJoinExpr
 {
     private final static long serialVersionUID = 1L;
-    private static final Logger log = LoggerFactory.getLogger(DBJoinExprEx.class);
+    private static final Logger log = LoggerFactory.getLogger(DBCompareJoinExpr.class);
     
     protected final DBCompareExpr cmp;
     
@@ -71,7 +71,7 @@
      * @param cmp the compare expression
      * @param joinType the join type
      */
-    public DBJoinExprEx(DBRowSet rset, DBCompareExpr cmp, DBJoinType joinType)
+    public DBCompareJoinExpr(DBRowSet rset, DBCompareExpr cmp, DBJoinType joinType)
     {
         super(firstRsetColumn(rset), findFirstColumn(cmp), joinType);
         this.cmp = cmp;
diff --git a/empire-db/src/main/java/org/apache/empire/db/expr/join/DBCrossJoinExpr.java b/empire-db/src/main/java/org/apache/empire/db/expr/join/DBCrossJoinExpr.java
new file mode 100644
index 0000000..c76da2f
--- /dev/null
+++ b/empire-db/src/main/java/org/apache/empire/db/expr/join/DBCrossJoinExpr.java
@@ -0,0 +1,177 @@
+/*
+ * 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.empire.db.expr.join;
+
+import java.util.Set;
+
+import org.apache.empire.db.DBColumn;
+import org.apache.empire.db.DBColumnExpr;
+import org.apache.empire.db.DBDatabase;
+import org.apache.empire.db.DBJoinType;
+import org.apache.empire.db.DBRowSet;
+
+/**
+ * This class is used for building a join expression of an SQL statement.
+ * <P>
+ * There is no need to explicitly create instances of this class.<BR>
+ * Instead use @link {@link org.apache.empire.db.DBCommand#join(DBColumnExpr, DBColumn, DBJoinType)}
+ * <P>
+ *
+ */
+public class DBCrossJoinExpr extends DBJoinExpr
+{
+    private final static long serialVersionUID = 1L;
+  
+    protected DBRowSet left;
+    protected DBRowSet right;
+    
+    /**
+     * Constructs a new DBJoinExpr object initialize this object with
+     * the left and right column and the data type of the join
+     * expression.
+     * 
+     * @param left left value
+     * @param right right value
+     * @param type data type (JOIN_INNER, JOIN_LEFT or JOIN_RIGHT)
+     */
+    public DBCrossJoinExpr(DBRowSet left, DBRowSet right)
+    {
+        super(DBJoinType.CROSS);
+        this.left = left;
+        this.right = right;
+    }
+
+    /**
+     * Returns the current DBDatabase object.
+     * 
+     * @return the current DBDatabase object
+     */
+    @Override
+    public DBDatabase getDatabase()
+    {
+        return left.getDatabase();
+    }
+    
+    /**
+     * returns the RowSet on the left of the join
+     */
+    @Override
+    public DBRowSet getLeftTable()
+    {
+        return left;
+    }
+    
+    /**
+     * returns the RowSet on the right of the join
+     */
+    @Override
+    public DBRowSet getRightTable()
+    {
+        return right;
+    }
+    
+    /**
+     * returns true if this join is using the given table or view or false otherwise
+     */
+    @Override
+    public boolean isJoinOn(DBRowSet rowset)
+    {
+        if (rowset==null)
+            return false;
+        return rowset.equals(left) || rowset.equals(right);
+    }
+    
+    /**
+     * returns true if this join is using the given column or false otherwise
+     */
+    @Override
+    public boolean isJoinOn(DBColumn column)
+    {
+        return false;
+    }
+
+    /**
+     * Returns the left table name if the data type= JOIN_LEFT and returns
+     * the right table if the data type= JOIN_RIGHT. If the
+     * data type = JOIN_INNER the return value is null.
+     * 
+     * @return the current DBDatabase object
+     */
+    @Override
+    public DBRowSet getOuterTable()
+    {
+        return null; // no outer table!
+    }
+
+    /**
+     * This function swaps the left and the right statements of the join expression.
+     */
+    @Override
+    public void reverse()
+    { // Swap Type of Join
+        DBRowSet swap = left;
+        left = right;
+        right = swap;
+    }
+
+    /**
+     * @see org.apache.empire.db.DBExpr#addReferencedColumns(Set)
+     */
+    @Override
+    public void addReferencedColumns(Set<DBColumn> list)
+    {
+        // No referenced columns
+    }
+
+    /** Not allowed, this operation have to be done in the DBCommand object. */
+    @Override
+    public void addSQL(StringBuilder buf, long context)
+    {
+        if ((context & CTX_NAME) != 0)
+            left.addSQL(buf, CTX_DEFAULT | CTX_ALIAS);
+        if ((context & CTX_VALUE) != 0)
+        { // Join Type
+            buf.append(" CROSS JOIN ");
+            right.addSQL(buf, CTX_DEFAULT | CTX_ALIAS);
+        }
+    }
+
+    /**
+     * Compares two DBJoinExpr objects.
+     * 
+     * @param obj other DBJoinExpr object
+     * @return true if the other DBJoinExpr object is equal to this object
+     */
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (!(obj instanceof DBCrossJoinExpr))
+            return super.equals(obj);
+        // object
+        DBCrossJoinExpr other = (DBCrossJoinExpr) obj;
+        if (left.equals(other.left) && right.equals(other.right))
+            return true;
+        // reversed
+        if (left.equals(other.right) && right.equals(other.left))
+            return true;
+        // not equal
+        return false;
+    }
+
+}
\ No newline at end of file
diff --git a/empire-db/src/main/java/org/apache/empire/db/expr/join/DBJoinExpr.java b/empire-db/src/main/java/org/apache/empire/db/expr/join/DBJoinExpr.java
index 1306e90..200f19f 100644
--- a/empire-db/src/main/java/org/apache/empire/db/expr/join/DBJoinExpr.java
+++ b/empire-db/src/main/java/org/apache/empire/db/expr/join/DBJoinExpr.java
@@ -18,16 +18,11 @@
  */
 package org.apache.empire.db.expr.join;
 
-import java.util.HashSet;
-import java.util.Set;
-
 import org.apache.empire.db.DBColumn;
 import org.apache.empire.db.DBColumnExpr;
-import org.apache.empire.db.DBDatabase;
 import org.apache.empire.db.DBExpr;
 import org.apache.empire.db.DBJoinType;
 import org.apache.empire.db.DBRowSet;
-import org.apache.empire.db.expr.compare.DBCompareExpr;
 
 /**
  * This class is used for building a join expression of an SQL statement.
@@ -37,17 +32,12 @@
  * <P>
  *
  */
-public class DBJoinExpr extends DBExpr
+public abstract class DBJoinExpr extends DBExpr
 {
     private final static long serialVersionUID = 1L;
   
-    protected DBColumnExpr  left;
-    protected DBColumnExpr  right;
     protected DBJoinType    type;
 
-    // Additional
-    public DBCompareExpr compExpr = null;
-
     /**
      * Constructs a new DBJoinExpr object initialize this object with
      * the left and right column and the data type of the join
@@ -57,41 +47,12 @@
      * @param right right value
      * @param type data type (JOIN_INNER, JOIN_LEFT or JOIN_RIGHT)
      */
-    public DBJoinExpr(DBColumnExpr left, DBColumnExpr right, DBJoinType type)
+    protected DBJoinExpr(DBJoinType type)
     {
-        this.left = left;
-        this.right = right;
         this.type = type;
     }
 
     /**
-     * Returns the current DBDatabase object.
-     * 
-     * @return the current DBDatabase object
-     */
-    @Override
-    public DBDatabase getDatabase()
-    {
-        return left.getDatabase();
-    }
-
-    /**
-     * returns the left join expression
-     */
-    public DBColumnExpr getLeft()
-    {
-        return left;
-    }
-
-    /**
-     * returns the right join expression
-     */
-    public DBColumnExpr getRight()
-    {
-        return right;
-    }
-
-    /**
      * returns the join type for this join
      */
     public DBJoinType getType()
@@ -100,39 +61,24 @@
     }
     
     /**
+     * returns the RowSet on the left of the join
+     */
+    public abstract DBRowSet getLeftTable();
+    
+    /**
+     * returns the RowSet on the right of the join
+     */
+    public abstract DBRowSet getRightTable();
+    
+    /**
      * returns true if this join is using the given table or view or false otherwise
      */
-    public boolean isJoinOn(DBRowSet rowset)
-    {
-        if (rowset==null)
-            return false;
-        DBColumn l = (left !=null ? left .getUpdateColumn() : null);
-        DBColumn r = (right!=null ? right.getUpdateColumn() : null);
-        DBRowSet rsl = (l!=null ? l.getRowSet() : null);
-        DBRowSet rsr = (r!=null ? r.getRowSet() : null);
-        return rowset.equals(rsl) || rowset.equals(rsr);
-    }
+    public abstract boolean isJoinOn(DBRowSet rowset);
     
     /**
      * returns true if this join is using the given column or false otherwise
      */
-    public boolean isJoinOn(DBColumn column)
-    {
-        if (column==null)
-            return false;
-        // Check Update Columns
-        if (column.equals(left.getUpdateColumn()) ||
-            column.equals(right.getUpdateColumn()))
-            return true;
-        if (compExpr!=null)
-        {   // Check expression
-            HashSet<DBColumn> set = new HashSet<DBColumn>();
-            compExpr.addReferencedColumns(set);
-            return set.contains(column);
-        }
-        // not found
-        return false;
-    }
+    public abstract boolean isJoinOn(DBColumn column);
 
     /**
      * Returns the left table name if the data type= JOIN_LEFT and returns
@@ -141,126 +87,11 @@
      * 
      * @return the current DBDatabase object
      */
-    public DBRowSet getOuterTable()
-    {
-        switch(type)
-        {
-            case LEFT:  return right.getUpdateColumn().getRowSet();
-            case RIGHT: return left .getUpdateColumn().getRowSet();
-            default:    return null; // no outer table!
-        }
-    }
+    public abstract DBRowSet getOuterTable();
 
     /**
      * This function swaps the left and the right statements of the join expression.
      */
-    public void reverse()
-    { // Swap Type of Join
-        DBColumnExpr swap = left;
-        left = right;
-        right = swap;
-        type = DBJoinType.reversed(type); // (type * -1);
-    }
-
-    /**
-     * Returns any additional constraints to the join
-     * @return a compare expression containing additional constraints or null 
-     */
-    public DBCompareExpr getWhere()
-    {
-        return compExpr;
-    }
-
-    /**
-     * This function adds an additional constraint to the join.
-     * 
-     * @param expr the compare expression
-     */
-    public void where(DBCompareExpr expr)
-    { // Set Compare Expression
-        compExpr = expr;
-    }
-
-    /**
-     * This function adds an additional constraint to the join.
-     * 
-     * @param c1 the first column
-     * @param c2 the second column
-     * 
-     * @return the object itself
-     */
-    public DBJoinExpr and(DBColumnExpr c1, DBColumnExpr c2)
-    {   // Set Compare Expression
-        if (compExpr==null)
-            compExpr = c1.is(c2);
-        else
-            compExpr = compExpr.and(c1.is(c2));
-        return this;
-    }
-
-    /**
-     * @see org.apache.empire.db.DBExpr#addReferencedColumns(Set)
-     */
-    @Override
-    public void addReferencedColumns(Set<DBColumn> list)
-    {
-        left.addReferencedColumns(list);
-        right.addReferencedColumns(list);
-        // Compare Expression
-        if (compExpr != null)
-            compExpr.addReferencedColumns(list);
-    }
-
-    /** Not allowed, this operation have to be done in the DBCommand object. */
-    @Override
-    public void addSQL(StringBuilder buf, long context)
-    {
-        if ((context & CTX_NAME) != 0)
-            left.getUpdateColumn().getRowSet().addSQL(buf, CTX_DEFAULT | CTX_ALIAS);
-        if ((context & CTX_VALUE) != 0)
-        { // Join Type
-            switch(type)
-            {
-                case LEFT:  buf.append(" LEFT JOIN ");break;
-                case INNER: buf.append(" INNER JOIN ");break;
-                case RIGHT: buf.append(" RIGHT JOIN ");break;
-                default:    buf.append(" JOIN "); // should not come here!
-            }
-            right.getUpdateColumn().getRowSet().addSQL(buf, CTX_DEFAULT | CTX_ALIAS);
-            // compare equal
-            buf.append(" ON ");
-            right.addSQL(buf, CTX_DEFAULT);
-            buf.append(" = ");
-            left.addSQL(buf, CTX_DEFAULT);
-            // Compare Expression
-            if (compExpr != null)
-            {
-                buf.append(" AND ");
-                compExpr.addSQL(buf, CTX_DEFAULT);
-            }
-        }
-    }
-
-    /**
-     * Compares two DBJoinExpr objects.
-     * 
-     * @param obj other DBJoinExpr object
-     * @return true if the other DBJoinExpr object is equal to this object
-     */
-    @Override
-    public boolean equals(Object obj)
-    {
-        if (obj==null || obj.getClass()!=getClass())
-            return super.equals(obj);
-        // object
-        DBJoinExpr other = (DBJoinExpr) obj;
-        if (left.equals(other.left) && right.equals(other.right) && type == other.type)
-            return true;
-        // reversed
-        if (left.equals(other.right) && right.equals(other.left) && type == DBJoinType.reversed(other.type))
-            return true;
-        // not equal
-        return false;
-    }
+    public abstract void reverse();
 
 }
\ No newline at end of file
diff --git a/empire-db/src/main/java/org/apache/empire/db/oracle/DBCommandOracle.java b/empire-db/src/main/java/org/apache/empire/db/oracle/DBCommandOracle.java
index f6b91cd..01ad81b 100644
--- a/empire-db/src/main/java/org/apache/empire/db/oracle/DBCommandOracle.java
+++ b/empire-db/src/main/java/org/apache/empire/db/oracle/DBCommandOracle.java
@@ -31,6 +31,7 @@
 import org.apache.empire.db.DBRowSet;
 import org.apache.empire.db.DBTable;
 import org.apache.empire.db.expr.compare.DBCompareExpr;
+import org.apache.empire.db.expr.join.DBColumnJoinExpr;
 import org.apache.empire.db.expr.join.DBJoinExpr;
 import org.apache.empire.db.expr.set.DBSetExpr;
 import org.apache.empire.exceptions.InvalidArgumentException;
@@ -286,13 +287,15 @@
         DBRowSet table =  set.get(0).getTable();
         table.addSQL(buf, CTX_FULLNAME|CTX_ALIAS);
         // join (only one allowed yet)
-        DBJoinExpr updateJoin = null;
+        DBColumnJoinExpr updateJoin = null;
         for (DBJoinExpr jex : joins)
         {   // The join
+            if (!(jex instanceof DBColumnJoinExpr))
+                continue;
             if (jex.isJoinOn(table)==false)
                 continue;
             // found the join
-            updateJoin = jex;
+            updateJoin = (DBColumnJoinExpr)jex;
             break;
         }
         if (updateJoin==null)
diff --git a/empire-db/src/main/java/org/apache/empire/db/sqlite/DBDatabaseDriverSQLite.java b/empire-db/src/main/java/org/apache/empire/db/sqlite/DBDatabaseDriverSQLite.java
index 24e345e..3f0bacb 100644
--- a/empire-db/src/main/java/org/apache/empire/db/sqlite/DBDatabaseDriverSQLite.java
+++ b/empire-db/src/main/java/org/apache/empire/db/sqlite/DBDatabaseDriverSQLite.java
@@ -41,6 +41,7 @@
 import org.apache.empire.db.DBJoinType;
 import org.apache.empire.db.DBObject;
 import org.apache.empire.db.DBSQLScript;
+import org.apache.empire.db.expr.join.DBColumnJoinExpr;
 import org.apache.empire.db.expr.join.DBJoinExpr;
 import org.apache.empire.exceptions.NotImplementedException;
 import org.apache.empire.exceptions.UnexpectedReturnValueException;
@@ -74,13 +75,13 @@
         }
         
         @Override
-		public DBJoinExpr join(DBColumnExpr left, DBColumnExpr right, DBJoinType joinType)
+		public DBColumnJoinExpr join(DBColumnExpr left, DBColumnExpr right, DBJoinType joinType)
         {
             // http://www.sqlite.org/omitted.html
-            if (joinType != DBJoinType.LEFT) { throw new NotImplementedException(joinType, left + " join " + right); }
-            DBJoinExpr join = new DBJoinExpr(left, right, joinType);
-            join(join);
-            return join;
+            if (joinType != DBJoinType.LEFT) {
+                throw new NotImplementedException(joinType, left + " join " + right); 
+            }
+            return super.join(left, right, joinType);
         }
         
         @Override
@@ -88,7 +89,11 @@
         {
             for (DBJoinExpr joinExpr : joinExprList)
             {
-                if (joinExpr.getType() != DBJoinType.LEFT) { throw new NotImplementedException(joinExpr.getType(), joinExpr.getLeft() + " join " + joinExpr.getLeft()); }
+                if ((joinExpr instanceof DBColumnJoinExpr) && 
+                    (joinExpr.getType() != DBJoinType.LEFT)) { 
+                    DBColumnJoinExpr join = (DBColumnJoinExpr)joinExpr;
+                    throw new NotImplementedException(joinExpr.getType(), join.getLeft() + " join " + join.getRight()); 
+                }
             }
             /*
              * Iterator<DBJoinExpr> iterator = joinExprList.iterator(); for