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 2014/09/16 21:50:42 UTC

svn commit: r1625364 - in /db/torque/torque4/trunk/torque-runtime/src: main/java/org/apache/torque/adapter/ main/java/org/apache/torque/criteria/ main/java/org/apache/torque/sql/ test/java/org/apache/torque/sql/

Author: tfischer
Date: Tue Sep 16 19:50:41 2014
New Revision: 1625364

URL: http://svn.apache.org/r1625364
Log:
TORQUE-322 provide support for set operations

Modified:
    db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/AbstractAdapter.java
    db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/Adapter.java
    db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/OracleAdapter.java
    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/SqlEnum.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/Query.java
    db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/SqlBuilder.java
    db/torque/torque4/trunk/torque-runtime/src/test/java/org/apache/torque/sql/SqlBuilderTest.java

Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/AbstractAdapter.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/AbstractAdapter.java?rev=1625364&r1=1625363&r2=1625364&view=diff
==============================================================================
--- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/AbstractAdapter.java (original)
+++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/AbstractAdapter.java Tue Sep 16 19:50:41 2014
@@ -160,7 +160,7 @@ public abstract class AbstractAdapter im
      *
      * @return The string in a case that can be ignored.
      */
-    public String ignoreCaseInOrderBy(String in)
+    public String ignoreCaseInOrderBy(final String in)
     {
         return ignoreCase(in);
     }
@@ -199,7 +199,7 @@ public abstract class AbstractAdapter im
      *
      * @throws TorqueException if any error occurs when building the query
      */
-    public void generateLimits(Query query, long offset, int limit)
+    public void generateLimits(final Query query, final long offset, final int limit)
         throws TorqueException
     {
         if (supportsNativeLimit())
@@ -249,4 +249,19 @@ public abstract class AbstractAdapter im
     {
         return false;
     }
+
+    /**
+     * Whether to use the MINUS operator instead of the EXCEPT operator.
+     *
+     * As most databases do not need to replace the EXCEPT operator
+     * by the MINUS operator, this implementationalways returns
+     * <code>false</code>.
+     * This behaviour can be overwritten in subclasses.
+     *
+     * @return whether to use the MINUS operator instead of the EXCEPT operator.
+     */
+    public boolean useExceptForMinus()
+    {
+        return false;
+    }
 }

Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/Adapter.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/Adapter.java?rev=1625364&r1=1625363&r2=1625364&view=diff
==============================================================================
--- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/Adapter.java (original)
+++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/Adapter.java Tue Sep 16 19:50:41 2014
@@ -219,4 +219,11 @@ public interface Adapter extends Seriali
      * @return whether the escape clause should be appended or not.
      */
     boolean useEscapeClauseForLike();
+
+    /**
+     * Whether to use the MINUS operator instead of the EXCEPT operator.
+     *
+     * @return whether to use the MINUS operator instead of the EXCEPT operator.
+     */
+    boolean useExceptForMinus();
 }

Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/OracleAdapter.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/OracleAdapter.java?rev=1625364&r1=1625363&r2=1625364&view=diff
==============================================================================
--- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/OracleAdapter.java (original)
+++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/adapter/OracleAdapter.java Tue Sep 16 19:50:41 2014
@@ -65,7 +65,7 @@ public class OracleAdapter extends Abstr
      * @return The upper case string.
      */
     @Override
-    public String toUpperCase(String in)
+    public String toUpperCase(final String in)
     {
         return new StringBuffer("UPPER(").append(in).append(")").toString();
     }
@@ -77,7 +77,7 @@ public class OracleAdapter extends Abstr
      * @return The string in a case that can be ignored.
      */
     @Override
-    public String ignoreCase(String in)
+    public String ignoreCase(final String in)
     {
         return new StringBuffer("UPPER(").append(in).append(")").toString();
     }
@@ -105,7 +105,7 @@ public class OracleAdapter extends Abstr
      * @see org.apache.torque.adapter.Adapter#getIDMethodSQL(Object)
      */
     @Override
-    public String getIDMethodSQL(Object sequenceName)
+    public String getIDMethodSQL(final Object sequenceName)
     {
         return ("select " + sequenceName + ".nextval from dual");
     }
@@ -118,7 +118,7 @@ public class OracleAdapter extends Abstr
      * @exception SQLException No Statement could be created or executed.
      */
     @Override
