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 da...@apache.org on 2009/10/23 20:05:18 UTC

svn commit: r829155 [1/2] - in /db/derby/code/trunk: java/engine/org/apache/derby/iapi/sql/compile/ java/engine/org/apache/derby/iapi/sql/execute/ java/engine/org/apache/derby/impl/sql/compile/ java/engine/org/apache/derby/impl/sql/execute/ java/engine...

Author: dag
Date: Fri Oct 23 18:05:03 2009
New Revision: 829155

URL: http://svn.apache.org/viewvc?rev=829155&view=rev
Log:
DERBY-3634 Cannot use row_number() in ORDER BY clause

Patch derby-3634-newimpl-4. This reimplements the ROW_NUMBER
functionality after it was moved in svn 820483 and 820494. The patch
makes ROW_NUMBER usable in all places it should be usable according to
the standard (modulo the current Derby SQL subset).  So, DERBY-3634 is
also fixed with this patch. The ordering problem seen in DERBY-4069 is
also fixed. More test cases have been to OLAPTest for ROW_NUMBER
usage.  The patch also adds some amount of generalizations to pave way
for other window functionality, but this needs more work.


Added:
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/AggregateWindowFunctionNode.java   (with props)
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ReplaceWindowFuncCallsWithCRVisitor.java   (with props)
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/RowNumberFunctionNode.java   (with props)
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowDefinitionNode.java   (with props)
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowFunctionNode.java   (with props)
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowList.java   (with props)
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowNode.java   (with props)
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowReferenceNode.java   (with props)
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowResultSetNode.java   (with props)
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/WindowResultSet.java   (with props)
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/rts/RealWindowResultSetStatistics.java   (with props)
Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/C_NodeTypes.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/execute/ResultSetFactory.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/AggregateNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/C_NodeNames.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ColumnReference.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DeleteNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromList.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/GroupByColumn.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/GroupByNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/JoinNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/NodeFactoryImpl.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OrderByColumn.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ProjectRestrictNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/RowResultSetNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SelectNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SetOperatorNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SubqueryNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericResultSetFactory.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/RealResultSetStatisticsFactory.java
    db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml
    db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/OLAPTest.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/_Suite.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/util/SQLStateConstants.java
    db/derby/code/trunk/tools/jar/DBMSnodes.properties

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/C_NodeTypes.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/C_NodeTypes.java?rev=829155&r1=829154&r2=829155&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/C_NodeTypes.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/C_NodeTypes.java Fri Oct 23 18:05:03 2009
@@ -236,8 +236,15 @@
     static final int CREATE_SEQUENCE_NODE = 224;
     static final int DROP_SEQUENCE_NODE = 225;
 
+	// Windowing
+	static final int AGGREGATE_WINDOW_FUNCTION_NODE = 226;
+	static final int ROW_NUMBER_FUNCTION_NODE = 227;
+	static final int WINDOW_DEFINITION_NODE = 228;
+	static final int WINDOW_REFERENCE_NODE = 229;
+	static final int WINDOW_RESULTSET_NODE = 230;
+
     // Final value in set, keep up to date!
-    static final int FINAL_VALUE = DROP_SEQUENCE_NODE;
+    static final int FINAL_VALUE = WINDOW_RESULTSET_NODE;
 
     /**
      * Extensions to this interface can use nodetypes > MAX_NODE_TYPE with out fear of collision

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/execute/ResultSetFactory.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/execute/ResultSetFactory.java?rev=829155&r1=829154&r2=829155&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/execute/ResultSetFactory.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/execute/ResultSetFactory.java Fri Oct 23 18:05:03 2009
@@ -1103,6 +1103,41 @@
 								double optimizerEstimatedCost)
 			throws StandardException;
 
+
+
+	/**
+	   A OLAP window on top of a regular result set. It is used to realize
+	   window functions.
+	   <p>
+	   @param activation   Activation
+	   @param source       The result set input to this result set.
+	   @param rowAllocator A reference to a method in the activation
+			               that generates rows of the right size and
+						   shape for the source.
+	   @param resultSetNumber The resultSetNumber for the ResultSet
+	   @param erdNumber    Int for ResultDescription
+	                       (so it can be turned back into an object)
+	   @param restriction  The restriction, if any, to be applied to the
+	                       base row
+	   @param optimizerEstimatedRowCount
+                           Estimated total # of rows by optimizer
+	   @param optimizerEstimatedCost
+                           Estimated total cost by optimizer
+	   @throws StandardException
+	 */
+	public NoPutResultSet getWindowResultSet(
+								Activation activation,
+								NoPutResultSet source,
+								GeneratedMethod rowAllocator,
+								int resultSetNumber,
+								int erdNumber,
+								GeneratedMethod restriction,
+								double optimizerEstimatedRowCount,
+								double optimizerEstimatedCost)
+			throws StandardException;
+
+
+
 	/**
 		A nested loop left outer join result set forms a result set on top of
 		2 other result sets.

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/AggregateNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/AggregateNode.java?rev=829155&r1=829154&r2=829155&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/AggregateNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/AggregateNode.java Fri Oct 23 18:05:03 2009
@@ -296,6 +296,10 @@
 						aggregateName);
 			}
 
+			// Also forbid any window function inside an aggregate unless in
+			// subquery, cf. SQL 2003, section 10.9, SR 7 a).
+			SelectNode.checkNoWindowFunctions(operand, aggregateName);
+
 			/*
 			** Check the type of the operand.  Make sure that the user
 			** defined aggregate can handle the operand datatype.

Added: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/AggregateWindowFunctionNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/AggregateWindowFunctionNode.java?rev=829155&view=auto
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/AggregateWindowFunctionNode.java (added)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/AggregateWindowFunctionNode.java Fri Oct 23 18:05:03 2009
@@ -0,0 +1,93 @@
+/*
+   Derby - Class org.apache.derby.impl.sql.compile.AggregateWindowFunctionNode
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to you under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+
+package org.apache.derby.impl.sql.compile;
+
+import org.apache.derby.iapi.error.StandardException;
+import org.apache.derby.iapi.types.TypeId;
+import org.apache.derby.iapi.services.sanity.SanityManager;
+import org.apache.derby.iapi.reference.SQLState;
+
+import java.sql.Types;
+import java.util.Vector;
+
+/**
+ * Represents aggregate function calls on a window
+ */
+public final class AggregateWindowFunctionNode extends WindowFunctionNode
+{
+
+    private AggregateNode aggregateFunction;
+
+    /**
+     * Initializer. QueryTreeNode override.
+     *
+     * @param arg1 The window definition or reference
+     * @param arg2 aggregate function node
+     *
+     * @exception StandardException
+     */
+    public void init(Object arg1, Object arg2)
+        throws StandardException
+    {
+        super.init(null, "?", arg1);
+        aggregateFunction = (AggregateNode)arg2;
+
+        throw StandardException.newException(
+            SQLState.NOT_IMPLEMENTED,
+            "WINDOW/" + aggregateFunction.getAggregateName());
+    }
+
+
+    /**
+     * ValueNode override.
+     * @see ValueNode#bindExpression
+     */
+    public ValueNode bindExpression(
+                    FromList            fromList,
+                    SubqueryList        subqueryList,
+                    Vector              aggregateVector)
+            throws StandardException
+    {
+        aggregateFunction.bindExpression(
+            fromList, subqueryList, aggregateVector);
+        return this;
+    }
+
+
+
+    /**
+     * QueryTreeNode override. Prints the sub-nodes of this object.
+     * @see QueryTreeNode#printSubNodes
+     *
+     * @param depth     The depth of this node in the tree
+     */
+
+    public void printSubNodes(int depth)
+    {
+        if (SanityManager.DEBUG)
+        {
+            super.printSubNodes(depth);
+
+            printLabel(depth, "aggregate: ");
+            aggregateFunction.treePrint(depth + 1);
+        }
+    }
+}

Propchange: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/AggregateWindowFunctionNode.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/C_NodeNames.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/C_NodeNames.java?rev=829155&r1=829154&r2=829155&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/C_NodeNames.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/C_NodeNames.java Fri Oct 23 18:05:03 2009
@@ -43,7 +43,6 @@
     // THEM TO tools/jar/DBMSnodes.properties
 
 	static final String AGGREGATE_NODE_NAME = "org.apache.derby.impl.sql.compile.AggregateNode";
-
 	static final String ALL_RESULT_COLUMN_NAME = "org.apache.derby.impl.sql.compile.AllResultColumn";
 
 	static final String ALTER_TABLE_NODE_NAME = "org.apache.derby.impl.sql.compile.AlterTableNode";
@@ -301,6 +300,11 @@
 	static final String SAVEPOINT_NODE_NAME = "org.apache.derby.impl.sql.compile.SavepointNode";
 
 	static final String XML_CONSTANT_NODE_NAME = "org.apache.derby.impl.sql.compile.XMLConstantNode";
