You are viewing a plain text version of this content. The canonical link for it is here.
Posted to torque-dev@db.apache.org by tf...@apache.org on 2015/10/06 04:52:34 UTC

svn commit: r1706947 - in /db/torque/torque4/trunk: torque-runtime/src/main/java/org/apache/torque/criteria/ torque-runtime/src/main/java/org/apache/torque/sql/ torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/ torque-runtime/src/main/j...

Author: tfischer
Date: Tue Oct  6 02:52:34 2015
New Revision: 1706947

URL: http://svn.apache.org/viewvc?rev=1706947&view=rev
Log:
TORQUE-290: 
- Subselects can now easily reference Columns in outer select
- made PreparedStatementPart an interface
- retain information about the structure of the select in the created query

Added:
    db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/PreparedStatementPartImpl.java
    db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/PreparedStatementPartForSubselect.java
    db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/CombinedPreparedStatementPart.java
    db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/NoReplacementsPreparedStatementPart.java
    db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/OnlyReplacementsPreparedStatementPart.java
Modified:
    db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/Criteria.java
    db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/PreparedStatementPart.java
    db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/JoinBuilder.java
    db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/SqlBuilder.java
    db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/ObjectOrColumnPsPartBuilder.java
    db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/ObjectPsPartBuilder.java
    db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/CurrentDateTimePsPartBuilder.java
    db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/EnumValueBuilder.java
    db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/InBuilder.java
    db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/LikeBuilder.java
    db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/NullValueBuilder.java
    db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/StandardBuilder.java
    db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/VerbatimSqlConditionBuilder.java
    db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/WhereClausePsPartBuilder.java
    db/torque/torque4/trunk/torque-runtime/src/test/java/org/apache/torque/sql/SqlBuilderTest.java
    db/torque/torque4/trunk/torque-test/src/test/java/org/apache/torque/generated/peer/WhereClauseSubselectTest.java

Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/Criteria.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/Criteria.java?rev=1706947&r1=1706946&r2=1706947&view=diff
==============================================================================
--- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/Criteria.java (original)
+++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/Criteria.java Tue Oct  6 02:52:34 2015
@@ -678,8 +678,8 @@ public class Criteria implements Seriali
     {
         assertNoComposite();
         joins.add(new Join(
-                new PreparedStatementPart(leftTable),
-                new PreparedStatementPart(rightTable),
+                new PreparedStatementPartImpl(leftTable),
+                new PreparedStatementPartImpl(rightTable),
                 joinCondition,
                 joinType));
         return this;

Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/PreparedStatementPart.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/PreparedStatementPart.java?rev=1706947&r1=1706946&r2=1706947&view=diff
==============================================================================
--- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/PreparedStatementPart.java (original)
+++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/PreparedStatementPart.java Tue Oct  6 02:52:34 2015
@@ -19,160 +19,28 @@ package org.apache.torque.criteria;
  * under the License.
  */
 
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
-
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang.builder.EqualsBuilder;
-import org.apache.commons.lang.builder.HashCodeBuilder;
 /**
  * The rendered SQL for a part of a prepared statement, including replacements for ? placeholders.
  *
  * @version $Id$
  */
-public class PreparedStatementPart implements Serializable
+public interface PreparedStatementPart
 {
-    /** Version id for serializing. */
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * The SQL for the part, not null.
-     */
-    private final StringBuilder sql = new StringBuilder();
-
-    /**
-     * The replacements for the prepared statement, not null.
-     */
-    private final List<Object> preparedStatementReplacements
-        = new ArrayList<Object>();
-
-    /**
-     * Default constructor, creates an empty PreparedStatementPart.
-     */
-    public PreparedStatementPart()
-    {
-        // empty
-    }
-
-    /**
-     * Constructor, creates a pre-filled PreparedStatementPart.
-     *
-     * @param sql The sql to fill into the sql buffer initially, or null.
-     * @param preparedStatementReplacements the prepared statement replacements
-     *        to start with, or null.
-     */
-    public PreparedStatementPart(
-            final String sql,
-            final Object... preparedStatementReplacements)
-    {
-        if (!StringUtils.isEmpty(sql))
-        {
-            this.sql.append(sql);
-        }
-        if (preparedStatementReplacements != null)
-        {
-            this.preparedStatementReplacements.addAll(
-                    Arrays.asList(preparedStatementReplacements));
-        }
-    }
-
-    /**
-     * Returns the SQL of the part.
-     *
-     * @return the SQL as mutable StringBuilder, not null.
-     */
-    public StringBuilder getSql()
-    {
-        return sql;
-    }
-
     /**
      * Returns the SQL of the part as String.
      *
      * @return the SQL, not null.
      */
-    public String getSqlAsString()
-    {
-        return sql.toString();
-    }
+    public String getSqlAsString();
 
     /**
      * Returns the list of prepared statement replacements.
+     * The implementation may or may not return a list which is modifiable
+     * and which may or may not, in case of modification,
+     * change the internal state of the surrounding PreparedStatementPart.
      *
-     * @return the modifiable list of prepared statement replacements, not null.
-     */
-    public List<Object> getPreparedStatementReplacements()
-    {
-        return preparedStatementReplacements;
-    }
-
-    /**
-     * Appends another PreparedStatementPart to this part.
-     *
-     * @param toAppend the part to append, not null.
-     *
-     * @return this PreparedStatementPart (with toAppend appended).
+     * @return the list of prepared statement replacements, not null.
      */
-    public PreparedStatementPart append(final PreparedStatementPart toAppend)
-    {
-        sql.append(toAppend.sql);
-        preparedStatementReplacements.addAll(
-                toAppend.preparedStatementReplacements);
-        return this;
-    }
-
-    /**
-     * Appends a SqlEnum to this part.
-     *
-     * @param toAppend the part to append, not null.
-     *
-     * @return this PreparedStatementPart (with toAppend appended).
-     */
-    public PreparedStatementPart append(final SqlEnum toAppend)
-    {
-        sql.append(toAppend);
-        return this;
-    }
-
-    @Override
-    public int hashCode()
-    {
-        HashCodeBuilder hashCodeBuilder = new HashCodeBuilder();
-        hashCodeBuilder.append(sql);
-        hashCodeBuilder.append(preparedStatementReplacements);
-        return hashCodeBuilder.toHashCode();
-    }
-
-    @Override
-    public boolean equals(final Object obj)
-    {
-        if (this == obj)
-        {
-            return true;
-        }
-        if (obj == null)
-        {
-            return false;
-        }
-        if (getClass() != obj.getClass())
-        {
-            return false;
-        }
-        PreparedStatementPart other = (PreparedStatementPart) obj;
-        EqualsBuilder equalsBuilder = new EqualsBuilder();
-        equalsBuilder.append(other.sql, this.sql);
-        equalsBuilder.append(
-                other.preparedStatementReplacements,
-                this.preparedStatementReplacements);
-        return equalsBuilder.isEquals();
-    }
-
-    @Override
-    public String toString()
-    {
-        return sql + ", preparedStatementReplacements="
-                + preparedStatementReplacements;
-    }
+    public List<Object> getPreparedStatementReplacements();
 }

Added: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/PreparedStatementPartImpl.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/PreparedStatementPartImpl.java?rev=1706947&view=auto
==============================================================================
--- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/PreparedStatementPartImpl.java (added)
+++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/PreparedStatementPartImpl.java Tue Oct  6 02:52:34 2015
@@ -0,0 +1,195 @@
+package org.apache.torque.criteria;
+
+/*
+ * 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.
+ */
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+/**
+ * Modifiable implementation of the PreparedStatementPart interface.
+ *
+ * @version $Id: PreparedStatementPart.java 1701510 2015-09-06 18:45:05Z tfischer $
+ */
+public class PreparedStatementPartImpl implements PreparedStatementPart, Serializable
+{
+    /** Version id for serializing. */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * The SQL for the part, not null.
+     */
+    private final StringBuilder sql = new StringBuilder();
+
+    /**
+     * The replacements for the prepared statement, not null.
+     */
+    private final List<Object> preparedStatementReplacements
+        = new ArrayList<Object>();
+
+    /**
+     * Default constructor, creates an empty PreparedStatementPart.
+     */
+    public PreparedStatementPartImpl()
+    {
+        // empty
+    }
+
+    /**
+     * Constructor, creates a pre-filled PreparedStatementPartImpl.
+     *
+     * @param sql The sql to fill into the sql buffer initially, or null.
+     * @param preparedStatementReplacements the prepared statement replacements
+     *        to start with, or null.
+     */
+    public PreparedStatementPartImpl(
+            final String sql,
+            final Object... preparedStatementReplacements)
+    {
+        if (!StringUtils.isEmpty(sql))
+        {
+            this.sql.append(sql);
+        }
+        if (preparedStatementReplacements != null)
+        {
+            this.preparedStatementReplacements.addAll(
+                    Arrays.asList(preparedStatementReplacements));
+        }
+    }
+
+    /**
+     * Copy-Constructor.
+     *
+     * @param toCopy the PreparedStatementPart to copy, not null.
+     */
+    public PreparedStatementPartImpl(final PreparedStatementPart toCopy)
+    {
+        String sqlAsString = toCopy.getSqlAsString();
+        if (!StringUtils.isEmpty(sqlAsString))
+        {
+            this.sql.append(sqlAsString);
+        }
+        if (toCopy.getPreparedStatementReplacements() != null)
+        {
+            this.preparedStatementReplacements.addAll(toCopy.getPreparedStatementReplacements());
+        }
+    }
+    /**
+     * Returns the SQL of the part.
+     *
+     * @return the SQL as mutable StringBuilder, not null.
+     */
+    public StringBuilder getSql()
+    {
+        return sql;
+    }
+
+    /**
+     * Returns the SQL of the part as String.
+     *
+     * @return the SQL, not null.
+     */
+    public String getSqlAsString()
+    {
+        return sql.toString();
+    }
+
+    /**
+     * Returns the list of prepared statement replacements.
+     *
+     * @return the modifiable list of prepared statement replacements, not null.
+     */
+    public List<Object> getPreparedStatementReplacements()
+    {
+        return preparedStatementReplacements;
+    }
+
+    /**
+     * Appends another PreparedStatementPart to this part.
+     *
+     * @param toAppend the part to append, not null.
+     *
+     * @return this PreparedStatementPart (with toAppend appended).
+     */
+    public PreparedStatementPartImpl append(final PreparedStatementPart toAppend)
+    {
+        sql.append(toAppend.getSqlAsString());
+        preparedStatementReplacements.addAll(
+                toAppend.getPreparedStatementReplacements());
+        return this;
+    }
+
+    /**
+     * Appends a SqlEnum to this part.
+     *
+     * @param toAppend the part to append, not null.
+     *
+     * @return this PreparedStatementPart (with toAppend appended).
+     */
+    public PreparedStatementPartImpl append(final SqlEnum toAppend)
+    {
+        sql.append(toAppend);
+        return this;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        HashCodeBuilder hashCodeBuilder = new HashCodeBuilder();
+        hashCodeBuilder.append(sql);
+        hashCodeBuilder.append(preparedStatementReplacements);
+        return hashCodeBuilder.toHashCode();
+    }
+
+    @Override
+    public boolean equals(final Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        PreparedStatementPartImpl other = (PreparedStatementPartImpl) obj;
+        EqualsBuilder equalsBuilder = new EqualsBuilder();
+        equalsBuilder.append(other.sql, this.sql);
+        equalsBuilder.append(
+                other.preparedStatementReplacements,
+                this.preparedStatementReplacements);
+        return equalsBuilder.isEquals();
+    }
+
+    @Override
+    public String toString()
+    {
+        return sql + ", preparedStatementReplacements="
+                + preparedStatementReplacements;
+    }
+}

Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/JoinBuilder.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/JoinBuilder.java?rev=1706947&r1=1706946&r2=1706947&view=diff
==============================================================================
--- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/JoinBuilder.java (original)
+++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/JoinBuilder.java Tue Oct  6 02:52:34 2015
@@ -30,6 +30,7 @@ import org.apache.torque.criteria.FromEl
 import org.apache.torque.criteria.Join;
 import org.apache.torque.criteria.JoinType;
 import org.apache.torque.criteria.PreparedStatementPart;
+import org.apache.torque.criteria.PreparedStatementPartImpl;
 import org.apache.torque.util.UniqueList;
 
 /**
@@ -147,8 +148,8 @@ public final class JoinBuilder
                             criteria);
 
                 }
-                addSchema(leftExpression, criteria);
-                addSchema(rightExpression, criteria);
+                leftExpression = addSchema(leftExpression, criteria);
+                rightExpression = addSchema(rightExpression, criteria);
 
                 // check whether the order of the join must be "reversed"
                 // This if the case if the fromClause already contains
@@ -163,7 +164,7 @@ public final class JoinBuilder
                                 leftExpression))
                     {
                         FromElement fromElement = new FromElement(
-                            leftExpression.getSql().toString(),
+                            leftExpression.getSqlAsString(),
                             null,
                             null,
                             leftExpression.getPreparedStatementReplacements());
@@ -171,9 +172,9 @@ public final class JoinBuilder
                     }
 
                     FromElement fromElement = new FromElement(
-                            rightExpression.getSql().toString(),
+                            rightExpression.getSqlAsString(),
                             joinType,
-                            buildJoinCondition(joinCondition, criteria));
+                            buildJoinCondition(joinCondition, criteria, query));
                     fromElement.getPreparedStatementReplacements().addAll(rightExpression.getPreparedStatementReplacements());
                     queryFromClause.add(fromElement);
                 }
@@ -188,8 +189,8 @@ public final class JoinBuilder
                         throw new TorqueException(
                                 "Unable to create a" + joinType
                                 + "because both expressions "
-                                + leftExpression.getSql()
-                                + " and " + rightExpression.getSql()
+                                + leftExpression.getSqlAsString()
+                                + " and " + rightExpression.getSqlAsString()
                                 + " are already in use. "
                                 + "Try to create an(other) alias.");
                     }
@@ -197,9 +198,9 @@ public final class JoinBuilder
                     // rightTableName must not be added
                     // because it is already present
                     FromElement fromElement = new FromElement(
-                        leftExpression.getSql().toString(),
+                        leftExpression.getSqlAsString(),
                         reverseJoinType(joinType),
-                        buildJoinCondition(joinCondition, criteria));
+                        buildJoinCondition(joinCondition, criteria, query));
                     queryFromClause.add(fromElement);
                 }
             }
@@ -240,6 +241,7 @@ public final class JoinBuilder
      *
      * @param joinCondition the join condition.
      * @param criteria the enclosing criteria.
+     * @param query the query which is currently built
      *
      * @return A join expression, e.g. table_a.column_a=table_b.column_b.
      *
@@ -247,11 +249,12 @@ public final class JoinBuilder
      */
     private static PreparedStatementPart buildJoinCondition(
                 final Criterion joinCondition,
-                final Criteria criteria)
+                final Criteria criteria,
+                final Query query)
             throws TorqueException
     {
-        PreparedStatementPart joinPart = new PreparedStatementPart();
-        appendJoinCondition(joinCondition, criteria, joinPart);
+        PreparedStatementPartImpl joinPart = new PreparedStatementPartImpl();
+        appendJoinCondition(joinCondition, criteria, joinPart, query);
         return joinPart;
     }
 
