You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by ba...@apache.org on 2005/01/07 01:59:43 UTC

svn commit: r124467 - in incubator/derby/code/trunk/java: engine/org/apache/derby/iapi/sql/compile engine/org/apache/derby/iapi/sql/execute engine/org/apache/derby/impl/sql engine/org/apache/derby/impl/sql/compile engine/org/apache/derby/impl/sql/execute engine/org/apache/derby/loc testing/org/apache/derbyTesting/functionTests/master testing/org/apache/derbyTesting/functionTests/suites testing/org/apache/derbyTesting/functionTests/tests/lang

Author: bandaram
Date: Thu Jan  6 16:59:41 2005
New Revision: 124467

URL: http://svn.apache.org/viewcvs?view=rev&rev=124467
Log:
Enhance Derby to support INTERSECT and EXCEPT clauses.

Submitted by Jack Klebanoff (klebanof@Mutagen.Net)


Modified:
   incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/C_NodeTypes.java
   incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/execute/ResultSetFactory.java
   incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/build.xml
   incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/C_NodeNames.java
   incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/NodeFactoryImpl.java
   incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OrderByColumn.java
   incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java
   incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableOperatorNode.java
   incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UnionNode.java
   incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj
   incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericResultSetFactory.java
   incubator/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties
   incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/LOB.out
   incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/groupBy.out
   incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/suites/derbylang.runall
   incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/copyfiles.ant

Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/C_NodeTypes.java
Url: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/C_NodeTypes.java?view=diff&rev=124467&p1=incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/C_NodeTypes.java&r1=124466&p2=incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/C_NodeTypes.java&r2=124467
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/C_NodeTypes.java	(original)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/C_NodeTypes.java	Thu Jan  6 16:59:41 2005
@@ -185,7 +185,8 @@
 	static final int SUBSTRING_OPERATOR_NODE = 154;
 	// UNUSED static final int BOOLEAN_NODE = 155;
 	static final int DROP_ALIAS_NODE = 156;
-	// 157 - 185 available
+    static final int INTERSECT_OR_EXCEPT_NODE = 157;
+	// 158 - 185 available
 	static final int MODIFY_COLUMN_TYPE_NODE = 186;
 	static final int MODIFY_COLUMN_CONSTRAINT_NODE = 187;
     static final int ABSOLUTE_OPERATOR_NODE = 188;

Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/execute/ResultSetFactory.java
Url: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/execute/ResultSetFactory.java?view=diff&rev=124467&p1=incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/execute/ResultSetFactory.java&r1=124466&p2=incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/execute/ResultSetFactory.java&r2=124467
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/execute/ResultSetFactory.java	(original)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/execute/ResultSetFactory.java	Thu Jan  6 16:59:41 2005
@@ -1428,6 +1428,45 @@
 					throws StandardException;
 
 
+    /**
+     * The SetOpResultSet is used to implement an INTERSECT or EXCEPT operation.
+     * It selects rows from two ordered input result sets.
+     *
+     * @param leftSource The result set that implements the left input
+     * @param rightSource The result set that implements the right input
+     * @param activation the activation for this result set
+     * @param resultSetNumber
+     * @param optimizerEstimatedRowCount
+     * @param optimizerEstimatedCost
+     * @param opType IntersectOrExceptNode.INTERSECT_OP or EXCEPT_OP
+     * @param all true if the operation is an INTERSECT ALL or an EXCEPT ALL,
+     *            false if the operation is an INTERSECT DISCTINCT or an EXCEPT DISCTINCT
+     * @param closeCleanup a method to be called by close
+     * @param intermediateOrderByColumnsSavedObject The saved object index for the array of order by columns for the
+     *        ordering of the left and right sources. That is, both the left and right sources have an order by
+     *        clause of the form ORDER BY intermediateOrderByColumns[0],intermediateOrderByColumns[1],...
+     * @param intermediateOrderByDirectionSavedObject The saved object index for the array of source
+     *        order by directions. That is, the ordering of the i'th order by column in the input is ascending
+     *        if intermediateOrderByDirection[i] is 1, descending if intermediateOrderByDirection[i] is -1.
+	 *
+	 * @return	A ResultSet from which the caller can get the INTERSECT or EXCEPT
+	 *
+	 * @exception StandardException		Thrown on failure
+	 */
+    NoPutResultSet getSetOpResultSet( NoPutResultSet leftSource,
+                                      NoPutResultSet rightSource,
+                                      Activation activation, 
+                                      int resultSetNumber,
+                                      long optimizerEstimatedRowCount,
+                                      double optimizerEstimatedCost,
+                                      int opType,
+                                      boolean all,
+                                      GeneratedMethod closeCleanup,
+                                      int intermediateOrderByColumnsSavedObject,
+                                      int intermediateOrderByDirectionSavedObject)
+        throws StandardException;
+                                                     
+                                                     
 	//
 	// Misc operations
 	//

Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/build.xml
Url: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/build.xml?view=diff&rev=124467&p1=incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/build.xml&r1=124466&p2=incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/build.xml&r2=124467
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/build.xml	(original)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/build.xml	Thu Jan  6 16:59:41 2005
@@ -16,6 +16,8 @@
   <property file="${properties.dir}/extrapath.properties"/>
   <property file="${properties.dir}/compilepath.properties"/>
 
+  <property name="cur.dir" value="impl/sql"/>
+
 <!-- Targets -->
   <target name="parser">
     <ant antfile="${src.dir}/build.xml" target="genParser">
@@ -42,9 +44,9 @@
       <classpath>
         <pathelement path="${compile.classpath}"/>
       </classpath>
-      <include name="${derby.dir}/impl/sql/**"/>
+      <include name="${derby.dir}/${cur.dir}/**"/>
     </javac>
-    <copy file="catalog/metadata_net.properties" tofile="${out.dir}/org/apache/derby/impl/sql/catalog/metadata_net.properties"/>
+    <copy file="${derby.engine.src.dir}/${derby.dir}/${cur.dir}/catalog/metadata_net.properties" tofile="${out.dir}/org/apache/derby/impl/sql/catalog/metadata_net.properties"/>
   </target>
 
 </project>

Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/C_NodeNames.java
Url: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/C_NodeNames.java?view=diff&rev=124467&p1=incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/C_NodeNames.java&r1=124466&p2=incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/C_NodeNames.java&r2=124467
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/C_NodeNames.java	(original)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/C_NodeNames.java	Thu Jan  6 16:59:41 2005
@@ -258,6 +258,8 @@
 
 	static final String UNION_NODE_NAME = "org.apache.derby.impl.sql.compile.UnionNode";
 
+	static final String INTERSECT_OR_EXCEPT_NODE_NAME = "org.apache.derby.impl.sql.compile.IntersectOrExceptNode";
+
 	static final String UNTYPED_NULL_CONSTANT_NODE_NAME = "org.apache.derby.impl.sql.compile.UntypedNullConstantNode";
 
 	static final String UPDATE_NODE_NAME = "org.apache.derby.impl.sql.compile.UpdateNode";

Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/NodeFactoryImpl.java
Url: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/NodeFactoryImpl.java?view=diff&rev=124467&p1=incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/NodeFactoryImpl.java&r1=124466&p2=incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/NodeFactoryImpl.java&r2=124467
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/NodeFactoryImpl.java	(original)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/NodeFactoryImpl.java	Thu Jan  6 16:59:41 2005
@@ -512,6 +512,9 @@
 		  case C_NodeTypes.UNION_NODE:
 		  	return C_NodeNames.UNION_NODE_NAME;
 