-    public void lockTable(Connection con, String table) throws SQLException
+    public void lockTable(final Connection con, final String table) throws SQLException
     {
         Statement statement = null;
         try
@@ -150,7 +150,7 @@ public class OracleAdapter extends Abstr
      * @exception SQLException No Statement could be created or executed.
      */
     @Override
-    public void unlockTable(Connection con, String table) throws SQLException
+    public void unlockTable(final Connection con, final String table) throws SQLException
     {
         // Tables in Oracle are unlocked when a commit is issued.  The
         // user may have issued a commit but do it here to be sure.
@@ -195,7 +195,7 @@ public class OracleAdapter extends Abstr
      * @param limit the limit Value
      */
     @Override
-    public void generateLimits(Query query, long offset, int limit)
+    public void generateLimits(final Query query, final long offset, final int limit)
     {
         StringBuffer preLimit = new StringBuffer()
         .append("SELECT B.* FROM ( ")
@@ -346,4 +346,18 @@ public class OracleAdapter extends Abstr
     {
         return true;
     }
+
+    /**
+     * Whether to use the MINUS operator instead of the EXCEPT operator.
+     *
+     * Oracle needs this, so this implementation always returns
+     * <code>true</code>.
+     *
+     * @return whether to use the MINUS operator instead of the EXCEPT operator.
+     */
+    @Override
+    public boolean useExceptForMinus()
+    {
+        return true;
+    }
 }

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=1625364&r1=1625363&r2=1625364&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 Sep 16 19:50:41 2014
@@ -31,6 +31,7 @@ import java.util.Map;
 import org.apache.commons.lang.builder.EqualsBuilder;
 import org.apache.commons.lang.builder.HashCodeBuilder;
 import org.apache.torque.Column;
+import org.apache.torque.TorqueRuntimeException;
 import org.apache.torque.sql.OrderBy;
 import org.apache.torque.sql.Query;
 import org.apache.torque.sql.SqlBuilder;
@@ -193,6 +194,10 @@ public class Criteria implements Seriali
     /** The JDBC statement fetch size, if any. */
     private Integer fetchSize;
 
+    private SqlEnum setOperator;
+
+    private final List<Criteria> setCriteriaParts;
+
     /**
      * Constructor.
      */
@@ -206,6 +211,7 @@ public class Criteria implements Seriali
         asColumns = new LinkedHashMap<String, Column>();
         joins = new ArrayList<Join>();
         aliases = new HashMap<String, Object>();
+        setCriteriaParts = new ArrayList<Criteria>();
     }
 
     /**
@@ -251,6 +257,41 @@ public class Criteria implements Seriali
         offset = toCopy.offset;
         aliases = new HashMap<String, Object>(toCopy.aliases);
         fetchSize = toCopy.fetchSize;
+        setOperator = toCopy.setOperator;
+        setCriteriaParts = new ArrayList<Criteria>(
+                toCopy.setCriteriaParts.size());
+        for (Criteria setCriteriaPart : toCopy.setCriteriaParts)
+        {
+            setCriteriaParts.add(new Criteria(setCriteriaPart));
+        }
+    }
+
+    /**
+     * Resets this Criteria to its original state.
+     *
+     * @param toCopy the criteria to copy.
+     */
+    protected void clear()
+    {
+        ignoreCase = false;
+        singleRecord = false;
+        selectModifiers.clear();
+        selectColumns.clear();
+        orderByColumns.clear();
+        groupByColumns.clear();
+        fromElements.clear();
+        having = null;
+        forUpdate = false;
+        topLevelCriterion = null;
+        asColumns.clear();
+        joins.clear();
+        dbName = null;
+        limit = -1;
+        offset = 0;
+        aliases.clear();
+        fetchSize = null;
+        setOperator = null;
+        setCriteriaParts.clear();
     }
 
     /**
@@ -268,9 +309,13 @@ public class Criteria implements Seriali
      * @param clause SQL clause to select from the table
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria addAsColumn(final String name, final Column clause)
     {
+        assertNoComposite();
         asColumns.put(name, clause);
         return this;
     }
@@ -302,9 +347,13 @@ public class Criteria implements Seriali
      *
      * @param alias the alias for the table name.
      * @param table the table name as known in the database.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria addAlias(final String alias, final String table)
     {
+        assertNoComposite();
         aliases.put(alias, table);
         return this;
     }
@@ -314,9 +363,13 @@ public class Criteria implements Seriali
      *
      * @param alias the alias for the subselect.
      * @param subselect the Criteria for the subselect.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria addAlias(final String alias, final Criteria subselect)
     {
+        assertNoComposite();
         aliases.put(alias, subselect);
         return this;
     }
@@ -401,9 +454,13 @@ public class Criteria implements Seriali
      * (but this is not resolved here).
      *
      * @param dbName The Database(Map) name.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public void setDbName(final String dbName)
     {
+        assertNoComposite();
         this.dbName = dbName;
     }
 
@@ -418,10 +475,15 @@ public class Criteria implements Seriali
      * </code>
      *
      * @param having A Criterion object
+     *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria addHaving(final Criterion having)
     {
+        assertNoComposite();
         this.having = having;
         return this;
     }
@@ -440,9 +502,13 @@ public class Criteria implements Seriali
      * Sets that FOR UPDATE clause should be added to the query.
      *
      * @return this object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria forUpdate()
     {
+        assertNoComposite();
         forUpdate = true;
         return this;
     }
@@ -454,9 +520,13 @@ public class Criteria implements Seriali
      *        false if not.
      *
      * @return this object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria setForUpdate(final boolean forUpdate)
     {
+        assertNoComposite();
         this.forUpdate = forUpdate;
         return this;
     }
@@ -482,10 +552,15 @@ public class Criteria implements Seriali
      *
      * @param left A String with the left side of the join.
      * @param right A String with the right side of the join.
+     *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria addJoin(final Column left, final Column right)
     {
+        assertNoComposite();
         return addJoin(left, right, null);
     }
 
@@ -503,12 +578,19 @@ public class Criteria implements Seriali
      * @param right A String with the right side of the join.
      * @param joinType The operator used for the join: must be one of null,
      *        Criteria.LEFT_JOIN, Criteria.RIGHT_JOIN, Criteria.INNER_JOIN
+     *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
-    public Criteria addJoin(final Column left, final Column right, final JoinType joinType)
+    public Criteria addJoin(
+            final Column left,
+            final Column right,
+            final JoinType joinType)
     {
+        assertNoComposite();
         joins.add(new Join(left, right, Criteria.EQUAL, joinType));
-
         return this;
     }
 
@@ -533,6 +615,9 @@ public class Criteria implements Seriali
      *        Criteria.LEFT_JOIN, Criteria.RIGHT_JOIN, Criteria.INNER_JOIN
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria addJoin(
             final Column left,
@@ -540,8 +625,8 @@ public class Criteria implements Seriali
             final SqlEnum comparison,
             final JoinType joinType)
     {
+        assertNoComposite();
         joins.add(new Join(left, right, comparison, joinType));
-
         return this;
     }
 
@@ -569,6 +654,9 @@ public class Criteria implements Seriali
      *        Criteria.LEFT_JOIN, Criteria.RIGHT_JOIN, Criteria.INNER_JOIN
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria addJoin(
             final String leftTable,
@@ -576,12 +664,12 @@ public class Criteria implements Seriali
             final Criterion joinCondition,
             final JoinType joinType)
     {
+        assertNoComposite();
         joins.add(new Join(
                 new PreparedStatementPart(leftTable),
                 new PreparedStatementPart(rightTable),
                 joinCondition,
                 joinType));
-
         return this;
     }
 
@@ -609,6 +697,9 @@ public class Criteria implements Seriali
      *        Criteria.LEFT_JOIN, Criteria.RIGHT_JOIN, Criteria.INNER_JOIN
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria addJoin(
             final PreparedStatementPart leftTable,
@@ -616,12 +707,12 @@ public class Criteria implements Seriali
             final Criterion joinCondition,
             final JoinType joinType)
     {
+        assertNoComposite();
         joins.add(new Join(
                 leftTable,
                 rightTable,
                 joinCondition,
                 joinType));
-
         return this;
     }
 
@@ -637,17 +728,25 @@ public class Criteria implements Seriali
 
     /**
      * Adds &quot;ALL &quot; to the SQL statement.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public void setAll()
     {
+        assertNoComposite();
         selectModifiers.add(ALL.toString());
     }
 
     /**
      * Adds &quot;DISTINCT &quot; to the SQL statement.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public void setDistinct()
     {
+        assertNoComposite();
         selectModifiers.add(DISTINCT.toString());
     }
 
@@ -656,11 +755,22 @@ public class Criteria implements Seriali
      * whenever String columns are encountered.
      *
      * @param ignoreCase True if case should be ignored.
+     *
      * @return A modified Criteria object.
      */
     public Criteria setIgnoreCase(final boolean ignoreCase)
     {
-        this.ignoreCase = ignoreCase;
+        if (isComposite())
+        {
+            for (Criteria criteria : setCriteriaParts)
+            {
+                criteria.setIgnoreCase(true);
+            }
+        }
+        else
+        {
+            this.ignoreCase = ignoreCase;
+        }
         return this;
     }
 
@@ -777,9 +887,13 @@ public class Criteria implements Seriali
      * @param column The select column to add.
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria addSelectColumn(final Column column)
     {
+        assertNoComposite();
         selectColumns.add(column);
         return this;
     }
@@ -810,9 +924,13 @@ public class Criteria implements Seriali
      * @param groupBy The column to group by.
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria addGroupByColumn(final Column groupBy)
     {
+        assertNoComposite();
         groupByColumns.add(groupBy);
         return this;
     }
@@ -848,7 +966,9 @@ public class Criteria implements Seriali
      *
      * @return A modified Criteria object.
      */
-    public Criteria addAscendingOrderByColumn(final Column column, final boolean ignoreCase)
+    public Criteria addAscendingOrderByColumn(
+            final Column column,
+            final boolean ignoreCase)
     {
         orderByColumns.add(new OrderBy(column, SqlEnum.ASC, ignoreCase));
         return this;
@@ -909,9 +1029,13 @@ public class Criteria implements Seriali
      * Adds a table to the from clause, not using a joinType or joinCondition.
      *
      * @return the modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria addFrom(final String tableName)
     {
+        assertNoComposite();
         fromElements.add(new FromElement(tableName));
         return this;
     }
@@ -920,9 +1044,13 @@ public class Criteria implements Seriali
      * Adds a new Element to the from clause.
      *
      * @return the modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria addFrom(final FromElement fromElement)
     {
+        assertNoComposite();
         fromElements.add(fromElement);
         return this;
     }
@@ -992,6 +1120,8 @@ public class Criteria implements Seriali
         equalsBuilder.append(criteria.asColumns, this.asColumns);
         equalsBuilder.append(criteria.joins, this.joins);
         equalsBuilder.append(criteria.fetchSize, this.fetchSize);
+        equalsBuilder.append(criteria.setOperator, this.setOperator);
+        equalsBuilder.append(criteria.setCriteriaParts, this.setCriteriaParts);
         return equalsBuilder.isEquals();
     }
 
@@ -1018,6 +1148,8 @@ public class Criteria implements Seriali
         hashCodeBuilder.append(asColumns);
         hashCodeBuilder.append(joins);
         hashCodeBuilder.append(fetchSize);
+        hashCodeBuilder.append(setOperator);
+        hashCodeBuilder.append(setCriteriaParts);
         return hashCodeBuilder.toHashCode();
     }
 