@@ -261,6 +264,7 @@ public final class JoinBuilder
      * @param joinCondition the join condition.
      * @param criteria the enclosing criteria.
      * @param joinPart the join part to append to.
+     * @param query the query which is currently built
      *
      * @return A join expression, e.g. table_a.column_a=table_b.column_b.
      *
@@ -269,7 +273,8 @@ public final class JoinBuilder
     private static void appendJoinCondition(
                 final Criterion joinCondition,
                 final Criteria criteria,
-                final PreparedStatementPart joinPart)
+                final PreparedStatementPartImpl joinPart,
+                final Query query)
             throws TorqueException
     {
         if (joinCondition.isComposite())
@@ -285,14 +290,15 @@ public final class JoinBuilder
                 appendJoinCondition(
                         part,
                         criteria,
-                        joinPart);
+                        joinPart,
+                        query);
                 firstPart = false;
             }
             joinPart.getSql().append(')');
             return;
         }
         PreparedStatementPart joinConditionStatementPart
-                = SqlBuilder.processCriterion(joinCondition, criteria);
+                = SqlBuilder.processCriterion(joinCondition, criteria, query);
         joinPart.append(joinConditionStatementPart);
     }
 
@@ -302,28 +308,31 @@ public final class JoinBuilder
      * @param tableNamePart the table name to add the schema name to, not null.
      * @param criteria the criteria from which the tableNamePart was created, not null.
      */
