blob: a3455b5edb234c57832c85efe30cd77e3601f33e [file] [log] [blame]
/*
Derby - Class org.apache.derbyTesting.functionTests.tests.jdbcapi.StatementJdbc20Test
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.jdbcapi;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
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.BaseTestSuite;
import org.apache.derbyTesting.junit.CleanDatabaseTestSetup;
import org.apache.derbyTesting.junit.JDBC;
import org.apache.derbyTesting.junit.TestConfiguration;
/**
* Test of additional methods in JDBC2.0 methods in statement and
* resultset classes.
* This test converts the old jdbcapi/statementJdbc20.java test
* to JUnit.
*/
public class StatementJdbc20Test extends BaseJDBCTestCase {
private static final String METHOD_NOT_ALLOWED = "XJ016";
private static final String CLOSED_STATEMENT = "XJ012";
/**
* Create a test with the given name.
*
* @param name name of the test.
*/
public StatementJdbc20Test(String name) {
super(name);
}
/**
* Create suite containing client and embedded tests and to run
* all tests in this class
*/
public static Test suite() {
BaseTestSuite suite = new BaseTestSuite("StatementJdbc20Test");
suite.addTest(baseSuite("StatementJdbc20Test:embedded"));
suite.addTest(
TestConfiguration.clientServerDecorator(
baseSuite("StatementJdbc20Test:client")));
return suite;
}
private static Test baseSuite(String name) {
BaseTestSuite suite = new BaseTestSuite(name);
suite.addTestSuite(StatementJdbc20Test.class);
return new CleanDatabaseTestSetup(suite) {
/**
* Creates the tables used in the test
* cases.
*
* @exception SQLException if a database error occurs
*/
protected void decorateSQL(Statement stmt) throws SQLException {
Connection conn = getConnection();
/**
* Creates the table used in the test cases.
*
*/
stmt.execute("create table tab1 (i int, s smallint, r real)");
stmt.executeUpdate("insert into tab1 values(1, 2, 3.1)");
stmt.execute
(
"create procedure dynamic_results() " +
"language java parameter style java external name '" +
StatementJdbc20Test.class.getName() + ".dynamicResults' " +
"dynamic result sets 2"
);
stmt.execute( "create table t_autogen( a int generated always as identity, b int )" );
}
};
}
/**
* Testing wrong values for setFetchSize
* and setFetchDirection.
*
* @exception SQLException if error occurs
*/
public void testWrongVaues() throws SQLException {
Statement stmt = createStatement();
stmt.setFetchSize(25);
stmt.setFetchDirection(ResultSet.FETCH_REVERSE);
stmt.setEscapeProcessing(true);
//Error testing : set wrong values ..
try {
stmt.setFetchSize(-1000);
fail("setFetchSize(-1000) expected to fail");
} catch(SQLException e) {
assertSQLState("XJ065", e);
}
try {
stmt.setFetchDirection(-1000);
fail("setFetchDirection(-1000) expected to fail");
} catch(SQLException e){
assertSQLState("XJ064", e);
}
assertEquals(stmt.getFetchSize(), 25);
assertEquals(stmt.getFetchDirection(), ResultSet.FETCH_REVERSE);
stmt.close();
}
/**
* Tests reading data from database
*
* @exception SQLException if error occurs
*/
public void testReadingData() throws SQLException {
Statement stmt = createStatement();
ResultSet rs;
// read the data just for the heck of it
rs = stmt.executeQuery("select * from tab1");
while (rs.next()) {
assertEquals(rs.getInt(1), 1);
assertEquals(rs.getShort(2), 2);
assertEquals(rs.getDouble(3), 3.1, 0.01);
}
rs.close();
stmt.close();
}
/**
* Tests values local to result set and get them back
*
* @exception SQLException if error occurs
*/
public void testLocalValuesOfResultSet() throws SQLException {
Statement stmt = createStatement();
ResultSet rs;
stmt.setFetchSize(25);
stmt.setFetchDirection(ResultSet.FETCH_REVERSE);
stmt.setEscapeProcessing(true);
rs = stmt.executeQuery("select * from tab1");
// Get the constatnts for a result set
assertEquals(rs.getFetchSize(), 25);
assertEquals(rs.getFetchDirection(), ResultSet.FETCH_REVERSE);
// change values local to result set and get them back
rs.setFetchSize(250);
try{
rs.setFetchDirection(ResultSet.FETCH_FORWARD);
}catch(SQLException e){
if (usingEmbedded())
assertSQLState("XJ061", e);
else
assertSQLState("XJ125", e);
}
assertEquals(rs.getFetchSize(), 250);
assertEquals(rs.getFetchDirection(), ResultSet.FETCH_REVERSE);
// Verify that fetch size can be set larger than maxRows
stmt.setMaxRows(10);
rs.setFetchSize(100);
//Error testing : set wrong values ..
try{
rs.setFetchSize(-2000);
fail("setFetchSize(-2000) expected to fail");
} catch(SQLException e){
assertSQLState("XJ062", e);
}
try{
rs.setFetchDirection(-2000);
} catch(SQLException e){
if (usingEmbedded())
assertSQLState("XJ061", e);
else
assertSQLState("XJ125", e);
}
// set the fetch size values to zero .. to ensure
// error condtions are correct !
rs.setFetchSize(0);
stmt.setFetchSize(0);
rs.close();
}
/**
* Tests creating tables with executeQuery which is
* not allowed on statements that return a row count
*
* @exception SQLException
* if error occurs
*/
public void testCreateTableWithExecuteQuery() throws SQLException {
Statement stmt = createStatement();
ResultSet rs;
//RESOLVE - uncomment tests in 3.5
// executeQuery() not allowed on statements
// that return a row count
try {
stmt.executeQuery("create table trash(c1 int)");
} catch (SQLException e) {
if (usingEmbedded())
assertSQLState("X0Y78", e);
else
assertSQLState("XJ207", e);
}
// verify that table was not created
try {
rs = stmt.executeQuery("select * from trash");
System.out.println("select from trash expected to fail");
} catch (SQLException e) {
assertSQLState("42X05", e);
}
// executeUpdate() not allowed on statements
// that return a ResultSet
try {
stmt.executeUpdate("values 1");
} catch (SQLException e) {
assertSQLState("X0Y79", e);
}
stmt.close();
commit();
}
/**
* Test the following clarification made by JDBC 4.1: You should
* raise an exception when addBatch(String) is called on a PreparedStatement
* or a CallableStatement.
*/
public void testAddBatchClarification_jdbc4_1() throws SQLException
{
PreparedStatement ps = prepareStatement( "select * from sys.systables" );
CallableStatement cs = prepareCall( "CALL SYSCS_UTIL.SYSCS_SET_RUNTIMESTATISTICS(1)" );
try {
ps.addBatch( "select * from sys.systables" );
fail( "Oops. ps.addBatch() worked." );
}
catch (SQLException se)
{
assertSQLState( METHOD_NOT_ALLOWED, se );
}
try {
cs.addBatch( "CALL SYSCS_UTIL.SYSCS_SET_RUNTIMESTATISTICS(1)" );
fail( "Oops. cs.addBatch() worked." );
}
catch (SQLException se)
{
assertSQLState( METHOD_NOT_ALLOWED, se );
}
}
/**
* Test the closeOnCompletion() and isCloseOnCompletion() methods
* added by JDBC 4.1.
*/
public void testCompletionClosure_jdbc4_1() throws Exception
{
if ( JDBC.vmSupportsJSR169() ) { return; }
vetClosure( false, false );
vetClosure( false, true );
vetClosure( true, false );
vetClosure( true, true );
}
private void vetClosure( boolean closeOnCompletion, boolean delayClosureCall ) throws Exception
{
vetClosedSelect( closeOnCompletion, delayClosureCall );
vetClosedCall( closeOnCompletion, delayClosureCall );
vetClosedPS( closeOnCompletion, delayClosureCall );
vetClosedAutoGen( closeOnCompletion, delayClosureCall );
}
private void vetClosedSelect( boolean closeOnCompletion, boolean delayClosureCall ) throws Exception
{
Statement stmt = createStatement();
ResultSet rs;
println( "Verifying SELECT wrapper on " + stmt.getClass().getName() +
" with closeOnCompletion = " + closeOnCompletion +
" and delayClosureCall = " + delayClosureCall );
Wrapper41Statement wrapper = new Wrapper41Statement( stmt );
if ( !delayClosureCall )
{ setCloseOnCompletion( wrapper, closeOnCompletion ); }
rs = stmt.executeQuery( "select * from tab1" );
if ( delayClosureCall )
{ setCloseOnCompletion( wrapper, closeOnCompletion ); }
rs.close();
assertEquals( closeOnCompletion, wrapper.isClosed() );
vetSuccessfulClosure( wrapper, closeOnCompletion );
}
private void vetClosedCall( boolean closeOnCompletion, boolean delayClosureCall ) throws Exception
{
Statement stmt = createStatement();
ResultSet rs;
println( "Verifying CALL wrapper on " + stmt.getClass().getName() +
" with closeOnCompletion = " + closeOnCompletion +
" and delayClosureCall = " + delayClosureCall );
Wrapper41Statement wrapper = new Wrapper41Statement( stmt );
if ( !delayClosureCall )
{ setCloseOnCompletion( wrapper, closeOnCompletion ); }
assertTrue( stmt.execute( "call dynamic_results()" ) );
assertFalse( wrapper.isClosed() );
ResultSet rs1 = stmt.getResultSet();
if ( delayClosureCall )
{ setCloseOnCompletion( wrapper, closeOnCompletion ); }
assertTrue( stmt.getMoreResults() ); // implicitly closes rs1
assertFalse( wrapper.isClosed() );
ResultSet rs2 = stmt.getResultSet();
rs2.close();
assertEquals( closeOnCompletion, wrapper.isClosed() );
vetSuccessfulClosure( wrapper, closeOnCompletion );
}
private void vetClosedPS( boolean closeOnCompletion, boolean delayClosureCall ) throws Exception
{
PreparedStatement ps = getConnection().prepareStatement( "select * from tab1" );
ResultSet rs;
println( "Verifying PreparedStatement wrapper on " + ps.getClass().getName() +
" with closeOnCompletion = " + closeOnCompletion +
" and delayClosureCall = " + delayClosureCall );
Wrapper41Statement wrapper = new Wrapper41Statement( ps );
if ( !delayClosureCall )
{ setCloseOnCompletion( wrapper, closeOnCompletion ); }
rs = ps.executeQuery();
if ( delayClosureCall )
{ setCloseOnCompletion( wrapper, closeOnCompletion ); }
rs.close();
assertEquals( closeOnCompletion, wrapper.isClosed() );
vetSuccessfulClosure( wrapper, closeOnCompletion );
if ( !wrapper.isClosed() ) { ps.close(); }
}
private void vetClosedAutoGen( boolean closeOnCompletion, boolean delayClosureCall ) throws Exception
{
Statement stmt = createStatement();
ResultSet rs;
println( "Verifying AUTOGENERATED KEYS wrapper on " + stmt.getClass().getName() +
" with closeOnCompletion = " + closeOnCompletion +
" and delayClosureCall = " + delayClosureCall );
Wrapper41Statement wrapper = new Wrapper41Statement( stmt );
if ( !delayClosureCall )
{ setCloseOnCompletion( wrapper, closeOnCompletion ); }
stmt.executeUpdate( "insert into t_autogen( b ) values ( 1 )", Statement.RETURN_GENERATED_KEYS );
rs = stmt.getGeneratedKeys();
if ( delayClosureCall )
{ setCloseOnCompletion( wrapper, closeOnCompletion ); }
assertFalse( wrapper.isClosed() );
rs.close();
assertEquals( closeOnCompletion, wrapper.isClosed() );
vetSuccessfulClosure( wrapper, closeOnCompletion );
}
private void setCloseOnCompletion( Wrapper41Statement wrapper, boolean closeOnCompletion )
throws Exception
{
assertFalse( wrapper.isCloseOnCompletion() );
if ( closeOnCompletion ) { wrapper.closeOnCompletion(); }
assertEquals( closeOnCompletion, wrapper.isCloseOnCompletion() );
}
private void vetSuccessfulClosure
( Wrapper41Statement wrapper, boolean closeOnCompletion )
throws Exception
{
if ( closeOnCompletion )
{
try {
wrapper.closeOnCompletion();
fail( "Expected closed statement failure." );
}
catch (SQLException se)
{
assertSQLState( CLOSED_STATEMENT, se );
}
try {
wrapper.isCloseOnCompletion();
fail( "Expected closed statement failure." );
}
catch (SQLException se)
{
assertSQLState( CLOSED_STATEMENT, se );
}
}
}
/**
* <p>
* Spec clarifications in JDBC 4.1. Verify that an exception is raised if a PreparedStatement
* or CallableStatement tries to execute one of the methods which compiles SQL text.
* </p>
*/
public void test_clarification_jdbc4_1() throws Exception
{
Connection conn = getConnection();
PreparedStatement ps = conn.prepareStatement( "select * from sys.syscolumns" );
CallableStatement cs = conn.prepareCall( "call dynamic_results()" );
vetNotAllowed( ps );
vetNotAllowed( cs );
ps.close();
cs.close();
}
private void vetNotAllowed( Statement stmt ) throws Exception
{
println( "Vetting a " + stmt.getClass().getName() );
try {
stmt.execute( "select * from sys.systables" );
failVNA();
}
catch (SQLException se)
{
assertSQLState( METHOD_NOT_ALLOWED, se );
}
try {
stmt.execute( "select * from sys.systables", Statement.NO_GENERATED_KEYS );
failVNA();
}
catch (SQLException se)
{
assertSQLState( METHOD_NOT_ALLOWED, se );
}
try {
stmt.execute( "select * from sys.systables", new int[] { 1 } );
failVNA();
}
catch (SQLException se)
{
assertSQLState( METHOD_NOT_ALLOWED, se );
}
try {
stmt.execute( "select * from sys.systables", new String[] { "COLUMNNAME" } );
failVNA();
}
catch (SQLException se)
{
assertSQLState( METHOD_NOT_ALLOWED, se );
}
try {
stmt.executeQuery( "select * from sys.systables" );
failVNA();
}
catch (SQLException se)
{
assertSQLState( METHOD_NOT_ALLOWED, se );
}
try {
stmt.executeUpdate( "insert into tab1 values(1, 2, 3.1)" );
failVNA();
}
catch (SQLException se)
{
assertSQLState( METHOD_NOT_ALLOWED, se );
}
try {
stmt.executeUpdate( "insert into tab1 values(1, 2, 3.1)", Statement.NO_GENERATED_KEYS );
failVNA();
}
catch (SQLException se)
{
assertSQLState( METHOD_NOT_ALLOWED, se );
}
try {
stmt.executeUpdate( "insert into tab1 values(1, 2, 3.1)", new int[] { 1 } );
failVNA();
}
catch (SQLException se)
{
assertSQLState( METHOD_NOT_ALLOWED, se );
}
try {
stmt.executeUpdate( "insert into tab1 values(1, 2, 3.1)", new String[] { "COLUMNNAME" } );
failVNA();
}
catch (SQLException se)
{
assertSQLState( METHOD_NOT_ALLOWED, se );
}
}
private void failVNA() throws Exception
{
fail( "Should have failed when run on a PreparedStatement or CallableStatement" );
}
///////////////////////////////////////////////////////////////////////
//
// PROCEDURES
//
///////////////////////////////////////////////////////////////////////
/**
* Stored procedure which returns 2 ResultSets.
*/
public static void dynamicResults
( ResultSet[] rs1, ResultSet[] rs2 )
throws SQLException
{
Connection c = DriverManager.getConnection("jdbc:default:connection");
rs1[0] = c.createStatement().executeQuery("VALUES(1)");
rs2[0] = c.createStatement().executeQuery("VALUES(2)");
}
}