+		  case C_NodeTypes.INTERSECT_OR_EXCEPT_NODE:
+		  	return C_NodeNames.INTERSECT_OR_EXCEPT_NODE_NAME;
+
 		  case C_NodeTypes.CREATE_TRIGGER_NODE:
 		  	return C_NodeNames.CREATE_TRIGGER_NODE_NAME;
 

Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OrderByColumn.java
Url: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OrderByColumn.java?view=diff&rev=124467&p1=incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OrderByColumn.java&r1=124466&p2=incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OrderByColumn.java&r2=124467
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OrderByColumn.java	(original)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OrderByColumn.java	Thu Jan  6 16:59:41 2005
@@ -172,7 +172,7 @@
 		ResultColumnList	targetCols = target.getResultColumns();
 
 		//bug 5716 - for db2 compatibility - no qualified names allowed in order by clause when union/union all operator is used 
-		if (target instanceof UnionNode && correlationName != null)
+		if (target instanceof SetOperatorNode && correlationName != null)
 		{
 			String fullName = (schemaName != null) ?
 				(schemaName + "." + correlationName + "." + columnName) :
@@ -207,7 +207,7 @@
 			 * because of the gyrations we go to with building the RCLs
 			 * for a UnionNode.
 			 */
-			if (target instanceof UnionNode)
+			if (target instanceof SetOperatorNode)
 			{
 				sourceTableNumber = ((FromTable) target).getTableNumber();
 			}

Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java
Url: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java?view=diff&rev=124467&p1=incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java&r1=124466&p2=incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java&r2=124467
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java	(original)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java	Thu Jan  6 16:59:41 2005
@@ -2025,7 +2025,7 @@
 	}
 
 	/**
-	 * Set up the result expressions for a UNION:
+	 * Set up the result expressions for a UNION, INTERSECT, or EXCEPT:
 	 *	o Verify union type compatiblity
 	 *	o Get dominant type for result (type + max length + nullability)
 	 *  o Create a new ColumnReference with dominant type and name of from this
@@ -2038,14 +2038,16 @@
 	 * @param otherRCL	RCL from other side of the UNION.
 	 * @param tableNumber	The tableNumber for the UNION.
 	 * @param level		The nesting level for the UNION.
+     * @param operatorName "UNION", "INTERSECT", or "EXCEPT"
 	 *
 	 * @return Nothing.
 	 *
 	 * @exception StandardException			Thrown on error
 	 */
 	public void	setUnionResultExpression(ResultColumnList otherRCL,
-						 int tableNumber,
-						 int level)
+                                         int tableNumber,
+                                         int level,
+                                         String operatorName)
 		throws StandardException
 	{
 		TableName		dummyTN;
@@ -2116,8 +2118,9 @@
 				!otherExpr.getTypeCompiler().storable(thisTypeId, cf))
 			{
 				throw StandardException.newException(SQLState.LANG_NOT_UNION_COMPATIBLE, 
-							thisTypeId.getSQLTypeName(),
-							otherTypeId.getSQLTypeName() );
+                                                     thisTypeId.getSQLTypeName(),
+                                                     otherTypeId.getSQLTypeName(),
+                                                     operatorName);
 			}
 
 			DataTypeDescriptor resultType = thisExpr.getTypeServices().getDominantType(

Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableOperatorNode.java
Url: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableOperatorNode.java?view=diff&rev=124467&p1=incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableOperatorNode.java&r1=124466&p2=incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableOperatorNode.java&r2=124467
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableOperatorNode.java	(original)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableOperatorNode.java	Thu Jan  6 16:59:41 2005
@@ -419,8 +419,8 @@
 					throws StandardException
 	{
 		/*
-		** Parameters not allowed in select list of either side of union,
-		** except when the union is for a table constructor.
+		** Parameters not allowed in select list of either side of a set operator,
+		** except when the set operator is for a table constructor.
 		*/
 		if ( ! (this instanceof UnionNode) ||
 			 ! ((UnionNode) this).tableConstructor())

Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UnionNode.java
Url: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UnionNode.java?view=diff&rev=124467&p1=incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UnionNode.java&r1=124466&p2=incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UnionNode.java&r2=124467
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UnionNode.java	(original)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UnionNode.java	Thu Jan  6 16:59:41 2005
@@ -20,15 +20,12 @@
 
 package	org.apache.derby.impl.sql.compile;
 
-import org.apache.derby.iapi.services.context.ContextManager;
-
 import org.apache.derby.iapi.services.compiler.MethodBuilder;
 
 import org.apache.derby.iapi.services.sanity.SanityManager;
 
 import org.apache.derby.iapi.error.StandardException;
 
-import org.apache.derby.iapi.sql.compile.CompilerContext;
 import org.apache.derby.iapi.sql.compile.Optimizable;
 import org.apache.derby.iapi.sql.compile.OptimizablePredicate;
 import org.apache.derby.iapi.sql.compile.OptimizablePredicateList;
@@ -37,33 +34,18 @@
 import org.apache.derby.iapi.sql.compile.RowOrdering;
 import org.apache.derby.iapi.sql.compile.C_NodeTypes;
 
-import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor;
-import org.apache.derby.iapi.sql.dictionary.DataDictionary;
-import org.apache.derby.iapi.sql.dictionary.DefaultDescriptor;
-import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
 import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
 
-import org.apache.derby.iapi.types.DataTypeDescriptor;
-
 import org.apache.derby.iapi.reference.SQLState;
 import org.apache.derby.iapi.reference.ClassName;
 
-import org.apache.derby.iapi.sql.Activation;
-import org.apache.derby.iapi.types.DataTypeDescriptor;
-import org.apache.derby.iapi.sql.ResultSet;
-import org.apache.derby.iapi.sql.Row;
-
-import org.apache.derby.iapi.types.TypeId;
-
 import org.apache.derby.impl.sql.compile.ActivationClassBuilder;
 
+import org.apache.derby.iapi.types.DataTypeDescriptor;
+
 import org.apache.derby.iapi.util.JBitSet;
 import org.apache.derby.iapi.services.classfile.VMOpcode;
 
-import org.apache.derby.catalog.types.DefaultInfoImpl;
-
-import java.util.Properties;
-
 /**
  * A UnionNode represents a UNION in a DML statement.  It contains a boolean
  * telling whether the union operation should eliminate duplicate rows.
@@ -71,25 +53,18 @@
  * @author Jeff Lichtman
  */
 
-public class UnionNode extends TableOperatorNode
+public class UnionNode extends SetOperatorNode
 {
-	/**
-	** Tells whether to eliminate duplicate rows.  all == TRUE means do
-	** not eliminate duplicates, all == FALSE means eliminate duplicates.
-	*/
-	boolean			all;
+	/* Only optimize it once */
+	/* Only call addNewNodes() once */
+	private boolean addNewNodesCalled;
 
-	/* Is this a UNION ALL generated for a table constructor. */
+	/* Is this a UNION ALL generated for a table constructor -- a VALUES expression with multiple rows. */
 	boolean			tableConstructor;
 
 	/* True if this is the top node of a table constructor */
 	boolean			topTableConstructor;
 
-	/* Only optimize a UNION once */
-	/* Only call addNewNodes() once */
-	private boolean addNewNodesCalled;
-
-	private OrderByList orderByList;
 
 	/**
 	 * Initializer for a UnionNode.
@@ -111,20 +86,11 @@
 					Object tableProperties)
 			throws StandardException
 	{
-		super.init(leftResult, rightResult, tableProperties);
-
-		this.all = ((Boolean) all).booleanValue();
+		super.init(leftResult, rightResult, all, tableProperties);
 
 		/* Is this a UNION ALL for a table constructor? */
 		this.tableConstructor = ((Boolean) tableConstructor).booleanValue();
-
-		/* resultColumns cannot be null, so we make a copy of the left RCL
-		 * for now.  At bind() time, we need to recopy the list because there
-		 * may have been a "*" in the list.  (We will set the names and
-		 * column types at that time, as expected.)
-		 */
-		resultColumns = leftResultSet.getResultColumns().copyListAndObjects();
-	}
+    } // end of init
 
 	/**
 	 * Mark this as the top node of a table constructor.
@@ -422,11 +388,7 @@
 	{
 		if (SanityManager.DEBUG)
 		{
-			return 	"all: " + all + "\n" +
-			 	"tableConstructor: " + tableConstructor + "\n" +
-				"orderByList: " + 
-				(orderByList != null ? orderByList.toString() : "null") + "\n" +
-				super.toString();
+			return 	"tableConstructor: " + tableConstructor + "\n" + super.toString();
 		}
 		else
 		{
@@ -465,33 +427,33 @@
 			** Step through all the rows in the table constructor to
 			** get the type of the first non-? in each column.
 			*/
-			DataTypeDescriptor[]	types =
+			DataTypeDescriptor[] types =
 				new DataTypeDescriptor[leftResultSet.getResultColumns().size()];
 			
-			ResultSetNode	rsn;
-			int				numTypes = 0;
+			ResultSetNode rsn;
+			int numTypes = 0;
 
 			/* By looping through the union nodes, we avoid recursion */
-			for (rsn = this; rsn instanceof UnionNode; )
+			for (rsn = this; rsn instanceof SetOperatorNode; )
 			{
-				UnionNode		union = (UnionNode) rsn;
+				SetOperatorNode		setOperator = (SetOperatorNode) rsn;
 
 				/*
 				** Assume that table constructors are left-deep trees of
-				** UnionNodes with RowResultSet nodes on the right.
+				** SetOperatorNodes with RowResultSet nodes on the right.
 				*/
 				if (SanityManager.DEBUG)
 					SanityManager.ASSERT(
-					 union.rightResultSet instanceof RowResultSetNode,
-					 "A " + union.rightResultSet.getClass().getName() +
-					 " is on the right side of a union in a table constructor");
+					 setOperator.rightResultSet instanceof RowResultSetNode,
+					 "A " + setOperator.rightResultSet.getClass().getName() +
+					 " is on the right side of a setOperator in a table constructor");
 
 				RowResultSetNode	rrsn =
-										(RowResultSetNode) union.rightResultSet;
+										(RowResultSetNode) setOperator.rightResultSet;
 
 				numTypes += getParamColumnTypes(types, rrsn);
 
-				rsn = union.leftResultSet;
+				rsn = setOperator.leftResultSet;
 			}
 
 			/* The last node on the left should be a result set node */