-    private static void addSchema(final PreparedStatementPart tableNamePart, final Criteria criteria)
+    private static PreparedStatementPart addSchema(final PreparedStatementPart tableNamePart, final Criteria criteria)
             throws TorqueException
     {
-        String tableName = tableNamePart.getSql().toString();
+        String tableName = tableNamePart.getSqlAsString();
         if (tableName.indexOf('.') != -1 // table name is already qualified
             || tableName.indexOf(' ') != -1 // table name is no simple table name
             || tableName.indexOf('(') != -1) // table name is no simple table name
         {
-            return;
+            return tableNamePart;
         }
         Object resolvedAlias = criteria.getAliases().get(tableName);
         if (resolvedAlias != null)
         {
-            return;
+            return tableNamePart;
         }
         final String dbName = criteria.getDbName();
         final Database database = Torque.getDatabase(dbName);
         String resolvedSchemaName = database.getSchema();
-        if (resolvedSchemaName != null)
+        if (resolvedSchemaName == null)
         {
-            tableNamePart.getSql().insert(0, '.');
-            tableNamePart.getSql().insert(0, resolvedSchemaName);
+            return tableNamePart;
         }
+        PreparedStatementPartImpl result = new PreparedStatementPartImpl(tableNamePart);
+        result.getSql().insert(0, '.');
+        result.getSql().insert(0, resolvedSchemaName);
+        return result;
     }
 }

Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/SqlBuilder.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/SqlBuilder.java?rev=1706947&r1=1706946&r2=1706947&view=diff
==============================================================================
--- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/SqlBuilder.java (original)
+++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/SqlBuilder.java Tue Oct  6 02:52:34 2015
@@ -36,6 +36,7 @@ import org.apache.torque.criteria.Criter
 import org.apache.torque.criteria.Criterion;
 import org.apache.torque.criteria.FromElement;
 import org.apache.torque.criteria.PreparedStatementPart;
+import org.apache.torque.criteria.PreparedStatementPartImpl;
 import org.apache.torque.criteria.SqlEnum;
 import org.apache.torque.map.ColumnMap;
 import org.apache.torque.map.DatabaseMap;
@@ -310,16 +311,17 @@ public final class SqlBuilder
                 query);
 
         PreparedStatementPart whereClausePartOutput
-            = processCriterion(criterion, criteria);
+            = processCriterion(criterion, criteria, query);
 
-        where.append(whereClausePartOutput.getSql());
+        where.append(whereClausePartOutput.getSqlAsString());
         query.getWhereClausePreparedStatementReplacements().addAll(
                 whereClausePartOutput.getPreparedStatementReplacements());
     }
 
     static PreparedStatementPart processCriterion(
                 final Criterion criterion,
-                final Criteria criteria)
+                final Criteria criteria,
+                final Query query)
             throws TorqueException
     {
         final String dbName = criteria.getDbName();
@@ -344,6 +346,7 @@ public final class SqlBuilder
                 whereClausePartOutput = builder.buildPs(
                         whereClausePartInput,
                         ignoreCase,
+                        query,
                         adapter);
                 break;
             }
@@ -618,7 +621,7 @@ public final class SqlBuilder
         if (!(toAddToFromClause instanceof Column))
         {
             // toAddToFromClause is a literal Value
-            return new PreparedStatementPart("?", toAddToFromClause);
+            return new PreparedStatementPartImpl("?", toAddToFromClause);
         }
         Column column = (Column) toAddToFromClause;
         Column resolvedColumn
@@ -632,7 +635,7 @@ public final class SqlBuilder
         {
             // If the tables have an alias, add an "<xxx> <yyy> statement"
             // <xxx> AS <yyy> causes problems on oracle
-            PreparedStatementPart result = new PreparedStatementPart();
+            PreparedStatementPartImpl result = new PreparedStatementPartImpl();
             result.getSql()
                     .append(fullTableName)
                     .append(" ")
@@ -647,7 +650,7 @@ public final class SqlBuilder
             {
                 Criteria subquery = (Criteria) resolvedAlias;
                 Query renderedSubquery = SqlBuilder.buildQuery(subquery);
-                PreparedStatementPart result = new PreparedStatementPart();
+                PreparedStatementPartImpl result = new PreparedStatementPartImpl();
                 result.getSql().append("(")
                         .append(renderedSubquery.toString())
                         .append(") ")
@@ -665,7 +668,7 @@ public final class SqlBuilder
             }
         }
 
-        return new PreparedStatementPart(fullTableName);
+        return new PreparedStatementPartImpl(fullTableName);
     }
 
     /**
@@ -899,11 +902,11 @@ public final class SqlBuilder
             final UniqueList<FromElement> fromClause,
             final PreparedStatementPart fromExpression)
     {
-        if (fromExpression == null || fromExpression.getSql().length() == 0)
+        if (fromExpression == null || fromExpression.getSqlAsString().length() == 0)
         {
             return false;
         }
-        String fromExpressionSql = fromExpression.getSql().toString();
+        String fromExpressionSql = fromExpression.getSqlAsString();
         for (FromElement fromElement : fromClause)
         {
             if (fromExpressionSql.equals(fromElement.getFromExpression()))
@@ -957,7 +960,7 @@ public final class SqlBuilder
             fromClauseExpression))
         {
             FromElement fromElement = new FromElement(
-                    fromClauseExpression.getSql().toString(),
+                    fromClauseExpression.getSqlAsString(),
                     null,
                     null,
                     fromClauseExpression.getPreparedStatementReplacements());

Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/ObjectOrColumnPsPartBuilder.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/ObjectOrColumnPsPartBuilder.java?rev=1706947&r1=1706946&r2=1706947&view=diff
==============================================================================
--- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/ObjectOrColumnPsPartBuilder.java (original)
+++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/ObjectOrColumnPsPartBuilder.java Tue Oct  6 02:52:34 2015
@@ -24,10 +24,10 @@ import org.apache.torque.TorqueException
 import org.apache.torque.adapter.Adapter;
 import org.apache.torque.criteria.Criteria;
 import org.apache.torque.criteria.PreparedStatementPart;
+import org.apache.torque.criteria.PreparedStatementPartImpl;
 import org.apache.torque.criteria.SqlEnum;
 import org.apache.torque.om.ObjectKey;
 import org.apache.torque.sql.Query;
-import org.apache.torque.sql.SqlBuilder;
 
 /**
  * Builds a PreparedStatementPart from a column or single value.
@@ -43,6 +43,7 @@ public class ObjectOrColumnPsPartBuilder
      * @param ignoreCase If true and columns represent Strings, the appropriate
      *        function defined for the database will be used to ignore
      *        differences in case.
+     * @param query the query which is currently built
      * @param adapter The adapter for the database for which the SQL
      *        should be created, not null.
      *
@@ -53,10 +54,11 @@ public class ObjectOrColumnPsPartBuilder
     public PreparedStatementPart buildPs(
             Object toBuildFrom,
             final boolean ignoreCase,
+            final Query query,
             final Adapter adapter)
         throws TorqueException
     {
-        PreparedStatementPart result = new PreparedStatementPart();
+        PreparedStatementPartImpl result = new PreparedStatementPartImpl();
         // check column
         if (toBuildFrom instanceof Column)
         {
@@ -75,11 +77,7 @@ public class ObjectOrColumnPsPartBuilder
         // check subselect
         if (toBuildFrom instanceof Criteria)
         {
-            Query subquery = SqlBuilder.buildQuery((Criteria) toBuildFrom);
-            result.getPreparedStatementReplacements().addAll(
-                    subquery.getPreparedStatementReplacements());
-            result.getSql().append("(").append(subquery.toString()).append(")");
-            return result;
+            return new PreparedStatementPartForSubselect((Criteria) toBuildFrom, query);
         }
 
         // plain object

Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/ObjectPsPartBuilder.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/ObjectPsPartBuilder.java?rev=1706947&r1=1706946&r2=1706947&view=diff
==============================================================================
--- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/ObjectPsPartBuilder.java (original)
+++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/ObjectPsPartBuilder.java Tue Oct  6 02:52:34 2015
@@ -22,6 +22,7 @@ package org.apache.torque.sql.objectbuil
 import org.apache.torque.TorqueException;
 import org.apache.torque.adapter.Adapter;
 import org.apache.torque.criteria.PreparedStatementPart;
+import org.apache.torque.sql.Query;
 
 /**
  * Builds a PreparedStatementPart from a single object
@@ -38,6 +39,7 @@ public interface ObjectPsPartBuilder
      * @param ignoreCase If true and columns represent Strings, the appropriate
      *        function defined for the database will be used to ignore
      *        differences in case.
+     * @param query the query which is currently built
      * @param adapter The adapter for the database for which the SQL
      *        should be created, not null.
      *
@@ -46,8 +48,9 @@ public interface ObjectPsPartBuilder
      * @throws TorqueException when rendering fails.
      */
     PreparedStatementPart buildPs(
-            Object toBuildFrom,
-            boolean ignoreCase,
-            Adapter adapter)
+            final Object toBuildFrom,
+            final boolean ignoreCase,
+            final Query query,
+            final Adapter adapter)
         throws TorqueException;
 }

