You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2007/04/03 17:09:24 UTC

svn commit: r525170 - in /cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src: main/java/org/apache/cayenne/access/jdbc/ main/java/org/apache/cayenne/dba/ main/java/org/apache/cayenne/query/ test/java/org/apache/cayenne/access/ test/java/org/ap...

Author: aadamchik
Date: Tue Apr  3 08:09:09 2007
New Revision: 525170

URL: http://svn.apache.org/viewvc?view=rev&rev=525170
Log:
CAY-452: EJB QL Cayenne Query
refactoring query translation, pushing it down to the JDBC layer, so that generated sql could be customized per adapter

Added:
    cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLAction.java
    cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLConditionTranslator.java
      - copied, changed from r522464, cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLConditionTranslator.java
    cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLFromTranslator.java
      - copied, changed from r522464, cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLFromTranslator.java
    cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLPathTranslator.java
      - copied, changed from r522464, cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLPathTranslator.java
    cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectColumnsTranslator.java
      - copied, changed from r520869, cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLSelectColumnsTranslator.java
    cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectOrderByTranslator.java
      - copied, changed from r520869, cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLSelectOrderByTranslator.java
    cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectTranslator.java
      - copied, changed from r522464, cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLSelectTranslator.java
    cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLTranslator.java
      - copied, changed from r522464, cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLTranslator.java
    cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLQueryMetadata.java
    cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/access/jdbc/EJBQLTranslatorTest.java
      - copied, changed from r522464, cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/query/EJBQLTranslatorTest.java
Removed:
    cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLConditionTranslator.java
    cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLFromTranslator.java
    cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLPathTranslator.java
    cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLSelectColumnsTranslator.java
    cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLSelectOrderByTranslator.java
    cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLSelectTranslator.java
    cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLTranslator.java
    cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/query/EJBQLTranslatorTest.java
Modified:
    cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/dba/JdbcActionBuilder.java
    cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLQuery.java
    cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/SQLActionVisitor.java
    cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/SQLTemplateMetadata.java
    cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/access/DataContextEJBQLJoinsTest.java
    cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/access/EmbeddingTest.java
    cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/resources/dml/access.DataContextEJBQLJoinsTest.xml

Added: cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLAction.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLAction.java?view=auto&rev=525170
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLAction.java (added)
+++ cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLAction.java Tue Apr  3 08:09:09 2007
@@ -0,0 +1,57 @@
+/*****************************************************************
+ *   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.cayenne.access.jdbc;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import org.apache.cayenne.access.OperationObserver;
+import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.ejbql.EJBQLCompiledExpression;
+import org.apache.cayenne.map.EntityResolver;
+import org.apache.cayenne.query.EJBQLQuery;
+import org.apache.cayenne.query.SQLActionVisitor;
+import org.apache.cayenne.query.SQLTemplate;
+
+/**
+ * Parses an EJBQL statement, converting it to SQL. Executes the resulting SQL.
+ * 
+ * @since 3.0
+ * @author Andrus Adamchik
+ */
+public class EJBQLAction extends BaseSQLAction {
+
+    protected SQLActionVisitor actionFactory;
+    protected EJBQLQuery query;
+
+    public EJBQLAction(EJBQLQuery query, SQLActionVisitor actionFactory,
+            DbAdapter adapter, EntityResolver entityResolver) {
+        super(adapter, entityResolver);
+
+        this.query = query;
+        this.actionFactory = actionFactory;
+    }
+
+    public void performAction(Connection connection, OperationObserver observer)
+            throws SQLException, Exception {
+        EJBQLCompiledExpression expression = query.getExpression(getEntityResolver());
+        SQLTemplate sql = new EJBQLTranslator(expression).translate();
+        actionFactory.sqlAction(sql).performAction(connection, observer);
+    }
+}

Copied: cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLConditionTranslator.java (from r522464, cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLConditionTranslator.java)
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLConditionTranslator.java?view=diff&rev=525170&p1=cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLConditionTranslator.java&r1=522464&p2=cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLConditionTranslator.java&r2=525170
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLConditionTranslator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLConditionTranslator.java Tue Apr  3 08:09:09 2007
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  ****************************************************************/
-package org.apache.cayenne.query;
+package org.apache.cayenne.access.jdbc;
 
 import java.math.BigDecimal;
 