@@ -1062,9 +1194,13 @@ public class Criteria implements Seriali
      * @param criterion A Criterion object.
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria and(final Criterion criterion)
     {
+        assertNoComposite();
         if (topLevelCriterion == null)
         {
             topLevelCriterion = new Criterion(criterion);
@@ -1101,6 +1237,9 @@ public class Criteria implements Seriali
      *        literal value.
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria and(final Object lValue, final Object rValue)
     {
@@ -1134,9 +1273,16 @@ public class Criteria implements Seriali
      *        to specify the expression manually in the rValue parameter.
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
-    public Criteria and(final Object lValue, final Object rValue, final SqlEnum comparison)
+    public Criteria and(
+            final Object lValue,
+            final Object rValue,
+            final SqlEnum comparison)
     {
+        assertNoComposite();
         Criterion newCriterion = new Criterion(lValue, rValue, comparison);
         if (topLevelCriterion == null)
         {
@@ -1168,8 +1314,15 @@ public class Criteria implements Seriali
      * @param day The day to compare to.
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
-    public Criteria andDate(final Object lValue, final int year, final int month, final int day)
+    public Criteria andDate(
+            final Object lValue,
+            final int year,
+            final int month,
+            final int day)
     {
         return and(lValue,
                 new GregorianCalendar(year, month, day).getTime(),
@@ -1196,8 +1349,15 @@ public class Criteria implements Seriali
      * @param comparison The comparison operator.
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
-    public Criteria andDate(final Object lValue, final int year, final int month, final int day,
+    public Criteria andDate(
+            final Object lValue,
+            final int year,
+            final int month,
+            final int day,
             final SqlEnum comparison)
     {
         return and(lValue,
@@ -1222,6 +1382,9 @@ public class Criteria implements Seriali
      * @param rValues The values to compare against.
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria andIn(final Object lValue, final Object[] rValues)
     {
@@ -1245,6 +1408,9 @@ public class Criteria implements Seriali
      * @param rValues The values to compare against.
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria andIn(final Object lValue, final Collection<?> rValues)
     {
@@ -1268,6 +1434,9 @@ public class Criteria implements Seriali
      * @param rValues The values to compare against.
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria andNotIn(final Object lValue, final Object[] rValues)
     {
@@ -1291,6 +1460,9 @@ public class Criteria implements Seriali
      * @param rValues The values to compare against.
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria andNotIn(final Object lValue, final Collection<?> rValues)
     {
@@ -1310,8 +1482,13 @@ public class Criteria implements Seriali
      * @param replacements the replacements for the "?" placeholders in SQL.
      *
      * @return the modified Criteria.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
-    public Criteria andVerbatimSql(final String sql, final Object[] replacements)
+    public Criteria andVerbatimSql(
+            final String sql,
+            final Object[] replacements)
     {
         Criterion criterion
                 = new Criterion(null, null, null, sql, replacements);
@@ -1338,6 +1515,9 @@ public class Criteria implements Seriali
      * @param toAddToFromClause2 a column to add to from clause, may be null.
      *
      * @return the modified Criteria.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria andVerbatimSql(
             final String sql,
@@ -1377,9 +1557,13 @@ public class Criteria implements Seriali
      * @param criterion A Criterion object.
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria or(final Criterion criterion)
     {
+        assertNoComposite();
         if (topLevelCriterion == null)
         {
             topLevelCriterion = new Criterion(criterion);
@@ -1416,6 +1600,9 @@ public class Criteria implements Seriali
      *        literal value.
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria or(final Object lValue, final Object rValue)
     {
@@ -1449,9 +1636,16 @@ public class Criteria implements Seriali
      *        to specify the expression manually in the value parameter.
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
-    public Criteria or(final Object lValue, final Object rValue, final SqlEnum comparison)
+    public Criteria or(
+            final Object lValue,
+            final Object rValue,
+            final SqlEnum comparison)
     {
+        assertNoComposite();
         Criterion newCriterion = new Criterion(lValue, rValue, comparison);
         if (topLevelCriterion == null)
         {
@@ -1483,8 +1677,15 @@ public class Criteria implements Seriali
      * @param day The day to compare to.
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
-    public Criteria orDate(final Object lValue, final int year, final int month, final int day)
+    public Criteria orDate(
+            final Object lValue,
+            final int year,
+            final int month,
+            final int day)
     {
         return or(lValue,
                 new GregorianCalendar(year, month, day).getTime(),
@@ -1511,8 +1712,15 @@ public class Criteria implements Seriali
      * @param comparison The comparison operator.
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
-    public Criteria orDate(final Object lValue, final int year, final int month, final int day,
+    public Criteria orDate(
+            final Object lValue,
+            final int year,
+            final int month,
+            final int day,
             final SqlEnum comparison)
     {
         return or(lValue,
@@ -1537,6 +1745,9 @@ public class Criteria implements Seriali
      * @param rValues The values to compare against.
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria orIn(final Object lValue, final Object[] rValues)
     {
@@ -1560,6 +1771,9 @@ public class Criteria implements Seriali
      * @param rValues The values to compare against.
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria orIn(final Object lValue, final Collection<?> rValues)
     {
@@ -1583,6 +1797,9 @@ public class Criteria implements Seriali
      * @param rValues The values to compare against.
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria orNotIn(final Object lValue, final Object[] rValues)
     {
@@ -1606,6 +1823,9 @@ public class Criteria implements Seriali
      * @param rValues The values to compare against.
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria orNotIn(final Object lValue, final Collection<?> rValues)
     {
@@ -1625,6 +1845,9 @@ public class Criteria implements Seriali
      * @param replacements the replacements for the "?" placeholders in SQL.
      *
      * @return the modified Criteria.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria orVerbatimSql(final String sql, final Object[] replacements)
     {
@@ -1653,6 +1876,9 @@ public class Criteria implements Seriali
      * @param toAddToFromClause2 a column to add to from clause, may be null.
      *
      * @return the modified Criteria.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria orVerbatimSql(
             final String sql,
@@ -1686,6 +1912,9 @@ public class Criteria implements Seriali
      * @param criterion A Criterion object.
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria where(final Criterion criterion)
     {
@@ -1719,6 +1948,9 @@ public class Criteria implements Seriali
      *        literal value.
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria where(final Object lValue, final Object rValue)
     {
@@ -1746,8 +1978,14 @@ public class Criteria implements Seriali
      *        to specify the expression manually in the value parameter.
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
-    public Criteria where(final Object lValue, final Object rValue, final SqlEnum comparison)
+    public Criteria where(
+            final Object lValue,
+            final Object rValue,
+            final SqlEnum comparison)
     {
         return and(lValue, rValue, comparison);
     }
@@ -1769,8 +2007,15 @@ public class Criteria implements Seriali
      * @param day The day to compare to.
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
-    public Criteria whereDate(final Object lValue, final int year, final int month, final int day)
+    public Criteria whereDate(
+            final Object lValue,
+            final int year,
+            final int month,
+            final int day)
     {
         return andDate(lValue, year, month, day);
     }
@@ -1793,8 +2038,15 @@ public class Criteria implements Seriali
      * @param comparison The comparison operator.
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
-    public Criteria whereDate(final Object lValue, final int year, final int month, final int day,
+    public Criteria whereDate(
+            final Object lValue,
+            final int year,
+            final int month,
+            final int day,
             final SqlEnum comparison)
     {
         return andDate(lValue, year, month, day, comparison);
@@ -1815,6 +2067,9 @@ public class Criteria implements Seriali
      * @param rValues The values to compare against.
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria whereIn(final Object lValue, final Object[] rValues)
     {
@@ -1836,6 +2091,9 @@ public class Criteria implements Seriali
      * @param rValues The values to compare against.
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria whereIn(final Object lValue, final Collection<?> rValues)
     {
@@ -1857,6 +2115,9 @@ public class Criteria implements Seriali
      * @param rValues The values to compare against.
      *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria whereNotIn(final Object lValue, final Object[] rValues)
     {
@@ -1876,7 +2137,11 @@ public class Criteria implements Seriali
      *        In all other cases, (e.G. string object), it is interpreted as
      *        literal value.
      * @param rValues The values to compare against.
+     *
      * @return A modified Criteria object.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria whereNotIn(final Object lValue, final Collection<?> rValues)
     {
@@ -1899,8 +2164,13 @@ public class Criteria implements Seriali
      * @param replacements the replacements for the "?" placeholders in SQL.
      *
      * @return the modified Criteria.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
-    public Criteria whereVerbatimSql(final String sql, final Object[] replacements)
+    public Criteria whereVerbatimSql(
+            final String sql,
+            final Object[] replacements)
     {
         Criterion criterion
                 = new Criterion(null, null, null, sql, replacements);
@@ -1930,6 +2200,9 @@ public class Criteria implements Seriali
      * @param toAddToFromClause2 a column to add to from clause, may be null.
      *
      * @return the modified Criteria.
+     *
+     * @throws TorqueRuntimeException if this operation is performed on a
+     *         Criteria composed of set parts (e.g. union, intersect, except).
      */
     public Criteria whereVerbatimSql(
             final String sql,
@@ -1946,4 +2219,176 @@ public class Criteria implements Seriali
         and(criterion);
         return this;
     }
+
+    /**
+     * Creates a SQL UNION between this Criteria and the passed other criteria.
+     *
+     * @param other the other part of the union.
+     *
+     * @return the modified Criteria.
+     */
+    public Criteria union(final Criteria other)
+    {
+        appendSetOperation(other, SqlEnum.UNION);
+        return this;
+    }
+
+    /**
+     * Creates a SQL UNION ALL between this Criteria
+     * and the passed other criteria.
+     *
+     * @param other the other part of the union.
+     *
+     * @return the modified Criteria.
+     */
+    public Criteria unionAll(final Criteria other)
+    {
+        appendSetOperation(other, SqlEnum.UNION_ALL);
+        return this;
+    }
+
+    /**
+     * Creates a SQL INTERSECT between this Criteria
+     * and the passed other criteria.
+     *
+     * @param other the other part of the union.
+     *
+     * @return the modified Criteria.
+     */
+    public Criteria intersect(final Criteria other)
+    {
+        appendSetOperation(other, SqlEnum.INTERSECT);
+        return this;
+    }
+
+    /**
+     * Creates a SQL INTERSECT ALL between this Criteria
+     * and the passed other criteria.
+     *
+     * @param other the other part of the union.
+     *
+     * @return the modified Criteria.
+     */
+    public Criteria intersectAll(final Criteria other)
+    {
+        appendSetOperation(other, SqlEnum.INTERSECT_ALL);
+        return this;
+    }
+
+    /**
+     * Creates a SQL EXCEPT between this Criteria
+     * and the passed other criteria.
+     *
+     * @param other the other part of the union.
+     *
+     * @return the modified Criteria.
+     */
+    public Criteria except(final Criteria other)
+    {
+        appendSetOperation(other, SqlEnum.EXCEPT);
+        return this;
+    }
+
+    /**
+     * Creates a SQL EXCEPT between this Criteria
+     * and the passed other criteria.
+     *
+     * @param other the other part of the union.
+     *
+     * @return the modified Criteria.
+     */
+    public Criteria exceptAll(final Criteria other)
+    {
+        appendSetOperation(other, SqlEnum.EXCEPT_ALL);
+        return this;
+    }
+
+    /**
+     * Appends a set operation (union, except, intersect) to this Criteria.
+     * If not already done, this criteria is converted to a composite criteria.
+     *
+     * @param other the other criteria, not null.
+     * @param setOperator the set operator, not null.
+     *
+     * @throws NullPointerException if other or setOperator are null.
+     */
+    protected void appendSetOperation(
+            final Criteria other,
+            final SqlEnum setOperator)
+    {
+        if (other == null)
+        {
+            throw new NullPointerException("other must not be null");
+        }
+        if (setOperator == null)
+        {
+            throw new NullPointerException("setOperator must not be null");
+        }
+        if (isComposite() && this.setOperator.equals(setOperator))
+        {
+            setCriteriaParts.add(other);
+        }
+        else
+        {
+            Criteria copy = new Criteria(this);
+            this.clear();
+            setCriteriaParts.add(copy);
+            setCriteriaParts.add(other);
+        }
+        this.setOperator = setOperator;
+    }
+
+    /**
+     * Return the parts of the criteria which compose a query using
+     * set operations (union, except, intersect).
+     *
+     * @return the parts, not null, empty if this query does not contain set
+     *         operations
+     */
+    public List<Criteria> getSetCriteriaParts()
+    {
+        return setCriteriaParts;
+    }
+
+    /**
+     * Returns the operator between the set operations.
+     *
+     * @return the operator, or null if this is not a composite criteria.
+     */
+    public SqlEnum getSetOperator()
+    {
+        return setOperator;
+    }
+
+    /**
+     * Returns whether this Criteria is a composite criteria, i.e. is composed
+     * from more than one Criteria related by set operations
+     * (e.g. union, except, intersect)..
+     *
+     * @return true if the criteria consists of several parts connected
+     *         by set operations, false otherwise.
+     */
+    public boolean isComposite()
+    {
+        return !setCriteriaParts.isEmpty();
+    }
+
+    /**
+     * Checks that this Criteria is no composite Criteria, and throws a
+     * TorqueRuntimeException otherwise.
+     *
+     * @throws TorqueRuntimeException if this Criteria is a composite Criteria.
+     */
+    protected void assertNoComposite() throws TorqueRuntimeException
+    {
+        if (isComposite())
+        {
+            throw new TorqueRuntimeException(
+                    "This operation cannot be performed "
+                    + "on a composite Criteria, which is composed "
+                    + "of several set operations."
+                    + " Try to perform the operation on the single parts"
+                    + " of this Criteria");
+        }
+    }
 }

Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/SqlEnum.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/SqlEnum.java?rev=1625364&r1=1625363&r2=1625364&view=diff
==============================================================================
--- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/SqlEnum.java (original)
+++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/criteria/SqlEnum.java Tue Sep 16 19:50:41 2014
@@ -124,10 +124,10 @@ public final class SqlEnum implements ja
     /** SQL Expression "DESC". */
     public static final SqlEnum DESC =
         new SqlEnum("DESC", -1);
-    /** SQL Expression " IS NULL ". */
+    /** SQL Expression " IS NULL". */
     public static final SqlEnum ISNULL =
         new SqlEnum(" IS NULL", 1);
-    /** SQL Expression " IS NOT NULL ". */
+    /** SQL Expression " IS NOT NULL". */
     public static final SqlEnum ISNOTNULL =
         new SqlEnum(" IS NOT NULL", 1);
     /** SQL Expression "CURRENT_DATE". */
@@ -148,6 +148,30 @@ public final class SqlEnum implements ja
     /** SQL Expression " ESCAPE ". */
     public static final SqlEnum ESCAPE =
         new SqlEnum(" ESCAPE ", -1);
+    /** SQL Expression " UNION ". */
+    public static final SqlEnum UNION =
+        new SqlEnum(" UNION ", -1);
+    /** SQL Expression " UNION ALL ". */
+    public static final SqlEnum UNION_ALL =
+            new SqlEnum(" UNION ALL ", -1);
+    /** SQL Expression " INTERSECT ". */
+    public static final SqlEnum INTERSECT =
+            new SqlEnum(" INTERSECT ", -1);
+    /** SQL Expression " INTERSECT ALL ". */
+    public static final SqlEnum INTERSECT_ALL =
+            new SqlEnum(" INTERSECT ALL ", -1);
+    /** SQL Expression " EXCEPT ". */
+    public static final SqlEnum EXCEPT =
+            new SqlEnum(" EXCEPT ", -1);
+    /** SQL Expression " EXCEPT ALL ". */
+    public static final SqlEnum EXCEPT_ALL =
+            new SqlEnum(" EXCEPT ALL ", -1);
+    /** SQL Expression " MINUS ". */
+    public static final SqlEnum MINUS =
+            new SqlEnum(" MINUS ", -1);
+    /** SQL Expression " MINUS ALL ". */
+    public static final SqlEnum MINUS_ALL =
+            new SqlEnum(" MINUS ALL ", -1);
 
     /**
      * returns whether o is the same SqlEnum as this object.

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=1625364&r1=1625363&r2=1625364&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 Sep 16 19:50:41 2014
@@ -63,6 +63,11 @@ public final class JoinBuilder
                 final Query query)
             throws TorqueException
     {
+        if (criteria.isComposite())
+        {
+            return;
+        }
+
         List<Join> criteriaJoins = criteria.getJoins();
 
         if (criteriaJoins.isEmpty())

Modified: db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/Query.java
URL: http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/Query.java?rev=1625364&r1=1625363&r2=1625364&view=diff
==============================================================================
--- db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/Query.java (original)
+++ db/torque/torque4/trunk/torque-runtime/src/main/java/org/apache/torque/sql/Query.java Tue Sep 16 19:50:41 2014
@@ -171,6 +171,16 @@ public class Query
     private Integer fetchSize;
 
     /**
+     * The parts of this query.
+     */
+    private final List<Query> parts = new ArrayList<Query>();
+
+    /**
+     * The Operator connecting the parts of the query.
+     */
+    public String partOperator;
+
+    /**
      * Retrieve the modifier buffer in order to add modifiers to this
      * query.  E.g. DISTINCT and ALL.
      *
@@ -252,6 +262,10 @@ public class Query
         {
             result.addAll(fromElement.getPreparedStatementReplacements());
         }
+        for (Query part : parts)
+        {
+            result.addAll(part.getPreparedStatementReplacements());
+        }
         result.addAll(whereClausePreparedStatementReplacements);
         return Collections.unmodifiableList(result);
     }
@@ -492,6 +506,36 @@ public class Query
     }
 
     /**
+     * Returns the parts of this query.
+     *
+     * @return a modifiable list containing the parts of this query, not null.
+     */
+    public List<Query> getParts()
+    {
+        return parts;
+    }
+
+    /**
+     * Returns the operator connecting the query parts.
+     *
+     * @return the operator connecting the parts, or null.
+     */
+    public String getPartOperator()
+    {
+        return this.partOperator;
+    }
+
+    /**
+     * Sets the operator connecting the query parts.
+     *
+     * @param partOperator the operator connecting the parts, or null.
+     */
+    public void setPartOperator(final String partOperator)
+    {
+        this.partOperator = partOperator;
+    }
+
+    /**
      * Outputs the query statement.
      *
      * @return A String with the query statement.
@@ -523,89 +567,107 @@ public class Query
                 .append(" ");
         }
 
-        if (Type.SELECT == type)
+        if (parts.isEmpty())
         {
-            stringBuilder.append(SELECT)
-                .append(StringUtils.join(selectModifiers.iterator(), " "))
-                .append(StringUtils.join(columns.iterator(), ", "))
-                .append(FROM);
-        }
-        else if (Type.UPDATE == type)
-        {
-            stringBuilder.append(UPDATE);
-        }
-        else if (Type.DELETE == type)
-        {
-            stringBuilder.append(DELETE_FROM);
-        }
+            if (Type.SELECT == type)
+            {
+                stringBuilder.append(SELECT)
+                    .append(StringUtils.join(selectModifiers.iterator(), " "))
+                    .append(StringUtils.join(columns.iterator(), ", "))
+                    .append(FROM);
+            }
+            else if (Type.UPDATE == type)
+            {
+                stringBuilder.append(UPDATE);
+            }
+            else if (Type.DELETE == type)
+            {
+                stringBuilder.append(DELETE_FROM);
+            }
 
-        boolean first = true;
-        for (Iterator<FromElement> it = fromClause.iterator(); it.hasNext();)
-        {
-            FromElement fromElement = it.next();
+            boolean first = true;
+            for (Iterator<FromElement> it = fromClause.iterator(); it.hasNext();)
+            {
+                FromElement fromElement = it.next();
+
+                if (!first && fromElement.getJoinCondition() == null)
+                {
+                    stringBuilder.append(", ");
+                }
+                first = false;
+                stringBuilder.append(fromElement.toString());
+            }
 
-            if (!first && fromElement.getJoinCondition() == null)
+            if (Type.SELECT == type
+                    && (forUpdate != null)
+                    && !"FOR UPDATE".equals(forUpdate))
             {
-                stringBuilder.append(", ");
+                stringBuilder.append(" ").append(forUpdate);
             }
-            first = false;
-            stringBuilder.append(fromElement.toString());
-        }
 
-        if (Type.SELECT == type
-                && (forUpdate != null)
-                && !"FOR UPDATE".equals(forUpdate))
-        {
-            stringBuilder.append(" ").append(forUpdate);
-        }
+            if (Type.UPDATE == type)
+            {
+            	stringBuilder.append(SET);
+                first = true;
+                for (Map.Entry<Column, JdbcTypedValue> entry
+                        : updateValues.entrySet())
+                {
+                    if (!first)
+                    {
+                        stringBuilder.append(",");
+                    }
+                    Column column = entry.getKey();
+                    String columnName = column.getColumnName();
+                    if (columnName == null)
+                    {
+                        columnName = column.getSqlExpression();
+                    }
+                    stringBuilder.append(columnName);
+                    if (entry.getValue().getSqlExpression() == null)
+                    {
+                        stringBuilder.append("=?");
+                    }
+                    else
+                    {
+                        Column sqlExpression = entry.getValue().getSqlExpression();
+                        stringBuilder.append("=")
+                                .append(sqlExpression.getSqlExpression());
+                    }
+                    first = false;
+                }
+            }
 
-        if (Type.UPDATE == type)
+            if (!whereClause.isEmpty())
+            {
+                stringBuilder.append(WHERE)
+                    .append(StringUtils.join(whereClause.iterator(), AND));
+            }
+            if (!groupByColumns.isEmpty())
+            {
+                stringBuilder.append(GROUP_BY)
+                    .append(StringUtils.join(groupByColumns.iterator(), ", "));
+            }
+            if (having != null)
+            {
+                stringBuilder.append(HAVING)
+                    .append(having);
+            }
+        }
+        else
         {
-        	stringBuilder.append(SET);
-            first = true;
-            for (Map.Entry<Column, JdbcTypedValue> entry
-                    : updateValues.entrySet())
+            boolean first = true;
+            for (Query part : parts)
             {
                 if (!first)
                 {
-                    stringBuilder.append(",");
-                }
-                Column column = entry.getKey();
-                String columnName = column.getColumnName();
-                if (columnName == null)
-                {
-                    columnName = column.getSqlExpression();
-                }
-                stringBuilder.append(columnName);
-                if (entry.getValue().getSqlExpression() == null)
-                {
-                    stringBuilder.append("=?");
-                }
-                else
-                {
-                    Column sqlExpression = entry.getValue().getSqlExpression();
-                    stringBuilder.append("=")
-                            .append(sqlExpression.getSqlExpression());
+                    stringBuilder.append(partOperator);
                 }
+                stringBuilder.append('(');
+                part.toStringBuilder(stringBuilder);
+                stringBuilder.append(')');
                 first = false;
             }
         }
-
-        if (!whereClause.isEmpty())
-        {
-            stringBuilder.append(WHERE)
-                .append(StringUtils.join(whereClause.iterator(), AND));
-        }
-        if (!groupByColumns.isEmpty())
-        {
-            stringBuilder.append(GROUP_BY)
-                .append(StringUtils.join(groupByColumns.iterator(), ", "));
-        }
-        if (having != null)
-        {
-            stringBuilder.append(HAVING)
-                .append(having);
-        }
         if (!orderByColumns.isEmpty())
         {
             stringBuilder.append(ORDER_BY)

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=1625364&r1=1625363&r2=1625364&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 Sep 16 19:50:41 2014
@@ -69,9 +69,6 @@ public final class SqlBuilder
     public static final String[] FUNCTION_DELIMITERS
             = {" ", ",", "(", ")", "<", ">"};
 
-    /** The backslash character*/
-    private static final char BACKSLASH = '\\';
-
     /**
      * The list of WhereClausePsPartBuilders which can build the where clause.
      */
@@ -133,6 +130,7 @@ public final class SqlBuilder
         processGroupBy(crit, sqlStatement);
         processHaving(crit, sqlStatement);
         processOrderBy(crit, sqlStatement);
+        processSetOperations(crit, sqlStatement);
         processLimits(crit, sqlStatement);
         processFromElements(crit, sqlStatement);
         processForUpdate(crit, sqlStatement);
@@ -154,6 +152,10 @@ public final class SqlBuilder
                 final Query query)
             throws TorqueException
     {
+        if (criteria.isComposite())
+        {
+            return;
+        }
         UniqueList<String> selectClause = query.getSelectClause();
         UniqueColumnList selectColumns = criteria.getSelectColumns();
 
@@ -190,6 +192,10 @@ public final class SqlBuilder
                 final Query query)
             throws TorqueException
     {
+        if (criteria.isComposite())
+        {
+            return;
+        }
         UniqueList<String> querySelectClause = query.getSelectClause();
         Map<String, Column> criteriaAsColumns = criteria.getAsColumns();
 
@@ -219,6 +225,10 @@ public final class SqlBuilder
             final Criteria criteria,
             final Query query)
     {
+        if (criteria.isComposite())
+        {
+            return;
+        }
         UniqueList<String> selectModifiers = query.getSelectModifiers();
         UniqueList<String> modifiers = criteria.getSelectModifiers();
         for (String modifier : modifiers)
@@ -240,6 +250,10 @@ public final class SqlBuilder
             final Query query)
         throws TorqueException
     {
+        if (criteria.isComposite())
+        {
+            return;
+        }
         if (criteria.getTopLevelCriterion() == null)
         {
             return;
@@ -350,21 +364,21 @@ public final class SqlBuilder
      * @throws TorqueException if the OrderBy-Columns can not be processed
      */
     private static void processOrderBy(
-            final Criteria crit,
+            final Criteria criteria,
             final Query query)
             throws TorqueException
     {
         UniqueList<String> orderByClause = query.getOrderByClause();
         UniqueList<String> selectClause = query.getSelectClause();
 
-        UniqueList<OrderBy> orderByList = crit.getOrderByColumns();
+        UniqueList<OrderBy> orderByList = criteria.getOrderByColumns();
 
         // Check for each String/Character column and apply
         // toUpperCase().
         for (OrderBy orderBy : orderByList)
         {
             Column column = orderBy.getColumn();
-            ColumnMap columnMap = MapHelper.getColumnMap(column, crit);
+            ColumnMap columnMap = MapHelper.getColumnMap(column, criteria);
             String sqlExpression = column.getSqlExpression();
 
             // Either we are not able to look up the column in the
@@ -377,9 +391,9 @@ public final class SqlBuilder
                     || (columnMap.getType() instanceof String
                         && sqlExpression.indexOf('(') == -1))
             {
-                if (orderBy.isIgnoreCase() || crit.isIgnoreCase())
+                if (orderBy.isIgnoreCase() || criteria.isIgnoreCase())
                 {
-                    final Adapter adapter = Torque.getAdapter(crit.getDbName());
+                    final Adapter adapter = Torque.getAdapter(criteria.getDbName());
                     orderByClause.add(
                             adapter.ignoreCaseInOrderBy(sqlExpression)
                                 + ' ' + orderBy.getOrder());
@@ -389,7 +403,7 @@ public final class SqlBuilder
                 else
                 {
                     orderByClause.add(sqlExpression + ' ' + orderBy.getOrder());
-                    if (crit.getAsColumns().get(sqlExpression) == null)
+                    if (criteria.getAsColumns().get(sqlExpression) == null)
                     {
                         selectClause.add(sqlExpression);
                     }
@@ -398,14 +412,14 @@ public final class SqlBuilder
             else
             {
                 orderByClause.add(sqlExpression + ' ' + orderBy.getOrder());
-                if (crit.getAsColumns().get(sqlExpression) == null)
+                if (criteria.getAsColumns().get(sqlExpression) == null)
                 {
                     selectClause.add(sqlExpression);
                 }
             }
             addTableToFromClause(
                    column,
-                   crit,
+                   criteria,
                    query);
         }
     }
@@ -423,6 +437,10 @@ public final class SqlBuilder
             final Query query)
             throws TorqueException
     {
+        if (criteria.isComposite())
+        {
+            return;
+        }
         UniqueList<String> groupByClause = query.getGroupByClause();
         UniqueList<String> selectClause = query.getSelectClause();
         UniqueColumnList groupBy = criteria.getGroupByColumns();
@@ -444,17 +462,22 @@ public final class SqlBuilder
     }
 
     /**
-     * adds the Having-Columns from the criteria to the query
+     * Adds the Having-Columns from the criteria to the query.
+     *
      * @param criteria the criteria from which the Having-Columns are taken
      * @param query the query to which the Having-Columns should be added
      * @throws TorqueException if the Having-Columns can not be processed
      */
     private static void processHaving(
-            final Criteria crit,
+            final Criteria criteria,
             final Query query)
             throws TorqueException
     {
-        Criterion having = crit.getHaving();
+        if (criteria.isComposite())
+        {
+            return;
+        }
+        Criterion having = criteria.getHaving();
         if (having != null)
         {
             query.setHaving(having.toString());
@@ -471,16 +494,16 @@ public final class SqlBuilder
      * @throws TorqueException if the Database adapter cannot be obtained
      */
     private static void processLimits(
-            final Criteria crit,
+            final Criteria criteria,
             final Query query)
             throws TorqueException
     {
-        int limit = crit.getLimit();
-        long offset = crit.getOffset();
+        int limit = criteria.getLimit();
+        long offset = criteria.getOffset();
 
         if (offset > 0 || limit >= 0)
         {
-            Adapter adapter = Torque.getAdapter(crit.getDbName());
+            Adapter adapter = Torque.getAdapter(criteria.getDbName());
             adapter.generateLimits(query, offset, limit);
         }
     }
@@ -496,6 +519,10 @@ public final class SqlBuilder
             final Criteria criteria,
             final Query query)
     {
+        if (criteria.isComposite())
+        {
+            return;
+        }
         if (criteria.getFromElements().isEmpty())
         {
             log.trace("criteria's from Elements is empty,"
@@ -527,6 +554,31 @@ public final class SqlBuilder
     }
 
     /**
+     * Adds set operations to the query.
+     *
+     * @param criteria the criteria from which the query should be built.
+     * @param query the query to build.
+     *
+     * @throws TorqueException if the Database adapter cannot be obtained
+     */
+    private static void processSetOperations(
+            final Criteria criteria,
+            final Query query)
+            throws TorqueException
+    {
+        if (!criteria.isComposite())
+        {
+            return;
+        }
+        query.setPartOperator(criteria.getSetOperator().toString());
+        for (Criteria part : criteria.getSetCriteriaParts())
+        {
+            Query queryPart = buildQuery(part);
+            query.getParts().add(queryPart);
+        }
+    }
+
+    /**
      * Returns the tablename which can be added to a From Clause.
      * This takes care of any aliases that might be defined.
      * For example, if an alias "a" for the table AUTHOR is defined

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=1625364&r1=1625363&r2=1625364&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 Sep 16 19:50:41 2014
@@ -2202,4 +2202,178 @@ public class SqlBuilderTest extends Base
         assertEquals(1, query.getPreparedStatementReplacements().size());
         assertEquals(1, query.getPreparedStatementReplacements().get(0));
     }
+
+
+    public void testUnion() throws Exception
+    {
+        Criteria criteria = new Criteria()
+            .addSelectColumn(new ColumnImpl("table2.column2"))
+            .where(new ColumnImpl("table2.columnb"), 3)
+            .union(new Criteria()
+                        .addSelectColumn(new ColumnImpl("table1.column1"))
+                        .where(new ColumnImpl("table1.columna"), 1));
+        Query query = SqlBuilder.buildQuery(criteria);
+        assertEquals("(SELECT table2.column2 FROM table2 "
+                + "WHERE table2.columnb=?) "
+                + "UNION (SELECT table1.column1 FROM table1 "
+                + "WHERE table1.columna=?)",
+            query.toString());
+        assertEquals(2, query.getPreparedStatementReplacements().size());
+        assertEquals(3, query.getPreparedStatementReplacements().get(0));
+        assertEquals(1, query.getPreparedStatementReplacements().get(1));
+    }
+
+    public void testUnionAll() throws Exception
+    {
+        Criteria criteria = new Criteria()
+            .addSelectColumn(new ColumnImpl("table2.column2"))
+            .where(new ColumnImpl("table2.columnb"), 3)
+            .unionAll(new Criteria()
+                        .addSelectColumn(new ColumnImpl("table1.column1"))
+                        .where(new ColumnImpl("table1.columna"), 1));
+        Query query = SqlBuilder.buildQuery(criteria);
+        assertEquals("(SELECT table2.column2 FROM table2 "
+                + "WHERE table2.columnb=?) "
+                + "UNION ALL (SELECT table1.column1 FROM table1 "
+                + "WHERE table1.columna=?)",
+            query.toString());
+        assertEquals(2, query.getPreparedStatementReplacements().size());
+        assertEquals(3, query.getPreparedStatementReplacements().get(0));
+        assertEquals(1, query.getPreparedStatementReplacements().get(1));
+    }
+
+    public void testExcept() throws Exception
+    {
+        Criteria criteria = new Criteria()
+            .addSelectColumn(new ColumnImpl("table2.column2"))
+            .where(new ColumnImpl("table2.columnb"), 3)
+            .except(new Criteria()
+                        .addSelectColumn(new ColumnImpl("table1.column1"))
+                        .where(new ColumnImpl("table1.columna"), 1));
+        Query query = SqlBuilder.buildQuery(criteria);
+        assertEquals("(SELECT table2.column2 FROM table2 "
+                + "WHERE table2.columnb=?) "
+                + "EXCEPT (SELECT table1.column1 FROM table1 "
+                + "WHERE table1.columna=?)",
+            query.toString());
+        assertEquals(2, query.getPreparedStatementReplacements().size());
+        assertEquals(3, query.getPreparedStatementReplacements().get(0));
+        assertEquals(1, query.getPreparedStatementReplacements().get(1));
+    }
+
+    public void testExceptAll() throws Exception
+    {
+        Criteria criteria = new Criteria()
+            .addSelectColumn(new ColumnImpl("table2.column2"))
+            .where(new ColumnImpl("table2.columnb"), 3)
+            .exceptAll(new Criteria()
+                        .addSelectColumn(new ColumnImpl("table1.column1"))
+                        .where(new ColumnImpl("table1.columna"), 1));
+        Query query = SqlBuilder.buildQuery(criteria);
+        assertEquals("(SELECT table2.column2 FROM table2 "
+                + "WHERE table2.columnb=?) "
+                + "EXCEPT ALL (SELECT table1.column1 FROM table1 "
+                + "WHERE table1.columna=?)",
+            query.toString());
+        assertEquals(2, query.getPreparedStatementReplacements().size());
+        assertEquals(3, query.getPreparedStatementReplacements().get(0));
+        assertEquals(1, query.getPreparedStatementReplacements().get(1));
+    }
+
+    public void testIntersect() throws Exception
+    {
+        Criteria criteria = new Criteria()
+            .addSelectColumn(new ColumnImpl("table2.column2"))
+            .where(new ColumnImpl("table2.columnb"), 3)
+            .intersect(new Criteria()
+                        .addSelectColumn(new ColumnImpl("table1.column1"))
+                        .where(new ColumnImpl("table1.columna"), 1));
+        Query query = SqlBuilder.buildQuery(criteria);
+        assertEquals("(SELECT table2.column2 FROM table2 "
+                + "WHERE table2.columnb=?) "
+                + "INTERSECT (SELECT table1.column1 FROM table1 "
+                + "WHERE table1.columna=?)",
+            query.toString());
+        assertEquals(2, query.getPreparedStatementReplacements().size());
+        assertEquals(3, query.getPreparedStatementReplacements().get(0));
+        assertEquals(1, query.getPreparedStatementReplacements().get(1));
+    }
+
+    public void testIntersectAll() throws Exception
+    {
+        Criteria criteria = new Criteria()
+            .addSelectColumn(new ColumnImpl("table2.column2"))
+            .where(new ColumnImpl("table2.columnb"), 3)
+            .intersectAll(new Criteria()
+                        .addSelectColumn(new ColumnImpl("table1.column1"))
+                        .where(new ColumnImpl("table1.columna"), 1));
+        Query query = SqlBuilder.buildQuery(criteria);
+        assertEquals("(SELECT table2.column2 FROM table2 "
+                + "WHERE table2.columnb=?) "
+                + "INTERSECT ALL (SELECT table1.column1 FROM table1 "
+                + "WHERE table1.columna=?)",
+            query.toString());
+        assertEquals(2, query.getPreparedStatementReplacements().size());
+        assertEquals(3, query.getPreparedStatementReplacements().get(0));
+        assertEquals(1, query.getPreparedStatementReplacements().get(1));
+    }
+
+    public void testUnionOrderByLimitOffset() throws Exception
+    {
+        Criteria criteria = new Criteria()
+            .addSelectColumn(new ColumnImpl("table2.column2"))
+            .where(new ColumnImpl("table2.columnb"), 3)
+            .union(new Criteria()
+                        .addSelectColumn(new ColumnImpl("table1.column1"))
+                        .where(new ColumnImpl("table1.columna"), 1))
+            .addAscendingOrderByColumn(new ColumnImpl("table2.column2"))
+            .setLimit(10)
+            .setOffset(20);
+        Query query = SqlBuilder.buildQuery(criteria);
+        assertEquals("(SELECT table2.column2 FROM table2 "
+                + "WHERE table2.columnb=?) "
+                + "UNION (SELECT table1.column1 FROM table1 "
+                + "WHERE table1.columna=?)"
+                + " ORDER BY table2.column2 ASC"
+                + " LIMIT 10 OFFSET 20",
+            query.toString());
+        assertEquals(2, query.getPreparedStatementReplacements().size());
+        assertEquals(3, query.getPreparedStatementReplacements().get(0));
+        assertEquals(1, query.getPreparedStatementReplacements().get(1));
+    }
+
+    public void testSetOperationBraces() throws Exception
+    {
+        Criteria criteria = new Criteria()
+            .addSelectColumn(new ColumnImpl("table4.column4"))
+            .where(new ColumnImpl("table4.columnd"), 4);
+        Criteria otherCriteria = new Criteria()
+            .addSelectColumn(new ColumnImpl("table3.column3"))
+            .where(new ColumnImpl("table3.columnc"), 3);
+        criteria.unionAll(otherCriteria);
+        Criteria intersectCriteria = new Criteria()
+            .addSelectColumn(new ColumnImpl("table2.column2"))
+            .where(new ColumnImpl("table2.columnb"), 2);
+        otherCriteria = new Criteria()
+            .addSelectColumn(new ColumnImpl("table1.column1"))
+            .where(new ColumnImpl("table1.columna"), 1);
+        intersectCriteria.unionAll(otherCriteria);
+        criteria.intersect(intersectCriteria);
+
+        Query query = SqlBuilder.buildQuery(criteria);
+        assertEquals("((SELECT table4.column4 FROM table4 "
+                + "WHERE table4.columnd=?) "
+                + "UNION ALL (SELECT table3.column3 FROM table3 "
+                + "WHERE table3.columnc=?))"
+                + " INTERSECT ((SELECT table2.column2 FROM table2 "
+                + "WHERE table2.columnb=?) "
+                + "UNION ALL (SELECT table1.column1 FROM table1 "
+                + "WHERE table1.columna=?))",
+            query.toString());
+        assertEquals(4, query.getPreparedStatementReplacements().size());
+        assertEquals(4, query.getPreparedStatementReplacements().get(0));
+        assertEquals(3, query.getPreparedStatementReplacements().get(1));
+        assertEquals(2, query.getPreparedStatementReplacements().get(2));
+        assertEquals(1, query.getPreparedStatementReplacements().get(3));
+    }
 }



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