Added: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/PreparedStatementPartForSubselect.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/PreparedStatementPartForSubselect.java?rev=1706947&view=auto
==============================================================================
--- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/PreparedStatementPartForSubselect.java (added)
+++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/objectbuilder/PreparedStatementPartForSubselect.java Tue Oct  6 02:52:34 2015
@@ -0,0 +1,121 @@
+package org.apache.torque.sql.objectbuilder;
+
+/*
+ * 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.
+ */
+
+import java.util.List;
+
+import org.apache.torque.TorqueException;
+import org.apache.torque.TorqueRuntimeException;
+import org.apache.torque.criteria.Criteria;
+import org.apache.torque.criteria.FromElement;
+import org.apache.torque.criteria.PreparedStatementPart;
+import org.apache.torque.criteria.PreparedStatementPartImpl;
+import org.apache.torque.sql.Query;
+import org.apache.torque.sql.SqlBuilder;
+import org.apache.torque.util.UniqueList;
+
+/**
+ * A PreparedStatementPart which encapsulates a subselect.
+ * The SQL and Replacements are not calculated immediately,
+ * but wait for the outer clause to be completed,
+ * as tables in the from clause which reference tables in the outer select
+ * are removed, and this can only be done when the outer query is known.
+ * This only works if the methofs getSqlAsString()
+ * and getPreparedStatementReplacements() are called after the outer query
+ * is calculated.
+ *
+ * @version $Id: $
+ */
+public class PreparedStatementPartForSubselect implements PreparedStatementPart
+{
+    /**
+     *  The calculated PreparedStatementPart for the subselect,
+     *  or null if it is not yet known.
+     */
+    private PreparedStatementPartImpl wrapped;
+
+    /** The criteria to build the subselect from. */
+    private final Criteria toBuildFrom;
+
+    /** The outer query in which this subselect is embedded. */
+    private final Query outerQuery;
+
+    /**
+     * Constructor.
+     *
+     * @param toBuildFrom The criteria to build the subselect from.
+     * @param outerQuery The outer query in which this subselect is embedded.
+     */
+    public PreparedStatementPartForSubselect(final Criteria toBuildFrom, final Query outerQuery)
+    {
+        this.toBuildFrom = toBuildFrom;
+        this.outerQuery = outerQuery;
+    }
+
+    private void calculate()
+    {
+        Query subquery;
+        try
+        {
+            subquery = SqlBuilder.buildQuery(toBuildFrom);
+        }
+        catch (TorqueException e)
+        {
+            throw new TorqueRuntimeException(e);
+        }
+        // assume that table names which are in the outer from clause are references to the outer from clause
+        // But only do this if any tables are remaining
+        UniqueList<FromElement> remainingTableNames = new UniqueList<FromElement>(subquery.getFromClause());
+        remainingTableNames.removeAll(outerQuery.getFromClause());
+        if (remainingTableNames.size() > 0)
+        {
+            subquery.getFromClause().removeAll(outerQuery.getFromClause());
+        }
+
+        PreparedStatementPartImpl result = new PreparedStatementPartImpl("(" + subquery.toString() + ")");
+        result.getPreparedStatementReplacements().addAll(
+                subquery.getPreparedStatementReplacements());
+        wrapped = result;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getSqlAsString()
+    {
+        if (wrapped == null)
+        {
+            calculate();
+        }
+        return wrapped.getSqlAsString();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Object> getPreparedStatementReplacements()
+    {
+        if (wrapped == null)
+        {
+            calculate();
+        }
+        return wrapped.getPreparedStatementReplacements();
+    }
+}

Added: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/CombinedPreparedStatementPart.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/CombinedPreparedStatementPart.java?rev=1706947&view=auto
==============================================================================
--- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/CombinedPreparedStatementPart.java (added)
+++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/CombinedPreparedStatementPart.java Tue Oct  6 02:52:34 2015
@@ -0,0 +1,121 @@
+package org.apache.torque.sql.whereclausebuilder;
+
+/*
+ * 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.
+ */
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.torque.criteria.PreparedStatementPart;
+
+/**
+ * A PreparedStatementPart which consists of a list of other PreparedStatementParts.
+ * @version $Id: $
+ */
+public class CombinedPreparedStatementPart implements PreparedStatementPart
+{
+    /** The list of PreparedStatementParts of which this PreparedStatementPart is made. */
+    private final List<PreparedStatementPart> parts = new ArrayList<PreparedStatementPart>();
+
+    /**
+     * Constructor.
+     * Constructs an empty CombinedPreparedStatementPart.
+     */
+    public CombinedPreparedStatementPart()
+    {
+    }
+
+    /**
+     * Constructor.
+     * Creates a CombinedPreparedStatementPart which contains the passed PreparedStatementPart
+     * as first part.
+     *
+     * @param toAdd the PreparedStatementPart to add, not null.
+     */
+    public CombinedPreparedStatementPart(final PreparedStatementPart toAdd)
+    {
+        append(toAdd);
+    }
+
+    /**
+     * Adds a PreparedStatementPart to the list of contained PreparedStatementParts.
+     *
+     * @param toAdd the PreparedStatementPart to add, not null.
+     */
+    public void append(final PreparedStatementPart toAdd)
+    {
+        if (toAdd == null)
+        {
+            throw new NullPointerException("toAdd must notbe null");
+        }
+        parts.add(toAdd);
+    }
+
+    /**
+     * Adds a PreparedStatementPart to the list of contained PreparedStatementParts,
+     * which contains only the given sql.
+     *
+     * @param sql the sql to add, not null.
+     */
+    public void appendSql(final String sql)
+    {
+        parts.add(new NoReplacementsPreparedStatementPart(sql));
+    }
+
+    /**
+     * Adds a PreparedStatementPart to the list of contained PreparedStatementParts,
+     * which contains only the given sreplacementql.
+     *
+     * @param toAdd the replacement to add, not null.
+     */
+    public void addPreparedStatementReplacement(final Object toAdd)
+    {
+        parts.add(new OnlyReplacementsPreparedStatementPart(toAdd));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getSqlAsString()
+    {
+        StringBuilder result = new StringBuilder();
+        for (PreparedStatementPart part : parts)
+        {
+            result.append(part.getSqlAsString());
+        }
+        return result.toString();
+    }
+
+    /**
+     * Returns the list of prepared statement replacements.
+     * The returned list is unmodifiable.
+     *
+     * @return the list of prepared statement replacements, not null.
+     */
+    public List<Object> getPreparedStatementReplacements()
+    {
+        List<Object> result = new ArrayList<Object>();
+        for (PreparedStatementPart part : parts)
+        {
+            result.addAll(part.getPreparedStatementReplacements());
+        }
+        return Collections.unmodifiableList(result);
+    }
+}

Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/CurrentDateTimePsPartBuilder.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/CurrentDateTimePsPartBuilder.java?rev=1706947&r1=1706946&r2=1706947&view=diff
==============================================================================
--- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/CurrentDateTimePsPartBuilder.java (original)
+++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/CurrentDateTimePsPartBuilder.java Tue Oct  6 02:52:34 2015
@@ -23,6 +23,7 @@ import org.apache.torque.TorqueException
 import org.apache.torque.adapter.Adapter;
 import org.apache.torque.criteria.PreparedStatementPart;
 import org.apache.torque.criteria.SqlEnum;
+import org.apache.torque.sql.Query;
 import org.apache.torque.sql.WhereClauseExpression;
 
 /**
@@ -38,20 +39,24 @@ public class CurrentDateTimePsPartBuilde
      * {@inheritDoc}
      */
     public PreparedStatementPart buildPs(
-            WhereClauseExpression whereClauseExpression,
-            boolean ignoreCase,
-            Adapter adapter)
+            final WhereClauseExpression whereClauseExpression,
+            final boolean ignoreCase,
+            final Query query,
+            final Adapter adapter)
         throws TorqueException
     {
-        PreparedStatementPart result
-            = getObjectOrColumnPsPartBuilder().buildPs(
+        CombinedPreparedStatementPart result
+            = new CombinedPreparedStatementPart(
+                getObjectOrColumnPsPartBuilder().buildPs(
                     whereClauseExpression.getLValue(),
                     ignoreCase,
-                    adapter);
-        result.getSql().append(whereClauseExpression.getOperator());
-        result .append(getObjectOrColumnPsPartBuilder().buildPs(
+                    query,
+                    adapter));
+        result.appendSql(whereClauseExpression.getOperator().toString());
+        result.append(getObjectOrColumnPsPartBuilder().buildPs(
                 whereClauseExpression.getRValue(),
                 ignoreCase,
+                query,
                 adapter));
         return result;
     }
@@ -60,8 +65,8 @@ public class CurrentDateTimePsPartBuilde
      * {@inheritDoc}
      */
     public boolean isApplicable(
-            WhereClauseExpression whereClauseExpression,
-            Adapter adapter)
+            final WhereClauseExpression whereClauseExpression,
+            final Adapter adapter)
     {
         if (whereClauseExpression.getOperator().equals(
                         SqlEnum.CURRENT_DATE)

Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/EnumValueBuilder.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/EnumValueBuilder.java?rev=1706947&r1=1706946&r2=1706947&view=diff
==============================================================================
--- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/EnumValueBuilder.java (original)
+++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/EnumValueBuilder.java Tue Oct  6 02:52:34 2015
@@ -25,6 +25,7 @@ import java.lang.reflect.Method;
 import org.apache.torque.TorqueException;
 import org.apache.torque.adapter.Adapter;
 import org.apache.torque.criteria.PreparedStatementPart;
+import org.apache.torque.sql.Query;
 import org.apache.torque.sql.SqlBuilder;
 import org.apache.torque.sql.WhereClauseExpression;
 
@@ -43,12 +44,14 @@ public class EnumValueBuilder extends Ab
      * @param ignoreCase If true and columns represent Strings, the appropriate
      *        function defined for the database will be used to ignore
      *        differences in case.
+     * @param query the query which is currently built
      * @param adapter The adapter for the database for which the SQL
      *        should be created, not null.
      */
     public PreparedStatementPart buildPs(
                 final WhereClauseExpression whereClausePart,
                 final boolean ignoreCase,
+                final Query query,
                 final Adapter adapter)
             throws TorqueException
     {
@@ -67,6 +70,7 @@ public class EnumValueBuilder extends Ab
                 return builder.buildPs(
                         whereClausePart,
                         ignoreCase,
+                        query,
                         adapter);
             }
         }

Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/InBuilder.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/InBuilder.java?rev=1706947&r1=1706946&r2=1706947&view=diff
==============================================================================
--- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/InBuilder.java (original)
+++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/InBuilder.java Tue Oct  6 02:52:34 2015
@@ -29,6 +29,7 @@ import org.apache.torque.criteria.Criter
 import org.apache.torque.criteria.Criterion;
 import org.apache.torque.criteria.PreparedStatementPart;
 import org.apache.torque.criteria.SqlEnum;
+import org.apache.torque.sql.Query;
 import org.apache.torque.sql.WhereClauseExpression;
 
 /**
@@ -49,16 +50,18 @@ public class InBuilder extends AbstractW
      * @param ignoreCase If true and columns represent Strings, the appropriate
      *        function defined for the database will be used to ignore
      *        differences in case.
+     * @param query the query which is currently built
      * @param adapter The adapter for the database for which the SQL
      *        should be created, not null.
      */
     public PreparedStatementPart buildPs(
-                WhereClauseExpression whereClausePart,
-                boolean ignoreCase,
-                Adapter adapter)
+                final WhereClauseExpression whereClausePart,
+                final boolean ignoreCase,
+                final Query query,
+                final Adapter adapter)
             throws TorqueException
     {
-        PreparedStatementPart result = new PreparedStatementPart();
+        CombinedPreparedStatementPart result = new CombinedPreparedStatementPart();
 
         boolean ignoreCaseApplied = false;
         List<String> inClause = new ArrayList<String>();
@@ -72,7 +75,7 @@ public class InBuilder extends AbstractW
                     nullContained = true;
                     continue;
                 }
-                result.getPreparedStatementReplacements().add(listValue);
+                result.addPreparedStatementReplacement(listValue);
                 if (ignoreCase && listValue instanceof String)
                 {
                     inClause.add(adapter.ignoreCase("?"));
@@ -93,7 +96,7 @@ public class InBuilder extends AbstractW
                     nullContained = true;
                     continue;
                 }
-                result.getPreparedStatementReplacements().add(arrayValue);
+                result.addPreparedStatementReplacement(arrayValue);
                 if (ignoreCase && arrayValue instanceof String)
                 {
                     inClause.add(adapter.ignoreCase("?"));
@@ -116,39 +119,42 @@ public class InBuilder extends AbstractW
 
         if (nullContained)
         {
-            result.getSql().append('(');
+            result.appendSql("(");
         }
 
         result.append(getObjectOrColumnPsPartBuilder().buildPs(
                 whereClausePart.getLValue(),
                 ignoreCaseApplied,
+                query,
                 adapter));
 
-        result.getSql().append(whereClausePart.getOperator())
-                .append('(')
-                .append(StringUtils.join(inClause.iterator(), ","))
-                .append(')');
+        result.appendSql(whereClausePart.getOperator().toString()
+                + '('
+                + StringUtils.join(inClause.iterator(), ",")
+                + ')');
         if (nullContained)
         {
             if (whereClausePart.getOperator() == SqlEnum.IN)
             {
-                result.getSql().append(Criterion.OR);
+                result.appendSql(Criterion.OR);
                 result.append(getObjectOrColumnPsPartBuilder().buildPs(
                         whereClausePart.getLValue(),
                         false,
+                        query,
                         adapter));
-                result.getSql().append(SqlEnum.ISNULL);
+                result.appendSql(SqlEnum.ISNULL.toString());
             }
             else if (whereClausePart.getOperator() == SqlEnum.NOT_IN)
             {
-                result.getSql().append(Criterion.AND);
+                result.appendSql(Criterion.AND);
                 result.append(getObjectOrColumnPsPartBuilder().buildPs(
                         whereClausePart.getLValue(),
                         false,
+                        query,
                         adapter));
-                result.getSql().append(SqlEnum.ISNOTNULL);
+                result.appendSql(SqlEnum.ISNOTNULL.toString());
             }
-            result.getSql().append(')');
+            result.appendSql(")");
         }
         return result;
     }
@@ -157,8 +163,8 @@ public class InBuilder extends AbstractW
      * {@inheritDoc}
      */
     public boolean isApplicable(
-            WhereClauseExpression whereClauseExpression,
-            Adapter adapter)
+            final WhereClauseExpression whereClauseExpression,
+            final Adapter adapter)
     {
         if (whereClauseExpression.getOperator().equals(Criteria.IN)
                 || whereClauseExpression.getOperator().equals(Criteria.NOT_IN))

Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/LikeBuilder.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/LikeBuilder.java?rev=1706947&r1=1706946&r2=1706947&view=diff
==============================================================================
--- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/LikeBuilder.java (original)
+++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/LikeBuilder.java Tue Oct  6 02:52:34 2015
@@ -23,6 +23,7 @@ import org.apache.torque.TorqueException
 import org.apache.torque.adapter.Adapter;
 import org.apache.torque.criteria.PreparedStatementPart;
 import org.apache.torque.criteria.SqlEnum;
+import org.apache.torque.sql.Query;
 import org.apache.torque.sql.WhereClauseExpression;
 
 /**
@@ -51,6 +52,7 @@ public class LikeBuilder extends Abstrac
      * @param ignoreCase If true and columns represent Strings, the appropriate
      *        function defined for the database will be used to ignore
      *        differences in case.
+     * @param query the query which is currently built
      * @param adapter The adapter for the database for which the SQL
      *        should be created, not null.
      *
@@ -59,6 +61,7 @@ public class LikeBuilder extends Abstrac
     public PreparedStatementPart buildPs(
                 final WhereClauseExpression whereClausePart,
                 final boolean ignoreCase,
+                final Query query,
                 final Adapter adapter)
             throws TorqueException
     {
@@ -122,7 +125,7 @@ public class LikeBuilder extends Abstrac
         }
         value = sb.toString();
 
-        PreparedStatementPart result;
+        CombinedPreparedStatementPart result;
         if (ignoreCase)
         {
             if (adapter.useIlike() && !replaceWithEquals)
@@ -135,22 +138,33 @@ public class LikeBuilder extends Abstrac
                 {
                     whereClausePart.setOperator(SqlEnum.NOT_ILIKE);
                 }
-                result = getObjectOrColumnPsPartBuilder().buildPs(
-                        whereClausePart.getLValue(), false, adapter);
+                result = new CombinedPreparedStatementPart(
+                        getObjectOrColumnPsPartBuilder().buildPs(
+                                whereClausePart.getLValue(),
+                                false,
+                                query,
+                                adapter));
             }
             else
             {
                 // no native case insensitive like is offered by the DB,
                 // or the LIKE was replaced with equals.
                 // need to ignore case manually.
-                result = getObjectOrColumnPsPartBuilder().buildPs(
-                        whereClausePart.getLValue(), true, adapter);
+                result = new CombinedPreparedStatementPart(
+                        getObjectOrColumnPsPartBuilder().buildPs(
+                                whereClausePart.getLValue(),
+                                true,
+                                query,
+                                adapter));
             }
         }
         else
         {
-            result = getObjectOrColumnPsPartBuilder().buildPs(
-                    whereClausePart.getLValue(), ignoreCase, adapter);
+            result = new CombinedPreparedStatementPart(getObjectOrColumnPsPartBuilder().buildPs(
+                    whereClausePart.getLValue(),
+                    ignoreCase,
+                    query,
+                    adapter));
         }
 
         if (replaceWithEquals
@@ -161,11 +175,11 @@ public class LikeBuilder extends Abstrac
             if (whereClausePart.getOperator().equals(SqlEnum.NOT_LIKE)
                     || whereClausePart.getOperator().equals(SqlEnum.NOT_ILIKE))
             {
-                result.getSql().append(SqlEnum.NOT_EQUAL);
+                result.appendSql(SqlEnum.NOT_EQUAL.toString());
             }
             else
             {
-                result.getSql().append(SqlEnum.EQUAL);
+                result.appendSql(SqlEnum.EQUAL.toString());
             }
 
             // remove escape backslashes from String
@@ -189,7 +203,7 @@ public class LikeBuilder extends Abstrac
         }
         else
         {
-            result.getSql().append(whereClausePart.getOperator());
+            result.appendSql(whereClausePart.getOperator().toString());
         }
 
         String rValueSql = "?";
@@ -204,8 +218,8 @@ public class LikeBuilder extends Abstrac
             rValueSql = rValueSql + SqlEnum.ESCAPE + "'\\'";
         }
 
-        result.getPreparedStatementReplacements().add(value);
-        result.getSql().append(rValueSql);
+        result.addPreparedStatementReplacement(value);
+        result.appendSql(rValueSql);
         return result;
     }
 

Added: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/NoReplacementsPreparedStatementPart.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/NoReplacementsPreparedStatementPart.java?rev=1706947&view=auto
==============================================================================
--- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/NoReplacementsPreparedStatementPart.java (added)
+++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/NoReplacementsPreparedStatementPart.java Tue Oct  6 02:52:34 2015
@@ -0,0 +1,65 @@
+package org.apache.torque.sql.whereclausebuilder;
+
+/*
+ * 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.
+ */
+
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.torque.criteria.PreparedStatementPart;
+
+/**
+ * A PreparedStatementPart which only contains SQL and no replacements.
+ *
+ * @version $Id: $
+ */
+public class NoReplacementsPreparedStatementPart implements PreparedStatementPart
+{
+    /** The contained sql. */
+    private final String sql;
+
+    /**
+     * Constructor.
+     *
+     * @param sql the contained sql.
+     */
+    public NoReplacementsPreparedStatementPart(final String sql)
+    {
+        this.sql = sql;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getSqlAsString()
+    {
+        return sql;
+    }
+
+    /**
+     * Returns the empty list of prepared statement replacements.
+     * The returned list is unmodifiable.
+     *
+     * @return the list of prepared statement replacements, not null.
+     */
+    public List<Object> getPreparedStatementReplacements()
+    {
+        return Collections.emptyList();
+    }
+}

Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/NullValueBuilder.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/NullValueBuilder.java?rev=1706947&r1=1706946&r2=1706947&view=diff
==============================================================================
--- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/NullValueBuilder.java (original)
+++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/NullValueBuilder.java Tue Oct  6 02:52:34 2015
@@ -24,6 +24,7 @@ import org.apache.torque.adapter.Adapter
 import org.apache.torque.criteria.PreparedStatementPart;
 import org.apache.torque.criteria.SqlEnum;
 import org.apache.torque.om.ObjectKey;
+import org.apache.torque.sql.Query;
 import org.apache.torque.sql.WhereClauseExpression;
 
 /**
@@ -45,24 +46,30 @@ public class NullValueBuilder extends Ab
      * @param ignoreCase If true and columns represent Strings, the appropriate
      *        function defined for the database will be used to ignore
      *        differences in case.
+     * @param query the query which is currently built
      * @param adapter The adapter for the database for which the SQL
      *        should be created, not null.
      *
      * @return the rendered SQL for the WhereClauseExpression
      */
     public PreparedStatementPart buildPs(
-                WhereClauseExpression whereClausePart,
-                boolean ignoreCase,
-                Adapter adapter)
+                final WhereClauseExpression whereClausePart,
+                final boolean ignoreCase,
+                final Query query,
+                final Adapter adapter)
             throws TorqueException
     {
-        PreparedStatementPart result;
+        CombinedPreparedStatementPart result;
         if (whereClausePart.getOperator().equals(SqlEnum.ISNULL)
             || whereClausePart.getOperator().equals(SqlEnum.ISNOTNULL))
         {
-            result = getObjectOrColumnPsPartBuilder().buildPs(
-                    whereClausePart.getLValue(), ignoreCase, adapter);
-            result.getSql().append(whereClausePart.getOperator());
+            result = new CombinedPreparedStatementPart(
+                    getObjectOrColumnPsPartBuilder().buildPs(
+                            whereClausePart.getLValue(),
+                            ignoreCase,
+                            query,
+                            adapter));
+            result.appendSql(whereClausePart.getOperator().toString());
             return result;
         }
 
@@ -70,18 +77,26 @@ public class NullValueBuilder extends Ab
         // an ObjectKey containing null
         if (whereClausePart.getOperator().equals(SqlEnum.EQUAL))
         {
-            result = getObjectOrColumnPsPartBuilder().buildPs(
-                    whereClausePart.getLValue(), ignoreCase, adapter);
-            result.getSql().append(SqlEnum.ISNULL);
+            result = new CombinedPreparedStatementPart(
+                    getObjectOrColumnPsPartBuilder().buildPs(
+                            whereClausePart.getLValue(),
+                            ignoreCase,
+                            query,
+                            adapter));
+            result.appendSql(SqlEnum.ISNULL.toString());
             return result;
         }
         if (whereClausePart.getOperator().equals(SqlEnum.NOT_EQUAL)
             || whereClausePart.getOperator().equals(
                     SqlEnum.ALT_NOT_EQUAL))
         {
-            result = getObjectOrColumnPsPartBuilder().buildPs(
-                    whereClausePart.getLValue(), ignoreCase, adapter);
-            result.getSql().append(SqlEnum.ISNOTNULL);
+            result = new CombinedPreparedStatementPart(
+                    getObjectOrColumnPsPartBuilder().buildPs(
+                            whereClausePart.getLValue(),
+                            ignoreCase,
+                            query,
+                            adapter));
+            result.appendSql(SqlEnum.ISNOTNULL.toString());
             return result;
         }
         throw new IllegalStateException("unknown operator "
@@ -99,8 +114,8 @@ public class NullValueBuilder extends Ab
      * @return true if applicable, false otherwise.
      */
     public boolean isApplicable(
-            WhereClauseExpression whereClauseExpression,
-            Adapter adapter)
+            final WhereClauseExpression whereClauseExpression,
+            final Adapter adapter)
     {
         if (whereClauseExpression.getOperator().equals(SqlEnum.ISNULL)
             || whereClauseExpression.getOperator().equals(SqlEnum.ISNOTNULL))

Added: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/OnlyReplacementsPreparedStatementPart.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/OnlyReplacementsPreparedStatementPart.java?rev=1706947&view=auto
==============================================================================
--- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/OnlyReplacementsPreparedStatementPart.java (added)
+++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/OnlyReplacementsPreparedStatementPart.java Tue Oct  6 02:52:34 2015
@@ -0,0 +1,68 @@
+package org.apache.torque.sql.whereclausebuilder;
+
+/*
+ * 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.
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.torque.criteria.PreparedStatementPart;
+
+/**
+ * A PreparedStatementPart which only contains replacements, no sql.
+ *
+ * @version $Id: $
+ */
+public class OnlyReplacementsPreparedStatementPart implements PreparedStatementPart
+{
+    /** The contained replacements. */
+    private final List<Object> replacements = new ArrayList<Object>();
+
+    /**
+     * Constructor.
+     *
+     * @param replacement the first replacement to be contained in this PreparedStatementPart.
+     */
+    public OnlyReplacementsPreparedStatementPart(final Object replacement)
+    {
+        replacements.add(replacement);
+    }
+
+    /**
+     * returns the empty sql.
+     *
+     * @return the empty sql, not null.
+     */
+    public String getSqlAsString()
+    {
+        return "";
+    }
+
+    /**
+     * Returns the list of prepared statement replacements.
+     * The returned list is modifiable.
+     * On modification of the returned list, the state of this object is changed.
+     *
+     * @return the list of prepared statement replacements, not null.
+     */
+    public List<Object> getPreparedStatementReplacements()
+    {
+        return replacements;
+    }
+}

Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/StandardBuilder.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/StandardBuilder.java?rev=1706947&r1=1706946&r2=1706947&view=diff
==============================================================================
--- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/StandardBuilder.java (original)
+++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/StandardBuilder.java Tue Oct  6 02:52:34 2015
@@ -22,6 +22,7 @@ package org.apache.torque.sql.whereclaus
 import org.apache.torque.TorqueException;
 import org.apache.torque.adapter.Adapter;
 import org.apache.torque.criteria.PreparedStatementPart;
+import org.apache.torque.sql.Query;
 import org.apache.torque.sql.WhereClauseExpression;
 
 /**
@@ -41,22 +42,31 @@ public class StandardBuilder extends Abs
      * @param ignoreCase If true and columns represent Strings, the appropriate
      *        function defined for the database will be used to ignore
      *        differences in case.
+     * @param query the query which is currently built
      * @param adapter The adapter for the database for which the SQL
      *        should be created, not null.
      *
      * @return the rendered SQL for the WhereClauseExpression
      */
     public PreparedStatementPart buildPs(
-                WhereClauseExpression whereClausePart,
-                boolean ignoreCase,
-                Adapter adapter)
+                final WhereClauseExpression whereClausePart,
+                final boolean ignoreCase,
+                final Query query,
+                final Adapter adapter)
             throws TorqueException
     {
-        PreparedStatementPart result = getObjectOrColumnPsPartBuilder().buildPs(
-                whereClausePart.getLValue(), ignoreCase, adapter);
-        result.getSql().append(whereClausePart.getOperator());
+        CombinedPreparedStatementPart result = new CombinedPreparedStatementPart(
+                getObjectOrColumnPsPartBuilder().buildPs(
+                        whereClausePart.getLValue(),
+                        ignoreCase,
+                        query,
+                        adapter));
+        result.appendSql(whereClausePart.getOperator().toString());
         result.append(getObjectOrColumnPsPartBuilder().buildPs(
-                whereClausePart.getRValue(), ignoreCase, adapter));
+                whereClausePart.getRValue(),
+                ignoreCase,
+                query,
+                adapter));
         return result;
     }
 
@@ -71,8 +81,8 @@ public class StandardBuilder extends Abs
      * @return true if applicable, false otherwise.
      */
     public boolean isApplicable(
-            WhereClauseExpression whereClauseExpression,
-            Adapter adapter)
+            final WhereClauseExpression whereClauseExpression,
+            final Adapter adapter)
     {
         return true;
     }

Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/VerbatimSqlConditionBuilder.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/VerbatimSqlConditionBuilder.java?rev=1706947&r1=1706946&r2=1706947&view=diff
==============================================================================
--- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/VerbatimSqlConditionBuilder.java (original)
+++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/VerbatimSqlConditionBuilder.java Tue Oct  6 02:52:34 2015
@@ -19,11 +19,11 @@ package org.apache.torque.sql.whereclaus
  * under the License.
  */
 
-import java.util.Arrays;
-
 import org.apache.torque.TorqueException;
 import org.apache.torque.adapter.Adapter;
 import org.apache.torque.criteria.PreparedStatementPart;
+import org.apache.torque.criteria.PreparedStatementPartImpl;
+import org.apache.torque.sql.Query;
 import org.apache.torque.sql.WhereClauseExpression;
 
 /**
@@ -41,26 +41,22 @@ public class VerbatimSqlConditionBuilder
      * @param whereClausePart the part of the where clause to build.
      *        Can be modified in this method.
      * @param ignoreCase is ignored here.
+     * @param query the query which is currently built
      * @param adapter The adapter for the database for which the SQL
      *        should be created, not null.
      *
      * @return the rendered SQL for the WhereClauseExpression
      */
     public PreparedStatementPart buildPs(
-                WhereClauseExpression whereClausePart,
-                boolean ignoreCase,
-                Adapter adapter)
+                final WhereClauseExpression whereClausePart,
+                final boolean ignoreCase,
+                final Query query,
+                final Adapter adapter)
             throws TorqueException
     {
-        PreparedStatementPart result = new PreparedStatementPart();
-        result.getSql().append(whereClausePart.getSql());
-        Object[] replacements
-                = whereClausePart.getPreparedStatementReplacements();
-        if (replacements != null)
-        {
-            result.getPreparedStatementReplacements().addAll(
-                    Arrays.asList(replacements));
-        }
+        PreparedStatementPartImpl result = new PreparedStatementPartImpl(
+                whereClausePart.getSql(),
+                whereClausePart.getPreparedStatementReplacements());
         return result;
     }
 