+	static final String AGGREGATE_WINDOW_FUNCTION_NAME = "org.apache.derby.impl.sql.compile.AggregateWindowFunctionNode";
+	static final String ROW_NUMBER_FUNCTION_NAME = "org.apache.derby.impl.sql.compile.RowNumberFunctionNode";
+	static final String WINDOW_DEFINITION_NAME = "org.apache.derby.impl.sql.compile.WindowDefinitionNode";
+	static final String WINDOW_REFERENCE_NAME = "org.apache.derby.impl.sql.compile.WindowReferenceNode";
+	static final String WINDOW_RESULTSET_NODE_NAME = "org.apache.derby.impl.sql.compile.WindowResultSetNode";
 
 	static final String ROW_COUNT_NODE_NAME = "org.apache.derby.impl.sql.compile.RowCountNode";
 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ColumnReference.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ColumnReference.java?rev=829155&r1=829154&r2=829155&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ColumnReference.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ColumnReference.java Fri Oct 23 18:05:03 2009
@@ -75,6 +75,7 @@
 	//Expression genResult;
 
 	private boolean		replacesAggregate;
+	private boolean		replacesWindowFunctionCall;
 
 	private int			nestingLevel = -1;
 	private int			sourceLevel = -1;
@@ -146,7 +147,11 @@
 				"tableNumber: " + tableNumber + "\n" +
 				"columnNumber: " + columnNumber + "\n" +
 				"replacesAggregate: " + replacesAggregate + "\n" +
-				"tableName: " + ( ( tableName != null) ? tableName.toString() : "null") + "\n" +
+				"replacesWindowFunctionCall: " +
+				    replacesWindowFunctionCall + "\n" +
+				"tableName: " + ( ( tableName != null) ?
+								  tableName.toString() :
+								  "null") + "\n" +
 				"nestingLevel: " + nestingLevel + "\n" +
 				"sourceLevel: " + sourceLevel + "\n" +
 				super.toString();
@@ -258,6 +263,15 @@
 		replacesAggregate = true;
 	}
 
+
+	/**
+	 * Mark this node as being generated to replace a window function call.
+	 */
+	public void markGeneratedToReplaceWindowFunctionCall()
+	{
+		replacesWindowFunctionCall = true;
+	}
+
 	/**
 	 * Determine whether or not this node was generated to
 	 * replace an aggregate in the user's SELECT.
@@ -270,6 +284,19 @@
 		return replacesAggregate;
 	}
 
+
+	/**
+	 * Determine whether or not this node was generated to
+	 * replace a window function call in the user's SELECT.
+	 *
+	 * @return boolean	Whether or not this node was generated to replace
+	 *					a window function call in the user's SELECT.
+	 */
+	public boolean getGeneratedToReplaceWindowFunctionCall()
+	{
+		return replacesWindowFunctionCall;
+	}
+
 	/**
 	 * Return a clone of this node.
 	 *
@@ -309,6 +336,8 @@
 		nestingLevel = oldCR.getNestingLevel();
 		sourceLevel = oldCR.getSourceLevel();
 		replacesAggregate = oldCR.getGeneratedToReplaceAggregate();
+		replacesWindowFunctionCall =
+			oldCR.getGeneratedToReplaceWindowFunctionCall();
 		scoped = oldCR.isScoped();
 	}
 
@@ -592,6 +621,8 @@
 	 * pushing the predicate into the SelectNode that evaluates the aggregate,
 	 * which doesn't make sense, since the having clause is supposed to be
 	 * applied to the result of the SelectNode.
+	 * This also goes for column references that replaces a window function.
+	 *
 	 *
 	 * RESOLVE - revisit this issue once we have views.
 	 *
@@ -611,6 +642,7 @@
 		referencedTabs.set(tableNumber);
 
 		return ( ! replacesAggregate ) &&
+			   ( ! replacesWindowFunctionCall ) &&
 			   ( (source.getExpression() instanceof ColumnReference) ||
 			     (source.getExpression() instanceof VirtualColumnNode) ||
 				 (source.getExpression() instanceof ConstantNode));

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DeleteNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DeleteNode.java?rev=829155&r1=829154&r2=829155&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DeleteNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DeleteNode.java Fri Oct 23 18:05:03 2009
@@ -787,7 +787,8 @@
                                                      whereClause, /* WHERE clause */
                                                      null, /* GROUP BY list */
                                                      null, /* having clause */
-                                                     getContextManager());
+													 null, /* windows */
+													 getContextManager());
 
         return (StatementNode) nodeFactory.getNode(
                                                     C_NodeTypes.DELETE_NODE,
@@ -836,7 +837,8 @@
                                                      fromList, /* FROM list */
                                                      whereClause, /* WHERE clause */
                                                      null, /* GROUP BY list */
-						     null, /* having clause */
+													 null, /* having clause */
+													 null, /* windows */
                                                      getContextManager());
 
         return (StatementNode) nodeFactory.getNode(

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromList.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromList.java?rev=829155&r1=829154&r2=829155&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromList.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromList.java Fri Oct 23 18:05:03 2009
@@ -73,6 +73,13 @@
 	 */
 	private boolean isTransparent;
 
+	/**
+	 * Window definitions used for resolving window functions not containing
+	 * in-line window specifications, but referring window definitions
+	 */
+	private WindowList windows;
+
+
 	/** Initializer for a FromList */
 
 	public void init(Object optimizeJoinOrder)
@@ -1615,4 +1622,21 @@
 
 		return this;
 	}
+
+
+	/**
+	 * Set windows field to the supplied value.
+	 * @param windows list of window definitions associated with a SELECT.
+	 */
+	public void setWindows(WindowList windows) {
+		this.windows = windows;
+	}
+
+
+	/**
+	 * @return list of window definitions associated with a SELECT.
+	 */
+	public WindowList getWindows() {
+		return windows;
+	}
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/GroupByColumn.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/GroupByColumn.java?rev=829155&r1=829154&r2=829155&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/GroupByColumn.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/GroupByColumn.java Fri Oct 23 18:05:03 2009
@@ -24,6 +24,8 @@
 import org.apache.derby.iapi.error.StandardException;
 
 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
+import org.apache.derby.iapi.sql.compile.Visitor;
+import org.apache.derby.iapi.sql.compile.Visitable;
 
 import org.apache.derby.iapi.types.TypeId;
 
@@ -136,4 +138,28 @@
 		this.columnExpression = cexpr;
 		
 	}
+
+	/**
+	 * Accept a visitor, and call v.visit()
+	 * on child nodes as necessary.
+	 *
+	 * @param v the visitor
+	 *
+	 * @exception StandardException on error
+	 */
+	public Visitable accept(Visitor v)
+		throws StandardException {
+
+		Visitable returnNode = v.visit(this);
+
+		if (v.skipChildren(this)) {
+			return returnNode;
+		}
+
+		if (columnExpression != null) {
+			columnExpression = (ValueNode)columnExpression.accept(v);
+		}
+
+		return returnNode;
+	}
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/GroupByNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/GroupByNode.java?rev=829155&r1=829154&r2=829155&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/GroupByNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/GroupByNode.java Fri Oct 23 18:05:03 2009
@@ -580,13 +580,15 @@
 			CollectNodesVisitor collectNodesVisitor = 
 				new CollectNodesVisitor(ColumnReference.class, AggregateNode.class);
 			havingClause.accept(collectNodesVisitor);
