blob: fab0b2aa0310a4273e24f80a28ad102fe938bc90 [file]
/*
* Class org.apache.derbyTesting.functionTests.tests.lang.PredicateTest
*
* 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.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
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.List;
import junit.framework.Test;
import org.apache.derbyTesting.junit.BaseJDBCTestCase;
import org.apache.derbyTesting.junit.JDBC;
import org.apache.derbyTesting.junit.TestConfiguration;
/**
* This class contains test cases for the correct handling of predicates in
* SQL queries.
*/
public class PredicateTest extends BaseJDBCTestCase {
public PredicateTest(String name) {
super(name);
}
public static Test suite() {
// We're testing engine functionality, so run in embedded only.
return TestConfiguration.embeddedSuite(PredicateTest.class);
}
/**
* DERBY-2282: Test that we're able to compute the transitive closure of
* predicates with constants on the left side of the comparison operator.
*/
public void testTransitiveClosureWithConstantsOnLeftSide()
throws SQLException, IOException {
setAutoCommit(false); // let tables be cleaned up automatically
Statement s = createStatement();
// insert test data
s.execute("create table t1 (i int)");
s.execute("create table t2 (j int)");
s.execute("insert into t1 values 1, 5, 7, 11, 13, 17, 19");
s.execute("insert into t2 values 23, 29, 31, 37, 43, 47, 53");
s.execute("insert into t1 select 23 * i from t1 where i < 19");
s.execute("insert into t2 select 23 * j from t2 where j < 55");
// enable runtime statistics
s.execute("call syscs_util.syscs_set_runtimestatistics(1)");
// Following will show two qualifiers for T2 and three for T1
// because transitive closure adds two new qualifiers, "t2.j >= 23"
// and "t1.i <= 30" to the list.
JDBC.assertSingleValueResultSet(
s.executeQuery(
"select i from t1, t2 where " +
"t1.i = t2.j and t1.i >= 23 and t2.j <= 30"),
"23");
List expectedOperators = Arrays.asList(new String[] {
"Operator: <", "Operator: <=",
"Operator: <", "Operator: <=", "Operator: ="
});
assertEquals(expectedOperators, extractOperators(getStatistics()));
// But if we put the constants on the left-hand side, we didn't
// detect the transitive closure and thus we had a single qualifier
// for T2 and only two qualifiers for T1.
JDBC.assertSingleValueResultSet(
s.executeQuery(
"select i from t1, t2 where " +
"t1.i = t2.j and 23 <= t1.i and 30 >= t2.j"),
"23");
// Verify that we now have all the expected qualifiers.
assertEquals(expectedOperators, extractOperators(getStatistics()));
// Now check that we get the same plan with parameters instead of
// constants on the right-hand side.
PreparedStatement paramRight = prepareStatement(
"select i from t1, t2 where " +
"t1.i = t2.j and t1.i >= ? and t2.j <= ?");
paramRight.setInt(1, 23);
paramRight.setInt(2, 30);
JDBC.assertSingleValueResultSet(paramRight.executeQuery(), "23");
assertEquals(expectedOperators, extractOperators(getStatistics()));
// Same plan expected with parameters on the left-hand side.
PreparedStatement paramLeft = prepareStatement(
"select i from t1, t2 where " +
"t1.i = t2.j and ? <= t1.i and ? >= t2.j");
paramLeft.setInt(1, 23);
paramLeft.setInt(2, 30);
JDBC.assertSingleValueResultSet(paramLeft.executeQuery(), "23");
assertEquals(expectedOperators, extractOperators(getStatistics()));
}
/**
* Get the runtime statistics for the previous statement executed on the
* default connection (if collection of runtime statistics has been
* enabled).
*
* @return a string with the runtime statistics
*/
private String getStatistics() throws SQLException {
ResultSet rs = createStatement().executeQuery(
"values syscs_util.syscs_get_runtimestatistics()");
rs.next();
String stats = rs.getString(1);
JDBC.assertEmpty(rs);
return stats;
}
/**
* Extract all the operators from the runtime statistics.
*
* @param stats the runtime statistics
* @return a list of all operators
*/
private List<String> extractOperators(String stats) throws IOException {
ArrayList<String> ops = new ArrayList<String>();
BufferedReader r = new BufferedReader(new StringReader(stats));
String line;
while ((line = r.readLine()) != null) {
line = line.trim();
if (line.startsWith("Operator: ")) {
ops.add(line);
}
}
return ops;
}
}