@@ -511,554 +473,20 @@
 			** nodes, and give them the type from the type array we just
 			** constructed.
 			*/
-			for (rsn = this; rsn instanceof UnionNode; )
+			for (rsn = this; rsn instanceof SetOperatorNode; )
 			{
-				UnionNode		union = (UnionNode) rsn;
-				RowResultSetNode	rrsn =
-										(RowResultSetNode) union.rightResultSet;
+				SetOperatorNode	setOperator = (SetOperatorNode) rsn;
+				RowResultSetNode rrsn = (RowResultSetNode) setOperator.rightResultSet;
 
 				setParamColumnTypes(types, rrsn);
 
-				rsn = union.leftResultSet;
+				rsn = setOperator.leftResultSet;
 			}
 
 			setParamColumnTypes(types, (RowResultSetNode) rsn);
 		}
 	}
 
-	/**
-	 * Bind the result columns of this ResultSetNode when there is no
-	 * base table to bind them to.  This is useful for SELECT statements,
-	 * where the result columns get their types from the expressions that
-	 * live under them.
-	 *
-	 * @param fromListParam		FromList to use/append to.
-	 *
-	 * @return	Nothing
-	 *
-	 * @exception StandardException		Thrown on error
-	 */
-	public void bindResultColumns(FromList fromListParam)
-					throws StandardException
-	{
-		super.bindResultColumns(fromListParam);
-
-		/* Now we build our RCL */
-		buildRCL();
-	}
-
-	/**
-	 * Bind the result columns for this ResultSetNode to a base table.
-	 * This is useful for INSERT and UPDATE statements, where the
-	 * result columns get their types from the table being updated or
-	 * inserted into.
-	 * If a result column list is specified, then the verification that the 
-	 * result column list does not contain any duplicates will be done when
-	 * binding them by name.
-	 *
-	 * @param targetTableDescriptor	The TableDescriptor for the table being
-	 *				updated or inserted into
-	 * @param targetColumnList	For INSERT statements, the user
-	 *					does not have to supply column
-	 *					names (for example, "insert into t
-	 *					values (1,2,3)".  When this
-	 *					parameter is null, it means that
-	 *					the user did not supply column
-	 *					names, and so the binding should
-	 *					be done based on order.  When it
-	 *					is not null, it means do the binding
-	 *					by name, not position.
-	 * @param statement			Calling DMLStatementNode (Insert or Update)
-	 * @param fromListParam		FromList to use/append to.
-	 *
-	 * @return	Nothing
-	 *
-	 * @exception StandardException		Thrown on error
-	 */
-
-	public void bindResultColumns(TableDescriptor targetTableDescriptor,
-					FromVTI targetVTI,
-					ResultColumnList targetColumnList,
-					DMLStatementNode statement,
-					FromList fromListParam)
-				throws StandardException
-	{
-		super.bindResultColumns(targetTableDescriptor,
-								targetVTI,
-								targetColumnList, statement,
-								fromListParam);
-
-		/* Now we build our RCL */
-		buildRCL();
-	}
-
-	/**
-	 * Build the RCL for this node.  We propagate the RCL up from the
-	 * left child to form this node's RCL.
-	 *
-	 * @return	Nothing
-	 *
-	 * @exception StandardException		Thrown on error
-	 */
-
-	private void buildRCL() throws StandardException
-	{
-		/* Verify that both sides of the union have the same # of columns in their
-		 * RCL.
-		 */
-		if (leftResultSet.getResultColumns().size() !=
-			rightResultSet.getResultColumns().size())
-		{
-			throw StandardException.newException(SQLState.LANG_UNION_UNMATCHED_COLUMNS);
-		}
-
-		/* We need to recreate resultColumns for this node, since there
-		 * may have been 1 or more *'s in the left's SELECT list.
-		 */
-		resultColumns = leftResultSet.getResultColumns().copyListAndObjects();
-
-		/* Create new expressions with the dominant types after verifying
-		 * union compatibility between left and right sides.
-		 */
-		resultColumns.setUnionResultExpression(rightResultSet.getResultColumns(), tableNumber, level);
-	}
-
-	/**
-	 * Bind the result columns of a table constructor to the types in the
-	 * given ResultColumnList.  Use when inserting from a table constructor,
-	 * and there are nulls in the values clauses.
-	 *
-	 * @param rcl	The ResultColumnList with the types to bind to
-	 *
-	 * @exception StandardException		Thrown on error.
-	 */
-	public void bindUntypedNullsToResultColumns(ResultColumnList rcl)
-				throws StandardException
-	{
-		/*
-		** If the RCL from the parent is null, then
-		** the types are coming from the union itself.
-		** So we have to cross check the two child
-		** rcls.
-		*/
-		if (rcl == null)
-		{
-			ResultColumnList lrcl = rightResultSet.getResultColumns();
-			ResultColumnList rrcl = leftResultSet.getResultColumns();
-
-			leftResultSet.bindUntypedNullsToResultColumns(rrcl);
-			rightResultSet.bindUntypedNullsToResultColumns(lrcl);
-		}
-		else	
-		{
-			leftResultSet.bindUntypedNullsToResultColumns(rcl);
-			rightResultSet.bindUntypedNullsToResultColumns(rcl);
-		}			
-	}
-
-	/**
-	 * Get the parameter types from the given RowResultSetNode into the
-	 * given array of types.  If an array position is already filled in,
-	 * don't clobber it.
-	 *
-	 * @param types	The array of types to fill in
-	 * @param rrsn	The RowResultSetNode from which to take the param types
-	 *
-	 * @return	The number of new types found in the RowResultSetNode
-	 */
-	int getParamColumnTypes(DataTypeDescriptor[] types, RowResultSetNode rrsn)
-	{
-		int	numTypes = 0;
-
-		/* Look for columns where we have not found a non-? yet. */
-		for (int i = 0; i < types.length; i++)
-		{
-			if (types[i] == null)
-			{
-				ResultColumn rc =
-					(ResultColumn) rrsn.getResultColumns().elementAt(i);
-				if ( ! (rc.getExpression().isParameterNode()))
-				{
-					types[i] = rc.getExpressionType();
-					numTypes++;
-				}
-			}
-		}
-
-		return numTypes;
-	}
-
-	/**
-	 * Set the type of each ? parameter in the given RowResultSetNode
-	 * according to its ordinal position in the given array of types.
-	 *
-	 * @param types	An array of types containing the proper type for each
-	 *				? parameter, by ordinal position.
-	 * @param rrsn	A RowResultSetNode that could contain ? parameters whose
-	 *				types need to be set.
-	 *
-	 * @exception StandardException		Thrown on error
-	 */
-	void setParamColumnTypes(DataTypeDescriptor[] types, RowResultSetNode rrsn)
-					throws StandardException
-	{
-		/*
-		** Look for ? parameters in the result column list
-		** of each RowResultSetNode
-		*/
-		ResultColumnList rrcl = rrsn.getResultColumns();
-		int rrclSize = rrcl.size();
-		for (int index = 0; index < rrclSize; index++)
-		{
-			ResultColumn	rc = (ResultColumn) rrcl.elementAt(index);
-
-			if (rc.getExpression().isParameterNode())
-			{
-				/*
-				** We found a ? - set its type to the type from the
-				** type array.
-				*/
-				((ParameterNode) rc.getExpression()).setDescriptor(
-											types[index]);
-			}
-		}
-	}
-
-	/**
-	 * Bind the expressions in the target list.  This means binding the
-	 * sub-expressions, as well as figuring out what the return type is
-	 * for each expression.  This is useful for EXISTS subqueries, where we
-	 * need to validate the target list before blowing it away and replacing
-	 * it with a SELECT true.
-	 *
-	 * @return	Nothing
-	 *
-	 * @exception StandardException		Thrown on error
-	 */
-
-	public void bindTargetExpressions(FromList fromListParam)
-					throws StandardException
-	{
-		leftResultSet.bindTargetExpressions(fromListParam);
-		rightResultSet.bindTargetExpressions(fromListParam);
-	}
-
-	/**
-	 * Push the order by list down from the cursor node
-	 * into its child result set so that the optimizer
-	 * has all of the information that it needs to 
-	 * consider sort avoidance.
-	 *
-	 * @param orderByList	The order by list
-	 *
-	 * @return Nothing.
-	 */
-	void pushOrderByList(OrderByList orderByList)
-	{
-		this.orderByList = orderByList;
-	}
-
-	/** 
-	 * Put a ProjectRestrictNode on top of each FromTable in the FromList.
-	 * ColumnReferences must continue to point to the same ResultColumn, so
-	 * that ResultColumn must percolate up to the new PRN.  However,
-	 * that ResultColumn will point to a new expression, a VirtualColumnNode, 
-	 * which points to the FromTable and the ResultColumn that is the source for
-	 * the ColumnReference.  
-	 * (The new PRN will have the original of the ResultColumnList and
-	 * the ResultColumns from that list.  The FromTable will get shallow copies
-	 * of the ResultColumnList and its ResultColumns.  ResultColumn.expression
-	 * will remain at the FromTable, with the PRN getting a new 
-	 * VirtualColumnNode for each ResultColumn.expression.)
-	 * We then project out the non-referenced columns.  If there are no referenced
-	 * columns, then the PRN's ResultColumnList will consist of a single ResultColumn
-	 * whose expression is 1.
-	 *
-	 * @param numTables			Number of tables in the DML Statement
-	 * @param gbl				The group by list, if any
-	 * @param fromList			The from list, if any
-	 *
-	 * @return The generated ProjectRestrictNode atop the original FromTable.
-	 *
-	 * @exception StandardException		Thrown on error
-	 */
-
-	public ResultSetNode preprocess(int numTables,
-									GroupByList gbl,
-									FromList fromList)
-								throws StandardException
-	{
-		ResultSetNode newTop = this;
-
-		/* RESOLVE - what does numTables and referencedTableMap mean here? */
-		leftResultSet = leftResultSet.preprocess(numTables, gbl, fromList);
-		rightResultSet = rightResultSet.preprocess(numTables, gbl, fromList);
-
-		/* Build the referenced table map (left || right) */
-		referencedTableMap = (JBitSet) leftResultSet.getReferencedTableMap().clone();
-		referencedTableMap.or((JBitSet) rightResultSet.getReferencedTableMap());
-
-		/* If this is a UNION without an all and we have
-		 * an order by then we can consider eliminating the sort for the
-		 * order by.  All of the columns in the order by list must
-		 * be ascending in order to do this.  There are 2 cases:
-		 *	o	The order by list is an in order prefix of the columns
-		 *		in the select list.  In this case the output of the
-		 *		sort from the distinct will be in the right order
-		 *		so we simply eliminate the order by list.
-		 *	o	The order by list is a subset of the columns in the
-		 *		the select list.  In this case we need to reorder the
-		 *		columns in the select list so that the ordering columns
-		 *		are an in order prefix of the select list and put a PRN
-		 *		above the select so that the shape of the result set
-		 *		is as expected.
-		 */
-		if ((! all) && orderByList != null && orderByList.allAscending())
-		{
-			/* Order by list currently restricted to columns in select
-			 * list, so we will always eliminate the order by here.
-			 */
-			if (orderByList.isInOrderPrefix(resultColumns))
-			{
-				orderByList = null;
-			}
-			/* RESOLVE - We currently only eliminate the order by if it is
-			 * a prefix of the select list.  We do not currently do the 
-			 * elimination if the order by is not a prefix because the code
-			 * doesn't work.  The problem has something to do with the
-			 * fact that we generate additional nodes between the union
-			 * and the PRN (for reordering that we would generate here)
-			 * when modifying the access paths.  VCNs under the PRN can be
-			 * seen as correlated since their source resultset is the Union
-			 * which is no longer the result set directly under them.  This
-			 * causes the wrong code to get generated. (jerry - 11/3/98)
-			 * (bug 59)
-			 */
-		}
-
-		return newTop;
-	}
-	
-	/**
-	 * Ensure that the top of the RSN tree has a PredicateList.
-	 *
-	 * @param numTables			The number of tables in the query.
-	 * @return ResultSetNode	A RSN tree with a node which has a PredicateList on top.
-	 *
-	 * @exception StandardException		Thrown on error
-	 */
-	public ResultSetNode ensurePredicateList(int numTables) 
-		throws StandardException
-	{
-		return genProjectRestrict(numTables);
-	}
-
-	/**
-	 * Verify that a SELECT * is valid for this type of subquery.
-	 *
-	 * @param outerFromList	The FromList from the outer query block(s)
-	 * @param subqueryType	The subquery type
-	 *
-	 * @return	None
-	 *
-	 * @exception StandardException		Thrown on error
-	 */
-	public void verifySelectStarSubquery(FromList outerFromList, int subqueryType) 
-					throws StandardException
-	{
-		/* Check both sides - SELECT * is not valid on either side */
-		leftResultSet.verifySelectStarSubquery(outerFromList, subqueryType);
-		rightResultSet.verifySelectStarSubquery(outerFromList, subqueryType);
-	}
-
-	/** 
-	 * Determine whether or not the specified name is an exposed name in
-	 * the current query block.
-	 *
-	 * @param name	The specified name to search for as an exposed name.
-	 * @param schemaName	Schema name, if non-null.
-	 * @param exactMatch	Whether or not we need an exact match on specified schema and table
-	 *						names or match on table id.
-	 *
-	 * @return The FromTable, if any, with the exposed name.
-	 *
-	 * @exception StandardException		Thrown on error
-	 */
-	protected FromTable getFromTableByName(String name, String schemaName, boolean exactMatch)
-		throws StandardException
-	{
-		/* We search both sides for a TableOperatorNode (join nodes)
-		 * but only the left side for a UnionNode.
-		 */
-		return leftResultSet.getFromTableByName(name, schemaName, exactMatch);
-	}
-
-	/**
-	 * Set the result column for the subquery to a boolean true,
-	 * Useful for transformations such as
-	 * changing:
-	 *		where exists (select ... from ...) 
-	 * to:
-	 *		where (select true from ...)
-	 *
-	 * NOTE: No transformation is performed if the ResultColumn.expression is
-	 * already the correct boolean constant.
-	 * 
-	 * @param onlyConvertAlls	Boolean, whether or not to just convert *'s
-	 *
-	 * @return Nothing.
-	 *
-	 * @exception StandardException		Thrown on error
-	 */
-	public void setResultToBooleanTrueNode(boolean onlyConvertAlls)
-				throws StandardException
-	{
-		super.setResultToBooleanTrueNode(onlyConvertAlls);
-		leftResultSet.setResultToBooleanTrueNode(onlyConvertAlls);
-		rightResultSet.setResultToBooleanTrueNode(onlyConvertAlls);
-	}
-
-	/**
-	 * This ResultSet is the source for an Insert.  The target RCL
-	 * is in a different order and/or a superset of this RCL.  In most cases
-	 * we will reorder and/or add defaults to the current RCL so that is
-	 * matches the target RCL.  Those RSNs whose generate() method does
-	 * not handle projects will insert a PRN, with a new RCL which matches
-	 * the target RCL, above the current RSN.
-	 * NOTE - The new or enhanced RCL will be fully bound.
-	 *
-	 * @param numTargetColumns	# of columns in target RCL
-	 * @param colMap[]			int array representation of correspondence between
-	 *							RCLs - colmap[i] = -1 -> missing in current RCL
-	 *								   colmap[i] = j -> targetRCL(i) <-> thisRCL(j+1)
-	 * @param dataDictionary	DataDictionary to use
-	 * @param targetTD			TableDescriptor for target if the target is not a VTI, null if a VTI
-     * @param targetVTI         Target description if it is a VTI, null if not a VTI
-	 *
-	 * @return ResultSetNode	The new top of the tree
-	 *
-	 * @exception StandardException		Thrown on error
-	 */
-	public ResultSetNode enhanceRCLForInsert(int numTargetColumns, int[] colMap, 
-											 DataDictionary dataDictionary,
-											 TableDescriptor targetTD,
-                                             FromVTI targetVTI)
-			throws StandardException
-	{
-		// our newResultCols are put into the bound form straight away.
-		ResultColumnList newResultCols =
-								(ResultColumnList) getNodeFactory().getNode(
-												C_NodeTypes.RESULT_COLUMN_LIST,
-												getContextManager());
-		int numResultSetColumns = resultColumns.size();
-
-		/* Create a massaged version of the source RCL.
-		 * (Much simpler to build new list and then assign to source,
-		 * rather than massage the source list in place.)
-		 */
-		for (int index = 0; index < numTargetColumns; index++)
-		{
-			ResultColumn	newResultColumn;
-			ResultColumn	oldResultColumn;
-			ColumnReference newColumnReference;
-
-			if (colMap[index] != -1)
-			{
-				// getResultColumn uses 1-based positioning, so offset the colMap entry appropriately
-				oldResultColumn = resultColumns.getResultColumn(colMap[index]+1);
-
-				newColumnReference = (ColumnReference) getNodeFactory().getNode(
-												C_NodeTypes.COLUMN_REFERENCE,
-												oldResultColumn.getName(),
-												null,
-												getContextManager());
-				/* The ColumnReference points to the source of the value */
-				newColumnReference.setSource(oldResultColumn);
-				// colMap entry is 0-based, columnId is 1-based.
-				newColumnReference.setType(oldResultColumn.getExpressionType());
-
-				// Source of an insert, so nesting levels must be 0
-				newColumnReference.setNestingLevel(0);
-				newColumnReference.setSourceLevel(0);
-
-				// because the insert already copied the target table's
-				// column descriptors into the result, we grab it from there.
-				// alternatively, we could do what the else clause does,
-				// and look it up in the DD again.
-				newResultColumn = (ResultColumn) getNodeFactory().getNode(
-						C_NodeTypes.RESULT_COLUMN,
-						oldResultColumn.getType(),
-						newColumnReference,
-						getContextManager());
-			}
-			else
-			{
-				newResultColumn = genNewRCForInsert(targetTD, targetVTI, index + 1, dataDictionary);
-			}
-
-			newResultCols.addResultColumn(newResultColumn);
-		}
-
-		/* The generated ProjectRestrictNode now has the ResultColumnList
-		 * in the order that the InsertNode expects.
-		 * NOTE: This code here is an exception to several "rules":
-		 *		o  This is the only ProjectRestrictNode that is currently
-		 *		   generated outside of preprocess().
-		 *	    o  The UnionNode is the only node which is not at the
-		 *		   top of the query tree which has ColumnReferences under
-		 *		   its ResultColumnList prior to expression push down.
-		 */
-		return (ResultSetNode) getNodeFactory().getNode(
-									C_NodeTypes.PROJECT_RESTRICT_NODE,
-									this,
-									newResultCols,
-									null,
-									null,
-									null,
-									null,
-									tableProperties,
-									getContextManager());
-	}
-
-	/**
-	 * Evaluate whether or not the subquery in a FromSubquery is flattenable.  
-	 * Currently, a FSqry is flattenable if all of the following are true:
-	 *		o  Subquery is a SelectNode. (ie, not a RowResultSetNode or a UnionNode)
-	 *		o  It contains no top level subqueries.  (RESOLVE - we can relax this)
-	 *		o  It does not contain a group by or having clause
-	 *		o  It does not contain aggregates.
-	 *
-	 * @param fromList	The outer from list
-	 *
-	 * @return boolean	Whether or not the FromSubquery is flattenable.
-	 */
-	public boolean flattenableInFromSubquery(FromList fromList)
-	{
-		/* Unions in FromSubquerys are not flattenable.	 */
-		return false;
-	}
-
-	/**
-	 * Return whether or not to materialize this ResultSet tree.
-	 *
-	 * @return Whether or not to materialize this ResultSet tree.
-	 *			would return valid results.
-	 *
-	 * @exception StandardException		Thrown on error
-	 */
-	public boolean performMaterialization(JBitSet outerTables)
-		throws StandardException
-	{
-		// RESOLVE - just say no to materialization right now - should be a cost based decision
-		return false;
-
-		/* Actual materialization, if appropriate, will be placed by our parent PRN.
-		 * This is because PRN might have a join condition to apply.  (Materialization
-		 * can only occur before that.
-		 */
-		//return true;
-	}
-
     /**
 	 * Generate the code for this UnionNode.
 	 *
@@ -1134,4 +562,9 @@
 
 		mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, "getUnionResultSet", ClassName.NoPutResultSet, 7);
 	}
+
+    String getOperatorName()
+    {
+        return "UNION";
+    }
 }

Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj
Url: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj?view=diff&rev=124467&p1=incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj&r1=124466&p2=incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj&r2=124467
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj	(original)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj	Thu Jan  6 16:59:41 2005
@@ -85,6 +85,7 @@
 import org.apache.derby.impl.sql.compile.TransactionStatementNode;
 import org.apache.derby.impl.sql.compile.TriggerReferencingStruct;
 import org.apache.derby.impl.sql.compile.UnionNode;
+import org.apache.derby.impl.sql.compile.IntersectOrExceptNode;
 import org.apache.derby.impl.sql.compile.UntypedNullConstantNode;
 import org.apache.derby.impl.sql.compile.UpdateNode;
 import org.apache.derby.impl.sql.compile.UserTypeConstantNode;
@@ -173,6 +174,15 @@
 	// Define for UTF8 max
 	private static final int	MAX_UTF8_LENGTH = 65535;
 
+    // Constants for set operator types
+    private static final int NO_SET_OP = 0;
+    private static final int UNION_OP = 1;
+    private static final int UNION_ALL_OP = 2;
+    private static final int EXCEPT_OP = 3;
+    private static final int EXCEPT_ALL_OP = 4;
+    private static final int INTERSECT_OP = 5;
+    private static final int INTERSECT_ALL_OP = 6;
+
 	private StringSlicer				stringSlicer;
 	private Object[]					paramDefaults;
 	private String						statementSQLText;
@@ -2662,7 +2672,7 @@
 	OrderByList orderCols = null;
 }
 {
-	queryExpression = queryExpression(null, Boolean.FALSE) 
+	queryExpression = queryExpression(null, NO_SET_OP) 
 		[ orderCols = orderByClause() ]
 		[ <FOR> forUpdateState = forUpdateClause(updateColumns) ]
 		[ isolationLevel = atIsolationLevel() ]
@@ -4108,24 +4118,37 @@
 
 /*
  * <A NAME="queryExpression">queryExpression</A>
+ *
+ * We have to be carefull to get the associativity correct. According to the SQL spec
+ *   <non-join query expression> ::=
+ *     <non-join query term>
+ *    | <query expression body> UNION [ ALL ] <query term>
+ *    | <query expression body> EXCEPT [ ALL ] <query term>
+ * Meaning that
+ *   t1 UNION ALL t2 UNION t3
+ * is equivalent to
+ *   (t1 UNION ALL t2) UNION t3
+ * However recursive descent parsers want recursion to be on the right, so this kind of associativity is unnatural
+ * for our parser. The queryExpression method must know whether it is being called as the right hand side of a
+ * set operator to produce a query tree with the correct associativity.
  */
 ResultSetNode