+
 			for (Iterator it = collectNodesVisitor.getList().iterator();
 			     it.hasNext(); ) 
 			{
 				ColumnReference cr = (ColumnReference)it.next();
-				
-				if (!cr.getGeneratedToReplaceAggregate() && 
-						cr.getSourceLevel() == level) {
+
+				if ( ! (cr.getGeneratedToReplaceAggregate() ||
+						cr.getGeneratedToReplaceWindowFunctionCall()) &&
+					 cr.getSourceLevel() == level) {
 					throw StandardException.newException(
 							SQLState.LANG_INVALID_COL_HAVING_CLAUSE, 
 							cr.getSQLColumnName());						

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/JoinNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/JoinNode.java?rev=829155&r1=829154&r2=829155&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/JoinNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/JoinNode.java Fri Oct 23 18:05:03 2009
@@ -826,6 +826,10 @@
 				throw se;
 			}
 
+			// SQL 2003, section 7.7 SR 5
+			SelectNode.checkNoWindowFunctions(joinClause, "ON");
+
+
 			/* DB2 doesn't allow subquerries in the ON clause */
 			if (subqueryList.size() > 0)
 				throw StandardException.newException(SQLState.LANG_DB2_ON_CLAUSE_INVALID); 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/NodeFactoryImpl.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/NodeFactoryImpl.java?rev=829155&r1=829154&r2=829155&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/NodeFactoryImpl.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/NodeFactoryImpl.java Fri Oct 23 18:05:03 2009
@@ -614,6 +614,21 @@
           case C_NodeTypes.TABLE_PRIVILEGES_NODE:
             return C_NodeNames.TABLE_PRIVILEGES_NAME;
 
+		  case C_NodeTypes.AGGREGATE_WINDOW_FUNCTION_NODE:
+			return C_NodeNames.AGGREGATE_WINDOW_FUNCTION_NAME;
+
+		  case C_NodeTypes.ROW_NUMBER_FUNCTION_NODE:
+			return C_NodeNames.ROW_NUMBER_FUNCTION_NAME;
+
+		  case C_NodeTypes.WINDOW_DEFINITION_NODE:
+			return C_NodeNames.WINDOW_DEFINITION_NAME;
+
+		  case C_NodeTypes.WINDOW_REFERENCE_NODE:
+			return C_NodeNames.WINDOW_REFERENCE_NAME;
+
+		  case C_NodeTypes.WINDOW_RESULTSET_NODE:
+			return C_NodeNames.WINDOW_RESULTSET_NODE_NAME;
+
           case C_NodeTypes.GENERATION_CLAUSE_NODE:
             return C_NodeNames.GENERATION_CLAUSE_NODE_NAME;
 		  	

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OrderByColumn.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OrderByColumn.java?rev=829155&r1=829154&r2=829155&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OrderByColumn.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OrderByColumn.java Fri Oct 23 18:05:03 2009
@@ -32,6 +32,8 @@
 import org.apache.derby.iapi.sql.compile.C_NodeTypes;
 
 import org.apache.derby.iapi.util.ReuseFactory;
+import org.apache.derby.iapi.sql.compile.Visitable;
+import org.apache.derby.iapi.sql.compile.Visitor;
 
 /**
  * An OrderByColumn is a column in the ORDER BY clause.  An OrderByColumn
@@ -84,7 +86,6 @@
 		}
 	}
 
-
 	/**
 	 * Prints the sub-nodes of this object.  See QueryTreeNode.java for
 	 * how tree printing is supposed to work.
@@ -497,4 +498,31 @@
 		if (addedColumnOffset > gap)
 			addedColumnOffset--;
 	}
+
+
+	/**
+	 * Accept a visitor, and call v.visit()
+	 * on child nodes as necessary.
+	 *
+	 * @param v the visitor
+	 *
+	 * @exception StandardException on error
+	 */
+	public Visitable accept(Visitor v)
+		throws StandardException
+	{
+		Visitable returnNode = v.visit(this);
+
+		if (v.skipChildren(this))
+		{
+			return returnNode;
+		}
+
+		if (expression != null && !v.stopTraversal())
+		{
+			expression = (ValueNode)expression.accept(v);
+		}
+		return returnNode;
+	}
+
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ProjectRestrictNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ProjectRestrictNode.java?rev=829155&r1=829154&r2=829155&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ProjectRestrictNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ProjectRestrictNode.java Fri Oct 23 18:05:03 2009
@@ -1099,11 +1099,27 @@
 		 * if we can push any of the predicates which just got pushed
 		 * down to our level into the SelectNode.
 		 */
-		if (pushPList != null && (childResult instanceof SelectNode))
+		if (pushPList != null &&
+				(childResult instanceof SelectNode))
 		{
-			pushPList.pushExpressionsIntoSelect((SelectNode) childResult, false);
+			SelectNode childSelect = (SelectNode)childResult;
+
+			if ( (childSelect.hasWindows()  &&
+				  childSelect.orderByList != null) ) {
+				// We can't push down if there is an ORDER BY and a window
+				// function because that would make ROW_NUMBER give wrong
+				// result:
+				// E.g.
+				//     SELECT * from (SELECT ROW_NUMBER() OVER (), j FROM T
+				//                    ORDER BY j) WHERE j=5
+				//
+			} else {
+				pushPList.pushExpressionsIntoSelect((SelectNode) childResult,
+													false);
+			}
 		}
 
+
 		/* DERBY-649: Push simple predicates into Unions. It would be up to UnionNode
 		 * to decide if these predicates can be pushed further into underlying SelectNodes
 		 * or UnionNodes.  Note, we also keep the predicateList at this

Added: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ReplaceWindowFuncCallsWithCRVisitor.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ReplaceWindowFuncCallsWithCRVisitor.java?rev=829155&view=auto
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ReplaceWindowFuncCallsWithCRVisitor.java (added)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ReplaceWindowFuncCallsWithCRVisitor.java Fri Oct 23 18:05:03 2009
@@ -0,0 +1,106 @@
+/*
+   Derby - Class org.apache.derby.impl.sql.compile.ReplaceWindowFuncCallsWithCRVisitor
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to you under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+
+
+package	org.apache.derby.impl.sql.compile;
+
+import org.apache.derby.iapi.sql.compile.Visitable;
+import org.apache.derby.iapi.sql.compile.Visitor;
+
+import org.apache.derby.iapi.error.StandardException;
+
+/**
+ * Replace all window function calls with result columns.
+ *
+ */
+public class ReplaceWindowFuncCallsWithCRVisitor implements Visitor
+{
+	private ResultColumnList rcl;
+	private Class skipOverClass;
+	private int tableNumber;
+
+	/**
+	 * Replace all window function calls with column references.  Add
+	 * the reference to the RCL.  Delegates most work to
+	 * WindowFunctionNode.replaceCallsWithColumnReferences(rcl, tableNumber).
+	 *
+	 * @param rcl the result column list
+	 * @param tableNumber	The tableNumber for the new CRs
+	 * @param skipOverClass Don't go past this
+	 */
+	public ReplaceWindowFuncCallsWithCRVisitor(ResultColumnList rcl,
+											int tableNumber,
+											Class skipOverClass)
+	{
+		this.rcl = rcl;
+		this.tableNumber = tableNumber;
+		this.skipOverClass = skipOverClass;
+	}
+
+	////////////////////////////////////////////////
+	//
+	// VISITOR INTERFACE
+	//
+	////////////////////////////////////////////////
+
+	/**
+	 * Don't do anything unless we have a window function node
+	 * node. Vistor override.
+	 * @see Visitor#visit
+	 *
+	 */
+	public Visitable visit(Visitable node)
+		throws StandardException
+	{
+		if (node instanceof WindowFunctionNode)
+		{
+			/*
+			** Let windowFunctionNode replace itself.
+			*/
+			node = ((WindowFunctionNode)node).
+				replaceCallsWithColumnReferences(rcl, tableNumber);
+		}
+
+		return node;
+	}
+
+	/**
+	 * Don't visit childen under the skipOverClass
+	 * node, if it isn't null. Vistor override.
+	 * @see Visitor#skipChildren
+	 */
+	public boolean skipChildren(Visitable node)
+	{
+		return (skipOverClass == null) ?
+				false:
+				skipOverClass.isInstance(node);
+	}
+
+
+	/**
+	 * Vistor override.
+	 * @return false
+	 * @see Visitor#skipChildren
+	 */
+	public boolean stopTraversal()
+	{
+		return false;
+	}
+}

Propchange: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ReplaceWindowFuncCallsWithCRVisitor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/RowNumberFunctionNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/RowNumberFunctionNode.java?rev=829155&view=auto
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/RowNumberFunctionNode.java (added)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/RowNumberFunctionNode.java Fri Oct 23 18:05:03 2009
@@ -0,0 +1,68 @@
+/*
+   Derby - Class org.apache.derby.impl.sql.compile.RowNumberFunctionNode
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to you under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+
+package org.apache.derby.impl.sql.compile;
+
+import org.apache.derby.iapi.error.StandardException;
+import org.apache.derby.iapi.types.TypeId;
+import org.apache.derby.iapi.services.sanity.SanityManager;
+
+import java.sql.Types;
+import java.util.Vector;
+
+/**
+ * Class that represents a call to the ROW_NUMBER() window function.
+ */
+public final class RowNumberFunctionNode extends WindowFunctionNode
+{
+
+    /**
+     * Initializer. QueryTreeNode override.
+     *
+     * @param arg1 null (Operand)
+     * @param arg2 The window definition or reference
+     *
+     * @exception StandardException
+     */
+    public void init(Object arg1, Object arg2)
+        throws StandardException
+    {
+        super.init(arg1, "ROW_NUMBER", arg2);
+        setType( TypeId.getBuiltInTypeId( Types.BIGINT ),
+                 TypeId.LONGINT_PRECISION,
+                 TypeId.LONGINT_SCALE,
+                 false,
+                 TypeId.LONGINT_MAXWIDTH);
+    }
+
+    /**
+     * ValueNode override.
+     * @see ValueNode#bindExpression
+     */
+    public ValueNode bindExpression(
+                    FromList            fromList,
+                    SubqueryList        subqueryList,
+                    Vector              aggregateVector)
+            throws StandardException
+    {
+        super.bindExpression(fromList, subqueryList, aggregateVector);
+        return this;
+    }
+}

Propchange: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/RowNumberFunctionNode.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/RowResultSetNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/RowResultSetNode.java?rev=829155&r1=829154&r2=829155&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/RowResultSetNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/RowResultSetNode.java Fri Oct 23 18:05:03 2009
@@ -244,6 +244,8 @@
 		{
 			throw StandardException.newException(SQLState.LANG_NO_AGGREGATES_IN_WHERE_CLAUSE);
 		}
+
+		SelectNode.checkNoWindowFunctions(resultColumns, "VALUES");
 	}
 
 	/**

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SelectNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SelectNode.java?rev=829155&r1=829154&r2=829155&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SelectNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SelectNode.java Fri Oct 23 18:05:03 2009
@@ -88,6 +88,16 @@
 	 */
 	GroupByList	groupByList;
 
+	/**
+	 * List of windows.
+	 */
+	WindowList windows;
+
+	/**
+	 * List of window function calls (e.g. ROW_NUMBER, AVG(i), DENSE_RANK).
+	 */
+	Vector windowFuncCalls;
+
 	/** User specified a group by without aggregates and we turned 
 	 * it into a select distinct 
 	 */
@@ -125,7 +135,8 @@
 			  Object fromList,
 			  Object whereClause,
 			  Object groupByList,
-			  Object havingClause)
+			  Object havingClause,
+			  Object windowDefinitionList)
 			throws StandardException
 	{
 		/* RESOLVE - remove aggregateList from constructor.
@@ -139,6 +150,15 @@
 		this.originalWhereClause = (ValueNode) whereClause;
 		this.groupByList = (GroupByList) groupByList;
 		this.havingClause = (ValueNode)havingClause;
+
+		// This initially represents an explicit <window definition list>, as
+		// opposed to <in-line window specifications>, see 2003, 6.10 and 6.11.
+		// <in-line window specifications> are added later, see right below for
+		// in-line window specifications used in window functions in the SELECT
+		// column list and in genProjectRestrict for such window specifications
+		// used in window functions in ORDER BY.
+		this.windows = (WindowList)windowDefinitionList;
+
 		bindTargetListOnly = false;
 		
 		this.originalWhereClauseHadSubqueries = false;
@@ -150,6 +170,65 @@
 				this.originalWhereClauseHadSubqueries = true;
 			}
 		}
+
+		if (resultColumns != null) {
+
+			// Collect window functions used in result columns, and check them
+			// for any <in-line window specification>s.
+
+			CollectNodesVisitor cnvw =
+				new CollectNodesVisitor(WindowFunctionNode.class);
+			resultColumns.accept(cnvw);
+			windowFuncCalls = cnvw.getList();
+
+			for (int i=0; i < windowFuncCalls.size(); i++) {
+				WindowFunctionNode wfn =
+					(WindowFunctionNode)windowFuncCalls.elementAt(i);
+
+				// Some window function, e.g. ROW_NUMBER() contains an inline
+				// window specification, so we add it to our list of window
+				// definitions.
+
+				if (wfn.getWindow() instanceof WindowDefinitionNode) {
+					// Window function call contains an inline definition, add
+					// it to our list of windows.
+					windows = addInlinedWindowDefinition(windows, wfn);
+				} else {
+					// a window reference, bind it later.
+
+					if (SanityManager.DEBUG) {
+						SanityManager.ASSERT(
+							wfn.getWindow() instanceof WindowReferenceNode);
+					}
+				}
+			}
+		}
+	}
+
+	private WindowList addInlinedWindowDefinition (WindowList wl,
+												   WindowFunctionNode wfn) {
+		WindowDefinitionNode wdn = (WindowDefinitionNode)wfn.getWindow();
+
+		if (wl == null) {
+			// This is the first window we see, so initialize list.
+			wl = new WindowList();
+			wl.setContextManager(getContextManager());
+		}
+
+		WindowDefinitionNode equiv = wdn.findEquivalentWindow(wl);
+
+		if (equiv != null) {
+			// If the window is equivalent an existing one, optimize
+			// it away.
+
+			wfn.setWindow(equiv);
+		} else {
+			// remember this window for posterity
+
+			wl.addWindow((WindowDefinitionNode)wfn.getWindow());
+		}
+
+		return wl;
 	}
 
 	/**
@@ -241,6 +320,11 @@
 				groupByList.treePrint(depth + 1);
 			}
 
+			if (havingClause != null) {
+				printLabel(depth, "havingClause:");
+				havingClause.treePrint(depth + 1);
+			}
+
 			if (orderByList != null) {
 				printLabel(depth, "orderByList:");
 				orderByList.treePrint(depth + 1);
@@ -252,6 +336,11 @@
 				preJoinFL.treePrint(depth + 1);
 			}
 
+			if (windows != null)
+			{
+				printLabel(depth, "windows: ");
+				windows.treePrint(depth + 1);
+			}
 		}
 	}
 
@@ -448,6 +537,18 @@
 			fromListParam.insertElementAt(fromList.elementAt(index), index);
 		}
 
+		// In preparation for resolving window references in expressions, we
+		// make the FromList carry the set of explicit window definitions.
+		//
+		// E.g. "select row_number () from r, .. from t window r as ()"
+		//
+		// Here the expression "row_number () from r" needs to be bound to r's
+		// definition. Window functions can also in-line window specifications,
+		// no resolution is necessary. See also
+		// WindowFunctionNode.bindExpression.
+
+		fromListParam.setWindows(windows);
+
 		resultColumns.bindExpressions(fromListParam, 
 									  selectSubquerys,
 									  selectAggregates);
@@ -496,6 +597,8 @@
 			
 			whereClause = whereClause.checkIsBoolean();
 			getCompilerContext().popCurrentPrivType();
+
+			checkNoWindowFunctions(whereClause, "WHERE");
 		}
 
 		if (havingClause != null) {
@@ -506,6 +609,7 @@
 			havingClause.bindExpression(
 					fromListParam, havingSubquerys, havingAggregates);
 			havingClause = havingClause.checkIsBoolean();
+			checkNoWindowFunctions(havingClause, "HAVING");
 		}
 		
 		/* Restore fromList */
@@ -541,6 +645,8 @@
 				SanityManager.ASSERT(gbAggregateVector.size() == 0,
 						"Unexpected Aggregate vector generated by Group By clause");
 			}