@@ -75,8 +71,8 @@ public class VerbatimSqlConditionBuilder
      * @return true if applicable, false otherwise.
      */
     public boolean isApplicable(
-            WhereClauseExpression whereClauseExpression,
-            Adapter adapter)
+            final WhereClauseExpression whereClauseExpression,
+            final Adapter adapter)
     {
         if (whereClauseExpression.isVerbatimSqlCondition())
         {

Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/WhereClausePsPartBuilder.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/WhereClausePsPartBuilder.java?rev=1706947&r1=1706946&r2=1706947&view=diff
==============================================================================
--- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/WhereClausePsPartBuilder.java (original)
+++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/whereclausebuilder/WhereClausePsPartBuilder.java Tue Oct  6 02:52:34 2015
@@ -22,6 +22,7 @@ package org.apache.torque.sql.whereclaus
 import org.apache.torque.TorqueException;
 import org.apache.torque.adapter.Adapter;
 import org.apache.torque.criteria.PreparedStatementPart;
+import org.apache.torque.sql.Query;
 import org.apache.torque.sql.WhereClauseExpression;
 
 /**
@@ -39,6 +40,7 @@ public interface WhereClausePsPartBuilde
      * @param ignoreCase If true and columns represent Strings, the appropriate
      *        function defined for the database will be used to ignore
      *        differences in case.
+     * @param query the query which is currently built
      * @param adapter The adapter for the database for which the SQL
      *        should be created, not null.
      *
@@ -47,9 +49,10 @@ public interface WhereClausePsPartBuilde
      * @throws TorqueException when rendering fails.
      */
     PreparedStatementPart buildPs(
-            WhereClauseExpression whereClauseExpression,
-            boolean ignoreCase,
-            Adapter adapter)
+            final WhereClauseExpression whereClauseExpression,
+            final boolean ignoreCase,
+            final Query query,
+            final Adapter adapter)
         throws TorqueException;
 
     /**
@@ -63,6 +66,6 @@ public interface WhereClausePsPartBuilde
      * @return true if applicable, false otherwise.
      */
     boolean isApplicable(
-            WhereClauseExpression whereClauseExpression,
-            Adapter adapter);
+            final WhereClauseExpression whereClauseExpression,
+            final Adapter adapter);
 }