Copied: cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLFromTranslator.java (from r522464, cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLFromTranslator.java)
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLFromTranslator.java?view=diff&rev=525170&p1=cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLFromTranslator.java&r1=522464&p2=cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLFromTranslator.java&r2=525170
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLFromTranslator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLFromTranslator.java Tue Apr  3 08:09:09 2007
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  ****************************************************************/
-package org.apache.cayenne.query;
+package org.apache.cayenne.access.jdbc;
 
 import org.apache.cayenne.ejbql.EJBQLBaseVisitor;
 import org.apache.cayenne.ejbql.EJBQLExpression;

Copied: cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLPathTranslator.java (from r522464, cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLPathTranslator.java)
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLPathTranslator.java?view=diff&rev=525170&p1=cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLPathTranslator.java&r1=522464&p2=cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLPathTranslator.java&r2=525170
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLPathTranslator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLPathTranslator.java Tue Apr  3 08:09:09 2007
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  ****************************************************************/
-package org.apache.cayenne.query;
+package org.apache.cayenne.access.jdbc;
 
 import org.apache.cayenne.ejbql.EJBQLBaseVisitor;
 import org.apache.cayenne.ejbql.EJBQLException;

Copied: cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectColumnsTranslator.java (from r520869, cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLSelectColumnsTranslator.java)
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectColumnsTranslator.java?view=diff&rev=525170&p1=cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLSelectColumnsTranslator.java&r1=520869&p2=cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectColumnsTranslator.java&r2=525170
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLSelectColumnsTranslator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectColumnsTranslator.java Tue Apr  3 08:09:09 2007
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  ****************************************************************/
-package org.apache.cayenne.query;
+package org.apache.cayenne.access.jdbc;
 
 import java.util.Iterator;
 import java.util.List;

Copied: cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectOrderByTranslator.java (from r520869, cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLSelectOrderByTranslator.java)
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectOrderByTranslator.java?view=diff&rev=525170&p1=cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLSelectOrderByTranslator.java&r1=520869&p2=cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectOrderByTranslator.java&r2=525170
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLSelectOrderByTranslator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectOrderByTranslator.java Tue Apr  3 08:09:09 2007
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  ****************************************************************/
-package org.apache.cayenne.query;
+package org.apache.cayenne.access.jdbc;
 
 import org.apache.cayenne.ejbql.EJBQLBaseVisitor;
 