+
+			checkNoWindowFunctions(groupByList, "GROUP BY");
 		}
 		/* If ungrouped query with aggregates in SELECT list, verify
 		 * that all result columns are valid aggregate expressions -
@@ -637,7 +743,6 @@
 		 */
 		fromList.bindResultColumns(fromListParam);
 		super.bindResultColumns(fromListParam);
-
 		/* Only 1012 elements allowed in select list */
 		if (resultColumns.size() > Limits.DB2_MAX_ELEMENTS_IN_SELECT_LIST)
 		{
@@ -969,7 +1074,6 @@
 				// columns are ones that have equality comparisons with
 				// constant expressions (e.g. x = 3)
 				orderByList.removeConstantColumns(wherePredicates);
-
 				/*
 				** It's possible for the order by list to shrink to nothing
 				** as a result of removing constant columns.  If this happens,
@@ -1099,6 +1203,42 @@
 		{
 			newTop.setReferencedTableMap((JBitSet) referencedTableMap.clone());
 		}
+
+
+		if (orderByList != null) {
+
+			// Collect window function calls and in-lined window definitions
+			// contained in them from the orderByList.
+
+			CollectNodesVisitor cnvw =
+				new CollectNodesVisitor(WindowFunctionNode.class);
+			orderByList.accept(cnvw);
+			Vector wfcInOrderBy = cnvw.getList();
+
+			for (int i=0; i < wfcInOrderBy.size(); i++) {
+				WindowFunctionNode wfn =
+					(WindowFunctionNode)wfcInOrderBy.elementAt(i);
+				windowFuncCalls.add(wfn);
+
+
+				if (wfn.getWindow() instanceof WindowDefinitionNode) {
+					// Window function call contains an inline definition, add
+					// it to our list of windows.
+					windows = addInlinedWindowDefinition(windows, wfn);
+
+				} else {
+					// a window reference, should be bound already.
+
+					if (SanityManager.DEBUG) {
+						SanityManager.ASSERT(
+							false,
+							"a window reference, should be bound already");
+					}
+				}
+			}
+		}
+
+
 		return newTop;
 	}
 
@@ -1267,7 +1407,6 @@
 		ResultColumnList	prRCList;
 		ResultSetNode		prnRSN;
 
-
 		prnRSN = (ResultSetNode) getNodeFactory().getNode(
 								C_NodeTypes.PROJECT_RESTRICT_NODE,
 								fromList.elementAt(0),	/* Child ResultSet */
@@ -1315,6 +1454,33 @@
 			eliminateSort = eliminateSort || gbn.getIsInSortedOrder();
 		}
 