Modified: db/torque/torque4/trunk/torque-runtime/src/test/java/org/apache/torque/sql/SqlBuilderTest.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/test/java/org/apache/torque/sql/SqlBuilderTest.java?rev=1706947&r1=1706946&r2=1706947&view=diff
==============================================================================
--- db/torque/torque4/trunk/torque-runtime/src/test/java/org/apache/torque/sql/SqlBuilderTest.java (original)
+++ db/torque/torque4/trunk/torque-runtime/src/test/java/org/apache/torque/sql/SqlBuilderTest.java Tue Oct  6 02:52:34 2015
@@ -32,8 +32,10 @@ import org.apache.torque.criteria.Criter
 import org.apache.torque.criteria.Criterion;
 import org.apache.torque.criteria.FromElement;
 import org.apache.torque.criteria.PreparedStatementPart;
+import org.apache.torque.criteria.PreparedStatementPartImpl;
 import org.apache.torque.criteria.SqlEnum;
 import org.apache.torque.om.NumberKey;
+import org.apache.torque.util.functions.Count;
 
 /**
  * Tests for SqlExpression
@@ -1131,14 +1133,14 @@ public class SqlBuilderTest extends Base
             .where(new ColumnImpl("table2.column2"), 5)
             .addSelectColumn(new ColumnImpl("table2.column1"));
         Query subselectQuery = SqlBuilder.buildQuery(subselect);
-        PreparedStatementPart fromClause = new PreparedStatementPart(
+        PreparedStatementPart fromClause = new PreparedStatementPartImpl(
                 "(" + subselectQuery.toString() + ") alias",
                 subselectQuery.getPreparedStatementReplacements().toArray());
         Criterion join = new Criterion(new ColumnImpl("table1.column1"), new ColumnImpl("alias.column1"));
 
         Criteria criteria = new Criteria()
             .addSelectColumn(new ColumnImpl("table1.column1"))
-            .addJoin(new PreparedStatementPart("table1"), fromClause, join, Criteria.INNER_JOIN)
+            .addJoin(new PreparedStatementPartImpl("table1"), fromClause, join, Criteria.INNER_JOIN)
             .where(new ColumnImpl("table1.column3"), 3);
 
         Query query = SqlBuilder.buildQuery(criteria);
@@ -1779,6 +1781,27 @@ public class SqlBuilderTest extends Base
         assertEquals("value2", query.getPreparedStatementReplacements().get(0));
     }
 
+    public void testSubselectReferenceOuterTable() throws Exception
+    {
+        Criteria subselect = new Criteria()
+            .where(new ColumnImpl("table.column1"), new ColumnImpl("table2.column2"))
+            .and(new ColumnImpl("table.column2"), 2)
+            .addSelectColumn(new Count("*"));
+
+        Criteria criteria = new Criteria()
+            .where(subselect, 1)
+            .addSelectColumn(new ColumnImpl("table.column1"));
+
+        Query query = SqlBuilder.buildQuery(criteria);
+        assertEquals(
+                "SELECT table.column1 FROM table WHERE "
+                + "(SELECT COUNT(*) FROM table2 WHERE (table.column1=table2.column2 AND table.column2=?))=?",
+            query.toString());
+        assertEquals(2, query.getPreparedStatementReplacements().size());
+        assertEquals(2, query.getPreparedStatementReplacements().get(0));
+        assertEquals(1, query.getPreparedStatementReplacements().get(1));
+    }
+
     public void testLike() throws Exception
     {
         Criteria criteria = new Criteria();

Modified: db/torque/torque4/trunk/torque-test/src/test/java/org/apache/torque/generated/peer/WhereClauseSubselectTest.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-test/src/test/java/org/apache/torque/generated/peer/WhereClauseSubselectTest.java?rev=1706947&r1=1706946&r2=1706947&view=diff
==============================================================================
--- db/torque/torque4/trunk/torque-test/src/test/java/org/apache/torque/generated/peer/WhereClauseSubselectTest.java (original)
+++ db/torque/torque4/trunk/torque-test/src/test/java/org/apache/torque/generated/peer/WhereClauseSubselectTest.java Tue Oct  6 02:52:34 2015
@@ -33,6 +33,7 @@ import org.apache.torque.test.dbobject.A
 import org.apache.torque.test.dbobject.Book;
 import org.apache.torque.test.peer.AuthorPeer;
 import org.apache.torque.test.peer.BookPeer;
+import org.apache.torque.util.functions.Count;
 
 /**
  * Tests subselects in the where clause.
@@ -246,7 +247,7 @@ public class WhereClauseSubselectTest ex
      *
      * @throws Exception if the test fails
      */