-queryExpression(ResultSetNode leftSide, Boolean unionAll) throws StandardException :
+queryExpression(ResultSetNode leftSide, int operatorType) throws StandardException :
 {
 	ResultSetNode	term;
 }
 {
-	term = nonJoinQueryTerm(leftSide, unionAll) [ term = union(term) ]
+	term = nonJoinQueryTerm(leftSide, operatorType) [ term = unionOrExcept(term) ]
 	{
 		return term;
 	}
 }
 
 /*
- * <A NAME="union">union</A>
+ * <A NAME="unionOrExcept">unionOrExcept</A>
  */
 ResultSetNode
-union(ResultSetNode term) throws StandardException :
+unionOrExcept(ResultSetNode term) throws StandardException :
 {
 	ResultSetNode	expression;
 	Token 			tok = null;
@@ -4133,7 +4156,14 @@
 {
 	<UNION> [ tok = <ALL> ] expression =
 				queryExpression(term,
-								(tok != null) ? Boolean.TRUE : Boolean.FALSE)
+								(tok != null) ? UNION_ALL_OP : UNION_OP)
+	{
+		return expression;
+	}
+|
+	<EXCEPT> [ tok = <ALL> ] expression =
+				queryExpression(term,
+								(tok != null) ? EXCEPT_ALL_OP : EXCEPT_OP)
 	{
 		return expression;
 	}
@@ -4142,33 +4172,113 @@
 
 /*
  * <A NAME="nonJoinQueryTerm">nonJoinQueryTerm</A>
+ *
+ * Be careful with the associativity of INTERSECT. According to the SQL spec
+ *   t1 INTERSECT t2 INTERSECT ALL t3
+ * is equivalent to
+ *   (t1 INTERSECT t2) INTERSECT ALL t3
+ * which is not the same as
+ *   t1 INTERSECT (t2 INTERSECT ALL t3)
+ * See the comment on queryExpression.
  */
 ResultSetNode
-nonJoinQueryTerm(ResultSetNode leftSide, Boolean unionAll) throws StandardException :
+nonJoinQueryTerm(ResultSetNode leftSide, int operatorType) throws StandardException :
 {
 	ResultSetNode	term;
 }
 {
-	/*
-	** Omitted "intersect".
-	*/
-	term = nonJoinQueryPrimary()
+	term = nonJoinQueryPrimary() [ term = intersect( term) ]
 	{
-		if (leftSide != null)
-		{
-			return (ResultSetNode) nodeFactory.getNode(
-									C_NodeTypes.UNION_NODE,
-									leftSide,
-									term,
-									unionAll,
-									Boolean.FALSE,
-									null,
-									getContextManager());
-		}
-		else
-		{
-			return term;
-		}
+        switch( operatorType)
+        {
+        case NO_SET_OP:
+            return term;
+
+        case UNION_OP:
+            return (ResultSetNode) nodeFactory.getNode(
+                C_NodeTypes.UNION_NODE,
+                leftSide,
+                term,
+                Boolean.FALSE,
+                Boolean.FALSE,
+                null,
+                getContextManager());
+
+        case UNION_ALL_OP:
+            return (ResultSetNode) nodeFactory.getNode(
+                C_NodeTypes.UNION_NODE,
+                leftSide,
+                term,
+                Boolean.TRUE,
+                Boolean.FALSE,
+                null,
+                getContextManager());
+
+        case EXCEPT_OP:
+            return (ResultSetNode) nodeFactory.getNode(
+                C_NodeTypes.INTERSECT_OR_EXCEPT_NODE,
+                ReuseFactory.getInteger( IntersectOrExceptNode.EXCEPT_OP),
+                leftSide,
+                term,
+                Boolean.FALSE,
+                null,
+                getContextManager());
+
+        case EXCEPT_ALL_OP:
+            return (ResultSetNode) nodeFactory.getNode(
+                C_NodeTypes.INTERSECT_OR_EXCEPT_NODE,
+                ReuseFactory.getInteger( IntersectOrExceptNode.EXCEPT_OP),
+                leftSide,
+                term,
+                Boolean.TRUE,
+                null,
+                getContextManager());
+
+        case INTERSECT_OP:
+            return (ResultSetNode) nodeFactory.getNode(
+                C_NodeTypes.INTERSECT_OR_EXCEPT_NODE,
+                ReuseFactory.getInteger( IntersectOrExceptNode.INTERSECT_OP),
+                leftSide,
+                term,
+                Boolean.FALSE,
+                null,
+                getContextManager());
+
+        case INTERSECT_ALL_OP:
+            return (ResultSetNode) nodeFactory.getNode(
+                C_NodeTypes.INTERSECT_OR_EXCEPT_NODE,
+                ReuseFactory.getInteger( IntersectOrExceptNode.INTERSECT_OP),
+                leftSide,
+                term,
+                Boolean.TRUE,
+                null,
+                getContextManager());
+
+
+        default:
+            if (SanityManager.DEBUG)
+            {
+                SanityManager.THROWASSERT( "Invalid set operator type: " + operatorType);
+            }
+            return null;
+        }
+    }
+}
+
+/*
+ * <A NAME="intersect">intersect</A>
+ */
+ResultSetNode
+intersect(ResultSetNode term) throws StandardException :
+{
+	ResultSetNode	expression;
+	Token 			tok = null;
+}
+{
+	<INTERSECT> [ tok = <ALL> ] expression =
+				nonJoinQueryTerm(term, (tok != null) ? INTERSECT_ALL_OP : INTERSECT_OP)
+	{
+		return expression;
 	}
 }
 
@@ -4186,7 +4296,7 @@
 		return primary;
 	}
 |
