blob: e6242dbccf5051980e51c35f6b73428068d138b7 [file] [log] [blame]
/**
* Derby - Class org.apache.derbyTesting.functionTests.tests.lang.NestedWhereSubqueryTest
*
* 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.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import junit.framework.Test;
import org.apache.derbyTesting.junit.BaseJDBCTestCase;
import org.apache.derbyTesting.junit.JDBC;
import org.apache.derbyTesting.junit.TestConfiguration;
/**
* Nested WHERE subquery tests. Tests nested WHERE EXISTS | ANY | IN functionality.
*
* Please refer to DERBY-3301 for more details.
*/
public class NestedWhereSubqueryTest extends BaseJDBCTestCase {
public NestedWhereSubqueryTest(String name) {
super(name);
}
/**
* Main test body
*
* @throws SQLException
*/
public void testBasicOperations()
throws SQLException {
Statement s = createStatement();
/*
* Create tables needed for DERBY-3301 regression test
*/
StringBuffer sb = new StringBuffer();
sb.append("CREATE TABLE departments ( ");
sb.append("ID INTEGER NOT NULL, ");
sb.append("NAME VARCHAR(32) NOT NULL, ");
sb.append("COMPANYID INTEGER, ");
sb.append("CONSTRAINT DEPTS_PK PRIMARY KEY (ID) ");
sb.append(")");
s.executeUpdate(sb.toString());
sb = new StringBuffer();
sb.append("CREATE TABLE employees ( ");
sb.append("EMPID INTEGER NOT NULL, ");
sb.append("FIRSTNAME VARCHAR(32) NOT NULL, ");
sb.append("DEPARTMENT INTEGER, ");
sb.append("CONSTRAINT PERS_DEPT_FK FOREIGN KEY (DEPARTMENT) REFERENCES departments, ");
sb.append("CONSTRAINT EMPS_PK PRIMARY KEY (EMPID) ");
sb.append(")");
s.executeUpdate(sb.toString());
sb = new StringBuffer();
sb.append("CREATE TABLE projects ( ");
sb.append("PROJID INTEGER NOT NULL, ");
sb.append("NAME VARCHAR(32) NOT NULL, ");
sb.append("CONSTRAINT PROJS_PK PRIMARY KEY (PROJID) ");
sb.append(")");
s.executeUpdate(sb.toString());
sb = new StringBuffer();
sb.append("CREATE TABLE project_employees ( ");
sb.append("PROJID INTEGER REFERENCES projects NOT NULL, ");
sb.append("EMPID INTEGER REFERENCES employees NOT NULL ");
sb.append(")");
s.executeUpdate(sb.toString());
/*
* Fill some data into the tables
*/
s.executeUpdate("INSERT INTO departments VALUES (1, 'Research', 1)");
s.executeUpdate("INSERT INTO departments VALUES (2, 'Marketing', 1)");
s.executeUpdate("INSERT INTO employees VALUES (11, 'Alex', 1)");
s.executeUpdate("INSERT INTO employees VALUES (12, 'Bill', 1)");
s.executeUpdate("INSERT INTO employees VALUES (13, 'Charles', 1)");
s.executeUpdate("INSERT INTO employees VALUES (14, 'David', 2)");
s.executeUpdate("INSERT INTO employees VALUES (15, 'Earl', 2)");
s.executeUpdate("INSERT INTO projects VALUES (101, 'red')");
s.executeUpdate("INSERT INTO projects VALUES (102, 'orange')");
s.executeUpdate("INSERT INTO projects VALUES (103, 'yellow')");
s.executeUpdate("INSERT INTO project_employees VALUES (102, 13)");
s.executeUpdate("INSERT INTO project_employees VALUES (101, 13)");
s.executeUpdate("INSERT INTO project_employees VALUES (102, 12)");
s.executeUpdate("INSERT INTO project_employees VALUES (103, 15)");
s.executeUpdate("INSERT INTO project_employees VALUES (103, 14)");
s.executeUpdate("INSERT INTO project_employees VALUES (101, 12)");
s.executeUpdate("INSERT INTO project_employees VALUES (101, 11)");
/*
* Preliminary data check
*/
ResultSet rs = s.executeQuery("select * from employees");
String[][] expectedRows = {{"11", "Alex", "1"},
{"12", "Bill", "1"},
{"13", "Charles", "1"},
{"14", "David", "2"},
{"15", "Earl", "2"}};
JDBC.assertUnorderedResultSet(rs, expectedRows);
rs = s.executeQuery("select * from departments");
expectedRows = new String [][] {{"1", "Research", "1"},
{"2","Marketing","1"}};
JDBC.assertUnorderedResultSet(rs, expectedRows);
rs = s.executeQuery("select * from projects");
expectedRows = new String [][] {{"101","red"},
{"102","orange"},
{"103","yellow"}};
JDBC.assertUnorderedResultSet(rs, expectedRows);
rs = s.executeQuery("select * from project_employees");
expectedRows = new String [][] {{"102","13"},
{"101","13"},
{"102","12"},
{"103","15"},
{"103","14"},
{"101","12"},
{"101","11"}};
JDBC.assertUnorderedResultSet(rs, expectedRows);
/*
* DERBY-3301: This query should return 7 rows
*/
sb = new StringBuffer();
sb.append("select unbound_e.empid, unbound_p.projid ");
sb.append("from departments this, ");
sb.append(" employees unbound_e, ");
sb.append(" projects unbound_p ");
sb.append("where exists ( ");
sb.append(" select 1 from employees this_employees_e ");
sb.append(" where exists ( ");
sb.append(" select 1 from project_employees this_employees_e_projects_p ");
sb.append(" where this_employees_e_projects_p.empid = this_employees_e.empid ");
sb.append(" and this_employees_e.department = this.id ");
sb.append(" and unbound_p.projid = this_employees_e_projects_p.projid ");
sb.append(" and unbound_e.empid = this_employees_e.empid) ");
sb.append(" )");
rs = s.executeQuery(sb.toString());
expectedRows = new String [][] {{"13", "101"},
{"12", "101"},
{"11", "101"},
{"13", "102"},
{"12", "102"},
{"15", "103"},
{"14", "103"}};
JDBC.assertUnorderedResultSet(rs, expectedRows);
/* A variation of the above WHERE EXISTS but using IN should return the same rows */
sb = new StringBuffer();
sb.append("select unbound_e.empid, unbound_p.projid ");
sb.append("from departments this, ");
sb.append(" employees unbound_e, ");
sb.append(" projects unbound_p ");
sb.append("where exists ( ");
sb.append(" select 1 from employees this_employees_e ");
sb.append(" where this_employees_e.empid in ( ");
sb.append(" select this_employees_e_projects_p.empid ");
sb.append(" from project_employees this_employees_e_projects_p ");
sb.append(" where this_employees_e_projects_p.empid = this_employees_e.empid ");
sb.append(" and this_employees_e.department = this.id ");
sb.append(" and unbound_p.projid = this_employees_e_projects_p.projid ");
sb.append(" and unbound_e.empid = this_employees_e.empid) ");
sb.append(" )");
rs = s.executeQuery(sb.toString());
JDBC.assertUnorderedResultSet(rs, expectedRows);
/* A variation of the above WHERE EXISTS but using ANY should return the same rows */
sb = new StringBuffer();
sb.append("select unbound_e.empid, unbound_p.projid ");
sb.append("from departments this, ");
sb.append(" employees unbound_e, ");
sb.append(" projects unbound_p ");
sb.append("where exists ( ");
sb.append(" select 1 from employees this_employees_e ");
sb.append(" where this_employees_e.empid = any ( ");
sb.append(" select this_employees_e_projects_p.empid ");
sb.append(" from project_employees this_employees_e_projects_p ");
sb.append(" where this_employees_e_projects_p.empid = this_employees_e.empid ");
sb.append(" and this_employees_e.department = this.id ");
sb.append(" and unbound_p.projid = this_employees_e_projects_p.projid ");
sb.append(" and unbound_e.empid = this_employees_e.empid) ");
sb.append(" )");
rs = s.executeQuery(sb.toString());
JDBC.assertUnorderedResultSet(rs, expectedRows);
/*
* The next 5 queries were also found problematic as part DERBY-3301
*/
sb = new StringBuffer();
sb.append("select unbound_e.empid from departments this, employees unbound_e ");
sb.append("where exists ( ");
sb.append(" select 1 from employees this_employees_e ");
sb.append(" where this_employees_e.department = this.id and ");
sb.append(" unbound_e.empid = this_employees_e.empid and this.id = 2)");
rs = s.executeQuery(sb.toString());
expectedRows = new String [][] {{"14"},{"15"}};
JDBC.assertUnorderedResultSet(rs, expectedRows);
sb = new StringBuffer();
sb.append("select this.id,unbound_e.empid,unbound_p.projid from departments this, ");
sb.append(" employees unbound_e, projects unbound_p ");
sb.append("where exists ( ");
sb.append(" select 1 from employees this_employees_e ");
sb.append(" where exists ( ");
sb.append(" select 1 from project_employees this_employees_e_projects_p ");
sb.append(" where this_employees_e_projects_p.\"EMPID\" = this_employees_e.empid and ");
sb.append(" unbound_p.projid = this_employees_e_projects_p.projid and ");
sb.append(" this_employees_e.department = this.id and ");
sb.append(" unbound_e.empid = this_employees_e.empid ");
sb.append(" )) ");
rs = s.executeQuery(sb.toString());
expectedRows = new String [][] {{"1","11","101"},
{"1","12","101"},
{"1","13","101"},
{"1","12","102"},
{"1","13","102"},
{"2","14","103"},
{"2","15","103"}};
JDBC.assertUnorderedResultSet(rs, expectedRows);
sb = new StringBuffer();
sb.append("select unbound_e.empid,unbound_p.projid from departments this, ");
sb.append(" employees unbound_e, projects unbound_p ");
sb.append("where exists ( ");
sb.append(" select 1 from employees this_employees_e ");
sb.append(" where exists ( ");
sb.append(" select 1 from project_employees this_employees_e_projects_p ");
sb.append(" where this_employees_e_projects_p.\"EMPID\" = this_employees_e.empid ");
sb.append(" and unbound_p.projid = this_employees_e_projects_p.projid ");
sb.append(" and this_employees_e.department = this.id ");
sb.append(" and unbound_e.empid = this_employees_e.empid ");
sb.append(" and this.id = 1)) ");
rs = s.executeQuery(sb.toString());
expectedRows = new String [][] {{"11","101"},
{"12","101"},
{"13","101"},
{"12","102"},
{"13","102"}};
JDBC.assertUnorderedResultSet(rs, expectedRows);
sb = new StringBuffer();
sb.append("select unbound_e.empid,unbound_p.projid from departments this, ");
sb.append(" employees unbound_e, projects unbound_p ");
sb.append("where exists ( ");
sb.append(" select 1 from employees this_employees_e ");
sb.append(" where exists ( ");
sb.append(" select 1 from project_employees this_employees_e_projects_p ");
sb.append(" where this_employees_e_projects_p.\"EMPID\" = this_employees_e.empid ");
sb.append(" and unbound_p.projid = this_employees_e_projects_p.projid ");
sb.append(" and this_employees_e.department = this.id ");
sb.append(" and unbound_e.empid = this_employees_e.empid ");
sb.append(" and this.companyid = 1))");
rs = s.executeQuery(sb.toString());
expectedRows = new String [][] {{"11","101"},
{"12","101"},
{"13","101"},
{"12","102"},
{"13","102"},
{"14","103"},
{"15","103"}};
JDBC.assertUnorderedResultSet(rs, expectedRows);
sb = new StringBuffer();
sb.append("select unbound_e.empid, unbound_p.projid ");
sb.append("from departments this, ");
sb.append(" employees unbound_e, ");
sb.append(" projects unbound_p ");
sb.append("where exists ( ");
sb.append(" select 1 from employees this_employees_e ");
sb.append(" where 1 = 1 and exists ( ");
sb.append(" select 1 from project_employees this_employees_e_projects_p ");
sb.append(" where this_employees_e_projects_p.empid = this_employees_e.empid ");
sb.append(" and this_employees_e.department = this.id ");
sb.append(" and unbound_p.projid = this_employees_e_projects_p.projid ");
sb.append(" and unbound_e.empid = this_employees_e.empid) ");
sb.append(")");
rs = s.executeQuery(sb.toString());
expectedRows = new String [][] {{"11","101"},
{"12","101"},
{"13","101"},
{"12","102"},
{"13","102"},
{"14","103"},
{"15","103"}};
JDBC.assertUnorderedResultSet(rs, expectedRows);
/* Variation of the above using WHERE IN ... WHERE IN */
sb = new StringBuffer();
sb.append("select unbound_e.empid, unbound_p.projid ");
sb.append("from departments this, employees unbound_e, projects unbound_p ");
sb.append("where this.id in ( ");
sb.append(" select this_employees_e.department from employees this_employees_e ");
sb.append(" where this_employees_e.empid in ( ");
sb.append(" select this_employees_e_projects_p.empid ");
sb.append(" from project_employees this_employees_e_projects_p ");
sb.append(" where this_employees_e_projects_p.empid = this_employees_e.empid ");
sb.append(" and this_employees_e.department = this.id ");
sb.append(" and unbound_p.projid = this_employees_e_projects_p.projid ");
sb.append(" and unbound_e.empid = this_employees_e.empid)");
sb.append(")");
rs = s.executeQuery(sb.toString());
/* Expected rows are as above */
JDBC.assertUnorderedResultSet(rs, expectedRows);
/* Variation of the above using WHERE ANY ... WHERE ANY */
sb = new StringBuffer();
sb.append("select unbound_e.empid, unbound_p.projid ");
sb.append("from departments this, employees unbound_e, projects unbound_p ");
sb.append("where this.id = any ( ");
sb.append(" select this_employees_e.department from employees this_employees_e ");
sb.append(" where this_employees_e.empid = any ( ");
sb.append(" select this_employees_e_projects_p.empid ");
sb.append(" from project_employees this_employees_e_projects_p ");
sb.append(" where this_employees_e_projects_p.empid = this_employees_e.empid ");
sb.append(" and this_employees_e.department = this.id ");
sb.append(" and unbound_p.projid = this_employees_e_projects_p.projid ");
sb.append(" and unbound_e.empid = this_employees_e.empid)");
sb.append(")");
rs = s.executeQuery(sb.toString());
/* Expected rows are as above */
JDBC.assertUnorderedResultSet(rs, expectedRows);
/*
* DERBY-3321 revealed an NPE with a subquery in the [NOT] EXIST subuery FromList.
*/
s.executeUpdate("create table a (aa int, bb int)");
s.executeUpdate("create table b (bb int)");
s.executeUpdate("insert into a values (1,1),(1,2),(2,2)");
s.executeUpdate("insert into b values (1)");
/* NOT EXISTS */
sb = new StringBuffer();
sb.append("select * from a ");
sb.append("where not exists ");
sb.append("(select bb from (select bb from b) p where a.bb=p.bb)");
rs = s.executeQuery(sb.toString());
expectedRows = new String [][] {{"1","2"},
{"2","2"}};
JDBC.assertUnorderedResultSet(rs, expectedRows);
/* EXISTS */
sb = new StringBuffer();
sb.append("select * from a ");
sb.append("where exists ");
sb.append("(select bb from (select bb from b) p where a.bb=p.bb)");
rs = s.executeQuery(sb.toString());
expectedRows = new String [][] {{"1","1"}};
JDBC.assertUnorderedResultSet(rs, expectedRows);
/*
* Clean up the tables used.
*/
s.executeUpdate("drop table project_employees");
s.executeUpdate("drop table projects");
s.executeUpdate("drop table employees");
s.executeUpdate("drop table departments");
s.executeUpdate("drop table a");
s.executeUpdate("drop table b");
s.close();
}
/**
* Allow multiple columns in EXISTS subquery. SQL feature T501 "Enhanced
* EXISTS predicate".
* <p/>
* Strictly speaking, this test belongs in a general subquery test class,
* but pending conversion of subquery.sql to JUnit, testDerby5501 resides
* here (FIXME).
*/
public void testDerby5501 () throws SQLException {
setAutoCommit(false);
Statement s = createStatement();
s.executeUpdate("create table t5501a(i int, j int, primary key(i,j))");
s.executeUpdate("create table t5501b(i int)");
s.executeUpdate("insert into t5501a values (1,1),(2,2),(3,3),(4,4)");
s.executeUpdate("insert into t5501b values 1,3,5");
// works before DERBY-5501
ResultSet rs = s.executeQuery(
"select i from t5501b t1 where not exists " +
" (select i from t5501a t2 where t1.i=t2.i)");
JDBC.assertUnorderedResultSet(rs, new String [][] {{"5"}});
rs = s.executeQuery(
"select i+3.14 from t5501b t1 where not exists " +
" (select i+3.14 from t5501a t2 where t1.i=t2.i)");
JDBC.assertUnorderedResultSet(rs, new String [][] {{"8.14"}});
// works before DERBY-5501: "*" is specially handled already
rs = s.executeQuery(
"select i from t5501b t1 where not exists " +
" (select * from t5501a t2 where t1.i=t2.i)");
JDBC.assertUnorderedResultSet(rs, new String [][] {{"5"}});
// fails before DERBY-5501
rs = s.executeQuery(
"select i from t5501b t1 where not exists " +
" (select i,j from t5501a t2 where t1.i=t2.i)");
JDBC.assertUnorderedResultSet(rs, new String [][] {{"5"}});
rs = s.executeQuery(
"select i from t5501b t1 where not exists " +
" (select true,j from t5501a t2 where t1.i=t2.i)");
JDBC.assertUnorderedResultSet(rs, new String [][] {{"5"}});
s.executeUpdate("delete from t5501a where i=1");
rs = s.executeQuery(
"select i from t5501b t1 where not exists " +
" (select i,j from t5501a t2 where t1.i=t2.i)");
JDBC.assertUnorderedResultSet(rs, new String [][] {{"1"}, {"5"}});
// should still fail: no column "k" exists
assertCompileError(
"42X04",
"select i from t5501b t1 where not exists " +
" (select i,k from t5501a t2 where t1.i=t2.i)");
// should still fail: no table "foo" exists
assertCompileError(
"42X10",
"select i from t5501b t1 where not exists " +
" (select t2.*,foo.* from t5501a t2 where t1.i=t2.i)");
// should still fail: illegal integer format in cast
assertCompileError(
"22018",
"select i from t5501b t1 where not exists " +
" (select t2.*,cast('a' as int) from t5501a t2 where t1.i=t2.i)");
}
public static Test suite() {
return TestConfiguration.defaultSuite(NestedWhereSubqueryTest.class);
}
}