Author: kmarsden
Date: Tue Nov 4 09:19:03 2008
New Revision: 711321
URL: http://svn.apache.org/viewvc?rev=711321&view=rev
Log:
DERBY-3880 NPE on a query with having clause involving a join
remap expression for AggregateNode operand if the JoinNode has been flattened.
Fix contributed by Army Brown
Modified:
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/AggregateNode.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GroupByTest.java
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=711321&r1=711320&r2=711321&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 Tue
Nov 4 09:19:03 2008
@@ -539,6 +539,27 @@
this.getNewNullResultExpression() :
operand;
+
+ /* The operand for this aggregate node was initialized at bind
+ * time. Between then and now it's possible that certain changes
+ * have been made to the query tree which affect this operand. In
+ * particular, if the operand was pointing to a result column in
+ * a JoinNode and then that JoinNode was flattened during pre-
+ * processing, all of the references to that JoinNode--including
+ * this aggregate's operand--need to be updated to reflect the
+ * fact that the Join Node no longer exists. So check to see if
+ * the operand is a column reference, and if so, make a call to
+ * remap it to its underlying expression. If nothing has happened
+ * then this will be a no-op; but if something has changed to void
+ * out the result column to which the operand points, the result
+ * column will be marked "redundant" and the following call should
+ * remap as appropriate. DERBY-3880.
+ */
+ if (operand instanceof ColumnReference)
+ {
+ ((ColumnReference)operand).remapColumnReferencesToExpressions();
+ }
+
return (ResultColumn) getNodeFactory().getNode(
C_NodeTypes.RESULT_COLUMN,
"##aggregate expression",
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GroupByTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GroupByTest.java?rev=711321&r1=711320&r2=711321&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GroupByTest.java
(original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GroupByTest.java
Tue Nov 4 09:19:03 2008
@@ -276,6 +276,16 @@
st.executeUpdate(
"insert into EMPTAB values( 1, 1000, 1 )");
+
+ // tables for DERBY-3880 testing
+ st.executeUpdate("CREATE TABLE T1_D3880(i int, c varchar(20))");
+ st.executeUpdate("create table t2_D3880(i int, c2 varchar(20), i2 int)");
+ st.executeUpdate("insert into t1_D3880 values(1, 'abc')");
+ st.executeUpdate("insert into t1_D3880 values(2, 'abc')");
+ st.executeUpdate("insert into t2_D3880 values(1, 'xyz', 10)");
+ st.executeUpdate("insert into t2_D3880 values(1, 'aaa', 20)");
+ st.executeUpdate("insert into t2_D3880 values(2, 'xxx', 30)");
+
}
/**
@@ -1446,6 +1456,16 @@
JDBC.assertEmpty(s.executeQuery("select orderID from session.ztemp group by orderID"));
}
+ public void testHavingWithInnerJoinDerby3880() throws SQLException {
+ Statement s = createStatement();
+ ResultSet rs = s.executeQuery("select t1_D3880.i, avg(t2_D3880.i2) from t1_D3880 " +
+ "inner join t2_D3880 on (t1_D3880.i = t2_D3880.i) group by t1_D3880.i having " +
+ "avg(t2_D3880.i2) > 0");
+ String[][] expRs = new String[][] {{"1","15"},{"2","30"}};
+ JDBC.assertFullResultSet(rs,expRs);
+
+ }
+
/**
* DERBY-280: Wrong result from select when aliasing to same name as used
* in group by
|