-	<LEFT_PAREN> primary = queryExpression(null, Boolean.FALSE) <RIGHT_PAREN>
+	<LEFT_PAREN> primary = queryExpression(null, NO_SET_OP) <RIGHT_PAREN>
 	{
 		return primary;
 	}
@@ -6729,7 +6839,7 @@
 		<LEFT_PAREN> columnList = insertColumnList() <RIGHT_PAREN>
 	]
 	[ targetProperties = propertyList() ]
-	queryExpression = queryExpression(null, Boolean.FALSE)
+	queryExpression = queryExpression(null, NO_SET_OP)
 	{
 		return (QueryTreeNode) nodeFactory.getNode(
 							C_NodeTypes.INSERT_NODE,
@@ -6976,7 +7086,7 @@
 	SubqueryNode	subqueryNode;
 }
 {
-	queryExpression = queryExpression(null, Boolean.FALSE)
+	queryExpression = queryExpression(null, NO_SET_OP)
 	{
 		subqueryNode = (SubqueryNode) nodeFactory.getNode(
 										C_NodeTypes.SUBQUERY_NODE,
@@ -8757,7 +8867,7 @@
 {
 	<VIEW> tableName = qualifiedName(DB2Limit.DB2_MAX_IDENTIFIER_LENGTH128) 
 		[ <LEFT_PAREN> resultColumns = viewColumnList() <RIGHT_PAREN> ]
-		<AS> queryExpression = queryExpression(null, Boolean.FALSE)
+		<AS> queryExpression = queryExpression(null, NO_SET_OP)
 	{
 		checkOptionType = ViewDescriptor.NO_CHECK_OPTION;
 		endToken = getToken(0);
@@ -9641,7 +9751,7 @@
 	<EXECUTE> <STATEMENT> stmtName = qualifiedName(DB2Limit.DB2_MAX_IDENTIFIER_LENGTH128) 
 		[ LOOKAHEAD( { getToken(1).kind == USING } )
 		  usingToken = <USING> usingClause =
-		  							queryExpression(null, Boolean.FALSE) ]
+		  							queryExpression(null, NO_SET_OP) ]
 	{
 		endToken = getToken(0);
 

Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericResultSetFactory.java
Url: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericResultSetFactory.java?view=diff&rev=124467&p1=incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericResultSetFactory.java&r1=124466&p2=incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericResultSetFactory.java&r2=124467
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericResultSetFactory.java	(original)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericResultSetFactory.java	Thu Jan  6 16:59:41 2005
@@ -1053,6 +1053,32 @@
 								  closeCleanup);
 	}
 
+    public NoPutResultSet getSetOpResultSet( NoPutResultSet leftSource,
+                                             NoPutResultSet rightSource,
+                                             Activation activation, 
+                                             int resultSetNumber,
+                                             long optimizerEstimatedRowCount,
+                                             double optimizerEstimatedCost,
+                                             int opType,
+                                             boolean all,
+                                             GeneratedMethod closeCleanup,
+                                             int intermediateOrderByColumnsSavedObject,
+                                             int intermediateOrderByDirectionSavedObject)
+        throws StandardException
+    {
+        return new SetOpResultSet( leftSource,
+                                   rightSource,
+                                   activation,
+                                   resultSetNumber,
+                                   optimizerEstimatedRowCount,
+                                   optimizerEstimatedCost,
+                                   opType,
+                                   all,
+                                   closeCleanup,
+                                   intermediateOrderByColumnsSavedObject,
+                                   intermediateOrderByDirectionSavedObject);
+    }
+
 	/**
 	 * A last index key sresult set returns the last row from
 	 * the index in question.  It is used as an ajunct to max().

Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties
Url: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties?view=diff&rev=124467&p1=incubator/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties&r1=124466&p2=incubator/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties&r2=124467
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties	(original)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties	Thu Jan  6 16:59:41 2005
@@ -469,10 +469,10 @@
 42X55=Table name ''{1}'' should be the same as ''{0}''.
 42X56=The number of columns in the view column list does not match the number of columns in the underlying query expression in the view definition for ''{0}''.
 42X57=The getColumnCount() for external virtual table ''{0}'' returned an invalid value ''{1}''.  Valid values are >= 1.
-42X58=The number of columns on the left and right sides of the UNION must be the same.
+42X58=The number of columns on the left and right sides of the {0} must be the same.
 42X59=The number of columns in each VALUES constructor must be the same.
 42X60=Invalid value ''{0}'' for insertMode property specified for table ''{1}''.
-42X61=Types ''{0}'' and ''{1}'' are not UNION compatible.
+42X61=Types ''{0}'' and ''{1}'' are not {2} compatible.
 42X62=''{0}'' is not allowed in the ''{1}'' schema.
 42X63=The USING clause did not return any results, no parameters can be set.
 42X64=Invalid value ''{0}'' specified for useStatistics property in the Properties list. TRUE or FALSE are the only valid values.
@@ -919,7 +919,7 @@
 X0X61.S=The values for column ''{4}'' in index ''{0}'' and table ''{1}.{2}'' do not match for row location {3}.  The value in the index is ''{5}'', while the value in the base table is ''{6}''.  The full index key, including the row location, is ''{7}''.  The suggested corrective action is to recreate the index.
 X0X62.S=Inconsistency found between table ''{0}'' and index ''{1}''.  Error when trying to retrieve row location ''{2}'' from the table.  The full index key, including the row location, is ''{3}''. The suggested corrective action is to recreate the index.
 X0X63.S=Got IOException ''{0}''.
-X0X67.S=Columns of type ''{0}'' may not be used in CREATE INDEX, ORDER BY, GROUP BY, UNION, or DISTINCT, because comparisons are not supported for that type.
+X0X67.S=Columns of type ''{0}'' may not be used in CREATE INDEX, ORDER BY, GROUP BY, UNION, INTERSECT, EXCEPT or DISTINCT, because comparisons are not supported for that type.
 X0X81.S={0} ''{1}'' does not exist.
 X0X85.S=Index ''{0}'' was not created because ''{1}'' is not a valid index type.
 X0X86.S=0 is an invalid parameter value for ResultSet.absolute(int row).

Modified: incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/LOB.out
Url: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/LOB.out?view=diff&rev=124467&p1=incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/LOB.out&r1=124466&p2=incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/LOB.out&r2=124467
==============================================================================
--- incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/LOB.out	(original)
+++ incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/LOB.out	Thu Jan  6 16:59:41 2005
@@ -266,13 +266,13 @@
 0 rows inserted/updated/deleted
 ij> -- create index (not allowed)
 create index ia on a(a);
-ERROR X0X67: Columns of type 'BLOB' may not be used in CREATE INDEX, ORDER BY, GROUP BY, UNION, or DISTINCT, because comparisons are not supported for that type.
+ERROR X0X67: Columns of type 'BLOB' may not be used in CREATE INDEX, ORDER BY, GROUP BY, UNION, INTERSECT, EXCEPT or DISTINCT, because comparisons are not supported for that type.
 ij> create index ib on b(a);
-ERROR X0X67: Columns of type 'CLOB' may not be used in CREATE INDEX, ORDER BY, GROUP BY, UNION, or DISTINCT, because comparisons are not supported for that type.
+ERROR X0X67: Columns of type 'CLOB' may not be used in CREATE INDEX, ORDER BY, GROUP BY, UNION, INTERSECT, EXCEPT or DISTINCT, because comparisons are not supported for that type.
 ij> create index ic on c(a);
 ERROR 42Y55: 'CREATE INDEX' cannot be performed on 'C' because it does not exist.
 ij> create index id on d(a);
-ERROR X0X67: Columns of type 'CLOB' may not be used in CREATE INDEX, ORDER BY, GROUP BY, UNION, or DISTINCT, because comparisons are not supported for that type.
+ERROR X0X67: Columns of type 'CLOB' may not be used in CREATE INDEX, ORDER BY, GROUP BY, UNION, INTERSECT, EXCEPT or DISTINCT, because comparisons are not supported for that type.
 ij> -- cleanup
 drop table a;
 0 rows inserted/updated/deleted
@@ -535,7 +535,7 @@
 1 row inserted/updated/deleted
 ij> -- UNION
 select * from testPredicate1 union select * from testPredicate2;
-ERROR X0X67: Columns of type 'LONG VARCHAR' may not be used in CREATE INDEX, ORDER BY, GROUP BY, UNION, or DISTINCT, because comparisons are not supported for that type.
+ERROR X0X67: Columns of type 'LONG VARCHAR' may not be used in CREATE INDEX, ORDER BY, GROUP BY, UNION, INTERSECT, EXCEPT or DISTINCT, because comparisons are not supported for that type.
 ij> -- IN predicate
 select c1 from testPredicate1 where c1 IN (select c1 from testPredicate2);
 ERROR 42818: Comparisons between 'LONG VARCHAR' and 'LONG VARCHAR' are not supported.
@@ -544,10 +544,10 @@
 ERROR 42818: Comparisons between 'LONG VARCHAR' and 'LONG VARCHAR' are not supported.
 ij> -- ORDER BY clause
 select * from testPredicate1 order by c1;
-ERROR X0X67: Columns of type 'LONG VARCHAR' may not be used in CREATE INDEX, ORDER BY, GROUP BY, UNION, or DISTINCT, because comparisons are not supported for that type.
+ERROR X0X67: Columns of type 'LONG VARCHAR' may not be used in CREATE INDEX, ORDER BY, GROUP BY, UNION, INTERSECT, EXCEPT or DISTINCT, because comparisons are not supported for that type.
 ij> -- GROUP BY clause
 select substr(c1,1,2) from testPredicate1 group by c1;
-ERROR X0X67: Columns of type 'LONG VARCHAR' may not be used in CREATE INDEX, ORDER BY, GROUP BY, UNION, or DISTINCT, because comparisons are not supported for that type.
+ERROR X0X67: Columns of type 'LONG VARCHAR' may not be used in CREATE INDEX, ORDER BY, GROUP BY, UNION, INTERSECT, EXCEPT or DISTINCT, because comparisons are not supported for that type.
 ij> -- JOIN
 select * from testPredicate1 t1, testPredicate2 t2 where t1.c1=t2.c1;
 ERROR 42818: Comparisons between 'LONG VARCHAR' and 'LONG VARCHAR' are not supported.
@@ -555,15 +555,15 @@
 ERROR 42818: Comparisons between 'LONG VARCHAR' and 'LONG VARCHAR' are not supported.
 ij> -- PRIMARY KEY
 create table testConst1(c1 long varchar not null primary key);
-ERROR X0X67: Columns of type 'LONG VARCHAR' may not be used in CREATE INDEX, ORDER BY, GROUP BY, UNION, or DISTINCT, because comparisons are not supported for that type.
+ERROR X0X67: Columns of type 'LONG VARCHAR' may not be used in CREATE INDEX, ORDER BY, GROUP BY, UNION, INTERSECT, EXCEPT or DISTINCT, because comparisons are not supported for that type.
 ij> -- UNIQUE KEY constraints
 CREATE TABLE testconst2 (col1 long varchar not null, CONSTRAINT uk UNIQUE (col1));
-ERROR X0X67: Columns of type 'LONG VARCHAR' may not be used in CREATE INDEX, ORDER BY, GROUP BY, UNION, or DISTINCT, because comparisons are not supported for that type.
+ERROR X0X67: Columns of type 'LONG VARCHAR' may not be used in CREATE INDEX, ORDER BY, GROUP BY, UNION, INTERSECT, EXCEPT or DISTINCT, because comparisons are not supported for that type.
 ij> -- FOREIGN KEY constraints
 create table testConst3 (c1 char(10) not null, primary key (c1));
 0 rows inserted/updated/deleted
 ij> create table testConst4 (c1 long varchar not null, constraint fk foreign key (c1) references testConst3 (c1));
-ERROR X0X67: Columns of type 'LONG VARCHAR' may not be used in CREATE INDEX, ORDER BY, GROUP BY, UNION, or DISTINCT, because comparisons are not supported for that type.
+ERROR X0X67: Columns of type 'LONG VARCHAR' may not be used in CREATE INDEX, ORDER BY, GROUP BY, UNION, INTERSECT, EXCEPT or DISTINCT, because comparisons are not supported for that type.
 ij> drop table testConst3;
 0 rows inserted/updated/deleted
 ij> -- MAX aggregate function

Modified: incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/groupBy.out
Url: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/groupBy.out?view=diff&rev=124467&p1=incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/groupBy.out&r1=124466&p2=incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/groupBy.out&r2=124467
==============================================================================
--- incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/groupBy.out	(original)
+++ incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/groupBy.out	Thu Jan  6 16:59:41 2005
@@ -45,7 +45,7 @@
 create table unmapped(c1 long varchar);
 0 rows inserted/updated/deleted
 ij> select c1, max(1) from unmapped group by c1;
-ERROR X0X67: Columns of type 'LONG VARCHAR' may not be used in CREATE INDEX, ORDER BY, GROUP BY, UNION, or DISTINCT, because comparisons are not supported for that type.
+ERROR X0X67: Columns of type 'LONG VARCHAR' may not be used in CREATE INDEX, ORDER BY, GROUP BY, UNION, INTERSECT, EXCEPT or DISTINCT, because comparisons are not supported for that type.
 ij> -- clean up
 drop table t1;
 0 rows inserted/updated/deleted

Modified: incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/suites/derbylang.runall
Url: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/suites/derbylang.runall?view=diff&rev=124467&p1=incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/suites/derbylang.runall&r1=124466&p2=incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/suites/derbylang.runall&r2=124467
==============================================================================
--- incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/suites/derbylang.runall	(original)
+++ incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/suites/derbylang.runall	Thu Jan  6 16:59:41 2005
@@ -67,6 +67,7 @@
 lang/infostreams.sql
 lang/innerjoin.sql
 lang/insert.sql
+lang/intersect.sql
 lang/isolationLevels.sql
 lang/joinDeadlock.sql
 lang/joins.sql

Modified: incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/copyfiles.ant
Url: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/copyfiles.ant?view=diff&rev=124467&p1=incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/copyfiles.ant&r1=124466&p2=incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/copyfiles.ant&r2=124467
==============================================================================
--- incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/copyfiles.ant	(original)
+++ incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/copyfiles.ant	Thu Jan  6 16:59:41 2005
@@ -95,6 +95,7 @@
 innerjoin.sql
 insert.sql
 insert_sed.properties
+intersect.sql
 isolationLevels.sql
 joinDeadlock.sql
 joinDeadlock.sql1