+
+		if (windows != null) {
+
+			// Now we add a window result set wrapped in a PRN on top of what
+			// we currently have.
+
+			if (windows.size() > 1) {
+				throw StandardException.newException(
+					SQLState.LANG_WINDOW_LIMIT_EXCEEDED);
+			}
+
+			WindowNode wn = (WindowNode)windows.elementAt(0);
+
+			WindowResultSetNode wrsn =
+				(WindowResultSetNode)getNodeFactory().getNode(
+					C_NodeTypes.WINDOW_RESULTSET_NODE,
+					prnRSN,
+					wn,
+					windowFuncCalls,
+					new Integer(nestingLevel),
+					getContextManager());
+
+			prnRSN = wrsn.getParent();
+			wrsn.assignCostEstimate(optimizer.getOptimizedCost());
+		}
+
+
 		// if it is distinct, that must also be taken care of.
 		if (isDistinct)
 		{
@@ -1386,6 +1552,7 @@
 		/* Generate the OrderByNode if a sort is still required for
 		 * the order by.
 		 */
+
 		if (orderByList != null)
 		{
 			if (orderByList.getSortNeeded())
@@ -1423,8 +1590,12 @@
 			}
 		}
 
-		
-		if (wasGroupBy && resultColumns.numGeneratedColumnsForGroupBy() > 0) {
+
+		if (wasGroupBy &&
+			resultColumns.numGeneratedColumnsForGroupBy() > 0 &&
+			windows == null) // windows handling already added a PRN which
+							 // obviates this.
+		{
 			// This case takes care of columns generated for group by's which 
 			// will need to be removed from the final projection. Note that the
 			// GroupByNode does remove generated columns but in certain cases
@@ -2224,4 +2395,35 @@
 	{
 		return !selectAggregates.isEmpty();
 	}
+
+	/**
+	 * Used by SubqueryNode to avoid flattening of a subquery if a window is
+	 * defined on it. Note that any inline window definitions should have been
+	 * collected from both the selectList and orderByList at the time this
+	 * method is called, so the windows list is complete. This is true after
+	 * preprocess is completed.
+	 *
+	 * @return true if this select node has any windows on it
+	 */
+	public boolean hasWindows()
+	{
+		return windows != null;
+	}
+
+
+	public static void checkNoWindowFunctions(QueryTreeNode clause,
+											   String clauseName)
+			throws StandardException {
+
+		// Clause cannot contain window functions except inside subqueries
+		HasNodeVisitor visitor = new HasNodeVisitor(WindowFunctionNode.class,
+													SubqueryNode.class);
+		clause.accept(visitor);
+
+		if (visitor.hasNode()) {
+			throw StandardException.newException(
+				SQLState.LANG_WINDOW_FUNCTION_CONTEXT_ERROR,
+				clauseName);
+		}
+	}
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SetOperatorNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SetOperatorNode.java?rev=829155&r1=829154&r2=829155&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SetOperatorNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SetOperatorNode.java Fri Oct 23 18:05:03 2009
@@ -1027,6 +1027,7 @@
 				null,     // WHERE clause
 				null,     // GROUP BY list
 				null,     // having clause
+				null, /* window list */
 				getContextManager());
 
 		/* And finally, transform the "*" in the new SELECT node

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SubqueryNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SubqueryNode.java?rev=829155&r1=829154&r2=829155&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SubqueryNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SubqueryNode.java Fri Oct 23 18:05:03 2009
@@ -627,6 +627,7 @@
 					  underTopAndNode && !havingSubquery &&
 					  !isWhereExistsAnyInWithWhereSubquery() &&
 					  parentComparisonOperator instanceof BinaryComparisonOperatorNode;
+
 		if (flattenable)
 		{
 			/* If we got this far and we are an expression subquery
@@ -680,6 +681,7 @@
 		 *	  that the flattening of the subquery will not
 		 *	  introduce duplicates into the result set.
          *  o The subquery is not part of a having clause (DERBY-3257)
+		 *  o There are no windows defined on it
 		 *
 		 *	OR,
 		 *  o The subquery is NOT EXISTS, NOT IN, ALL (beetle 5173).
@@ -691,6 +693,7 @@
 		boolean flattenableNotExists = (isNOT_EXISTS() || canAllBeFlattened());
 
 		flattenable = (resultSet instanceof SelectNode) &&
+ 			          !((SelectNode)resultSet).hasWindows() &&
 					  underTopAndNode && !havingSubquery &&
 					  !isWhereExistsAnyInWithWhereSubquery() &&
 					  (isIN() || isANY() || isEXISTS() || flattenableNotExists ||
@@ -728,6 +731,7 @@
 				}
 				/* Never flatten to normal join for NOT EXISTS.
 				 */
+
 				if ((! flattenableNotExists) && select.uniqueSubquery(additionalEQ))
 				{
 					// Flatten the subquery

Added: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowDefinitionNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowDefinitionNode.java?rev=829155&view=auto
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowDefinitionNode.java (added)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowDefinitionNode.java Fri Oct 23 18:05:03 2009
@@ -0,0 +1,155 @@
+/*
+
+   Derby - Class org.apache.derby.impl.sql.compile.WindowDefinitionNode
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to you under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+
+package org.apache.derby.impl.sql.compile;
+
+import org.apache.derby.iapi.error.StandardException;
+import org.apache.derby.iapi.types.TypeId;
+import org.apache.derby.iapi.services.sanity.SanityManager;
+import org.apache.derby.iapi.reference.SQLState;
+
+import java.sql.Types;
+
+/**
+ * This class represents an OLAP window definition.
+ */
+public final class WindowDefinitionNode extends WindowNode
+{
+    /**
+     * True of the window definition was inlined.
+     */
+    private boolean inlined;
+
+    /**
+     * The order by list if the window definition contains a <window order
+     * clause>, else null.
+     */
+    private OrderByList orderByList;
+
+    /**
+     * Initializer.
+     *
+     * @param arg1 The window name, null if in-lined definition
+     * @param arg2 ORDER BY list
+     * @exception StandardException
+     */
+    public void init(Object arg1,
+                     Object arg2)
+        throws StandardException
+    {
+        String name = (String)arg1;
+
+        orderByList = (OrderByList)arg2;
+
+        if (name != null) {
+            super.init(arg1);
+            inlined = false;
+        } else {
+            super.init("IN-LINE");
+            inlined = true;
+        }
+
+        if (orderByList != null) {
+            throw StandardException.newException(SQLState.NOT_IMPLEMENTED,
+                                                 "WINDOW/ORDER BY");
+        }
+    }
+
+
+    /**
+     * java.lang.Object override.
+     * @see QueryTreeNode#toString
+     */
+    public String toString() {
+        return ("name: " + getName() + "\n" +
+                "inlined: " + inlined + "\n" +
+                "()\n");
+    }
+
+
+
+    /**
+     * QueryTreeNode override. Prints the sub-nodes of this object.
+     * @see QueryTreeNode#printSubNodes
+     *
+     * @param depth     The depth of this node in the tree
+     */
+
+    public void printSubNodes(int depth)
+    {
+        if (SanityManager.DEBUG)
+        {
+            super.printSubNodes(depth);
+
+            if (orderByList != null) {
+                printLabel(depth, "orderByList: "  + depth);
+                orderByList.treePrint(depth + 1);
+            }
+        }
+    }
+
+
+    /**
+     * Used to merge equivalent window definitions.
+     *
+     * @param wl list of window definitions
+     * @return an existing window definition from wl, if 'this' is equivalent
+     * to a window in wl.
+     */
+    public WindowDefinitionNode findEquivalentWindow(WindowList wl) {
+        for (int i = 0; i < wl.size(); i++) {
+            WindowDefinitionNode old = (WindowDefinitionNode)wl.elementAt(i);
+
+            if (isEquivalent(old)) {
+                return old;
+            }
+        }
+        return null;
+    }
+
+
+
+    /**
+     * @return true if the window specifications are equal; no need to create
+     * more than one window then.
+     */
+    private boolean isEquivalent(WindowDefinitionNode other) {
+        if (orderByList == null && other.getOrderByList() == null) {
+            return true;
+        }
+
+        if (SanityManager.DEBUG) {
+            SanityManager.ASSERT(
+                false,
+                "FIXME: ordering in windows not implemented yet");
+        }
+        return false;
+    }
+
+
+
+    /**
+     * @return the order by list of this window definition if any, else null.
+     */
+    public OrderByList getOrderByList() {
+        return orderByList;
+    }
+}

Propchange: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowDefinitionNode.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowFunctionNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowFunctionNode.java?rev=829155&view=auto
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowFunctionNode.java (added)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowFunctionNode.java Fri Oct 23 18:05:03 2009
@@ -0,0 +1,275 @@
+/*
+   Derby - Class org.apache.derby.impl.sql.compile.WindowFunctionNode
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to you under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+
+package org.apache.derby.impl.sql.compile;
+
+import org.apache.derby.iapi.error.StandardException;
+import org.apache.derby.iapi.types.TypeId;
+import org.apache.derby.iapi.services.sanity.SanityManager;
+import org.apache.derby.iapi.sql.compile.CompilerContext;
+import org.apache.derby.iapi.sql.compile.C_NodeTypes;
+import org.apache.derby.iapi.reference.SQLState;
+
+import java.sql.Types;
+import java.util.Vector;
+
+
+/**
+ * Superclass of any window function call.
+ */
+public abstract class WindowFunctionNode extends UnaryOperatorNode
+{
+
+    private WindowNode window; // definition or reference
+
+    /*
+    ** We wind up pushing all window function calls into a different
+    ** resultColumnList.  When we do this (in replaceCallsWithColumnReference),
+    ** we return a column reference and create a new result column.  This is
+    ** used to store that result column.
+    */
+    private ResultColumn            generatedRC;
+    private ColumnReference         generatedRef;
+
+    /**
+     * Initializer for a WindowFunctionNode
+     * @param arg1 null (operand)
+     * @param arg2 function mame (operator)
+     * @param arg3 window node (definition or reference)
+     * @exception StandardException
+     */
+    public void init(Object arg1, Object arg2, Object arg3)
+    {
+        super.init(arg1, arg2, null);
+        this.window = (WindowNode)arg3;
+    }
+
+    /**
+     * ValueNode override.
+     * @see ValueNode#isConstantExpression
+     */
+    public boolean isConstantExpression()
+    {
+        return false;
+    }
+
+    /**
+     * ValueNode override.
+     * @see ValueNode#isConstantExpression
+     */
+    public boolean constantExpression(PredicateList whereClause)
+    {
+        // Without this, an ORDER by on ROW_NUMBER could get optimised away
+        // if there is a restriction, e.g.
+        //
+        // SELECT -ABS(i) a, ROW_NUMBER() OVER () c FROM t
+        //     WHERE i > 1 ORDER BY c DESC
+        return false;
+    }
+
+
+    /**
+     * @return window associated with this window function
+     */
+    public WindowNode getWindow() {
+        return window;
+    }
+
+
+    /**
+     * Set window associated with this window function call.
+     * @param wdn window definition
+     */
+    public void setWindow(WindowDefinitionNode wdn) {
+        this.window = wdn;
+    }
+
+
+    /**
+     * ValueNode override.
+     * @see ValueNode#bindExpression
+     */
+    public ValueNode bindExpression(
+            FromList fromList,
+            SubqueryList subqueryList,
+            Vector  aggregateVector)
+        throws StandardException
+    {
+        if (window instanceof WindowReferenceNode) {
+
+            WindowDefinitionNode found =
+                definedWindow(fromList.getWindows(), window.getName());
+
+            if (found != null) {
+                window = found;
+            } else {
+                throw StandardException.
+                    newException(SQLState.LANG_NO_SUCH_WINDOW,
+                                 window.getName());
+            }
+        }
+
+        return this;
+    }
+
+
+    /**
+     * @return if name matches a defined window (in windows), return the
+     * definition of that window, else null.
+     */
+    private WindowDefinitionNode definedWindow(WindowList windows,
+                                               String name) {
+        for (int i=0; i < windows.size(); i++) {
+            WindowDefinitionNode wdn =
+                (WindowDefinitionNode)windows.elementAt(i);
+
+            if (wdn.getName().equals(name)) {
+                return wdn;
+            }
+        }
+        return null;
+    }
+
+
+    /**
+     * QueryTreeNode override.
+     * @see QueryTreeNode#printSubNodes
+     */
+
+    public void printSubNodes(int depth)
+    {
+        if (SanityManager.DEBUG)
+        {
+            super.printSubNodes(depth);
+
+            printLabel(depth, "window: ");
+            window.treePrint(depth + 1);
+        }
+    }
+
+    /**
+     * Replace window function calls in the expression tree with a
+     * ColumnReference to that window function, append the aggregate to the
+     * supplied RCL (assumed to be from the child ResultSetNode) and return the
+     * ColumnReference.
+     *
+     * @param rcl   The RCL to append to.
+     * @param tableNumber   The tableNumber for the new ColumnReference
+     *
+     * @return ValueNode    The (potentially) modified tree.
+     *
+     * @exception StandardException         Thrown on error
+     */
+    public ValueNode replaceCallsWithColumnReferences(ResultColumnList rcl,
+                                                      int tableNumber)
+        throws StandardException
+    {
+        /*
+         * This call is idempotent.  Do the right thing if we have already
+         * replaced ourselves.
+         */
+        if (generatedRef == null)
+        {
+            String                  generatedColName;
+            CompilerContext         cc = getCompilerContext();
+            generatedColName ="SQLCol" + cc.getNextColumnNumber();
+            generatedRC = (ResultColumn) getNodeFactory().getNode(
+                                            C_NodeTypes.RESULT_COLUMN,
+                                            generatedColName,
+                                            this,
+                                            getContextManager());
+            generatedRC.markGenerated();
+
+            // Parse time.
+            //
+            generatedRef = (ColumnReference) getNodeFactory().getNode(
+                                                C_NodeTypes.COLUMN_REFERENCE,
+                                                generatedRC.getName(),
+                                                null,
+                                                getContextManager());
+
+            // RESOLVE - unknown nesting level, but not correlated, so nesting
+            // levels must be 0
+            generatedRef.setSource(generatedRC);
+            generatedRef.setNestingLevel(0);
+            generatedRef.setSourceLevel(0);
+
+            if (tableNumber != -1)
+            {
+                generatedRef.setTableNumber(tableNumber);
+            }
+
+            rcl.addResultColumn(generatedRC);
+
+
+            // Mark the ColumnReference as being generated to replace a call to
+            // a window function
+
+            generatedRef.markGeneratedToReplaceWindowFunctionCall();
+        }
+        else
+        {
+            rcl.addResultColumn(generatedRC);
+        }
+
+        return generatedRef;
+    }
+
+    /**
+     * Get the generated ColumnReference to this window function after the
+     * parent called replaceCallsWithColumnReferences().
+     * <p/>
+     * There are cases where this will not have been done because the tree has
+     * been re-written to eliminate the window function, e.g. for this query:
+     * <p/><pre>
+     *     {@code SELECT * FROM t WHERE EXISTS
+     *           (SELECT ROW_NUMBER() OVER () FROM t)}
+     * </pre><p/>
+     * in which case the top PRN of the subquery sitting over a
+     * WindowResultSetNode just contains a RC which is boolean constant {@code
+     * true}. This means that the replaceCallsWithColumnReferences will not
+     * have been called for {@code this}, so the returned {@code generatedRef}
+     * is null.
+     *
+     * @return the column reference
+     */
+    public ColumnReference getGeneratedRef()
+    {
+        return generatedRef;
+    }
+
+
+    /**
+     * Get the null result expression column.
+     *
+     * @return the value node
+     *
+     * @exception StandardException on error
+     */
+    public ValueNode    getNewNullResultExpression()
+        throws StandardException
+    {
+        //
+        // Create a result column with the aggregate operand
+        // it.
+        //
+        return getNullNode(getTypeServices());
+    }
+}

Propchange: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowFunctionNode.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowList.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowList.java?rev=829155&view=auto
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowList.java (added)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowList.java Fri Oct 23 18:05:03 2009
@@ -0,0 +1,40 @@
+/*
+
+   Derby - Class org.apache.derby.impl.sql.compile.WindowList
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to you under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+
+package org.apache.derby.impl.sql.compile;
+
+/**
+ * A WindowList represents the list of windows (definitions) for a table
+ * expression, either defined explicitly in a WINDOW clause, or inline in the
+ * SELECT list or ORDER BY clause.
+ *
+ */
+
+public class WindowList extends OrderedColumnList
+{
+    /**
+     * @param window the window definition to add to the list
+     */
+    public void addWindow(WindowDefinitionNode window)
+    {
+        addElement(window);
+    }
+}

Propchange: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowList.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowNode.java?rev=829155&view=auto
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowNode.java (added)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowNode.java Fri Oct 23 18:05:03 2009
@@ -0,0 +1,68 @@
+/*
+
+   Derby - Class org.apache.derby.impl.sql.compile.WindowNode
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to you under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+
+package org.apache.derby.impl.sql.compile;
+
+import org.apache.derby.iapi.error.StandardException;
+import org.apache.derby.iapi.types.TypeId;
+import org.apache.derby.iapi.services.sanity.SanityManager;
+
+import java.sql.Types;
+import java.util.Vector;
+
+/**
+ * Superclass of window definition and window reference.
+ */
+public abstract class WindowNode extends QueryTreeNode
+{
+    /**
+     * The provided name of the window if explicitly defined in a window
+     * clause. If the definition is inlined, currently the definition has
+     * windowName "IN_LINE".  The standard 2003 sec. 4.14.9 calls for a
+     * impl. defined one.
+     */
+    private String windowName;
+
+
+    /**
+     * Initializer
+     *
+     * @param arg1 The window name
+     *
+     * @exception StandardException
+     */
+    public void init(Object arg1)
+        throws StandardException
+    {
+        windowName = (String)arg1;
+    }
+
+
+    /**
+     * @return the name of this window
+     */
+    public String getName() {
+        return windowName;
+    }
+
+
+
+}

Propchange: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowNode.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowReferenceNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowReferenceNode.java?rev=829155&view=auto
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowReferenceNode.java (added)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowReferenceNode.java Fri Oct 23 18:05:03 2009
@@ -0,0 +1,54 @@
+/*
+
+   Derby - Class org.apache.derby.impl.sql.compile.WindowReferenceNode
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to you under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+
+package org.apache.derby.impl.sql.compile;
+
+import org.apache.derby.iapi.error.StandardException;
+import org.apache.derby.iapi.types.TypeId;
+import org.apache.derby.iapi.services.sanity.SanityManager;
+
+import java.sql.Types;
+import java.util.Vector;
+
+/**
+ * Represents a reference to an explicitly defined window
+ */
+public final class WindowReferenceNode extends WindowNode
+{
+    /**
+     * Initializer
+     *
+     * @param arg1 The window name referenced
+     *
+     * @exception StandardException
+     */
+    public void init(Object arg1)
+        throws StandardException
+    {
+        super.init(arg1);
+    }
+
+    // java.lang.Object override
+    public String toString() {
+        return "referenced window: " + getName() + "\n" +
+            super.toString();
+    }
+}

Propchange: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowReferenceNode.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowResultSetNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowResultSetNode.java?rev=829155&view=auto
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowResultSetNode.java (added)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowResultSetNode.java Fri Oct 23 18:05:03 2009
@@ -0,0 +1,455 @@
+/*
+   Derby - Class org.apache.derby.impl.sql.compile.WindowResultSetNode
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to you under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+
+package org.apache.derby.impl.sql.compile;
+
+import java.util.Iterator;
+import java.util.Vector;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Collections;
+
+import org.apache.derby.catalog.IndexDescriptor;
+import org.apache.derby.iapi.error.StandardException;
+import org.apache.derby.iapi.reference.ClassName;
+import org.apache.derby.iapi.reference.SQLState;
+import org.apache.derby.iapi.services.classfile.VMOpcode;
+import org.apache.derby.iapi.services.compiler.MethodBuilder;
+import org.apache.derby.iapi.services.io.FormatableArrayHolder;
+import org.apache.derby.iapi.services.io.FormatableBitSet;
+import org.apache.derby.iapi.services.sanity.SanityManager;
+import org.apache.derby.iapi.sql.LanguageFactory;
+import org.apache.derby.iapi.sql.ResultColumnDescriptor;
+import org.apache.derby.iapi.sql.compile.AccessPath;
+import org.apache.derby.iapi.sql.compile.C_NodeTypes;
+import org.apache.derby.iapi.sql.compile.CostEstimate;
+import org.apache.derby.iapi.sql.compile.Optimizable;
+import org.apache.derby.iapi.sql.compile.OptimizablePredicate;
+import org.apache.derby.iapi.sql.compile.OptimizablePredicateList;
+import org.apache.derby.iapi.sql.compile.Optimizer;
+import org.apache.derby.iapi.sql.compile.RequiredRowOrdering;
+import org.apache.derby.iapi.sql.compile.RowOrdering;
+import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
+import org.apache.derby.iapi.sql.dictionary.DataDictionary;
+import org.apache.derby.iapi.store.access.ColumnOrdering;
+import org.apache.derby.impl.sql.execute.AggregatorInfo;
+import org.apache.derby.impl.sql.execute.AggregatorInfoList;
+
+
+/**
+ * A WindowResultSetNode represents a result set for a window partitioning on a
+ * select. Modelled on the code in GroupByNode.
+ */
+public class WindowResultSetNode extends SingleChildResultSetNode
+{
+    /**
+     * The parent to the WindowResultSetNode.  We generate a ProjectRestrict
+     * over the windowing node and parent is set to that node.
+     */
+    FromTable   parent;
+    Vector windowFuncCalls;
+    WindowDefinitionNode wdn;
+
+    /**
+     * Intializer for a WindowResultSetNode.
+     * @param bottomPR The project restrict result set we want to wrap
+     * @param windowDef The window definition
+     * @param windowFuncCalls All window function calls in SELECT's select list
+     * and order by list.
+     * @param nestingLevel Nesting level
+     *
+     * @exception StandardException     Thrown on error
+     */
+    public void init(
+        Object bottomPR,
+        Object windowDef,
+        Object windowFuncCalls,
+        Object nestingLevel) throws StandardException
+    {
+        super.init(bottomPR, null);
+        this.wdn = (WindowDefinitionNode)windowDef;
+        this.windowFuncCalls = (Vector)windowFuncCalls;
+        setLevel(((Integer)nestingLevel).intValue());
+
+        ResultColumnList newBottomRCL;
+
+        this.parent = this;
+
+        /*
+        ** The first thing we do is put ourselves on top of the SELECT.  The
+        ** select becomes the childResult.  So our RCL becomes its RCL (so
+        ** nodes above it now point to us).  Map our RCL to its columns.
+        */
+        newBottomRCL = childResult.getResultColumns().copyListAndObjects();
+        resultColumns = childResult.getResultColumns();
+        childResult.setResultColumns(newBottomRCL);
+
+        // Wrao purselved int a project/restrict as per convention.
+        addNewPRNode();
+
+        // Add the extra result columns required
+        addNewColumns();
+    }
+
+    /**
+     * Add a new PR node.  Put the new PR under any sort.
+     *
+     * @exception standard exception
+     */
+    private void addNewPRNode()
+        throws StandardException
+    {
+        /*
+        ** Get the new PR, put above the WindowResultSetNode.
+        */
+        ResultColumnList rclNew = (ResultColumnList)getNodeFactory().
+            getNode(C_NodeTypes.RESULT_COLUMN_LIST,
+                    getContextManager());
+
+        int sz = resultColumns.size();
+        for (int i = 0; i < sz; i++)
+        {
+            ResultColumn rc = (ResultColumn) resultColumns.elementAt(i);
+            if (!rc.isGenerated()) {
+                rclNew.addElement(rc);
+            }
+        }
+
+        // if any columns in the source RCL were generated for an order by
+        // remember it in the new RCL as well. After the sort is done it will
+        // have to be projected out upstream.
+        rclNew.copyOrderBySelect(resultColumns);
+
+        parent = (FromTable) getNodeFactory().getNode(
+                                        C_NodeTypes.PROJECT_RESTRICT_NODE,
+                                        this, // child
+                                        rclNew,
+                                        null, // havingClause,
+                                        null, // restriction list
+                                        null, // project subqueries
+                                        null, // havingSubquerys,
+                                        null, // tableProperties,
+                                        getContextManager());
+
+
+        /*
+         * Reset the bottom RCL to be empty.
+         */
+        childResult.setResultColumns((ResultColumnList)
+                                            getNodeFactory().getNode(
+                                                C_NodeTypes.RESULT_COLUMN_LIST,
+                                                getContextManager()));
+
+        /*
+         * Set the Windowing RCL to be empty
+         */
+        resultColumns = (ResultColumnList) getNodeFactory().getNode(
+                                            C_NodeTypes.RESULT_COLUMN_LIST,
+                                            getContextManager());
+
+
+        // Add all referenced columns in select list to windowing node's RCL
+        // and substitute references in original node to point to the Windowing
+        // result set. (modelled on GroupByNode's action for addUnAggColumns)
+        CollectNodesVisitor getCRVisitor =
+            new CollectNodesVisitor(ColumnReference.class);
+
+        ResultColumnList prcl = parent.getResultColumns();
+
+        parent.getResultColumns().accept(getCRVisitor);
+
+        Vector colRefs = getCRVisitor.getList();
+
+        // Find all unique columns referenced and add those to windowing result
+        // set.
+        Vector uniqueCols = new Vector();
+        for (int i= 0; i< colRefs.size(); i++) {
+            ColumnReference cr = (ColumnReference)colRefs.elementAt(i);
+            if (!colRefAlreadySeen(uniqueCols, cr)) {
+                uniqueCols.add(cr);
+            }
+        }
+
+        // Add all virtual column select list to windowing node's RCL and
+        // substitute references in original node to point to the Windowing
+        // result set. Happens for example when we have a window over a group
+        // by.
+        CollectNodesVisitor getVCVisitor =
+            new CollectNodesVisitor(VirtualColumnNode.class);
+
+        parent.getResultColumns().accept(getVCVisitor);
+        Vector vcs = getVCVisitor.getList();
+
+        // Add any virtual columns to windowing result.
+        for (int i= 0; i< vcs.size(); i++) {
+            uniqueCols.add(vcs.elementAt(i));
+        }
+
+        ResultColumnList bottomRCL  = childResult.getResultColumns();
+        ResultColumnList windowingRCL = resultColumns;
+
+        for (int i= 0; i< uniqueCols.size(); i++) {
+            ValueNode crOrVcn = (ValueNode)uniqueCols.elementAt(i);
+
+            ResultColumn newRC = (ResultColumn) getNodeFactory().getNode(
+                    C_NodeTypes.RESULT_COLUMN,
+                    "##UnWindowingColumn",
+                    crOrVcn,
+                    getContextManager());
+
+            // add this result column to the bottom rcl
+            bottomRCL.addElement(newRC);
+            newRC.markGenerated();
+            newRC.bindResultColumnToExpression();
+            newRC.setVirtualColumnId(bottomRCL.size());
+
+            // now add this column to the windowing result column list
+            ResultColumn wRC = (ResultColumn) getNodeFactory().getNode(
+                    C_NodeTypes.RESULT_COLUMN,
+                    "##UnWindowingColumn",
+                    crOrVcn,
+                    getContextManager());
+            windowingRCL.addElement(wRC);
+            wRC.markGenerated();
+            wRC.bindResultColumnToExpression();
+            wRC.setVirtualColumnId(windowingRCL.size());
+
+            /*
+             ** Reset the original node to point to the
+             ** Windowing result set.
+             */
+            VirtualColumnNode vc = (VirtualColumnNode) getNodeFactory().getNode(
+                    C_NodeTypes.VIRTUAL_COLUMN_NODE,
+                    this, // source result set.
+                    wRC,
+                    new Integer(windowingRCL.size()),
+                    getContextManager());
+
+            SubstituteExpressionVisitor seVis =
+                new SubstituteExpressionVisitor(crOrVcn, vc, null);
+            parent.getResultColumns().accept(seVis);
+        }
+    }
+
+
+    /**
+     * @return true if an equivalent column reference to cand is already
+     * present in uniqueColRefs
+     */
+    private boolean colRefAlreadySeen(Vector uniqueColRefs,
+                                      ColumnReference cand)
+            throws StandardException {
+
+        for (int i= 0; i< uniqueColRefs.size(); i++) {
+            ColumnReference cr = (ColumnReference)uniqueColRefs.elementAt(i);
+
+            if (cr.isEquivalent(cand)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Substitute new result columns for window function calls and add the
+     * result columns to childResult's list of columns.
+     */
+    private void addNewColumns() throws StandardException {
+        /*
+         * Now process all of the window function calls.  Replace every
+         * call with an RC.  We toss out the list of RCs, we need to get
+         * each RC as we process its corresponding window function.
+         */
+        LanguageFactory lf =
+            getLanguageConnectionContext().getLanguageFactory();
+
+        ResultColumnList bottomRCL  = childResult.getResultColumns();
+        ResultColumnList windowingRCL = resultColumns;
+
+        ReplaceWindowFuncCallsWithCRVisitor replaceCallsVisitor =
+            new ReplaceWindowFuncCallsWithCRVisitor(
+                (ResultColumnList) getNodeFactory().getNode(
+                    C_NodeTypes.RESULT_COLUMN_LIST,
+                    getContextManager()),
+                ((FromTable) childResult).getTableNumber(),
+                ResultSetNode.class);
+        parent.getResultColumns().accept(replaceCallsVisitor);
+
+        for (int i=0; i < windowFuncCalls.size(); i++) {
+            WindowFunctionNode winFunc =
+                (WindowFunctionNode)windowFuncCalls.elementAt(i);
+
+            if (SanityManager.DEBUG) {
+                SanityManager.ASSERT(
+                    !(winFunc.getWindow() instanceof WindowReferenceNode),
+                    "unresolved window-reference: " +
+                    winFunc.getWindow().getName());
+            }
+
+            WindowDefinitionNode funcWindow =
+                (WindowDefinitionNode)winFunc.getWindow();
+
+            if (funcWindow == wdn) {
+                ResultColumn newRC = (ResultColumn) getNodeFactory().getNode(
+                    C_NodeTypes.RESULT_COLUMN,
+                    "##winFuncResult",
+                    winFunc.getNewNullResultExpression(),
+                    getContextManager());
+
+                newRC.markGenerated();
+                newRC.bindResultColumnToExpression();
+                bottomRCL.addElement(newRC);
+                newRC.setVirtualColumnId(bottomRCL.size());
+                int winFuncResultVColId = newRC.getVirtualColumnId();
+
+                /*
+                ** Set the WindowResultSetNode result column to point to this.
+                ** The Windowing Node result was created when we called
+                ** ReplaceWindowFuncCallsWithCRVisitor.
+                */
+                ColumnReference newColumnRef =
+                    (ColumnReference) getNodeFactory().getNode(
+                        C_NodeTypes.COLUMN_REFERENCE,
+                        newRC.getName(),
+                        null,
+                        getContextManager());
+
+                newColumnRef.setSource(newRC);
+                newColumnRef.setNestingLevel(this.getLevel());
+                newColumnRef.setSourceLevel(this.getLevel());
+                newColumnRef.markGeneratedToReplaceWindowFunctionCall();
+
+                ResultColumn tmpRC = (ResultColumn) getNodeFactory().getNode(
+                    C_NodeTypes.RESULT_COLUMN,
+                    newRC.getColumnName(),
+                    newColumnRef,
+                    getContextManager());
+
+                tmpRC.markGenerated();
+                tmpRC.bindResultColumnToExpression();
+                windowingRCL.addElement(tmpRC);
+                tmpRC.setVirtualColumnId(windowingRCL.size());
+
+                /*
+                ** Set the column reference to point to
+                ** this.
+                */
+                newColumnRef = winFunc.getGeneratedRef();
+
+                if (newColumnRef != null) {
+                    newColumnRef.setSource(tmpRC);
+                } // Not generated, meaning it's no longer in use
+            }
+        }
+    }
+
+
+    /**
+     * override
+     * @see QueryTreeNode#generate
+     */
+    public void generate(ActivationClassBuilder acb,
+                         MethodBuilder mb)
+            throws StandardException
+    {
+        // Get the next ResultSet#, so we can number this ResultSetNode, its
+        // ResultColumnList and ResultSet.
+
+        assignResultSetNumber();
+
+        // Get the final cost estimate from the child.
+        costEstimate = childResult.getFinalCostEstimate();
+
+
+        acb.pushGetResultSetFactoryExpression(mb);
+
+        int rclSize = resultColumns.size();
+        FormatableBitSet referencedCols = new FormatableBitSet(rclSize);
+
+        /*
+         * Build a FormatableBitSet for columns to copy from source.
+         */
+
+        for (int index = rclSize-1; index >= 0; index--) {
+            ResultColumn rc = (ResultColumn) resultColumns.elementAt(index);
+            ValueNode expr = rc.getExpression();
+
+            if (rc.isGenerated() &&
+                    (expr instanceof ColumnReference) &&
+                    ((ColumnReference)expr).
+                        getGeneratedToReplaceWindowFunctionCall()) {
+
+                // meaningless to copy these, they arise in this rs.
+            } else {
+                referencedCols.set(index);
+            }
+        }
+
+        int erdNumber = acb.addItem(referencedCols);
+
+        acb.pushThisAsActivation(mb); // arg 1
+
+        childResult.generate(acb, mb);    // arg 2
+        mb.upCast(ClassName.NoPutResultSet);
+
+        /* row allocator */
+        resultColumns.generateHolder(acb, mb); // arg 3
+
+        mb.push(resultSetNumber); //arg 4
+
+        /* Pass in the erdNumber for the referenced column FormatableBitSet */
+        mb.push(erdNumber); // arg 5
+
+        /* There is no restriction at this level, we just want to pass null. */
+        mb.pushNull(ClassName.GeneratedMethod); // arg 6
+
+        mb.push(costEstimate.rowCount()); //arg 7
+        mb.push(costEstimate.getEstimatedCost()); // arg 8
+
+        mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null,
+            "getWindowResultSet", ClassName.NoPutResultSet, 8);
+
+    }
+
+
+
+    /**
+     * @return parent of this node, a PRN, used by SelectNode to retrieve new
+     * top result set node after window result set rewrite of result set tree.
+     */
+    public FromTable getParent() {
+        return parent;
+    }
+
+
+    /**
+     * QueryTreeNode override
+     * @see QueryTreeNode#printSubNodes
+     */
+    public void printSubNodes(int depth) {
+        if (SanityManager.DEBUG) {
+			super.printSubNodes(depth);
+
+            printLabel(depth, "wdn: ");
+            wdn.treePrint(depth + 1);
+        }
+    }
+
+}

Propchange: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/WindowResultSetNode.java
------------------------------------------------------------------------------
    svn:eol-style = native