-    public void testSubselectReferencingOuterSelect() throws Exception
+    public void testSubselectReferencingOuterSelectWithManuallyAddedFromClause() throws Exception
     {
         if (!supportsSubselects())
         {
@@ -261,11 +262,45 @@ public class WhereClauseSubselectTest ex
         Criteria criteria = new Criteria();
         criteria.where(subquery, 1);
 
-        List<?> result = AuthorPeer.doSelect(criteria);
+        List<Author> result = AuthorPeer.doSelect(criteria);
         assertEquals("Expected result of size 1 but got " + result.size(),
                 1,
                 result.size());
-        Author author = (Author) result.get(0);
+        Author author = result.get(0);
+        assertEquals("Expected author with Id "
+                + author3.getAuthorId()
+                + " but got "
+                + author.getAuthorId(),
+                author3.getAuthorId(),
+                author.getAuthorId());
+    }
+
+    /**
+     * Tests whether we can execute subselects which reference the outer select
+     * in the subselect.
+     *
+     * @throws Exception if the test fails
+     */
+    public void testSubselectReferencingOuterSelect() throws Exception
+    {
+        if (!supportsSubselects())
+        {
+            return;
+        }
+
+        Criteria subquery = new Criteria();
+        subquery.where(BookPeer.AUTHOR_ID, AuthorPeer.AUTHOR_ID);
+        subquery.and(BookPeer.TITLE, book3.getTitle());
+        subquery.addSelectColumn(new Count("*"));
+
+        Criteria criteria = new Criteria();
+        criteria.where(subquery, 1);
+
+        List<Author> result = AuthorPeer.doSelect(criteria);
+        assertEquals("Expected result of size 1 but got " + result.size(),
+                1,
+                result.size());
+        Author author = result.get(0);
         assertEquals("Expected author with Id "
                 + author3.getAuthorId()
                 + " but got "



---------------------------------------------------------------------
To unsubscribe, e-mail: torque-dev-unsubscribe@db.apache.org
For additional commands, e-mail: torque-dev-help@db.apache.org