@@ -26,10 +26,7 @@
  */
 class EJBQLSelectOrderByTranslator extends EJBQLBaseVisitor {
 
-    private EJBQLSelectTranslator parent;
-    
-    EJBQLSelectOrderByTranslator(EJBQLSelectTranslator parent) {
+    EJBQLSelectOrderByTranslator() {
         super(false);
-        this.parent = parent;
     }
 }

Copied: cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectTranslator.java (from r522464, cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLSelectTranslator.java)
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectTranslator.java?view=diff&rev=525170&p1=cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLSelectTranslator.java&r1=522464&p2=cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectTranslator.java&r2=525170
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLSelectTranslator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLSelectTranslator.java Tue Apr  3 08:09:09 2007
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  ****************************************************************/
-package org.apache.cayenne.query;
+package org.apache.cayenne.access.jdbc;
 
 import java.util.HashSet;
 import java.util.Iterator;
@@ -133,7 +133,7 @@
 
     public boolean visitOrderBy(EJBQLExpression expression) {
         parent.getBuffer().append(" ORDER BY");
-        setDelegate(new EJBQLSelectOrderByTranslator(this));
+        setDelegate(new EJBQLSelectOrderByTranslator());
         return true;
     }
 

Copied: cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLTranslator.java (from r522464, cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLTranslator.java)
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLTranslator.java?view=diff&rev=525170&p1=cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLTranslator.java&r1=522464&p2=cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLTranslator.java&r2=525170
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLTranslator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLTranslator.java Tue Apr  3 08:09:09 2007
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  ****************************************************************/
-package org.apache.cayenne.query;
+package org.apache.cayenne.access.jdbc;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -24,6 +24,7 @@
 import org.apache.cayenne.ejbql.EJBQLBaseVisitor;
 import org.apache.cayenne.ejbql.EJBQLCompiledExpression;
 import org.apache.cayenne.ejbql.EJBQLExpression;
+import org.apache.cayenne.query.SQLTemplate;
 
 /**
  * A translator of {@link EJBQLExpression} statements into the database SQL.

Modified: cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/dba/JdbcActionBuilder.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/dba/JdbcActionBuilder.java?view=diff&rev=525170&r1=525169&r2=525170
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/dba/JdbcActionBuilder.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/dba/JdbcActionBuilder.java Tue Apr  3 08:09:09 2007
@@ -20,12 +20,14 @@
 package org.apache.cayenne.dba;
 
 import org.apache.cayenne.access.jdbc.BatchAction;
+import org.apache.cayenne.access.jdbc.EJBQLAction;
 import org.apache.cayenne.access.jdbc.ProcedureAction;
 import org.apache.cayenne.access.jdbc.SQLTemplateAction;
 import org.apache.cayenne.access.jdbc.SelectAction;
 import org.apache.cayenne.access.jdbc.UpdateAction;
 import org.apache.cayenne.map.EntityResolver;
 import org.apache.cayenne.query.BatchQuery;
+import org.apache.cayenne.query.EJBQLQuery;
 import org.apache.cayenne.query.ProcedureQuery;
 import org.apache.cayenne.query.Query;
 import org.apache.cayenne.query.SQLAction;
@@ -80,6 +82,13 @@
         }
 
         return new UpdateAction(query, adapter, entityResolver);
+    }
+
+    /**
+     * @since 3.0
+     */
+    public SQLAction ejbqlAction(EJBQLQuery query) {
+        return new EJBQLAction(query, this, adapter, entityResolver);
     }
 
     /**

Modified: cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLQuery.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLQuery.java?view=diff&rev=525170&r1=525169&r2=525170
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLQuery.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLQuery.java Tue Apr  3 08:09:09 2007
@@ -18,9 +18,11 @@
  ****************************************************************/
 package org.apache.cayenne.query;
 
+import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.ejbql.EJBQLCompiledExpression;
 import org.apache.cayenne.ejbql.EJBQLException;
 import org.apache.cayenne.ejbql.EJBQLParserFactory;
+import org.apache.cayenne.map.DataMap;
 import org.apache.cayenne.map.EntityResolver;
 
 /**
@@ -29,22 +31,36 @@
  * @since 3.0
  * @author Andrus Adamchik
  */
-public class EJBQLQuery extends IndirectQuery {
+public class EJBQLQuery implements Query {
 
+    protected String name;
     protected String ejbqlStatement;
 
     protected transient EJBQLCompiledExpression expression;
+    EJBQLQueryMetadata metadata = new EJBQLQueryMetadata();
 
     public EJBQLQuery(String ejbqlStatement) {
         this.ejbqlStatement = ejbqlStatement;
     }
 
-    /**
-     * Compiles EJBQL into a SQLTemplate query and returns this query.
-     */
-    protected Query createReplacementQuery(EntityResolver resolver) {
-        EJBQLCompiledExpression expression = getExpression(resolver);
-        return new EJBQLTranslator(expression).translate();
+    public QueryMetadata getMetaData(EntityResolver resolver) {
+        metadata.resolve(resolver, this);
+        return metadata;
+    }
+
+    public void route(QueryRouter router, EntityResolver resolver, Query substitutedQuery) {
+        DataMap map = getMetaData(resolver).getDataMap();
+
+        if (map == null) {
+            throw new CayenneRuntimeException("No DataMap found, can't route query "
+                    + this);
+        }
+
+        router.route(router.engineForDataMap(map), this, substitutedQuery);
+    }
+
+    public SQLAction createSQLAction(SQLActionVisitor visitor) {
+        return visitor.ejbqlAction(this);
     }
 
     /**
@@ -57,7 +73,8 @@
     /**
      * Returns lazily initialized EJBQLCompiledExpression for this query EJBQL.
      */
-    EJBQLCompiledExpression getExpression(EntityResolver resolver) throws EJBQLException {
+    public EJBQLCompiledExpression getExpression(EntityResolver resolver)
+            throws EJBQLException {
         if (expression == null) {
             this.expression = EJBQLParserFactory.getParser().compile(
                     ejbqlStatement,
@@ -65,5 +82,13 @@
         }
 
         return expression;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
     }
 }

Added: cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLQueryMetadata.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLQueryMetadata.java?view=auto&rev=525170
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLQueryMetadata.java (added)
+++ cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/EJBQLQueryMetadata.java Tue Apr  3 08:09:09 2007
@@ -0,0 +1,38 @@
+/*****************************************************************
+ *   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.cayenne.query;
+
+import org.apache.cayenne.map.EntityResolver;
+import org.apache.cayenne.map.ObjEntity;
+
+/**
+ * A metadata object for the {@link EJBQLQuery}.
+ * 
+ * @since 3.0
+ * @author Andrus Adamchik
+ */
+class EJBQLQueryMetadata extends BaseQueryMetadata {
+
+    boolean resolve(EntityResolver resolver, EJBQLQuery query) {
+        ObjEntity root = query.getExpression(resolver).getRootDescriptor().getEntity();
+
+        // TODO: andrus, 4/3/2007 - generate cache key based on EJBQL statement
+        return super.resolve(root, resolver, null);
+    }
+}

Modified: cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/SQLActionVisitor.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/SQLActionVisitor.java?view=diff&rev=525170&r1=525169&r2=525170
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/SQLActionVisitor.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/SQLActionVisitor.java Tue Apr  3 08:09:09 2007
@@ -17,16 +17,15 @@
  *  under the License.
  ****************************************************************/
 
-
 package org.apache.cayenne.query;
 
 /**
  * A factory interface to create standard SQLActions for a set of standard queries.
  * Instances of SQLActionVisitor are passed by Cayenne to a Query in
- * {@link org.apache.cayenne.query.Query#createSQLAction(SQLActionVisitor)},
- * allowing query to choose the action type and convert itself to a "standard" query if
- * needed. Individual DbAdapters would provide special visitors, thus allowing for
- * DB-dependent execution algorithms.
+ * {@link org.apache.cayenne.query.Query#createSQLAction(SQLActionVisitor)}, allowing
+ * query to choose the action type and convert itself to a "standard" query if needed.
+ * Individual DbAdapters would provide special visitors, thus allowing for DB-dependent
+ * execution algorithms.
  * 
  * @see org.apache.cayenne.query.Query#createSQLAction(SQLActionVisitor)
  * @since 1.2
@@ -35,27 +34,32 @@
 public interface SQLActionVisitor {
 
     /**
-     * Executes a generic update query.
+     * Creates an action to execute a generic update query.
      */
     SQLAction updateAction(Query query);
 
     /**
-     * Executes a batch update query.
+     * Creates an action to execute a batch update query.
      */
     SQLAction batchAction(BatchQuery query);
 
     /**
-     * Executes a SelectQuery.
+     * Creates an action to execute a SelectQuery.
      */
     SQLAction objectSelectAction(SelectQuery query);
 
     /**
-     * Executes a SQLTemplate.
+     * Creates an action to execute a SQLTemplate.
      */
     SQLAction sqlAction(SQLTemplate query);
 
     /**
-     * Executes a ProcedureQuery.
+     * Creates an action to execute a ProcedureQuery.
      */
     SQLAction procedureAction(ProcedureQuery query);
+
+    /**
+     * Creates an action to execute EJBQL query.
+     */
+    SQLAction ejbqlAction(EJBQLQuery query);
 }

Modified: cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/SQLTemplateMetadata.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/SQLTemplateMetadata.java?view=diff&rev=525170&r1=525169&r2=525170
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/SQLTemplateMetadata.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/query/SQLTemplateMetadata.java Tue Apr  3 08:09:09 2007
@@ -31,7 +31,7 @@
  * @since 3.0
  * @author Andrus Adamchik
  */
-public class SQLTemplateMetadata extends BaseQueryMetadata {
+class SQLTemplateMetadata extends BaseQueryMetadata {
 
     boolean resolve(Object root, EntityResolver resolver, SQLTemplate query) {
 

Modified: cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/access/DataContextEJBQLJoinsTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/access/DataContextEJBQLJoinsTest.java?view=diff&rev=525170&r1=525169&r2=525170
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/access/DataContextEJBQLJoinsTest.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/access/DataContextEJBQLJoinsTest.java Tue Apr  3 08:09:09 2007
@@ -18,14 +18,6 @@
  ****************************************************************/
 package org.apache.cayenne.access;
 
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-
-import org.apache.art.Artist;
-import org.apache.cayenne.DataObjectUtils;
-import org.apache.cayenne.query.EJBQLQuery;
 import org.apache.cayenne.unit.CayenneCase;
 
 public class DataContextEJBQLJoinsTest extends CayenneCase {
@@ -37,34 +29,34 @@
     public void testThetaJoins() throws Exception {
         createTestData("testThetaJoins");
 
-//        String ejbql = "SELECT DISTINCT a "
-//                + "FROM Artist a, Painting b "
-//                + "WHERE a.artistName = b.paintingTitle";
-//
-//        List artists = createDataContext().performQuery(new EJBQLQuery(ejbql));
-//        assertEquals(2, artists.size());
-//
-//        Set names = new HashSet(2);
-//        Iterator it = artists.iterator();
-//        while (it.hasNext()) {
-//            Artist a = (Artist) it.next();
-//            names.add(a.getArtistName());
-//        }
-//
-//        assertTrue(names.contains("AA1"));
-//        assertTrue(names.contains("BB2"));
+        // String ejbql = "SELECT DISTINCT a "
+        // + "FROM Artist a, Painting b "
+        // + "WHERE a.artistName = b.paintingTitle";
+        //
+        // List artists = createDataContext().performQuery(new EJBQLQuery(ejbql));
+        // assertEquals(2, artists.size());
+        //
+        // Set names = new HashSet(2);
+        // Iterator it = artists.iterator();
+        // while (it.hasNext()) {
+        // Artist a = (Artist) it.next();
+        // names.add(a.getArtistName());
+        // }
+        //
+        // assertTrue(names.contains("AA1"));
+        // assertTrue(names.contains("BB2"));
     }
 
     public void testInnerJoins() throws Exception {
         createTestData("testInnerJoins");
 
-//        String ejbql = "SELECT a "
-//                + "FROM Artist a INNER JOIN a.paintingArray p "
-//                + "WHERE a.artistName = 'A1'";
-//
-//        List artists = createDataContext().performQuery(new EJBQLQuery(ejbql));
-//        assertEquals(1, artists.size());
-//        assertEquals(33001, DataObjectUtils.intPKForObject((Artist) artists.get(0)));
+        // String ejbql = "SELECT a "
+        // + "FROM Artist a INNER JOIN a.paintingArray p "
+        // + "WHERE a.artistName = 'A1'";
+        //
+        // List artists = createDataContext().performQuery(new EJBQLQuery(ejbql));
+        // assertEquals(1, artists.size());
+        // assertEquals(33001, DataObjectUtils.intPKForObject((Artist) artists.get(0)));
     }
 
     public void testOuterJoins() throws Exception {
@@ -83,7 +75,51 @@
         // ids.add(DataObjectUtils.pkForObject(a));
         // }
         //
-        //        assertTrue(ids.contains(new Integer(33001)));
-        //        assertTrue(ids.contains(new Integer(33005)));
+        // assertTrue(ids.contains(new Integer(33001)));
+        // assertTrue(ids.contains(new Integer(33005)));
+    }
+
+    public void testChainedJoins() throws Exception {
+        createTestData("testChainedJoins");
+        // String ejbql = "SELECT a "
+        // + "FROM Artist a JOIN a.paintingArray p JOIN p.toGallery g "
+        // + "WHERE g.galleryName = 'gallery2'";
+        //
+        // List artists = createDataContext().performQuery(new EJBQLQuery(ejbql));
+        // assertEquals(1, artists.size());
+        // assertEquals(33002, DataObjectUtils.intPKForObject((Artist) artists.get(0)));
+    }
+
+    public void testImplicitJoins() throws Exception {
+        createTestData("testChainedJoins");
+        // String ejbql = "SELECT a "
+        // + "FROM Artist a "
+        // + "WHERE a.paintingArray.gallery.galleryName = 'gallery2'";
+        //
+        // List artists = createDataContext().performQuery(new EJBQLQuery(ejbql));
+        // assertEquals(1, artists.size());
+        // assertEquals(33002, DataObjectUtils.intPKForObject((Artist) artists.get(0)));
+    }
+
+    public void testPartialImplicitJoins() throws Exception {
+        createTestData("testChainedJoins");
+        // String ejbql = "SELECT a "
+        // + "FROM Artist a JOIN a.paintingArray b "
+        // + "WHERE a.paintingArray.gallery.galleryName = 'gallery2'";
+        //
+        // List artists = createDataContext().performQuery(new EJBQLQuery(ejbql));
+        // assertEquals(1, artists.size());
+        // assertEquals(33002, DataObjectUtils.intPKForObject((Artist) artists.get(0)));
+    }
+
+    public void testMultipleJoinsToTheSameTable() throws Exception {
+        createTestData("testMultipleJoinsToTheSameTable");
+        // String ejbql = "SELECT a "
+        // + "FROM Artist a JOIN a.paintingArray b JOIN a.paintingArray c "
+        // + "WHERE b.paintingTitle = 'P1' AND c.paintingTitle = 'P2'";
+        //
+        // List artists = createDataContext().performQuery(new EJBQLQuery(ejbql));
+        // assertEquals(1, artists.size());
+        //        assertEquals(33001, DataObjectUtils.intPKForObject((Artist) artists.get(0)));
     }
 }

Modified: cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/access/EmbeddingTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/access/EmbeddingTest.java?view=diff&rev=525170&r1=525169&r2=525170
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/access/EmbeddingTest.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/access/EmbeddingTest.java Tue Apr  3 08:09:09 2007
@@ -23,7 +23,6 @@
 import org.apache.cayenne.DataObjectUtils;
 import org.apache.cayenne.DataRow;
 import org.apache.cayenne.ObjectContext;
-import org.apache.cayenne.PersistenceState;
 import org.apache.cayenne.query.SelectQuery;
 import org.apache.cayenne.testdo.embeddable.EmbedEntity1;
 import org.apache.cayenne.testdo.embeddable.Embeddable1;

Copied: cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/access/jdbc/EJBQLTranslatorTest.java (from r522464, cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/query/EJBQLTranslatorTest.java)
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/access/jdbc/EJBQLTranslatorTest.java?view=diff&rev=525170&p1=cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/query/EJBQLTranslatorTest.java&r1=522464&p2=cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/access/jdbc/EJBQLTranslatorTest.java&r2=525170
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/query/EJBQLTranslatorTest.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/access/jdbc/EJBQLTranslatorTest.java Tue Apr  3 08:09:09 2007
@@ -16,11 +16,12 @@
  *  specific language governing permissions and limitations
  *  under the License.
  ****************************************************************/
-package org.apache.cayenne.query;
+package org.apache.cayenne.access.jdbc;
 
 import org.apache.cayenne.ejbql.EJBQLCompiledExpression;
 import org.apache.cayenne.ejbql.EJBQLParser;
 import org.apache.cayenne.ejbql.EJBQLParserFactory;
+import org.apache.cayenne.query.SQLTemplate;
 import org.apache.cayenne.unit.CayenneCase;
 
 public class EJBQLTranslatorTest extends CayenneCase {

Modified: cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/resources/dml/access.DataContextEJBQLJoinsTest.xml
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/resources/dml/access.DataContextEJBQLJoinsTest.xml?view=diff&rev=525170&r1=525169&r2=525170
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/resources/dml/access.DataContextEJBQLJoinsTest.xml (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/resources/dml/access.DataContextEJBQLJoinsTest.xml Tue Apr  3 08:09:09 2007
@@ -1,96 +1,201 @@
 <?xml version="1.0" encoding="UTF-8" ?>
 <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
 
-<beans default-lazy-init="true">	
+<beans default-lazy-init="true">
 	<bean id="A1" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
-		<constructor-arg type="java.lang.Class"><value>org.apache.art.Artist</value></constructor-arg>
-		<constructor-arg><value>
-		insert into ARTIST (ARTIST_ID, ARTIST_NAME) values (33001, 'AA1')
-		</value></constructor-arg>
+		<constructor-arg type="java.lang.Class">
+			<value>org.apache.art.Artist</value>
+		</constructor-arg>
+		<constructor-arg>
+			<value>insert into ARTIST (ARTIST_ID, ARTIST_NAME) values (33001, 'AA1')</value>
+		</constructor-arg>
 	</bean>
-	
+
 	<bean id="A2" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
-		<constructor-arg type="java.lang.Class"><value>org.apache.art.Artist</value></constructor-arg>
-		<constructor-arg><value>
-		insert into ARTIST (ARTIST_ID, ARTIST_NAME) values (33002, 'AA2')
-		</value></constructor-arg>
+		<constructor-arg type="java.lang.Class">
+			<value>org.apache.art.Artist</value>
+		</constructor-arg>
+		<constructor-arg>
+			<value>insert into ARTIST (ARTIST_ID, ARTIST_NAME) values (33002, 'AA2')</value>
+		</constructor-arg>
 	</bean>
-	
+
 	<bean id="A3" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
-		<constructor-arg type="java.lang.Class"><value>org.apache.art.Artist</value></constructor-arg>
-		<constructor-arg><value>
-		insert into ARTIST (ARTIST_ID, ARTIST_NAME) values (33003, 'BB1')
-		</value></constructor-arg>
+		<constructor-arg type="java.lang.Class">
+			<value>org.apache.art.Artist</value>
+		</constructor-arg>
+		<constructor-arg>
+			<value>insert into ARTIST (ARTIST_ID, ARTIST_NAME) values (33003, 'BB1')</value>
+		</constructor-arg>
 	</bean>
-	
+
 	<bean id="A4" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
-		<constructor-arg type="java.lang.Class"><value>org.apache.art.Artist</value></constructor-arg>
-		<constructor-arg><value>
-		insert into ARTIST (ARTIST_ID, ARTIST_NAME) values (33004, 'BB2')
-		</value></constructor-arg>
+		<constructor-arg type="java.lang.Class">
+			<value>org.apache.art.Artist</value>
+		</constructor-arg>
+		<constructor-arg>
+			<value>insert into ARTIST (ARTIST_ID, ARTIST_NAME) values (33004, 'BB2')</value>
+		</constructor-arg>
 	</bean>
-	
+
 	<bean id="A5" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
-		<constructor-arg type="java.lang.Class"><value>org.apache.art.Artist</value></constructor-arg>
-		<constructor-arg><value>
-		insert into ARTIST (ARTIST_ID, ARTIST_NAME) values (33005, 'AA1')
-		</value></constructor-arg>
+		<constructor-arg type="java.lang.Class">
+			<value>org.apache.art.Artist</value>
+		</constructor-arg>
+		<constructor-arg>
+			<value>insert into ARTIST (ARTIST_ID, ARTIST_NAME) values (33005, 'AA1')</value>
+		</constructor-arg>
 	</bean>
-	
+
 	<bean id="P11" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
-		<constructor-arg type="java.lang.Class"><value>org.apache.art.Painting</value></constructor-arg>
-		<constructor-arg><value>
-		INSERT INTO PAINTING (PAINTING_ID, PAINTING_TITLE, ARTIST_ID, ESTIMATED_PRICE) VALUES (33001, 'P1', 33001, 3000)
-		</value></constructor-arg>
+		<constructor-arg type="java.lang.Class">
+			<value>org.apache.art.Painting</value>
+		</constructor-arg>
+		<constructor-arg>
+			<value>
+				INSERT INTO PAINTING (PAINTING_ID, PAINTING_TITLE, ARTIST_ID, ESTIMATED_PRICE)
+				VALUES (33001, 'P1', 33001, 3000)
+			</value>
+		</constructor-arg>
 	</bean>
-	
+
 	<bean id="P12" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
-		<constructor-arg type="java.lang.Class"><value>org.apache.art.Painting</value></constructor-arg>
-		<constructor-arg><value>
-		INSERT INTO PAINTING (PAINTING_ID, PAINTING_TITLE, ARTIST_ID, ESTIMATED_PRICE) VALUES (33002, 'P2', 33002, 5000)
-		</value></constructor-arg>
+		<constructor-arg type="java.lang.Class">
+			<value>org.apache.art.Painting</value>
+		</constructor-arg>
+		<constructor-arg>
+			<value>
+				INSERT INTO PAINTING (PAINTING_ID, PAINTING_TITLE, ARTIST_ID, ESTIMATED_PRICE)
+				VALUES (33002, 'P2', 33002, 5000)
+			</value>
+		</constructor-arg>
 	</bean>
-	
+
 	<bean id="P13" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
-		<constructor-arg type="java.lang.Class"><value>org.apache.art.Painting</value></constructor-arg>
+		<constructor-arg type="java.lang.Class">
+			<value>org.apache.art.Painting</value>
+		</constructor-arg>
+		<constructor-arg>
+			<value>
+				INSERT INTO PAINTING (PAINTING_ID, PAINTING_TITLE, ARTIST_ID, ESTIMATED_PRICE)
+				VALUES (33003, 'AA1', 33001, 3000)
+			</value>
+		</constructor-arg>
+	</bean>
+
+	<bean id="P23" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
+		<constructor-arg type="java.lang.Class">
+			<value>org.apache.art.Painting</value>
+		</constructor-arg>
+		<constructor-arg>
+			<value>
+				INSERT INTO PAINTING (PAINTING_ID, PAINTING_TITLE, ARTIST_ID, ESTIMATED_PRICE)
+				VALUES (33004, 'BB2', 33002, 3000)
+			</value>
+		</constructor-arg>
+	</bean>
+	
+	<bean id="P14" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
+		<constructor-arg type="java.lang.Class">
+			<value>org.apache.art.Painting</value>
+		</constructor-arg>
+		<constructor-arg>
+			<value>
+				INSERT INTO PAINTING (PAINTING_ID, GALLERY_ID, PAINTING_TITLE, ARTIST_ID, ESTIMATED_PRICE)
+				VALUES (33005, 33001, 'CC1', 33001, 5000)
+			</value>
+		</constructor-arg>
+	</bean>
+	
+	<bean id="P24" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
+		<constructor-arg type="java.lang.Class">
+			<value>org.apache.art.Painting</value>
+		</constructor-arg>
+		<constructor-arg>
+			<value>
+				INSERT INTO PAINTING (PAINTING_ID, GALLERY_ID, PAINTING_TITLE, ARTIST_ID, ESTIMATED_PRICE)
+				VALUES (33006, 33002, 'CC2', 33002, 5000)
+			</value>
+		</constructor-arg>
+	</bean>
+	
+	<bean id="P15" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
+		<constructor-arg type="java.lang.Class">
+			<value>org.apache.art.Painting</value>
+		</constructor-arg>
+		<constructor-arg>
+			<value>
+				INSERT INTO PAINTING (PAINTING_ID, PAINTING_TITLE, ARTIST_ID, ESTIMATED_PRICE)
+				VALUES (33007, 'P2', 33001, 5000)
+			</value>
+		</constructor-arg>
+	</bean>
+	
+	<bean id="G1" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
+		<constructor-arg type="java.lang.Class"><value>org.apache.art.Gallery</value></constructor-arg>
 		<constructor-arg><value>
-		INSERT INTO PAINTING (PAINTING_ID, PAINTING_TITLE, ARTIST_ID, ESTIMATED_PRICE) VALUES (33003, 'AA1', 33001, 3000)
+		INSERT INTO GALLERY (GALLERY_ID, GALLERY_NAME) VALUES (33001, 'gallery1')
 		</value></constructor-arg>
 	</bean>
 	
-	<bean id="P23" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
-		<constructor-arg type="java.lang.Class"><value>org.apache.art.Painting</value></constructor-arg>
+	<bean id="G2" class="org.apache.cayenne.unit.util.UpdatingSQLTemplate">
+		<constructor-arg type="java.lang.Class"><value>org.apache.art.Gallery</value></constructor-arg>
 		<constructor-arg><value>
-		INSERT INTO PAINTING (PAINTING_ID, PAINTING_TITLE, ARTIST_ID, ESTIMATED_PRICE) VALUES (33004, 'BB2', 33002, 3000)
+		INSERT INTO GALLERY (GALLERY_ID, GALLERY_NAME) VALUES (33002, 'gallery2')
 		</value></constructor-arg>
 	</bean>
-	
+
 
 	<!-- ======================================= -->
 	<!-- Data Sets -->
-	<!-- ======================================= -->	
-	
+	<!-- ======================================= -->
+
 	<bean id="testThetaJoins" class="java.util.ArrayList">
 		<constructor-arg>
 			<list>
-				<ref bean="A1"/>
-				<ref bean="A2"/>
-				<ref bean="A3"/>
-				<ref bean="A4"/>
-				<ref bean="P11"/>
-				<ref bean="P12"/>
-				<ref bean="P13"/>
-				<ref bean="P23"/>
+				<ref bean="A1" />
+				<ref bean="A2" />
+				<ref bean="A3" />
+				<ref bean="A4" />
+				<ref bean="P11" />
+				<ref bean="P12" />
+				<ref bean="P13" />
+				<ref bean="P23" />
 			</list>
 		</constructor-arg>
 	</bean>
-	
+
 	<bean id="testInnerJoins" class="java.util.ArrayList">
 		<constructor-arg>
 			<list>
-				<ref bean="A1"/>
-				<ref bean="A5"/>
-				<ref bean="P11"/>
+				<ref bean="A1" />
+				<ref bean="A5" />
+				<ref bean="P11" />
+			</list>
+		</constructor-arg>
+	</bean>
+
+	<bean id="testChainedJoins" class="java.util.ArrayList">
+		<constructor-arg>
+			<list>
+				<ref bean="A1" />
+				<ref bean="A2" />
+				<ref bean="G1" />
+				<ref bean="G2" />
+				<ref bean="P14" />
+				<ref bean="P24" />
+			</list>
+		</constructor-arg>
+	</bean>
+	
+	<bean id="testMultipleJoinsToTheSameTable" class="java.util.ArrayList">
+		<constructor-arg>
+			<list>
+				<ref bean="A1" />
+				<ref bean="A2" />
+				<ref bean="P11" />
+				<ref bean="P12" />
+				<ref bean="P15" />
 			</list>
 		</constructor-arg>
 	</bean>