| /* |
| |
| Derby - Class org.apache.derbyTesting.functionTests.tests.lang.GroupByTest |
| |
| 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.derbyTesting.functionTests.tests.lang; |
| |
| import java.sql.PreparedStatement; |
| import java.sql.ResultSet; |
| import java.sql.SQLException; |
| import java.sql.Statement; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import junit.framework.Test; |
| import org.apache.derby.shared.common.sanity.SanityManager; |
| import org.apache.derbyTesting.junit.BaseJDBCTestCase; |
| import org.apache.derbyTesting.junit.BaseTestSuite; |
| import org.apache.derbyTesting.junit.CleanDatabaseTestSetup; |
| import org.apache.derbyTesting.junit.JDBC; |
| import org.apache.derbyTesting.junit.RuntimeStatisticsParser; |
| import org.apache.derbyTesting.junit.SQLUtilities; |
| |
| /** |
| * Many of these test cases were converted from the old groupBy.sql |
| * using the DERBY-2151 SQLToJUnit conversion utility. |
| */ |
| public class GroupByTest extends BaseJDBCTestCase { |
| |
| public GroupByTest(String name) { |
| super(name); |
| } |
| |
| public static Test suite() { |
| return new CleanDatabaseTestSetup( |
| new BaseTestSuite(GroupByTest.class, "GroupByTest")) { |
| protected void decorateSQL(Statement s) |
| throws SQLException |
| { |
| createSchemaObjects(s); |
| } |
| }; |
| } |
| |
| String [][] expRS; |
| String [] expColNames; |
| |
| /** |
| * Creates a variety of tables used by the various GroupBy tests |
| * @throws SQLException |
| */ |
| private static void createSchemaObjects(Statement st) |
| throws SQLException |
| { |
| st.executeUpdate("create table bug280 (a int, b int)"); |
| st.executeUpdate("insert into bug280 (a, b) " + |
| "values (1,1), (1,2), (1,3), (2,1), (2,2)"); |
| st.executeUpdate("CREATE TABLE A2937 (C CHAR(10) NOT NULL, " + |
| "D DATE NOT NULL, DC DECIMAL(6,2))"); |
| st.executeUpdate("INSERT INTO A2937 VALUES ('aaa', " + |
| "DATE('2007-07-10'), 500.00)"); |
| st.executeUpdate("create table yy (a double, b double)"); |
| st.executeUpdate("insert into yy values (2,4), (2, 4), " + |
| "(5,7), (2,3), (2,3), (2,3), (2,3), (9,7)"); |
| |
| st.executeUpdate("create table t1 (a int, b int, c int)"); |
| st.executeUpdate("create table t2 (a int, b int, c int)"); |
| st.executeUpdate("insert into t2 values (1,1,1), (2,2,2)"); |
| |
| st.executeUpdate("create table unmapped(c1 long varchar)"); |
| st.executeUpdate("create table t_twoints(c1 int, c2 int)"); |
| st.executeUpdate("create table t5920(c int, d int)"); |
| st.executeUpdate("insert into t5920(c,d) values " |
| + "(1,10),(2,20),(2,20),(3,30),(3,30),(3,30)"); |
| st.executeUpdate("create table t5653 (c1 float)"); |
| st.executeUpdate("insert into t5653 values 0.0, 90.0"); |
| |
| st.executeUpdate("create table d3613 (a int, b int, c int, d int)"); |
| st.executeUpdate("insert into d3613 values (1,2,1,2), (1,2,3,4), " + |
| "(1,3,5,6), (2,2,2,2)"); |
| |
| st.executeUpdate("create table d2085 (a int, b int, c int, d int)"); |
| st.executeUpdate("insert into d2085 values (1,1,1,1), (1,2,3,4), " + |
| "(4,3,2,1), (2,2,2,2)"); |
| |
| st.execute("create table d3219 (a varchar(10), b varchar(1000))"); |
| |
| st.execute("CREATE TABLE d3904_T1( " + |
| "D1 DATE NOT NULL PRIMARY KEY, N1 VARCHAR( 10 ))"); |
| st.execute("CREATE TABLE d3904_T2( " + |
| "D2 DATE NOT NULL PRIMARY KEY, N2 VARCHAR( 10 ))"); |
| st.execute("INSERT INTO d3904_T1 VALUES "+ |
| "( DATE( '2008-10-01' ), 'something' ), "+ |
| "( DATE( '2008-10-02' ), 'something' )" ); |
| st.execute("INSERT INTO d3904_T2 VALUES" + |
| "( DATE( '2008-10-01' ), 'something' )" ); |
| |
| st.executeUpdate("create table d2457_o (name varchar(20), ord int)"); |
| st.executeUpdate("create table d2457_a (ord int, amount int)"); |
| st.executeUpdate("insert into d2457_o values ('John', 1)," + |
| " ('Jerry', 2), ('Jerry', 3), ('John', 4), ('John', 5)"); |
| st.executeUpdate("insert into d2457_a values (1, 12), (2, 23), " + |
| "(3, 34), (4, 45), (5, 56)"); |
| |
| st.executeUpdate("create table d4071(i int, v char(10))"); |
| st.executeUpdate("insert into d4071 " + |
| " values (1, '0123456789')," + |
| " (1, '1234567890')," + |
| " (3, '2345678901')," + |
| " (4, '0123456789')," + |
| " (5, '1234567890')"); |
| |
| |
| // create an all types tables |
| |
| st.executeUpdate( |
| "create table t (i int, s smallint, l bigint, c " |
| + "char(10), v varchar(50), lvc long varchar, d double " |
| + "precision, r real, dt date, t time, ts timestamp, b " |
| + "char(2) for bit data, bv varchar(2) for bit data, " |
| + "lbv long varchar for bit data)"); |
| |
| st.executeUpdate( |
| " create table tab1 ( i integer, s smallint, l " |
| + "bigint, c char(30), v varchar(30), lvc long " |
| + "varchar, d double precision, r real, dt date, t " |
| + "time, ts timestamp)"); |
| |
| // populate tables |
| |
| st.executeUpdate("insert into t (i) values (null)"); |
| st.executeUpdate("insert into t (i) values (null)"); |
| |
| st.executeUpdate( |
| " insert into t values (0, 100, 1000000, 'hello', " |
| + "'everyone is here', 'what the heck do we care?', " |
| + "200.0e0, 200.0e0, date('1992-01-01'), " |
| + "time('12:30:30'), timestamp('1992-01-01 12:30:30'), " |
| + "X'12af', X'0f0f', X'ABCD')"); |
| |
| st.executeUpdate( |
| " insert into t values (0, 100, 1000000, 'hello', " |
| + "'everyone is here', 'what the heck do we care?', " |
| + "200.0e0, 200.0e0, date('1992-01-01'), " |
| + "time('12:30:30'), timestamp('1992-01-01 12:30:30'), " |
| + "X'12af', X'0f0f', X'ABCD')"); |
| |
| st.executeUpdate( |
| " insert into t values (1, 100, 1000000, 'hello', " |
| + "'everyone is here', 'what the heck do we care?', " |
| + "200.0e0, 200.0e0, date('1992-01-01'), " |
| + "time('12:30:30'), timestamp('1992-01-01 12:30:30'), " |
| + "X'12af', X'0f0f', X'ABCD')"); |
| |
| st.executeUpdate( |
| " insert into t values (0, 200, 1000000, 'hello', " |
| + "'everyone is here', 'what the heck do we care?', " |
| + "200.0e0, 200.0e0, date('1992-01-01'), " |
| + "time('12:30:30'), timestamp('1992-01-01 12:30:30'), " |
| + "X'12af', X'0f0f', X'ABCD')"); |
| |
| st.executeUpdate( |
| " insert into t values (0, 100, 2000000, 'hello', " |
| + "'everyone is here', 'what the heck do we care?', " |
| + "200.0e0, 200.0e0, date('1992-01-01'), " |
| + "time('12:30:30'), timestamp('1992-01-01 12:30:30'), " |
| + "X'12af', X'0f0f', X'ABCD')"); |
| |
| st.executeUpdate( |
| " insert into t values (0, 100, 1000000, 'goodbye', " |
| + "'everyone is here', 'adios, muchachos', 200.0e0, " |
| + "200.0e0, date('1992-01-01'), time('12:30:30'), " |
| + "timestamp('1992-01-01 12:30:30'), X'12af', X'0f0f', X'ABCD')"); |
| |
| st.executeUpdate( |
| " insert into t values (0, 100, 1000000, 'hello', " |
| + "'noone is here', 'what the heck do we care?', " |
| + "200.0e0, 200.0e0, date('1992-01-01'), " |
| + "time('12:30:30'), timestamp('1992-01-01 12:30:30'), " |
| + "X'12af', X'0f0f', X'ABCD')"); |
| |
| st.executeUpdate( |
| " insert into t values (0, 100, 1000000, 'hello', " |
| + "'everyone is here', 'what the heck do we care?', " |
| + "200.0e0, 200.0e0, date('1992-01-01'), " |
| + "time('12:30:30'), timestamp('1992-01-01 12:30:30'), " |
| + "X'12af', X'0f0f', X'ABCD')"); |
| |
| st.executeUpdate( |
| " insert into t values (0, 100, 1000000, 'hello', " |
| + "'everyone is here', 'what the heck do we care?', " |
| + "100.0e0, 200.0e0, date('1992-01-01'), " |
| + "time('12:30:30'), timestamp('1992-01-01 12:30:30'), " |
| + "X'12af', X'0f0f', X'ABCD')"); |
| |
| st.executeUpdate( |
| " insert into t values (0, 100, 1000000, 'hello', " |
| + "'everyone is here', 'what the heck do we care?', " |
| + "200.0e0, 100.0e0, date('1992-01-01'), " |
| + "time('12:30:30'), timestamp('1992-01-01 12:30:30'), " |
| + "X'12af', X'0f0f', X'ABCD')"); |
| |
| st.executeUpdate( |
| " insert into t values (0, 100, 1000000, 'hello', " |
| + "'everyone is here', 'what the heck do we care?', " |
| + "200.0e0, 200.0e0, date('1992-09-09'), " |
| + "time('12:30:30'), timestamp('1992-01-01 12:30:30'), " |
| + "X'12af', X'0f0f', X'ABCD')"); |
| |
| st.executeUpdate( |
| " insert into t values (0, 100, 1000000, 'hello', " |
| + "'everyone is here', 'what the heck do we care?', " |
| + "200.0e0, 200.0e0, date('1992-01-01'), " |
| + "time('12:55:55'), timestamp('1992-01-01 12:30:30'), " |
| + "X'12af', X'0f0f', X'ABCD')"); |
| |
| st.executeUpdate( |
| " insert into t values (0, 100, 1000000, 'hello', " |
| + "'everyone is here', 'what the heck do we care?', " |
| + "200.0e0, 200.0e0, date('1992-01-01'), " |
| + "time('12:30:30'), timestamp('1992-01-01 12:55:55'), " |
| + "X'12af', X'0f0f', X'ABCD')"); |
| |
| st.executeUpdate( |
| " insert into t values (0, 100, 1000000, 'hello', " |
| + "'everyone is here', 'what the heck do we care?', " |
| + "200.0e0, 200.0e0, date('1992-01-01'), " |
| + "time('12:30:30'), timestamp('1992-01-01 12:30:30'), " |
| + "X'ffff', X'0f0f', X'1234')"); |
| |
| st.executeUpdate( |
| " insert into t values (0, 100, 1000000, 'hello', " |
| + "'everyone is here', 'what the heck do we care?', " |
| + "200.0e0, 200.0e0, date('1992-01-01'), " |
| + "time('12:30:30'), timestamp('1992-01-01 12:30:30'), " |
| + "X'12af', X'ffff', X'ABCD')"); |
| |
| // bit maps to Byte[], so can't test for now |
| |
| st.executeUpdate( |
| "insert into tab1 select i, s, l, c, v, lvc, d, r, " |
| + "dt, t, ts from t"); |
| |
| //Following setup is for DERBY-3872 |
| st.executeUpdate( |
| "CREATE TABLE EMPTAB (EMPID INTEGER NOT NULL, " |
| + "SALARY DECIMAL(10, 4), DEPT_DEPTNO INTEGER)"); |
| |
| st.executeUpdate( |
| "ALTER TABLE EMPTAB ADD CONSTRAINT " + |
| "PK_EMPTAB PRIMARY KEY (EMPID)"); |
| |
| st.executeUpdate( |
| "CREATE TABLE DEPTTAB (DEPTNO INTEGER NOT NULL)"); |
| |
| st.executeUpdate( |
| "ALTER TABLE DEPTTAB ADD CONSTRAINT "+ |
| "PK_DEPTTAB PRIMARY KEY (DEPTNO)"); |
| |
| st.executeUpdate( |
| "insert into DEPTTAB values( 1 )"); |
| |
| 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)"); |
| |
| // for DERBY-3631 testing |
| st.executeUpdate("CREATE FUNCTION MAXOF2(ONE DOUBLE, TWO DOUBLE) RETURNS DOUBLE PARAMETER STYLE JAVA NO SQL LANGUAGE JAVA EXTERNAL NAME 'java.lang.Math.max'"); |
| st.executeUpdate("CREATE TABLE Testd3631( GroupCol INT, Value1 INT, Value2 INT )"); |
| st.executeUpdate("INSERT INTO Testd3631 VALUES (1, 1, 5)"); |
| st.executeUpdate("INSERT INTO Testd3631 VALUES (2, -7, 2)"); |
| st.executeUpdate("INSERT INTO Testd3631 VALUES (2, 1, -5)"); |
| |
| } |
| |
| /** |
| * Test various invalid GROUP BY statements. |
| * @throws Exception |
| */ |
| public void testGroupByErrors() |
| throws Exception |
| { |
| Statement st = createStatement(); |
| |
| // group by constant. should compile but fail because it |
| // is not a valid grouping expression. |
| |
| assertStatementError("42Y36", st, |
| "select * from t1 group by 1"); |
| |
| // column in group by list not in from list |
| |
| assertStatementError("42X04", st, |
| "select a as d from t1 group by d"); |
| |
| // column in group by list not in select list |
| |
| assertStatementError("42Y36", st, |
| "select a as b from t1 group by b"); |
| |
| assertStatementError("42Y36", st, |
| " select a from t1 group by b"); |
| |
| assertStatementError("42Y36", st, |
| " select a, char(b) from t1 group by a"); |
| |
| // cursor with group by is not updatable |
| |
| assertCompileError("42Y90", |
| "select a from t1 group by a for update"); |
| |
| // noncorrelated subquery that returns too many rows |
| |
| assertStatementError("21000", st, |
| "select a, (select a from t2) from t1 group by a"); |
| |
| // correlation on outer table |
| |
| assertStatementError("42Y30", st, |
| "select t2.a, (select b from t1 where t1.b = t2.b) " |
| + "from t1 t2 group by t2.a"); |
| |
| // having clause cannot contain column references which |
| // are not grouping columns |
| |
| assertStatementError("42X24", st, |
| "select a from t1 group by a having c = 1"); |
| |
| assertStatementError("42X04", st, |
| " select a from t1 o group by a having a = (select a " |
| + "from t1 where b = b.o)"); |
| |
| // ?s in group by |
| |
| assertStatementError("42X01", st, |
| "select a from t1 group by ?"); |
| |
| // group by on long varchar type |
| |
| assertStatementError("X0X67", st, |
| " select c1, max(1) from unmapped group by c1"); |
| |
| // group by on aggregate |
| assertCompileError("42Y26", "select sum(a) from t1 group by sum(a)"); |
| |
| // group by on subquery (DERBY-4403) |
| assertCompileError("42Y26", |
| "select sum(a) from t1 group by (select a from t1)"); |
| } |
| |
| /** |
| * Verify the correct behavior of GROUP BY with various datatypes. |
| * @throws Exception |
| */ |
| public void testGroupByWithVariousDatatypes() |
| throws Exception |
| { |
| Statement st = createStatement(); |
| ResultSet rs = null; |
| |
| // Test group by and having clauses with no aggregates |
| |
| // simple grouping |
| |
| rs = st.executeQuery( |
| "select i from t group by i order by i"); |
| |
| expColNames = new String [] {"I"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"0"}, |
| {"1"}, |
| {null} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| rs = st.executeQuery( |
| " select s from t group by s order by s"); |
| |
| expColNames = new String [] {"S"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"100"}, |
| {"200"}, |
| {null} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| rs = st.executeQuery( |
| " select l from t group by l order by l"); |
| |
| expColNames = new String [] {"L"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"1000000"}, |
| {"2000000"}, |
| {null} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| rs = st.executeQuery( |
| " select c from t group by c order by c"); |
| |
| expColNames = new String [] {"C"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"goodbye"}, |
| {"hello"}, |
| {null} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| rs = st.executeQuery( |
| " select v from t group by v order by v"); |
| |
| expColNames = new String [] {"V"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"everyone is here"}, |
| {"noone is here"}, |
| {null} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| rs = st.executeQuery( |
| " select d from t group by d order by d"); |
| |
| expColNames = new String [] {"D"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"100.0"}, |
| {"200.0"}, |
| {null} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| rs = st.executeQuery( |
| " select r from t group by r order by r"); |
| |
| expColNames = new String [] {"R"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"100.0"}, |
| {"200.0"}, |
| {null} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| rs = st.executeQuery( |
| " select dt from t group by dt order by dt"); |
| |
| expColNames = new String [] {"DT"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"1992-01-01"}, |
| {"1992-09-09"}, |
| {null} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| rs = st.executeQuery( |
| " select t from t group by t order by t"); |
| |
| expColNames = new String [] {"T"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"12:30:30"}, |
| {"12:55:55"}, |
| {null} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| rs = st.executeQuery( |
| " select ts from t group by ts order by ts"); |
| |
| expColNames = new String [] {"TS"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"1992-01-01 12:30:30.0"}, |
| {"1992-01-01 12:55:55.0"}, |
| {null} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| rs = st.executeQuery( |
| " select b from t group by b order by b"); |
| |
| expColNames = new String [] {"B"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"12af"}, |
| {"ffff"}, |
| {null} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| rs = st.executeQuery( |
| " select bv from t group by bv order by bv"); |
| |
| expColNames = new String [] {"BV"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"0f0f"}, |
| {"ffff"}, |
| {null} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| // grouping by long varchar [for bit data] cols should |
| // fail in db2 mode |
| |
| assertStatementError("X0X67", st, |
| "select lbv from t group by lbv order by lbv"); |
| st.close(); |
| } |
| |
| /** |
| * Test multicolumn grouping. |
| * @throws Exception |
| */ |
| public void testMulticolumnGrouping() |
| throws Exception |
| { |
| Statement st = createStatement(); |
| ResultSet rs = null; |
| |
| rs = st.executeQuery( |
| "select i, dt, b from t where 1=1 group by i, dt, b " |
| + "order by i,dt,b"); |
| |
| expColNames = new String [] {"I", "DT", "B"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"0", "1992-01-01", "12af"}, |
| {"0", "1992-01-01", "ffff"}, |
| {"0", "1992-09-09", "12af"}, |
| {"1", "1992-01-01", "12af"}, |
| {null, null, null} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| rs = st.executeQuery( |
| " select i, dt, b from t group by i, dt, b order by i,dt,b"); |
| |
| expColNames = new String [] {"I", "DT", "B"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"0", "1992-01-01", "12af"}, |
| {"0", "1992-01-01", "ffff"}, |
| {"0", "1992-09-09", "12af"}, |
| {"1", "1992-01-01", "12af"}, |
| {null, null, null} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| rs = st.executeQuery( |
| " select i, dt, b from t group by b, i, dt order by i,dt,b"); |
| |
| expColNames = new String [] {"I", "DT", "B"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"0", "1992-01-01", "12af"}, |
| {"0", "1992-01-01", "ffff"}, |
| {"0", "1992-09-09", "12af"}, |
| {"1", "1992-01-01", "12af"}, |
| {null, null, null} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| rs = st.executeQuery( |
| " select i, dt, b from t group by dt, i, b order by i,dt,b"); |
| |
| expColNames = new String [] {"I", "DT", "B"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"0", "1992-01-01", "12af"}, |
| {"0", "1992-01-01", "ffff"}, |
| {"0", "1992-09-09", "12af"}, |
| {"1", "1992-01-01", "12af"}, |
| {null, null, null} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| st.close(); |
| } |
| |
| /** |
| * Test the use of a subquery to group by an expression. |
| * @throws Exception |
| */ |
| public void testGroupByExpression() |
| throws Exception |
| { |
| Statement st = createStatement(); |
| ResultSet rs = null; |
| |
| rs = st.executeQuery( |
| "select expr1, expr2 from (select i * s, c || v from " |
| + "t) t (expr1, expr2) group by expr2, expr1 order by " |
| + "expr2,expr1"); |
| |
| expColNames = new String [] {"EXPR1", "EXPR2"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"0", "goodbye everyone is here"}, |
| {"0", "hello everyone is here"}, |
| {"100", "hello everyone is here"}, |
| {"0", "hello noone is here"}, |
| {null, null} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| st.close(); |
| } |
| |
| /** |
| * Test using GROUP BY in a correlated subquery. |
| * @throws Exception |
| */ |
| public void testGroupByCorrelatedSubquery() |
| throws Exception |
| { |
| Statement st = createStatement(); |
| ResultSet rs = null; |
| |
| rs = st.executeQuery( |
| "select i, expr1 from (select i, (select distinct i " |
| + "from t m where m.i = t.i) from t) t (i, expr1) " |
| + "group by i, expr1 order by i,expr1"); |
| |
| expColNames = new String [] {"I", "EXPR1"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"0", "0"}, |
| {"1", "1"}, |
| {null, null} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| st.close(); |
| } |
| |
| /** |
| * Test GROUP BY and DISTINCT. |
| * @throws Exception |
| */ |
| public void testGroupByDistinct() |
| throws Exception |
| { |
| Statement st = createStatement(); |
| ResultSet rs = null; |
| |
| rs = st.executeQuery( |
| "select distinct i, dt, b from t group by i, dt, b " |
| + "order by i,dt,b"); |
| |
| expColNames = new String [] {"I", "DT", "B"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"0", "1992-01-01", "12af"}, |
| {"0", "1992-01-01", "ffff"}, |
| {"0", "1992-09-09", "12af"}, |
| {"1", "1992-01-01", "12af"}, |
| {null, null, null} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| st.close(); |
| } |
| |
| /** |
| * Test combinations of GROUP BY and ORDER BY. |
| * @throws Exception |
| */ |
| public void testGroupByOrderBy() |
| throws Exception |
| { |
| Statement st = createStatement(); |
| ResultSet rs = null; |
| |
| // order by and group by same order |
| |
| rs = st.executeQuery( |
| "select i, dt, b from t group by i, dt, b order by i, dt, b"); |
| |
| expColNames = new String [] {"I", "DT", "B"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"0", "1992-01-01", "12af"}, |
| {"0", "1992-01-01", "ffff"}, |
| {"0", "1992-09-09", "12af"}, |
| {"1", "1992-01-01", "12af"}, |
| {null, null, null} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| // subset in same order |
| |
| rs = st.executeQuery( |
| "select i, dt, b from t group by i, dt, b order by i, dt"); |
| |
| expColNames = new String [] {"I", "DT", "B"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"0", "1992-01-01", "12af"}, |
| {"0", "1992-01-01", "ffff"}, |
| {"0", "1992-09-09", "12af"}, |
| {"1", "1992-01-01", "12af"}, |
| {null, null, null} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| // different order |
| |
| rs = st.executeQuery( |
| "select i, dt, b from t group by i, dt, b order by b, dt, i"); |
| |
| expColNames = new String [] {"I", "DT", "B"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"0", "1992-01-01", "12af"}, |
| {"1", "1992-01-01", "12af"}, |
| {"0", "1992-09-09", "12af"}, |
| {"0", "1992-01-01", "ffff"}, |
| {null, null, null} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| // subset in different order |
| |
| rs = st.executeQuery( |
| "select i, dt, b from t group by i, dt, b order by b, dt"); |
| |
| expColNames = new String [] {"I", "DT", "B"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"0", "1992-01-01", "12af"}, |
| {"1", "1992-01-01", "12af"}, |
| {"0", "1992-09-09", "12af"}, |
| {"0", "1992-01-01", "ffff"}, |
| {null, null, null} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| st.close(); |
| } |
| |
| /** |
| * group by without having in from subquery. |
| * @throws Exception |
| */ |
| public void testGroupByInSubquery() |
| throws Exception |
| { |
| Statement st = createStatement(); |
| ResultSet rs = null; |
| |
| |
| rs = st.executeQuery( |
| "select * from (select i, dt from t group by i, dt) " |
| + "t (t_i, t_dt), (select i, dt from t group by i, dt) " |
| + "m (m_i, m_dt) where t_i = m_i and t_dt = m_dt order " |
| + "by t_i,t_dt,m_i,m_dt"); |
| |
| expColNames = new String [] {"T_I", "T_DT", "M_I", "M_DT"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"0", "1992-01-01", "0", "1992-01-01"}, |
| {"0", "1992-09-09", "0", "1992-09-09"}, |
| {"1", "1992-01-01", "1", "1992-01-01"} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| rs = st.executeQuery( |
| " select * from (select i, dt from t group by i, dt) " |
| + "t (t_i, t_dt), (select i, dt from t group by i, dt) " |
| + "m (m_i, m_dt) group by t_i, t_dt, m_i, m_dt order " |
| + "by t_i,t_dt,m_i,m_dt"); |
| |
| expColNames = new String [] {"T_I", "T_DT", "M_I", "M_DT"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"0", "1992-01-01", "0", "1992-01-01"}, |
| {"0", "1992-01-01", "0", "1992-09-09"}, |
| {"0", "1992-01-01", "1", "1992-01-01"}, |
| {"0", "1992-01-01", null, null}, |
| {"0", "1992-09-09", "0", "1992-01-01"}, |
| {"0", "1992-09-09", "0", "1992-09-09"}, |
| {"0", "1992-09-09", "1", "1992-01-01"}, |
| {"0", "1992-09-09", null, null}, |
| {"1", "1992-01-01", "0", "1992-01-01"}, |
| {"1", "1992-01-01", "0", "1992-09-09"}, |
| {"1", "1992-01-01", "1", "1992-01-01"}, |
| {"1", "1992-01-01", null, null}, |
| {null, null, "0", "1992-01-01"}, |
| {null, null, "0", "1992-09-09"}, |
| {null, null, "1", "1992-01-01"}, |
| {null, null, null, null} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| rs = st.executeQuery( |
| " select * from (select i, dt from t group by i, dt) " |
| + "t (t_i, t_dt), (select i, dt from t group by i, dt) " |
| + "m (m_i, m_dt) where t_i = m_i and t_dt = m_dt group " |
| + "by t_i, t_dt, m_i, m_dt order by t_i,t_dt,m_i,m_dt"); |
| |
| expColNames = new String [] {"T_I", "T_DT", "M_I", "M_DT"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"0", "1992-01-01", "0", "1992-01-01"}, |
| {"0", "1992-09-09", "0", "1992-09-09"}, |
| {"1", "1992-01-01", "1", "1992-01-01"} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| rs = st.executeQuery( |
| " select t.*, m.* from (select i, dt from t group by " |
| + "i, dt) t (t_i, t_dt), (select i, dt from t group by " |
| + "i, dt) m (t_i, t_dt) where t.t_i = m.t_i and t.t_dt " |
| + "= m.t_dt group by t.t_i, t.t_dt, m.t_i, m.t_dt " |
| + "order by t.t_i,t.t_dt,m.t_i,m.t_dt"); |
| |
| expColNames = new String [] {"T_I", "T_DT", "T_I", "T_DT"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"0", "1992-01-01", "0", "1992-01-01"}, |
| {"0", "1992-09-09", "0", "1992-09-09"}, |
| {"1", "1992-01-01", "1", "1992-01-01"} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| rs = st.executeQuery( |
| " select t.t_i, t.t_dt, m.* from (select i, dt from " |
| + "t group by i, dt) t (t_i, t_dt), (select i, dt from " |
| + "t group by i, dt) m (t_i, t_dt) where t.t_i = m.t_i " |
| + "and t.t_dt = m.t_dt group by t.t_i, t.t_dt, m.t_i, " |
| + "m.t_dt order by t.t_i,t.t_dt,m.t_i,m.t_dt"); |
| |
| expColNames = new String [] {"T_I", "T_DT", "T_I", "T_DT"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"0", "1992-01-01", "0", "1992-01-01"}, |
| {"0", "1992-09-09", "0", "1992-09-09"}, |
| {"1", "1992-01-01", "1", "1992-01-01"} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| st.close(); |
| } |
| |
| /** |
| * additional columns in group by list not in select list. |
| * @throws Exception |
| */ |
| public void testGroupByWithAdditionalColumns() |
| throws Exception |
| { |
| Statement st = createStatement(); |
| ResultSet rs = null; |
| |
| rs = st.executeQuery( |
| "select i, dt, b from t group by i, dt, b order by i,dt,b"); |
| |
| expColNames = new String [] {"I", "DT", "B"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"0", "1992-01-01", "12af"}, |
| {"0", "1992-01-01", "ffff"}, |
| {"0", "1992-09-09", "12af"}, |
| {"1", "1992-01-01", "12af"}, |
| {null, null, null} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| rs = st.executeQuery( |
| " select t.i from t group by i, dt, b order by i"); |
| |
| expColNames = new String [] {"I"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"0"}, |
| {"0"}, |
| {"0"}, |
| {"1"}, |
| {null} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| rs = st.executeQuery( |
| " select t.dt from t group by i, dt, b order by dt"); |
| |
| expColNames = new String [] {"DT"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"1992-01-01"}, |
| {"1992-01-01"}, |
| {"1992-01-01"}, |
| {"1992-09-09"}, |
| {null} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| rs = st.executeQuery( |
| " select t.b from t group by i, dt, b order by b"); |
| |
| expColNames = new String [] {"B"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"12af"}, |
| {"12af"}, |
| {"12af"}, |
| {"ffff"}, |
| {null} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| rs = st.executeQuery( |
| " select t.t_i, m.t_i from (select i, dt from t " |
| + "group by i, dt) t (t_i, t_dt), (select i, dt from t " |
| + "group by i, dt) m (t_i, t_dt) where t.t_i = m.t_i " |
| + "and t.t_dt = m.t_dt group by t.t_i, t.t_dt, m.t_i, " |
| + "m.t_dt order by t.t_i,m.t_i"); |
| |
| expColNames = new String [] {"T_I", "T_I"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"0", "0"}, |
| {"0", "0"}, |
| {"1", "1"} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| st.close(); |
| } |
| |
| /** |
| * Test parameter markers in the having clause. |
| * @throws Exception |
| */ |
| public void testParameterMarkersInHavingClause() |
| throws Exception |
| { |
| ResultSet rs = null; |
| |
| PreparedStatement pSt = prepareStatement( |
| "select i, dt, b from t group by i, dt, b having i = " |
| + "? order by i,dt,b"); |
| |
| pSt.setInt(1, 0); |
| |
| rs = pSt.executeQuery(); |
| expColNames = new String [] {"I", "DT", "B"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"0", "1992-01-01", "12af"}, |
| {"0", "1992-01-01", "ffff"}, |
| {"0", "1992-09-09", "12af"} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| pSt.close(); |
| } |
| |
| /** |
| * group by with having in from subquery. |
| * @throws Exception |
| */ |
| public void testHavingClauseInSubquery() |
| throws Exception |
| { |
| Statement st = createStatement(); |
| ResultSet rs = null; |
| |
| rs = st.executeQuery( |
| "select * from (select i, dt from t group by i, dt " |
| + "having 1=1) t (t_i, t_dt), (select i, dt from t " |
| + "group by i, dt having i = 0) m (m_i, m_dt) where " |
| + "t_i = m_i and t_dt = m_dt order by t_i,t_dt,m_i,m_dt"); |
| |
| expColNames = new String [] {"T_I", "T_DT", "M_I", "M_DT"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"0", "1992-01-01", "0", "1992-01-01"}, |
| {"0", "1992-09-09", "0", "1992-09-09"} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| rs = st.executeQuery( |
| " select * from (select i, dt from t group by i, dt " |
| + "having 1=1) t (t_i, t_dt), (select i, dt from t " |
| + "group by i, dt having i = 0) m (m_i, m_dt) group by " |
| + "t_i, t_dt, m_i, m_dt order by t_i,t_dt,m_i,m_dt"); |
| |
| expColNames = new String [] {"T_I", "T_DT", "M_I", "M_DT"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"0", "1992-01-01", "0", "1992-01-01"}, |
| {"0", "1992-01-01", "0", "1992-09-09"}, |
| {"0", "1992-09-09", "0", "1992-01-01"}, |
| {"0", "1992-09-09", "0", "1992-09-09"}, |
| {"1", "1992-01-01", "0", "1992-01-01"}, |
| {"1", "1992-01-01", "0", "1992-09-09"}, |
| {null, null, "0", "1992-01-01"}, |
| {null, null, "0", "1992-09-09"} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| rs = st.executeQuery( |
| " select * from (select i, dt from t group by i, dt " |
| + "having 1=1) t (t_i, t_dt), (select i, dt from t " |
| + "group by i, dt having i = 0) m (m_i, m_dt) where " |
| + "t_i = m_i and t_dt = m_dt group by t_i, t_dt, m_i, " |
| + "m_dt having t_i * m_i = m_i * t_i order by t_i,t_dt,m_i,m_dt"); |
| |
| expColNames = new String [] {"T_I", "T_DT", "M_I", "M_DT"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"0", "1992-01-01", "0", "1992-01-01"}, |
| {"0", "1992-09-09", "0", "1992-09-09"} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| //Test case for DERBY-3872 Prior to fix for DERBY-3872, following |
| //query resulted in NPE because of missing chain of |
| //VirtualColumn-to-ResultColumn nodes for the where clause in |
| //the HAVING clause. The reason for this that we didn't overwrite |
| //the method "accept()" in IndexToBaseRowNode. This missing code |
| //caused Derby to associate the ResultColumn for the HAVING |
| //clause incorrectly with the ResultColumn used for the join |
| //clause. More info can be found in the jira |
| rs = st.executeQuery( |
| "select q1.DEPTNO from DEPTTAB q1, EMPTAB q2 where "+ |
| "( integer (1.1) = 1) and ( q2.DEPT_DEPTNO = q1.DEPTNO) "+ |
| " GROUP BY q1.DEPTNO HAVING max( q2.SALARY) >= "+ |
| "( select q3.SALARY from EMPTAB q3 where "+ |
| "(q3.EMPID = q1.DEPTNO) )"); |
| |
| expRS = new String [][] |
| { |
| {"1"} |
| }; |
| JDBC.assertFullResultSet(rs, expRS, true); |
| st.close(); |
| } |
| |
| /** |
| * correlated subquery in having clause. |
| * @throws Exception |
| */ |
| public void testCorrelatedSubqueryInHavingClause() |
| throws Exception |
| { |
| Statement st = createStatement(); |
| ResultSet rs = null; |
| |
| rs = st.executeQuery( |
| "select i, dt from t group by i, dt having i = " |
| + "(select distinct i from tab1 where t.i = tab1.i) " |
| + "order by i,dt"); |
| |
| expColNames = new String [] {"I", "DT"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"0", "1992-01-01"}, |
| {"0", "1992-09-09"}, |
| {"1", "1992-01-01"} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| rs = st.executeQuery( |
| " select i, dt from t group by i, dt having i = " |
| + "(select i from t m group by i having t.i = m.i) " |
| + "order by i,dt"); |
| |
| expColNames = new String [] {"I", "DT"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"0", "1992-01-01"}, |
| {"0", "1992-09-09"}, |
| {"1", "1992-01-01"} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| st.close(); |
| } |
| |
| /** |
| * column references in having clause match columns in group by list. |
| * @throws Exception |
| */ |
| public void testHavingClauseColumnRef() |
| throws Exception |
| { |
| Statement st = createStatement(); |
| ResultSet rs = null; |
| |
| rs = st.executeQuery( |
| "select i as outer_i, dt from t group by i, dt " |
| + "having i = (select i from t m group by i having t.i " |
| + "= m.i) order by outer_i,dt"); |
| |
| expColNames = new String [] {"OUTER_I", "DT"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"0", "1992-01-01"}, |
| {"0", "1992-09-09"}, |
| {"1", "1992-01-01"} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| st.close(); |
| } |
| |
| /** |
| * additional columns in group by list not in select list. |
| * @throws Exception |
| */ |
| public void testGroupByColumnsNotInSelectList() |
| throws Exception |
| { |
| Statement st = createStatement(); |
| ResultSet rs = null; |
| |
| rs = st.executeQuery( |
| "select i, dt from t group by i, dt order by i,dt"); |
| |
| expColNames = new String [] {"I", "DT"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"0", "1992-01-01"}, |
| {"0", "1992-09-09"}, |
| {"1", "1992-01-01"}, |
| {null, null} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| rs = st.executeQuery( |
| " select t.dt from t group by i, dt having i = 0 " |
| + "order by t.dt"); |
| |
| expColNames = new String [] {"DT"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"1992-01-01"}, |
| {"1992-09-09"} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| rs = st.executeQuery( |
| " select t.dt from t group by i, dt having i <> 0 " |
| + "order by t.dt"); |
| |
| expColNames = new String [] {"DT"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"1992-01-01"} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| rs = st.executeQuery( |
| " select t.dt from t group by i, dt having i != 0 " |
| + "order by t.dt"); |
| |
| expColNames = new String [] {"DT"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"1992-01-01"} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| st.close(); |
| } |
| |
| /** |
| * negative tests for selects with a having clause without a group by. |
| * @throws Exception |
| */ |
| public void testInvalidHavingClauses() |
| throws Exception |
| { |
| Statement st = createStatement(); |
| |
| // binding of having clause |
| |
| assertStatementError("42X19", st, |
| "select 1 from t_twoints having 1"); |
| |
| // column references in having clause not allowed if no |
| // group by |
| |
| assertStatementError("42Y35", st, |
| "select * from t_twoints having c1 = 1"); |
| |
| assertStatementError("42X24", st, |
| " select 1 from t_twoints having c1 = 1"); |
| |
| // correlated subquery in having clause |
| |
| assertStatementError("42Y35", st, |
| "select * from t_twoints t1_outer having 1 = (select 1 from " |
| + "t_twoints where c1 = t1_outer.c1)"); |
| st.close(); |
| } |
| |
| /** |
| * Tests for Bug 5653 restrictions. |
| * @throws Exception |
| */ |
| public void testHavingClauseRestrictions5653() |
| throws Exception |
| { |
| Statement st = createStatement(); |
| ResultSet rs = null; |
| |
| // bug 5653 test (almost useful) restrictions on a having |
| // clause without a group by clause create the table |
| |
| // this is the only query that should not fail filter out |
| // all rows |
| |
| rs = st.executeQuery( |
| "select 1 from t5653 having 1=0"); |
| |
| expColNames = new String [] {"1"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| JDBC.assertDrainResults(rs, 0); |
| |
| // all 6 queries below should fail after bug 5653 is fixed |
| // select * |
| |
| assertStatementError("42Y35", st, |
| "select * from t5653 having 1=1"); |
| |
| // select column |
| |
| assertStatementError("42Y35", st, |
| "select c1 from t5653 having 1=1"); |
| |
| // select with a built-in function sqrt |
| |
| assertStatementError("42Y35", st, |
| "select sqrt(c1) from t5653 having 1=1"); |
| |
| // non-correlated subquery in having clause |
| |
| assertStatementError("42Y35", st, |
| "select * from t5653 having 1 = (select 1 from t5653 where " |
| + "c1 = 0.0)"); |
| |
| // expression in select list |
| |
| assertStatementError("42Y35", st, |
| "select (c1 * c1) / c1 from t5653 where c1 <> 0 having 1=1"); |
| |
| // between |
| |
| assertStatementError("42Y35", st, |
| "select * from t5653 having 1 between 1 and 2"); |
| st.close(); |
| } |
| |
| /** |
| * bug 5920 test that HAVING without GROUPBY makes one group. |
| * @throws Exception |
| */ |
| public void testHavingWithoutGroupBy5920() |
| throws Exception |
| { |
| Statement st = createStatement(); |
| ResultSet rs = null; |
| |
| rs = st.executeQuery( |
| " select avg(c) from t5920 having 1 < 2"); |
| |
| expColNames = new String [] {"1"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"2"} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| // used to give several rows, now gives only one |
| |
| rs = st.executeQuery( |
| "select 10 from t5920 having 1 < 2"); |
| |
| expColNames = new String [] {"1"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"10"} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| |
| // ok, gives one row |
| |
| rs = st.executeQuery( |
| "select 10,avg(c) from t5920 having 1 < 2"); |
| |
| expColNames = new String [] {"1", "2"}; |
| JDBC.assertColumnNames(rs, expColNames); |
| |
| expRS = new String [][] |
| { |
| {"10", "2"} |
| }; |
| |
| JDBC.assertFullResultSet(rs, expRS, true); |
| st.close(); |
| } |
| |
| /** |
| * DERBY-5613: Queries with group by column not included in the column list |
| * for JOIN(INNER or OUTER) with NATURAL or USING does not fail |
| * |
| * Derby does not replace join columns in the select list with coalesce as |
| * suggested by SQL spec, instead it binds the join column with the left |
| * table when working with natural left outer join or inner join and it |
| * binds the join column with the right table when working with natural |
| * right outer join. This causes incorrect GROUP BY and HAVING queries |
| * to pass as shown below. |
| * |
| * The tests below show that GROUP BY and HAVING clauses are able to use a |
| * column which is not part of the SELECT list. This happens for USING |
| * clause and NATURAL joins with queries using INNER JOINS and OUTER JOINS. |
| * When using the JOIN with ON clause, we do not run into this problem |
| * because we are expected to qualify the JOIN column with table name |
| * in the SELECT list when using thw ON clause. |
| * |
| * @throws SQLException |
| */ |
| public void testGroupByWithUsingClause() throws SQLException { |
| Statement s = createStatement(); |
| //JOIN queries with ON clause do not cause ambiguity on join columns |
| // because such queries require that join columns in SELECT query |
| // should be qualified with left or right table name. Just a note |
| // that ON clause is not allowed on CROSS and NATURAL JOINS. |
| // |
| //The join queries with ON clause are not impacted by DERBY-5613 and |
| // hence following tests are showing the correct behavior. |
| // |
| //Try INNER JOIN with ON clause. |
| assertStatementError("42X03", s, |
| "select i from t1_D3880 " + |
| "inner join t2_D3880 ON t1_D3880.i = t2_D3880.i " + |
| "group by t1_D3880.i"); |
| ResultSet rs = s.executeQuery("select t1_D3880.i from t1_D3880 " + |
| "inner join t2_D3880 ON t1_D3880.i = t2_D3880.i " + |
| "group by t1_D3880.i"); |
| String[][] expRs = new String[][] {{"1"},{"2"}}; |
| JDBC.assertFullResultSet(rs,expRs); |
| //Try LEFT OUTER JOIN with ON clause. |
| assertStatementError("42X03", s, |
| "select i from t1_D3880 " + |
| "LEFT OUTER JOIN t2_D3880 ON t1_D3880.i = t2_D3880.i " + |
| "group by t1_D3880.i"); |
| rs = s.executeQuery("select t1_D3880.i from t1_D3880 " + |
| "LEFT OUTER JOIN t2_D3880 ON t1_D3880.i = t2_D3880.i " + |
| "group by t1_D3880.i"); |
| JDBC.assertFullResultSet(rs,expRs); |
| //Try RIGHT OUTER JOIN with ON clause. |
| assertStatementError("42X03", s, |
| "select i from t1_D3880 " + |
| "RIGHT OUTER JOIN t2_D3880 ON t1_D3880.i = t2_D3880.i " + |
| "group by t1_D3880.i"); |
| rs = s.executeQuery("select t1_D3880.i from t1_D3880 " + |
| "RIGHT OUTER JOIN t2_D3880 ON t1_D3880.i = t2_D3880.i " + |
| "group by t1_D3880.i"); |
| JDBC.assertFullResultSet(rs,expRs); |
| |
| //Test group by on a column which is not part of SELECT query (query |
| // uses USING clause). We see the incorrect behavior where the group |
| // by does not raise an error for using |
| // leftTable(orRightTable).joinColumn even though that column is not |
| // part of the SELECT list. Just a note that ON clause is not allowed |
| // on CROSS and NATURAL JOINS. |
| // |
| //Try INNER JOIN with USING clause. |
| //Following query should have given compile time error. |
| //Once DERBY-5613 is fixed, this query will run into compile time |
| // error for using t1_D3880.i in group by clause because that column |
| // is not part of the SELECT list. |
| rs = s.executeQuery("select i from t1_D3880 " + |
| "inner join t2_D3880 USING(i) group by t1_D3880.i"); |
| expRs = new String[][] {{"1"},{"2"}}; |
| JDBC.assertFullResultSet(rs,expRs); |
| //Following query does not allow t2_D3880.i in group by clause |
| // because join column i the select query gets associated with |
| // left table in case of INNER JOIN. |
| assertStatementError("42Y36", s, |
| "select i from t1_D3880 " + |
| "inner join t2_D3880 USING(i) group by t2_D3880.i"); |
| |
| //Test the GROUP BY problem with LEFT OUTER JOIN and USING clause. |
| //Following query should have given compile time error. |
| //Once DERBY-5613 is fixed, this query will run into compile time |
| // error for using t1_D3880.i in group by clause because that column |
| // is not part of the SELECT list. |
| rs = s.executeQuery("select i from t1_D3880 " + |
| "LEFT OUTER JOIN t2_D3880 USING(i) GROUP BY t1_D3880.i"); |
| JDBC.assertFullResultSet(rs,expRs); |
| //Following query does not allow t2_D3880.i in group by clause |
| // because join column i the select query gets associated with |
| // left table in case of LEFT OUTER JOIN. |
| assertStatementError("42Y36", s, |
| "select i from t1_D3880 " + |
| "LEFT OUTER JOIN t2_D3880 USING(i) GROUP BY t2_D3880.i"); |
| |
| //Test the GROUP BY problem with RIGHT OUTER JOIN and USING clause. |
| //Following query should have given compile time error. |
| //Once DERBY-5613 is fixed, this query will run into compile time |
| // error for using t2_D3880.i in group by clause because that column |
| // is not part of the SELECT list. |
| rs = s.executeQuery("select i from t1_D3880 " + |
| "RIGHT OUTER JOIN t2_D3880 USING(i) GROUP BY t2_D3880.i"); |
| JDBC.assertFullResultSet(rs,expRs); |
| //Following query does not allow t1_D3880.i in group by clause |
| // because join column i the select query gets associated with |
| // right table in case of RIGHT OUTER JOIN. |
| assertStatementError("42Y36", s, |
| "select i from t1_D3880 " + |
| "RIGHT OUTER JOIN t2_D3880 USING(i) GROUP BY t1_D3880.i"); |
| |
| //The correct queries for GROUP BY and USING clause |
| // |
| //INNER JOIN with USING clause. |
| rs = s.executeQuery("select t1_D3880.i from t1_D3880 " + |
| "inner join t2_D3880 USING(i) group by t1_D3880.i"); |
| JDBC.assertFullResultSet(rs,expRs); |
| //GROUP BY with LEFT OUTER JOIN and USING clause. |
| rs = s.executeQuery("select t1_D3880.i from t1_D3880 " + |
| "LEFT OUTER JOIN t2_D3880 USING(i) GROUP BY t1_D3880.i"); |
| JDBC.assertFullResultSet(rs,expRs); |
| //GROUP BY with RIGHT OUTER JOIN and USING clause. |
| rs = s.executeQuery("select t2_D3880.i from t1_D3880 " + |
| "RIGHT OUTER JOIN t2_D3880 USING(i) GROUP BY t2_D3880.i"); |
| JDBC.assertFullResultSet(rs,expRs); |
| |
| //Test group by on a column which is not part of SELECT query (query |
| // uses NATURAL JOIN). We see the incorrect behavior where the group |
| // by does not raise an error for using |
| // leftTable(orRightTable).joinColumn even though that column is not |
| // part of the SELECT list. Just a note that a CROSS JOIN can't be a |
| // NATURAL JOIN. |
| // |
| //Try the GROUP BY problem with NATURAL INNER JOIN |
| //Following query should have given compile time error. |
| //Once DERBY-5613 is fixed, this query will run into compile time |
| // error for using t1_D3880.i in group by clause because that column |
| // is not part of the SELECT list. |
| rs = s.executeQuery("select i from t1_D3880 " + |
| "NATURAL inner join t2_D3880 group by t1_D3880.i"); |
| JDBC.assertFullResultSet(rs,expRs); |
| //Test the GROUP BY problem with NATURAL LEFT OUTER JOIN |
| //Following query should have given compile time error. |
| //Once DERBY-5613 is fixed, this query will run into compile time |
| // error for using t1_D3880.i in group by clause because that column |
| // is not part of the SELECT list. |
| rs = s.executeQuery("select i from t1_D3880 " + |
| "NATURAL LEFT OUTER JOIN t2_D3880 GROUP BY t1_D3880.i"); |
| JDBC.assertFullResultSet(rs,expRs); |
| //Test the GROUP BY problem with NATURAL RIGHT OUTER JOIN |
| //Following query should have given compile time error. |
| //Once DERBY-5613 is fixed, this query will run into compile time |
| // error for using t2_D3880.i in group by clause because that column |
| // is not part of the SELECT list. |
| rs = s.executeQuery("select i from t1_D3880 " + |
| "NATURAL RIGHT OUTER JOIN t2_D3880 GROUP BY t2_D3880.i"); |
| JDBC.assertFullResultSet(rs,expRs); |
| |
| //The correct queries for GROUP BY and NATURAL JOIN |
| // |
| //NATURAL INNER JOIN |
| rs = s.executeQuery("select t1_D3880.i from t1_D3880 " + |
| "NATURAL inner join t2_D3880 group by t1_D3880.i"); |
| JDBC.assertFullResultSet(rs,expRs); |
| //NATURAL LEFT OUTER JOIN |
| rs = s.executeQuery("select t1_D3880.i from t1_D3880 " + |
| "NATURAL LEFT OUTER JOIN t2_D3880 GROUP BY t1_D3880.i"); |
| JDBC.assertFullResultSet(rs,expRs); |
| //NATURAL RIGHT OUTER JOIN |
| //Following query should have given compile time error. |
| //Once DERBY-5613 is fixed, this query will run into compile time |
| // error for using t2_D3880.i in group by clause because that column |
| // is not part of the SELECT list. |
| rs = s.executeQuery("select t2_D3880.i from t1_D3880 " + |
| "NATURAL RIGHT OUTER JOIN t2_D3880 GROUP BY t2_D3880.i"); |
| JDBC.assertFullResultSet(rs,expRs); |
| |
| //Similar query for HAVING clause. HAVING clause should not be able |
| // to use a column which is not part of the SELECT column list. |
| // Doing this testing with USING clause |
| //Following query should have given compile time error. |
| //Once DERBY-5613 is fixed, this query will run into compile time |
| // error for using t1_D3880.i in group by clause because that column |
| // is not part of the SELECT list. |
| rs = s.executeQuery("select i from t1_D3880 " + |
| "inner join t2_D3880 USING(i) group by t1_D3880.i " + |
| "HAVING t1_D3880.i > 1"); |
| expRs = new String[][] {{"2"}}; |
| JDBC.assertFullResultSet(rs,expRs); |
| // Doing the same test as above with NATURAL JOIN |
| //Following query should have given compile time error. |
| //Once DERBY-5613 is fixed, this query will run into compile time |
| // error for using t1_D3880.i in group by clause because that column |
| // is not part of the SELECT list. |
| rs = s.executeQuery("select i from t1_D3880 " + |
| "NATURAL inner join t2_D3880 group by t1_D3880.i " + |
| "HAVING t1_D3880.i > 1"); |
| expRs = new String[][] {{"2"}}; |
| JDBC.assertFullResultSet(rs,expRs); |
| //Following query should have given compile time error. |
| //Once DERBY-5613 is fixed, this query will run into compile time |
| // error for using t1_D3880.i in group by clause because that column |
| // is not part of the SELECT list. |
| rs = s.executeQuery("select i from t1_D3880 " + |
| "LEFT OUTER join t2_D3880 USING(i) group by t1_D3880.i " + |
| "HAVING t1_D3880.i > 1"); |
| JDBC.assertFullResultSet(rs,expRs); |
| //Following query should have given compile time error. |
| //Once DERBY-5613 is fixed, this query will run into compile time |
| // error for using t1_D3880.i in group by clause because that column |
| // is not part of the SELECT list. |
| rs = s.executeQuery("select i from t1_D3880 " + |
| "NATURAL LEFT OUTER join t2_D3880 group by t1_D3880.i " + |
| "HAVING t1_D3880.i > 1"); |
| JDBC.assertFullResultSet(rs,expRs); |
| //Following query should have given compile time error. |
| //Once DERBY-5613 is fixed, this query will run into compile time |
| // error for using t2_D3880.i in group by clause because that column |
| // is not part of the SELECT list. |
| rs = s.executeQuery("select i from t1_D3880 " + |
| "RIGHT OUTER join t2_D3880 USING(i) group by t2_D3880.i " + |
| "HAVING t2_D3880.i > 1"); |
| JDBC.assertFullResultSet(rs,expRs); |
| //Following query should have given compile time error. |
| //Once DERBY-5613 is fixed, this query will run into compile time |
| // error for using t2_D3880.i in group by clause because that column |
| // is not part of the SELECT list. |
| rs = s.executeQuery("select i from t1_D3880 " + |
| "NATURAL RIGHT OUTER join t2_D3880 group by t2_D3880.i " + |
| "HAVING t2_D3880.i > 1"); |
| JDBC.assertFullResultSet(rs,expRs); |
| |
| //The correct query for HAVING should be written as follows |
| rs = s.executeQuery("select t1_D3880.i from t1_D3880 " + |
| "inner join t2_D3880 USING(i) group by t1_D3880.i " + |
| "HAVING t1_D3880.i > 1"); |
| JDBC.assertFullResultSet(rs,expRs); |
| rs = s.executeQuery("select t1_D3880.i from t1_D3880 " + |
| "NATURAL inner join t2_D3880 group by t1_D3880.i " + |
| "HAVING t1_D3880.i > 1"); |
| JDBC.assertFullResultSet(rs,expRs); |
| rs = s.executeQuery("select t1_D3880.i from t1_D3880 " + |
| "LEFT OUTER join t2_D3880 USING(i) group by t1_D3880.i " + |
| "HAVING t1_D3880.i > 1"); |
| JDBC.assertFullResultSet(rs,expRs); |
| rs = s.executeQuery("select t1_D3880.i from t1_D3880 " + |
| "NATURAL LEFT OUTER join t2_D3880 group by t1_D3880.i " + |
| "HAVING t1_D3880.i > 1"); |
| JDBC.assertFullResultSet(rs,expRs); |
| rs = s.executeQuery("select t2_D3880.i from t1_D3880 " + |
| "RIGHT OUTER join t2_D3880 USING(i) group by t2_D3880.i " + |
| "HAVING t2_D3880.i > 1"); |
| JDBC.assertFullResultSet(rs,expRs); |
| rs = s.executeQuery("select t2_D3880.i from t1_D3880 " + |
| "NATURAL RIGHT OUTER join t2_D3880 group by t2_D3880.i " + |
| "HAVING t2_D3880.i > 1"); |
| JDBC.assertFullResultSet(rs,expRs); |
| } |
| |
| /** |
| * DERBY-578: select with group by on a temp table caused NPE |
| * @throws SQLException |
| */ |
| public void testGroupByWithTempTable() throws SQLException { |
| Statement s = createStatement(); |
| s.execute("declare global temporary table session.ztemp ( orderID varchar( 50 ) ) not logged"); |
| 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 |
| */ |
| public void testGroupByWithAliasToSameName() throws SQLException { |
| |
| Statement s = createStatement(); |
| |
| String[][] expected1 = {{"1", "3"}, {"2", "2"}}; |
| JDBC.assertUnorderedResultSet( |
| s.executeQuery("select a, count(a) from bug280 group by a"), |
| expected1); |
| // The second query should return the same results as the first. Would |
| // throw exception before DERBY-681. |
| JDBC.assertUnorderedResultSet( |
| s.executeQuery("select a, count(a) as a from bug280 group by a"), |
| expected1); |
| |
| // should return same results as first query (but with extra column) |
| String[][] expected2 = {{"1", "3", "1"}, {"2", "2", "2"}}; |
| JDBC.assertUnorderedResultSet( |
| s.executeQuery("select a, count(a), a from bug280 group by a"), |
| expected2); |
| |
| // different tables with same column name ok |
| String[][] expected3 = { |
| {"1","1"}, {"1","1"}, {"1","1"}, {"2","2"}, {"2","2"} }; |
| JDBC.assertFullResultSet( |
| s.executeQuery("select t.t_i, m.t_i from " + |
| "(select a, b from bug280 group by a, b) " + |
| "t (t_i, t_dt), " + |
| "(select a, b from bug280 group by a, b) " + |
| "m (t_i, t_dt) " + |
| "where t.t_i = m.t_i and t.t_dt = m.t_dt " + |
| "group by t.t_i, t.t_dt, m.t_i, m.t_dt " + |
| "order by t.t_i,m.t_i"), |
| expected3); |
| |
| // should be allowed |
| String[][] expected4 = { {"1", "1"}, {"2", "2"} }; |
| JDBC.assertUnorderedResultSet( |
| s.executeQuery("select a, a from bug280 group by a"), |
| expected4); |
| JDBC.assertUnorderedResultSet( |
| s.executeQuery("select bug280.a, a from bug280 group by a"), |
| expected4); |
| JDBC.assertUnorderedResultSet( |
| s.executeQuery("select bug280.a, bug280.a from bug280 group by a"), |
| expected4); |
| JDBC.assertUnorderedResultSet( |
| s.executeQuery("select a, bug280.a from bug280 group by a"), |
| expected4); |
| |
| s.close(); |
| } |
| |
| /** |
| * DERBY-2397 showed incorrect typing of aggregate nodes |
| * that lead to a SUBSTR throwing an exception that its |
| * position/length were out of range. |
| * @throws SQLException |
| */ |
| public void testDERBY2937() throws SQLException { |
| Statement s = createStatement(); |
| |
| ResultSet rs = s.executeQuery("SELECT A.C, SUBSTR (MAX(CAST(A.D AS CHAR(10)) || " + |
| "CAST(A.DC AS CHAR(8))), 11, 8) AS BUG " + |
| "FROM A2937 A GROUP BY A.C"); |
| JDBC.assertFullResultSet(rs, |
| new String[][] {{"aaa","500.00"}}); |
| } |
| |
| public void testDerbyOrderByOnAggregate() throws SQLException |
| { |
| Statement s = createStatement(); |
| |
| ResultSet rs = s.executeQuery( |
| "select b, count(*) from yy where a=5 or a=2 " + |
| "group by b order by count(*) desc"); |
| |
| JDBC.assertFullResultSet( |
| rs, |
| new Object[][]{ |
| {3.0, 4}, |
| {4.0, 2}, |
| {7.0, 1}}, |
| false); |
| |
| rs = s.executeQuery( |
| "select b, count(*) from yy where a=5 or a=2 " + |
| "group by b order by count(*) asc"); |
| |
| JDBC.assertFullResultSet( |
| rs, |
| new Object[][]{ |
| {7.0, 1}, |
| {4.0, 2}, |
| {3.0, 4}}, |
| false); |
| } |
| |
| |
| /** |
| * DERBY-3257 check for correct number of rows returned with |
| * or in having clause. |
| * |
| * @throws SQLException |
| */ |
| public void testOrNodeInHavingClause() throws SQLException |
| { |
| Statement s = createStatement(); |
| s.executeUpdate("CREATE TABLE TAB ( ID VARCHAR(20), INFO VARCHAR(20))"); |
| s.executeUpdate("insert into TAB values ('1', 'A')"); |
| s.executeUpdate("insert into TAB values ('2', 'A')"); |
| s.executeUpdate("insert into TAB values ('3', 'B')"); |
| s.executeUpdate("insert into TAB values ('4', 'B')"); |
| ResultSet rs = s.executeQuery("SELECT t0.INFO, COUNT(t0.ID) FROM TAB t0 GROUP BY t0.INFO HAVING (t0.INFO = 'A' OR t0.INFO = 'B') AND t0.INFO IS NOT NULL"); |
| String [][] expectedRows = {{"A","2"},{"B","2"}}; |
| JDBC.assertFullResultSet(rs, expectedRows); |
| s.executeUpdate("DROP TABLE TAB"); |
| } |
| |
| /** |
| * DERBY-3613 check combinations of DISTINCT and GROUP BY |
| */ |
| public void testDistinctGroupBy() throws SQLException |
| { |
| Statement s = createStatement(); |
| ResultSet rs; |
| // First, a number of queries without aggregates: |
| rs = s.executeQuery("select distinct a from d3613 group by a"); |
| JDBC.assertUnorderedResultSet(rs, new String[][] {{"2"},{"1"}}); |
| rs = s.executeQuery("select distinct a from d3613 group by a,b"); |
| JDBC.assertUnorderedResultSet(rs, new String[][] {{"2"},{"1"}}); |
| rs = s.executeQuery("select a,b from d3613"); |
| JDBC.assertUnorderedResultSet(rs, |
| new String[][] {{"1","2"},{"1","2"},{"1","3"},{"2","2"}}); |
| rs = s.executeQuery("select distinct a,b from d3613 group by a,b,c"); |
| JDBC.assertUnorderedResultSet(rs, |
| new String[][] {{"1","2"},{"1","3"},{"2","2"}}); |
| rs = s.executeQuery("select distinct a,b from d3613 group by a,b"); |
| JDBC.assertUnorderedResultSet(rs, |
| new String[][] {{"1","2"},{"1","3"},{"2","2"}}); |
| rs = s.executeQuery("select distinct a,b from d3613 group by a,c,b"); |
| JDBC.assertUnorderedResultSet(rs, |
| new String[][] {{"1","2"},{"1","3"},{"2","2"}}); |
| // Second, a number of similar queries, with aggregates: |
| rs = s.executeQuery("select a,sum(b) from d3613 group by a,b"); |
| JDBC.assertUnorderedResultSet(rs, |
| new String[][] {{"1","4"},{"1","3"},{"2","2"}}); |
| rs = s.executeQuery("select distinct a,sum(b) from d3613 group by a,b"); |
| JDBC.assertUnorderedResultSet(rs, |
| new String[][] {{"1","4"},{"1","3"},{"2","2"}}); |
| rs = s.executeQuery("select a,sum(b) from d3613 group by a,c"); |
| JDBC.assertUnorderedResultSet(rs, |
| new String[][] {{"1","2"},{"1","2"},{"1","3"},{"2","2"}}); |
| rs = s.executeQuery("select distinct a,sum(b) from d3613 group by a,c"); |
| JDBC.assertUnorderedResultSet(rs, |
| new String[][] {{"1","2"},{"1","3"},{"2","2"}}); |
| rs = s.executeQuery( |
| "select a,sum(b) from d3613 group by a,b,c"); |
| JDBC.assertUnorderedResultSet(rs, |
| new String[][] {{"1","2"},{"1","2"},{"1","3"},{"2","2"}}); |
| rs = s.executeQuery( |
| "select distinct a,sum(b) from d3613 group by a,b,c"); |
| JDBC.assertUnorderedResultSet(rs, |
| new String[][] {{"1","2"},{"1","3"},{"2","2"}}); |
| rs = s.executeQuery( |
| "select distinct a,sum(b) from d3613 group by a"); |
| JDBC.assertUnorderedResultSet(rs, |
| new String[][] {{"1","7"},{"2","2"}}); |
| // A few error cases: |
| assertStatementError("42Y36", s, |
| "select distinct a,b from d3613 group by a"); |
| assertStatementError("42Y36", s, |
| "select distinct a,b from d3613 group by a,c"); |
| assertStatementError("42Y36", s, |
| "select distinct a,b,sum(b) from d3613 group by a"); |
| |
| // A few queries from other parts of this suite, with DISTINCT added: |
| JDBC.assertFullResultSet( |
| s.executeQuery("select distinct t.t_i, m.t_i from " + |
| "(select a, b from bug280 group by a, b) " + |
| "t (t_i, t_dt), " + |
| "(select a, b from bug280 group by a, b) " + |
| "m (t_i, t_dt) " + |
| "where t.t_i = m.t_i and t.t_dt = m.t_dt " + |
| "group by t.t_i, t.t_dt, m.t_i, m.t_dt " + |
| "order by t.t_i,m.t_i"), |
| new String[][] { {"1","1"}, {"2","2"} } ); |
| |
| JDBC.assertFullResultSet( |
| s.executeQuery( |
| " select distinct t.i from t group by i, dt, b order by i"), |
| new String [][] { {"0"}, {"1"}, {null} }); |
| JDBC.assertFullResultSet( |
| s.executeQuery( |
| " select distinct t.dt from t group by i, dt, b order by dt"), |
| new String [][] { {"1992-01-01"}, {"1992-09-09"}, {null} }); |
| } |
| /** |
| * DERBY-2085 check message on order by of non-grouped column |
| */ |
| public void testOrderByNonGroupedColumn() throws SQLException |
| { |
| Statement s = createStatement(); |
| ResultSet rs; |
| assertStatementError("42Y36", s, |
| "select a from d2085 group by a order by b"); |
| assertStatementError("42Y36", s, |
| "select a from d2085 group by a,b order by c"); |
| assertStatementError("42Y36", s, |
| "select a,b from d2085 group by a,b order by c*2"); |
| } |
| |
| /** |
| * DERBY-3219: Check that MaxMinAggregator's external format works |
| * properly with a string of length 0. |
| */ |
| public void testGroupByMaxWithEmptyString() throws SQLException |
| { |
| // Force all sorts to be external sorts, for DERBY-3219. This |
| // property only takes effect for debug sane builds, but that |
| // should be adequate since at least some developers routinely |
| // run tests in that configuration. |
| boolean wasSet = false; |
| if (SanityManager.DEBUG) |
| { |
| wasSet = SanityManager.DEBUG_ON("testSort"); |
| SanityManager.DEBUG_SET("testSort"); |
| } |
| |
| Statement st = createStatement(); |
| loadRows(); |
| ResultSet rs = st.executeQuery("select b,max(a) from d3219 group by b"); |
| while (rs.next()); |
| // If we can read the results, the test passed. DERBY-3219 resulted |
| // in an externalization data failure during the group by processing. |
| if (SanityManager.DEBUG) |
| { |
| if (! wasSet) |
| SanityManager.DEBUG_CLEAR("testSort"); |
| } |
| } |
| |
| /** |
| * Load enough rows into the table to get some externalized |
| * MaxMinAggregator instances. To ensure that the values are externalized, |
| * we set up this test to run with -Dderby.debug.true=testSort. Note that |
| * we load the column 'a' with a string of length 0, because DERBY-3219 |
| * occurs when the computed MAX value is a string of length 0. |
| */ |
| private void loadRows() |
| throws SQLException |
| { |
| PreparedStatement ps = prepareStatement( |
| "insert into d3219 (a, b) values ('', ?)"); |
| |
| for (int i = 0; i < 2000; i++) |
| { |
| ps.setString(1, genString(1000)); |
| ps.executeUpdate(); |
| } |
| } |
| private static String genString(int len) |
| { |
| StringBuffer buf = new StringBuffer(len); |
| |
| for (int i = 0; i < len; i++) |
| buf.append(chars[(int) (chars.length * Math.random())]); |
| return buf.toString(); |
| } |
| private static char []chars = { |
| 'q','w','e','r','t','y','u','i','o','p', |
| 'a','s','d','f','g','h','j','k','l', |
| 'z','x','c','v','b','n','m' |
| }; |
| |
| /** |
| * DERBY-2457: Derby does not support column aliases in the |
| * GROUP BY and HAVING clauses. |
| */ |
| public void testColumnAliasInGroupByAndHaving() throws SQLException |
| { |
| Statement s = createStatement(); |
| // 1) Using the underlying column names works fine, with or |
| // without a table alias: |
| JDBC.assertUnorderedResultSet( |
| s.executeQuery("select name, count(ord) from d2457_o " + |
| " group by name having count(ord) > 2"), |
| new String[][] { {"John","3"} } ); |
| JDBC.assertUnorderedResultSet( |
| s.executeQuery("select name as col1, count(ord) as col2 " + |
| " from d2457_o group by name having count(ord) > 2"), |
| new String[][] { {"John","3"} } ); |
| JDBC.assertUnorderedResultSet( |
| s.executeQuery("select name as col1, count(ord) as col2 " + |
| " from d2457_o ordertable group by name " + |
| " having count(ord) > 2"), |
| new String[][] { {"John","3"} } ); |
| JDBC.assertUnorderedResultSet( |
| s.executeQuery("select ordertable.name as col1, " + |
| " count(ord) as col2 from d2457_o ordertable " + |
| " group by name having count(ord) > 2"), |
| new String[][] { {"John","3"} } ); |
| // 2) References to column aliases in GROUP BY and HAVING are |
| // rejected with an error message: |
| assertStatementError("42X04", s, |
| "select name as col1, count(ord) as col2 from d2457_o " + |
| " group by name having col2 > 2"); |
| assertStatementError("42X04", s, |
| "select name as col1, count(ord) as col2 from d2457_o " + |
| " group by col1 having col2 > 2"); |
| assertStatementError("42X04", s, |
| "select name as col1, count(ord) as col2 from d2457_o " + |
| " group by col1 having count(ord) > 2"); |
| assertStatementError("42X04", s, |
| "select name as col1, sum(amount) as col2 " + |
| " from d2457_o, d2457_a where d2457_o.ord = d2457_a.ord " + |
| " group by col1 having col2 > 2"); |
| assertStatementError("42X04", s, |
| "select name as col1, sum(amount) as col2 " + |
| " from d2457_o t1, d2457_a t2 where t1.ord = t2.ord " + |
| " group by col1 having col2 > 2"); |
| assertStatementError("42X04", s, |
| "select name as col1, sum(amount) as col2 " + |
| " from d2457_o t1, d2457_a t2 where t1.ord = t2.ord " + |
| " group by col1 having sum(amount) > 2"); |
| assertStatementError("42X04", s, |
| "select name as col1, sum(amount) as col2 " + |
| " from d2457_o t1, d2457_a t2 where t1.ord = t2.ord " + |
| " group by col1 having col2 > 2"); |
| assertStatementError("42X04", s, |
| "select * from (select t1.name as col, sum(amount) " + |
| " from d2457_o t1, d2457_a t2 where t1.ord = t2.ord " + |
| " group by col) as t12(col1, col2) where col2 > 2"); |
| // 3) Demonstrate that column aliasing works correctly when the |
| // GROUP BY is packaged as a subquery: |
| JDBC.assertUnorderedResultSet( |
| s.executeQuery("select * from " + |
| "(select name, count(ord) from d2457_o ordertable " + |
| " group by ordertable.name) as ordertable(col1, col2) " + |
| " where col2 > 2"), |
| new String[][] { {"John","3"} } ); |
| JDBC.assertUnorderedResultSet( |
| s.executeQuery("select * from " + |
| "(select name as col, sum(amount) " + |
| " from d2457_o t1, d2457_a t2 where t1.ord = t2.ord " + |
| " group by name) as t12(col1, col2) where col2 > 2"), |
| new String[][] { {"Jerry", "57"}, {"John","113"} } ); |
| // 4) Demonatrate that table aliases can be used in GROUP BY and |
| // HAVING clauses |
| JDBC.assertUnorderedResultSet( |
| s.executeQuery("select t1.name as col1, " + |
| " sum(t2.amount) as col2 from d2457_o t1, d2457_a t2 " + |
| " where t1.ord = t2.ord group by t1.name " + |
| " having sum(t2.amount) > 2"), |
| new String[][] { {"Jerry", "57"}, {"John","113"} } ); |
| JDBC.assertUnorderedResultSet( |
| s.executeQuery("select name as col1, sum(amount) as col2 " + |
| " from d2457_o t1, d2457_a t2 where t1.ord = t2.ord " + |
| " group by name having sum(amount) > 2"), |
| new String[][] { {"Jerry", "57"}, {"John","113"} } ); |
| JDBC.assertUnorderedResultSet( |
| s.executeQuery("select t1.name as col1, sum(amount) as col2 " + |
| " from d2457_o t1, d2457_a t2 where t1.ord = t2.ord " + |
| " group by name having sum(amount) > 2"), |
| new String[][] { {"Jerry", "57"}, {"John","113"} } ); |
| JDBC.assertUnorderedResultSet( |
| s.executeQuery("select name as col1, sum(t2.amount) as col2 " + |
| " from d2457_o t1, d2457_a t2 where t1.ord = t2.ord " + |
| " group by name having sum(amount) > 2"), |
| new String[][] { {"Jerry", "57"}, {"John","113"} } ); |
| } |
| |
| /** |
| * Test that GROUP BY can be used in the sub-expressions of set operations |
| * (DERBY-3764). |
| */ |
| public void testSetOperationsAndGroupBy() throws SQLException { |
| // turn off auto-commit to clean up test data automatically |
| getConnection().setAutoCommit(false); |
| |
| Statement s = createStatement(); |
| |
| s.execute("CREATE TABLE D3764A (A1 INTEGER, A2 VARCHAR(10))"); |
| |
| int[] valuesA = { 1, 2, 3, 4, 5, 6, 5, 3, 1 }; |
| |
| PreparedStatement insertA = |
| prepareStatement("INSERT INTO D3764A (A1) VALUES (?)"); |
| |
| for (int i = 0; i < valuesA.length; i++) { |
| insertA.setInt(1, valuesA[i]); |
| insertA.executeUpdate(); |
| } |
| |
| s.execute("CREATE TABLE D3764B (B1 INTEGER, B2 VARCHAR(10))"); |
| |
| int[] valuesB = { 1, 2, 3, 3, 7, 9 }; |
| |
| PreparedStatement insertB = |
| prepareStatement("INSERT INTO D3764B (B1) VALUES (?)"); |
| |
| for (int i = 0; i < valuesB.length; i++) { |
| insertB.setInt(1, valuesB[i]); |
| insertB.executeUpdate(); |
| } |
| |
| // Define some queries with one result column and a varying number of |
| // grouping columns. |
| String[] singleColumnQueries = { |
| "SELECT A1 FROM D3764A", |
| "SELECT COUNT(A1) FROM D3764A", |
| "SELECT COUNT(A1) FROM D3764A GROUP BY A1", |
| "SELECT COUNT(A1) FROM D3764A GROUP BY A2", |
| "SELECT COUNT(A1) FROM D3764A GROUP BY A1, A2", |
| "SELECT B1 FROM D3764B", |
| "SELECT COUNT(B1) FROM D3764B", |
| "SELECT COUNT(B1) FROM D3764B GROUP BY B1", |
| "SELECT COUNT(B1) FROM D3764B GROUP BY B2", |
| "SELECT COUNT(B1) FROM D3764B GROUP BY B1, B2", |
| "VALUES 1, 2, 3, 4", |
| }; |
| |
| // The expected results from the queries above. |
| String[][][] singleColumnExpected = { |
| { {"1"}, {"2"}, {"3"}, {"4"}, {"5"}, {"6"}, {"5"}, {"3"}, {"1"} }, |
| { { Integer.toString(valuesA.length) } }, |
| { {"2"}, {"1"}, {"2"}, {"1"}, {"2"}, {"1"} }, |
| { { Integer.toString(valuesA.length) } }, |
| { {"2"}, {"1"}, {"2"}, {"1"}, {"2"}, {"1"} }, |
| { {"1"}, {"2"}, {"3"}, {"3"}, {"7"}, {"9"} }, |
| { { Integer.toString(valuesB.length) } }, |
| { {"1"}, {"1"}, {"2"}, {"1"}, {"1"} }, |
| { { Integer.toString(valuesB.length) } }, |
| { {"1"}, {"1"}, {"2"}, {"1"}, {"1"} }, |
| { {"1"}, {"2"}, {"3"}, {"4"} }, |
| }; |
| |
| // Test all the set operations with all the combinations of the queries |
| // above. |
| doAllSetOperations(s, singleColumnQueries, singleColumnExpected); |
| |
| // Define some queries with two result columns and a varying number of |
| // grouping columns. |
| String[] twoColumnQueries = { |
| "SELECT A1-1, A1+1 FROM D3764A", |
| "SELECT COUNT(A1), A1 FROM D3764A GROUP BY A1", |
| "SELECT COUNT(A1), LENGTH(A2) FROM D3764A GROUP BY A2", |
| "SELECT COUNT(A1), A1 FROM D3764A GROUP BY A1, A2", |
| "SELECT B1-1, B1+1 FROM D3764B", |
| "SELECT COUNT(B1), B1 FROM D3764B GROUP BY B1", |
| "SELECT COUNT(B1), LENGTH(B2) FROM D3764B GROUP BY B2", |
| "SELECT COUNT(B1), B1 FROM D3764B GROUP BY B1, B2", |
| "VALUES (1, 2), (3, 4)", |
| }; |
| |
| // The expected results from the queries above. |
| String[][][] twoColumnExpected = { |
| { {"0","2"}, {"1","3"}, {"2","4"}, {"3","5"}, {"4","6"}, |
| {"5","7"}, {"4","6"}, {"2","4"}, {"0","2"} }, |
| { {"2","1"}, {"1","2"}, {"2","3"}, {"1","4"}, {"2","5"}, |
| {"1","6"} }, |
| { { Integer.toString(valuesA.length), null } }, |
| { {"2","1"}, {"1","2"}, {"2","3"}, {"1","4"}, {"2","5"}, |
| {"1","6"} }, |
| { {"0","2"}, {"1","3"}, {"2","4"}, {"2","4"}, {"6","8"}, |
| {"8","10"} }, |
| { {"1","1"}, {"1","2"}, {"2","3"}, {"1","7"}, {"1","9"} }, |
| { { Integer.toString(valuesB.length), null } }, |
| { {"1","1"}, {"1","2"}, {"2","3"}, {"1","7"}, {"1","9"} }, |
| { {"1","2"}, {"3","4"} }, |
| }; |
| |
| // Test all the set operations with all the combinations of the queries |
| // above. |
| doAllSetOperations(s, twoColumnQueries, twoColumnExpected); |
| |
| // Test that set operations cannot be used on sub-queries with |
| // different number of columns. |
| assertSetOpErrors("42X58", s, singleColumnQueries, twoColumnQueries); |
| assertSetOpErrors("42X58", s, twoColumnQueries, singleColumnQueries); |
| } |
| |
| /** |
| * Try all set operations (UNION [ALL], EXCEPT [ALL], INTERSECT [ALL]) on |
| * all combinations of the specified queries. |
| * |
| * @param s the statement used to execute the queries |
| * @param queries the different queries to use, all of which must be union |
| * compatible |
| * @param expectedResults the expected results from the different queries |
| */ |
| private static void doAllSetOperations(Statement s, String[] queries, |
| String[][][] expectedResults) |
| throws SQLException { |
| |
| assertEquals(queries.length, expectedResults.length); |
| |
| for (int i = 0; i < queries.length; i++) { |
| final String query1 = queries[i]; |
| final List<List<String>> rows1 = |
| resultArrayToList(expectedResults[i]); |
| |
| for (int j = 0; j < queries.length; j++) { |
| final String query2 = queries[j]; |
| final List<List<String>> rows2 = |
| resultArrayToList(expectedResults[j]); |
| |
| String query = query1 + " UNION " + query2; |
| String[][] rows = union(rows1, rows2, false); |
| JDBC.assertUnorderedResultSet(s.executeQuery(query), rows); |
| |
| query = query1 + " UNION ALL " + query2; |
| rows = union(rows1, rows2, true); |
| JDBC.assertUnorderedResultSet(s.executeQuery(query), rows); |
| |
| query = query1 + " EXCEPT " + query2; |
| rows = except(rows1, rows2, false); |
| JDBC.assertUnorderedResultSet(s.executeQuery(query), rows); |
| |
| query = query1 + " EXCEPT ALL " + query2; |
| rows = except(rows1, rows2, true); |
| JDBC.assertUnorderedResultSet(s.executeQuery(query), rows); |
| |
| query = query1 + " INTERSECT " + query2; |
| rows = intersect(rows1, rows2, false); |
| JDBC.assertUnorderedResultSet(s.executeQuery(query), rows); |
| |
| query = query1 + " INTERSECT ALL " + query2; |
| rows = intersect(rows1, rows2, true); |
| JDBC.assertUnorderedResultSet(s.executeQuery(query), rows); |
| } |
| } |
| } |
| |
| /** |
| * Try all set operations with queries from {@code queries1} in the left |
| * operand and queries from {@code queries2} in the right operand. All the |
| * set operations are expected to fail with the same SQLState. |
| * |
| * @param sqlState the expected SQLState |
| * @param s the statement used to execute the queries |
| * @param queries1 queries to use as the left operand |
| * @param queries2 queries to use as the right operand |
| */ |
| private static void assertSetOpErrors(String sqlState, |
| Statement s, |
| String[] queries1, |
| String[] queries2) |
| throws SQLException { |
| |
| final String[] operators = { |
| " UNION ", " UNION ALL ", " EXCEPT ", " EXCEPT ALL ", |
| " INTERSECT ", " INTERSECT ALL " |
| }; |
| |
| for (int i = 0; i < queries1.length; i++) { |
| for (int j = 0; j < queries2.length; j++) { |
| for (int k = 0; k < operators.length; k++) { |
| assertStatementError( |
| sqlState, s, queries1[i] + operators[k] + queries2[j]); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Find the union between two collections of rows (each row is a list of |
| * strings). Return the union as an array of string arrays. |
| * |
| * @param rows1 the first collection of rows |
| * @param rows2 the second collection of rows |
| * @param all whether or not bag semantics (as in UNION ALL) should be used |
| * instead of set semantics |
| * @return the union of {@code rows1} and {@code rows2}, as a {@code |
| * String[][]} |
| */ |
| private static String[][] union(Collection<List<String>> rows1, |
| Collection<List<String>> rows2, |
| boolean all) { |
| Collection<List<String>> bagOrSet = newBagOrSet(all); |
| bagOrSet.addAll(rows1); |
| bagOrSet.addAll(rows2); |
| return toResultArray(bagOrSet); |
| } |
| |
| /** |
| * Find the difference between two collections of rows (each row is a list |
| * of strings). Return the difference as an array of string arrays. |
| * |
| * @param rows1 the first operand to the set difference operator |
| * @param rows2 the second operand to the set difference operator |
| * @param all whether or not bag semantics (as in EXCEPT ALL) should be |
| * used instead of set semantics |
| * @return the difference between {@code rows1} and {@code rows2}, as a |
| * {@code String[][]} |
| */ |
| private static String[][] except(Collection<List<String>> rows1, |
| Collection<List<String>> rows2, |
| boolean all) { |
| Collection<List<String>> bagOrSet = newBagOrSet(all); |
| bagOrSet.addAll(rows1); |
| // could use removeAll() for sets, but need other behaviour for bags |
| for (List<String> row : rows2) { |
| bagOrSet.remove(row); |
| } |
| return toResultArray(bagOrSet); |
| } |
| |
| /** |
| * Find the intersection between two collections of rows (each row is a |
| * list of strings). Return the intersection as an array of string arrays. |
| * |
| * @param rows1 the first collection of rows |
| * @param rows2 the second collection of rows |
| * @param all whether or not bag semantics (as in INTERSECT ALL) should be |
| * used instead of set semantics |
| * @return the intersection between {@code rows1} and {@code rows2}, as a |
| * {@code String[][]} |
| */ |
| private static String[][] intersect(Collection<List<String>> rows1, |
| Collection<List<String>> rows2, |
| boolean all) { |
| Collection<List<String>> bagOrSet = newBagOrSet(all); |
| List<List<String>> copyOfRows2 = new ArrayList<List<String>>(rows2); |
| // could use retainAll() for sets, but need other behaviour for bags |
| for (List<String> x : rows1) { |
| if (copyOfRows2.remove(x)) { |
| // x is present in both of the collections, add it |
| bagOrSet.add(x); |
| } |
| } |
| return toResultArray(bagOrSet); |
| } |
| |
| /** |
| * Create a {@code Collection} that can be used as a bag or a set. |
| * |
| * @param bag tells whether or not the collection should be a bag |
| * @return a {@code List} if a bag is requested, or a {@code Set} otherwise |
| */ |
| private static Collection<List<String>> newBagOrSet(boolean bag) { |
| if (bag) { |
| return new ArrayList<List<String>>(); |
| } else { |
| return new HashSet<List<String>>(); |
| } |
| } |
| |
| /** |
| * Convert a {@code Collection} of rows to an array of string arrays that |
| * can be passed as an argument with expected results to |
| * {@link JDBC#assertUnorderedResultSet(ResultSet,String[][])}. |
| * |
| * @param rows a collection of rows, where each row is a list of strings |
| * @return a {@code String[][]} containing the same values as {@code rows} |
| */ |
| private static String[][] toResultArray(Collection<List<String>> rows) { |
| String[][] results = new String[rows.size()][]; |
| Iterator<List<String>> it = rows.iterator(); |
| for (int i = 0; i < results.length; i++) { |
| List<String> row = it.next(); |
| results[i] = row.toArray(new String[row.size()]); |
| } |
| return results; |
| } |
| |
| /** |
| * Return a list of lists containing the same values as the specified array |
| * of string arrays. This method can be used to make it easier to perform |
| * set operations on a two-dimensional array of strings. |
| * |
| * @param results a two dimensional array of strings (typically expected |
| * results from a query} |
| * @return the values of {@code results} in a list of lists |
| */ |
| private static List<List<String>> resultArrayToList(String[][] results) { |
| ArrayList<List<String>> rows = |
| new ArrayList<List<String>>(results.length); |
| for (int i = 0; i < results.length; i++) { |
| rows.add(Arrays.asList(results[i])); |
| } |
| return rows; |
| } |
| |
| /** |
| * DERBY-3904: Min/Max optimization needs to be aware of joins. |
| */ |
| public void testDerby3904MinMaxOptimization() throws SQLException |
| { |
| Statement s = createStatement(); |
| |
| JDBC.assertFullResultSet( |
| s.executeQuery("SELECT d3904_T1.D1 " + |
| "FROM d3904_T1 LEFT JOIN d3904_T2 " + |
| "ON d3904_T1.D1 = d3904_T2.D2 " + |
| "WHERE d3904_T2.D2 IS NULL"), |
| new String[][] { {"2008-10-02"} } ); |
| JDBC.assertFullResultSet( |
| s.executeQuery("SELECT MAX( d3904_T1.D1 ) as D " + |
| "FROM d3904_T1 WHERE d3904_T1.D1 NOT IN " + |
| "( SELECT d3904_T2.D2 FROM d3904_T2 )"), |
| new String[][] { {"2008-10-02"} } ); |
| // |
| // In DERBY-3904, this next query fails with a null pointer |
| // exception because GroupByNode doesn't realize that there |
| // is a join involved here |
| // |
| JDBC.assertFullResultSet( |
| s.executeQuery("SELECT MAX( d3904_T1.D1 ) AS D " + |
| "FROM d3904_T1 LEFT JOIN d3904_T2 " + |
| "ON d3904_T1.D1 = d3904_T2.D2 " + |
| "WHERE d3904_T2.D2 IS NULL"), |
| new String[][] { {"2008-10-02"} } ); |
| |
| // Verify that the min/max optimization still works for the |
| // simple query SELECT MAX(D1) FROM T1: |
| s.execute("call SYSCS_UTIL.SYSCS_SET_RUNTIMESTATISTICS(1)"); |
| JDBC.assertFullResultSet( |
| s.executeQuery("SELECT MAX(D1) FROM D3904_T1"), |
| new String[][] { {"2008-10-02"} } ); |
| RuntimeStatisticsParser rtsp = |
| SQLUtilities.getRuntimeStatisticsParser(s); |
| assertTrue(rtsp.usedLastKeyIndexScan()); |
| assertFalse(rtsp.usedIndexRowToBaseRow()); |
| |
| // A form of the Beetle 4423 query: |
| JDBC.assertFullResultSet( |
| s.executeQuery("SELECT MAX(D1) " + |
| "FROM d3904_T1, D3904_T2 WHERE d3904_T1.D1='2008-10-02'"), |
| new String[][] { {"2008-10-02"} } ); |
| } |
| |
| |
| /** |
| * Test aggregate used in group by query. |
| * @throws SQLException |
| */ |
| public void testDerby3631AggregateInGroupByQuery() throws SQLException { |
| Statement s = createStatement(); |
| ResultSet rs = s.executeQuery("SELECT GroupCol, MAXOF2(CAST(SUM(Value1) AS DOUBLE), CAST(SUM(Value2) AS DOUBLE)) AS MaxOf2 FROM Testd3631 GROUP BY GroupCol "); |
| JDBC.assertFullResultSet(rs, new String[][] {{"1","5.0"},{"2","-3.0"}}); |
| rs = s.executeQuery("SELECT GroupCol, MAXOF2(SUM(Value1), SUM(Value2)) AS MaxOf2 FROM Testd3631 GROUP BY GroupCol"); |
| JDBC.assertFullResultSet(rs, new String[][] {{"1","5.0"},{"2","-3.0"}}); |
| } |
| |
| |
| /** |
| * Test aggregate function on a GROUP BY column also present in a HAVING |
| * clause. Iff the GROUP BY column is not the first column in the table, |
| * this would fail before DERBY-4071 was fixed. |
| * |
| * @throws SQLException |
| */ |
| public void testDerby4071AggregateOnGroupByColumnInHaving() throws SQLException { |
| Statement s = createStatement(); |
| ResultSet rs = s.executeQuery("SELECT MAX(i), COUNT(T.V) FROM d4071 T " + |
| " GROUP BY T.V HAVING COUNT(T.V) > 1"); |
| |
| JDBC.assertFullResultSet(rs, new String[][] {{"4","2"},{"5","2"}}); |
| } |
| |
| /** |
| * GROUP BY in an IN-subquery inside HAVING clause whose select list is |
| * subset of group by columns. |
| * |
| * @throws SQLException |
| */ |
| public void testDerby4450() throws SQLException { |
| setAutoCommit(false); |
| Statement s = createStatement(); |
| ResultSet rs; |
| |
| s.executeUpdate( |
| "create table tt(i int not null," + |
| " j int, k int)"); |
| s.executeUpdate( |
| "insert into tt values " + |
| " (1,10,1), (1,40,1),(3,45,1),(4,46,1),(5,90,1)"); |
| |
| rs = s.executeQuery( |
| "select sum(j) from tt group by i having i " + |
| " in (select i from tt group by i,j )"); |
| |
| JDBC.assertFullResultSet(rs, new String[][] { |
| {"50"},{"45"},{"46"},{"90"}}); |
| rollback(); |
| } |
| |
| |
| /** |
| * HAVING with an aggregate function in presence of join flattening |
| * DERBY-4698. See also DERBY-3880. |
| * @throws SQLException |
| */ |
| public void testDerby4698() throws SQLException { |
| setAutoCommit(false); |
| Statement s = createStatement(); |
| ResultSet rs; |
| |
| s.executeUpdate( |
| "create table usr ( user_id bigint primary key," + |
| " deleted char(1) not null)"); |
| s.executeUpdate( |
| "create table user_account ( user_account_id bigint primary key," + |
| " user_id bigint not null," + |
| " account_id bigint not null)"); |
| |
| s.executeUpdate( |
| "CREATE TABLE ACCOUNT (ACCOUNT_ID BIGINT PRIMARY KEY," + |
| " ACCOUNT_TYPE VARCHAR(10) NOT NULL," + |
| " BALANCE DOUBLE NOT NULL)"); |
| |
| s.executeUpdate( |
| "insert into usr values " + |
| " (3003, 'Y'), (3004, 'N'), (1001, 'N'), (1002, 'Y')," + |
| " (1003, 'N'), (1004, 'N'), (1005, 'N'), (1006, 'N')," + |
| " (1007, 'N'), (1008, 'N'), (2002, 'N')"); |
| |
| s.executeUpdate( |
| "insert into user_account values " + |
| " (4004, 3003, 9009), (4005, 3004, 9010), (5005, 1001, 10010)," + |
| " (5006, 3004, 10011), (5007, 2002, 10012), (5008, 1003, 10013)," + |
| " (5009, 1004, 10014), (5010, 1005, 10015), (5011, 1006, 10016)," + |
| " (5012, 1007, 10017), (5013, 1008, 10018), (6006, 1001, 11011)," + |
| " (6007, 3004, 11012), (6008, 2002, 11013), (6009, 1003, 11014)," + |
| " (6010, 1004, 11015), (6011, 1005, 11016), (6012, 1006, 11017)," + |
| " (6013, 1007, 11018), (6014, 1008, 11019), (1001, 1001, 1002)," + |
| " (1002, 1002, 1003), (1003, 1003, 1004), (1004, 1004, 1005)," + |
| " (1005, 1005, 1006), (1006, 1006, 1007), (1007, 1007, 1008)," + |
| " (1008, 1008, 1009), (1009, 1004, 1010), (2002, 1004, 6006)," + |
| " (3003, 2002, 7007)"); |
| |
| s.executeUpdate( |
| "insert into account values " + |
| " (9009, 'USER', 12.5), (9010, 'USER', 12.5)," + |
| " (10010, 'USER-01', 0.0), (10011, 'USER-01', 0.0)," + |
| " (10012, 'USER-01', 0.0), (10013, 'USER-01', 0.0)," + |
| " (10014, 'USER-01', 99.0), (10015, 'USER-01', 0.0)," + |
| " (10016, 'USER-01', 0.0), (10017, 'USER-01', 0.0)," + |
| " (10018, 'USER-01', 0.0), (11011, 'USER-02', 0.0)," + |
| " (11012, 'USER-02', 0.0), (11013, 'USER-02', 0.0)," + |
| " (11014, 'USER-02', 0.0), (11015, 'USER-02', 0.0)," + |
| " (11016, 'USER-02', 0.0), (11017, 'USER-02', 0.0)," + |
| " (11018, 'USER-02', 0.0), (11019, 'USER-02', 0.0)," + |
| " (1002, 'USER', 10.0), (1003, 'USER', 80.31)," + |
| " (1004, 'USER', 10.0), (1005, 'USER', 161.7)," + |
| " (1006, 'USER', 10.0), (1007, 'USER', 10.0)," + |
| " (1008, 'USER', 10.0), (1009, 'USER', 10.0)," + |
| " (7007, 'USER', 11.0)"); |
| |
| rs = s.executeQuery( |
| "SELECT user0_.user_id AS col_0_0_," + |
| " SUM(account2_.balance) AS col_1_0_ " + |
| " FROM usr user0_ " + |
| " INNER JOIN user_account accountlin1_ " + |
| " ON user0_.user_id = accountlin1_.user_id " + |
| " INNER JOIN account account2_ " + |
| " ON accountlin1_.account_id = account2_.account_id " + |
| "WHERE user0_.deleted = 'N' " + |
| " AND ( account2_.account_type IN ( 'USER-01', 'USER' ) )" + |
| "GROUP BY user0_.user_id " + |
| "HAVING SUM(account2_.balance) >= 100.0 "); |
| |
| JDBC.assertFullResultSet(rs, new String[][] { |
| {"1004", "260.7"} }); |
| |
| rollback(); |
| } |
| |
| |
| /** |
| * DISTINCT aggregates in result sets which are opened multiple times. |
| * DERBY-5584. |
| * @throws SQLException |
| */ |
| public void testDerby5584() |
| throws SQLException |
| { |
| setAutoCommit(false); |
| Statement s = createStatement(); |
| ResultSet rs; |
| |
| s.executeUpdate( |
| "CREATE TABLE TEST_5 (" + |
| " profile_id INTEGER NOT NULL," + |
| " group_ref INTEGER NOT NULL," + |
| " matched_count INTEGER NOT NULL )"); |
| |
| s.executeUpdate( |
| "CREATE TABLE TEST_6 ( " + |
| " profile_id INTEGER NOT NULL, " + |
| " group_ref INTEGER NOT NULL, " + |
| " matched_count INTEGER NOT NULL )"); |
| |
| s.executeUpdate( "insert into test_5 values (1, 10000, 1)" ); |
| s.executeUpdate( "insert into test_5 values (2, 10000, 2)" ); |
| |
| s.executeUpdate( "insert into test_6 values (1, 10000, 1)" ); |
| s.executeUpdate( "insert into test_6 values (2, 10000, 2)" ); |
| |
| rs = s.executeQuery( "SELECT ps1.group_ref," + |
| "COUNT(DISTINCT ps1.matched_count) AS matched_count" + |
| " FROM test_5 ps1 " + |
| " GROUP BY ps1.group_ref, ps1.profile_id" ); |
| JDBC.assertFullResultSet(rs, new String[][] { |
| {"10000", "1"}, |
| {"10000", "1"} |
| }); |
| |
| rs = s.executeQuery( "SELECT ps1.group_ref," + |
| "COUNT(ps1.matched_count) AS matched_count" + |
| " FROM test_5 ps1 " + |
| " GROUP BY ps1.group_ref, ps1.profile_id" ); |
| JDBC.assertFullResultSet(rs, new String[][] { |
| {"10000", "1"}, |
| {"10000", "1"} |
| }); |
| |
| String cartProdWithDISTINCTsubqueries = " SELECT *" + |
| " FROM " + |
| " (SELECT ps1.group_ref, ps1.profile_id, " + |
| " COUNT(DISTINCT ps1.matched_count) AS matched_count " + |
| " FROM test_5 ps1" + |
| " GROUP BY ps1.group_ref, ps1.profile_id " + |
| " ) a, " + |
| " (SELECT ps2.group_ref, ps2.profile_id, " + |
| " COUNT( DISTINCT ps2.matched_count) AS matched_count" + |
| " FROM test_6 ps2" + |
| " GROUP BY ps2.group_ref, ps2.profile_id " + |
| ") b "; |
| |
| String cartProdWithSubqueries = " SELECT * " + |
| " FROM " + |
| " (SELECT ps1.group_ref, ps1.profile_id, " + |
| " COUNT(ps1.matched_count) AS matched_count " + |
| " FROM test_5 ps1 " + |
| " GROUP BY ps1.group_ref, ps1.profile_id " + |
| ") a, " + |
| " (SELECT ps2.group_ref, ps2.profile_id, " + |
| " COUNT( ps2.matched_count) AS matched_count " + |
| " FROM test_6 ps2 " + |
| " GROUP BY ps2.group_ref, ps2.profile_id " + |
| ") b "; |
| |
| String cartProdWithOrderBySubqueries = "SELECT * " + |
| " FROM " + |
| " (SELECT ps1.group_ref, ps1.profile_id " + |
| " FROM test_5 ps1 ORDER BY profile_id fetch first 3 rows only) a, " + |
| " (SELECT ps2.group_ref, ps2.profile_id " + |
| " FROM test_6 ps2 ORDER BY PROFILE_ID fetch first 2 rows only) b "; |
| |
| |
| rs = s.executeQuery( cartProdWithDISTINCTsubqueries ); |
| JDBC.assertFullResultSet(rs, new String[][] { |
| {"10000", "1", "1", "10000", "1", "1"}, |
| {"10000", "1", "1", "10000", "2", "1"}, |
| {"10000", "2", "1", "10000", "1", "1"}, |
| {"10000", "2", "1", "10000", "2", "1"} |
| }); |
| |
| rs = s.executeQuery( cartProdWithSubqueries ); |
| JDBC.assertFullResultSet(rs, new String[][] { |
| {"10000", "1", "1", "10000", "1", "1"}, |
| {"10000", "1", "1", "10000", "2", "1"}, |
| {"10000", "2", "1", "10000", "1", "1"}, |
| {"10000", "2", "1", "10000", "2", "1"} |
| }); |
| |
| s.executeUpdate( "insert into test_5 values (3, 10000, 3)" ); |
| |
| rs = s.executeQuery( cartProdWithDISTINCTsubqueries ); |
| JDBC.assertFullResultSet(rs, new String[][] { |
| {"10000", "1", "1", "10000", "1", "1"}, |
| {"10000", "1", "1", "10000", "2", "1"}, |
| {"10000", "2", "1", "10000", "1", "1"}, |
| {"10000", "2", "1", "10000", "2", "1"}, |
| {"10000", "3", "1", "10000", "1", "1"}, |
| {"10000", "3", "1", "10000", "2", "1"} |
| }); |
| |
| rs = s.executeQuery( cartProdWithSubqueries ); |
| JDBC.assertFullResultSet(rs, new String[][] { |
| {"10000", "1", "1", "10000", "1", "1"}, |
| {"10000", "1", "1", "10000", "2", "1"}, |
| {"10000", "2", "1", "10000", "1", "1"}, |
| {"10000", "2", "1", "10000", "2", "1"}, |
| {"10000", "3", "1", "10000", "1", "1"}, |
| {"10000", "3", "1", "10000", "2", "1"} |
| }); |
| |
| s.executeUpdate( "insert into test_5 values (4, 10000, 4) "); |
| s.executeUpdate( "insert into test_6 values (3, 10000, 3) "); |
| |
| // NOTE: At this point, |
| // test_5 contains: test_6 contains: |
| // 1, 10000, 1 1, 10000, 1 |
| // 2, 10000, 2 2, 10000, 2 |
| // 3, 10000, 3 3, 10000, 3 |
| // 4, 10000, 4 |
| |
| rs = s.executeQuery( cartProdWithDISTINCTsubqueries ); |
| JDBC.assertFullResultSet(rs, new String[][] { |
| {"10000", "1", "1", "10000", "1", "1"}, |
| {"10000", "1", "1", "10000", "2", "1"}, |
| {"10000", "1", "1", "10000", "3", "1"}, |
| {"10000", "2", "1", "10000", "1", "1"}, |
| {"10000", "2", "1", "10000", "2", "1"}, |
| {"10000", "2", "1", "10000", "3", "1"}, |
| {"10000", "3", "1", "10000", "1", "1"}, |
| {"10000", "3", "1", "10000", "2", "1"}, |
| {"10000", "3", "1", "10000", "3", "1"}, |
| {"10000", "4", "1", "10000", "1", "1"}, |
| {"10000", "4", "1", "10000", "2", "1"}, |
| {"10000", "4", "1", "10000", "3", "1"} |
| }); |
| |
| rs = s.executeQuery( cartProdWithSubqueries ); |
| JDBC.assertFullResultSet(rs, new String[][] { |
| {"10000", "1", "1", "10000", "1", "1"}, |
| {"10000", "1", "1", "10000", "2", "1"}, |
| {"10000", "1", "1", "10000", "3", "1"}, |
| {"10000", "2", "1", "10000", "1", "1"}, |
| {"10000", "2", "1", "10000", "2", "1"}, |
| {"10000", "2", "1", "10000", "3", "1"}, |
| {"10000", "3", "1", "10000", "1", "1"}, |
| {"10000", "3", "1", "10000", "2", "1"}, |
| {"10000", "3", "1", "10000", "3", "1"}, |
| {"10000", "4", "1", "10000", "1", "1"}, |
| {"10000", "4", "1", "10000", "2", "1"}, |
| {"10000", "4", "1", "10000", "3", "1"} |
| }); |
| |
| s.executeUpdate( "insert into test_6 values (2, 10000, 1) "); |
| |
| rs = s.executeQuery( cartProdWithDISTINCTsubqueries ); |
| JDBC.assertFullResultSet(rs, new String[][] { |
| {"10000", "1", "1", "10000", "1", "1"}, |
| {"10000", "1", "1", "10000", "2", "2"}, |
| {"10000", "1", "1", "10000", "3", "1"}, |
| {"10000", "2", "1", "10000", "1", "1"}, |
| {"10000", "2", "1", "10000", "2", "2"}, |
| {"10000", "2", "1", "10000", "3", "1"}, |
| {"10000", "3", "1", "10000", "1", "1"}, |
| {"10000", "3", "1", "10000", "2", "2"}, |
| {"10000", "3", "1", "10000", "3", "1"}, |
| {"10000", "4", "1", "10000", "1", "1"}, |
| {"10000", "4", "1", "10000", "2", "2"}, |
| {"10000", "4", "1", "10000", "3", "1"} |
| }); |
| |
| rs = s.executeQuery( cartProdWithSubqueries ); |
| JDBC.assertFullResultSet(rs, new String[][] { |
| {"10000", "1", "1", "10000", "1", "1"}, |
| {"10000", "1", "1", "10000", "2", "2"}, |
| {"10000", "1", "1", "10000", "3", "1"}, |
| {"10000", "2", "1", "10000", "1", "1"}, |
| {"10000", "2", "1", "10000", "2", "2"}, |
| {"10000", "2", "1", "10000", "3", "1"}, |
| {"10000", "3", "1", "10000", "1", "1"}, |
| {"10000", "3", "1", "10000", "2", "2"}, |
| {"10000", "3", "1", "10000", "3", "1"}, |
| {"10000", "4", "1", "10000", "1", "1"}, |
| {"10000", "4", "1", "10000", "2", "2"}, |
| {"10000", "4", "1", "10000", "3", "1"} |
| }); |
| |
| // Now introduce some duplicate values so that the DISTINCT |
| // aggregates have some work to do |
| |
| |
| s.executeUpdate( "insert into test_6 values (1, 10000, 1) "); |
| s.executeUpdate( "insert into test_6 values (2, 10000, 2) "); |
| |
| // NOTE: At this point, |
| // test_5 contains: test_6 contains: |
| // 1, 10000, 1 1, 10000, 1 (2 vals, 1 distinct) |
| // 2, 10000, 2 1, 10000, 1 |
| // 3, 10000, 3 2, 10000, 1 (3 vals, 2 distinct) |
| // 4, 10000, 4 2, 10000, 2 |
| // 2, 10000, 2 |
| // 3, 10000, 2 (1 val, 1 distinct) |
| |
| rs = s.executeQuery( cartProdWithDISTINCTsubqueries ); |
| JDBC.assertFullResultSet(rs, new String[][] { |
| {"10000", "1", "1", "10000", "1", "1"}, |
| {"10000", "1", "1", "10000", "2", "2"}, |
| {"10000", "1", "1", "10000", "3", "1"}, |
| {"10000", "2", "1", "10000", "1", "1"}, |
| {"10000", "2", "1", "10000", "2", "2"}, |
| {"10000", "2", "1", "10000", "3", "1"}, |
| {"10000", "3", "1", "10000", "1", "1"}, |
| {"10000", "3", "1", "10000", "2", "2"}, |
| {"10000", "3", "1", "10000", "3", "1"}, |
| {"10000", "4", "1", "10000", "1", "1"}, |
| {"10000", "4", "1", "10000", "2", "2"}, |
| {"10000", "4", "1", "10000", "3", "1"} |
| }); |
| |
| rs = s.executeQuery( cartProdWithSubqueries ); |
| JDBC.assertFullResultSet(rs, new String[][] { |
| {"10000", "1", "1", "10000", "1", "2"}, |
| {"10000", "1", "1", "10000", "2", "3"}, |
| {"10000", "1", "1", "10000", "3", "1"}, |
| {"10000", "2", "1", "10000", "1", "2"}, |
| {"10000", "2", "1", "10000", "2", "3"}, |
| {"10000", "2", "1", "10000", "3", "1"}, |
| {"10000", "3", "1", "10000", "1", "2"}, |
| {"10000", "3", "1", "10000", "2", "3"}, |
| {"10000", "3", "1", "10000", "3", "1"}, |
| {"10000", "4", "1", "10000", "1", "2"}, |
| {"10000", "4", "1", "10000", "2", "3"}, |
| {"10000", "4", "1", "10000", "3", "1"} |
| }); |
| |
| rs = s.executeQuery( cartProdWithOrderBySubqueries ); |
| JDBC.assertFullResultSet(rs, new String[][] { |
| {"10000", "1", "10000", "1"}, |
| {"10000", "1", "10000", "1"}, |
| {"10000", "2", "10000", "1"}, |
| {"10000", "2", "10000", "1"}, |
| {"10000", "3", "10000", "1"}, |
| {"10000", "3", "10000", "1"} |
| }); |
| |
| rollback(); |
| } |
| |
| /** |
| * GROUP BY on an expression in a JOIN used to trigger an assert failure. |
| * See DERBY-5313. |
| */ |
| public void testDerby5313() throws SQLException { |
| setAutoCommit(false); |
| |
| Statement s = createStatement(); |
| s.execute("create table d5313_1(a int, b int)"); |
| s.execute("create table d5313_2(b int, c int)"); |
| s.execute("insert into d5313_1 values (3, 1), (2, 2), (3, 3)"); |
| s.execute("insert into d5313_2 values (0, 1), (1, 2), (2, 3), (3, 4)"); |
| |
| JDBC.assertUnorderedResultSet( |
| s.executeQuery("select a+b, sum(c) from " |
| + "d5313_1 natural join d5313_2 group by a+b"), |
| new String[][] { { "4", "5" }, { "6", "4" } }); |
| |
| JDBC.assertUnorderedResultSet( |
| s.executeQuery("select case when a=2 then 1 else 2 end, sum(c) " |
| + "from d5313_1 natural join d5313_2 group by " |
| + "case when a=2 then 1 else 2 end"), |
| new String[][] { { "1", "3" }, { "2", "6" } }); |
| } |
| } |