blob: 01f778d3fd4a207e8f46251ef31c4a0b3bf0f69e [file] [log] [blame]
/*
Derby - Class org.apache.derbyTesting.functionTests.tests.jdbc4.Wrapper41Test
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.jdbc4;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.CallableStatement;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Date;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Calendar;
import org.apache.derbyTesting.junit.BaseJDBCTestCase;
/**
* <p>
* Machinery shared by the JDBC 4.1 tests for ResultSets and CallableStatements.
* </p>
*/
public class Wrapper41Test extends BaseJDBCTestCase
{
///////////////////////////////////////////////////////////////////////
//
// CONSTANTS
//
///////////////////////////////////////////////////////////////////////
private static final String UNSUPPORTED_COERCION = "22005";
private static final String BAD_FORMAT = "22018";
private static final String BAD_DATETIME = "22007";
private static final String VARIABLE_STRING = "XXXXX";
public static final byte[] BINARY_VALUE = new byte[] { (byte) 0xde };
static final long TIME_VALUE = 83342000L;
static final long TIMESTAMP_VALUE = -229527385766L;
///////////////////////////////////////////////////////////////////////
//
// STATE
//
///////////////////////////////////////////////////////////////////////
private Class _byteArrayClass;
private boolean _rowOfNulls;
///////////////////////////////////////////////////////////////////////
//
// CONSTRUCTOR
//
///////////////////////////////////////////////////////////////////////
/**
* Create test with given name.
*
* @param name name of the test.
*/
public Wrapper41Test( String name ) { super( name ); }
///////////////////////////////////////////////////////////////////////
//
// BEHAVIOR
//
///////////////////////////////////////////////////////////////////////
protected void examineJDBC4_1extensions( Wrapper41 wrapper, boolean rowOfNulls ) throws Exception
{
println( "Vetting a " + wrapper.getWrappedObject().getClass().getName() + ". rowOfNulls = " + rowOfNulls );
_byteArrayClass = Class.forName( "[B" );
_rowOfNulls = rowOfNulls;
vetWrappedNull( wrapper );
vetWrappedInteger( wrapper, 1, "BIGINTCOL" );
vetWrappedBlob( wrapper );
vetWrappedBoolean( wrapper );
vetWrappedString( wrapper, 4, "CHARCOL" );
vetWrappedBinary( wrapper, 5, "CHARFORBITDATACOL" );
vetWrappedClob( wrapper );
vetWrappedDate( wrapper );
vetWrappedFloatingPoint( wrapper, 8, "DOUBLECOL" );
vetWrappedFloatingPoint( wrapper, 9, "FLOATCOL" );
vetWrappedInteger( wrapper, 10, "INTCOL" );
vetWrappedString( wrapper, 11, "LONGVARCHARCOL" );
vetWrappedBinary( wrapper, 12, "LONGVARCHARFORBITDATACOL" );
vetWrappedInteger( wrapper, 13, "NUMERICCOL" );
vetWrappedFloatingPoint( wrapper, 14, "REALCOL" );
vetWrappedInteger( wrapper, 15, "SMALLINTCOL" );
vetWrappedTime( wrapper );
vetWrappedTimestamp( wrapper );
vetWrappedString( wrapper, 18, "VARCHARCOL" );
vetWrappedBinary( wrapper, 19, "VARCHARFORBITDATACOL" );
}
private void vetWrappedNull( Wrapper41 wrapper ) throws Exception
{
try {
wrapper.getObject( 1, (Class<?>) null );
fail( "Did not expect to get a result for a null class type." );
}
catch (SQLException e)
{
assertSQLState( "Null type", UNSUPPORTED_COERCION, e );
}
// String overloads not implemented for CallableStatements
if ( wrapper.getWrappedObject() instanceof CallableStatement ) { return; }
try {
wrapper.getObject( "BIGINTCOL", (Class<?>) null );
fail( "Did not expect to get a result for a null class type." );
}
catch (SQLException e)
{
assertSQLState( "Null type", UNSUPPORTED_COERCION, e );
}
}
private void vetWrappedInteger( Wrapper41 wrapper, int colID, String colName ) throws Exception
{
vetWrapperOK
(
wrapper,
colID,
colName,
_rowOfNulls ? null : "1",
new Class[] { String.class, BigDecimal.class, Byte.class, Short.class, Integer.class, Long.class, Number.class, Object.class }
);
vetWrapperOK
(
wrapper,
colID,
colName,
_rowOfNulls ? null : "1.0",
new Class[] { Float.class, Double.class }
);
vetWrapperOK
(
wrapper,
colID,
colName,
_rowOfNulls ? null : "true",
new Class[] { Boolean.class }
);
vetNoWrapper
(
wrapper,
colID,
colName,
new Class[] { Date.class, Time.class, Timestamp.class, Blob.class, Clob.class, _byteArrayClass, getClass() }
);
}
private void vetWrappedBlob( Wrapper41 wrapper ) throws Exception
{
vetWrapperOK
(
wrapper,
2,
"BLOBCOL",
_rowOfNulls ? null : BINARY_VALUE,
new Class[] { Blob.class, Object.class, _byteArrayClass, String.class, }
);
vetNoWrapper
(
wrapper,
2,
"BLOBCOL",
new Class[]
{
BigDecimal.class, Boolean.class,
Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class,
Date.class, Time.class, Timestamp.class
}
);
//
// We don't try to get a Clob value because we have already gotten a LOB value.
// Trying to open another LOB stream raises an error. Using a random class type
// also takes us down that code path, so we don't verify against getClass() either.
//
}
private void vetWrappedBoolean( Wrapper41 wrapper ) throws Exception
{
vetWrapperOK
(
wrapper,
3,
"BOOLEANCOL",
_rowOfNulls ? null : "true",
new Class[] { String.class, Boolean.class, Object.class }
);
vetWrapperOK
(
wrapper,
3,
"BOOLEANCOL",
_rowOfNulls ? null : "1",
new Class[] { BigDecimal.class, Byte.class, Short.class, Integer.class, Long.class }
);
vetWrapperOK
(
wrapper,
3,
"BOOLEANCOL",
_rowOfNulls ? null : "1.0",
new Class[] { Float.class, Double.class }
);
vetNoWrapper
(
wrapper,
3,
"BOOLEANCOL",
new Class[] { Date.class, Time.class, Timestamp.class, Blob.class, Clob.class, _byteArrayClass, getClass() }
);
}
private void vetWrappedString( Wrapper41 wrapper, int colID, String colName ) throws Exception
{
vetWrapperOK
(
wrapper,
colID,
colName,
_rowOfNulls ? null : "a",
new Class[] { String.class, Object.class }
);
vetWrapperOK
(
wrapper,
colID,
colName,
_rowOfNulls ? null : "true",
new Class[] { Boolean.class }
);
vetCoercionError
(
wrapper,
colID,
colName,
new Class[]
{
BigDecimal.class, Byte.class, Short.class, Integer.class, Long.class,
Float.class, Double.class,
},
BAD_FORMAT
);
vetCoercionError
(
wrapper,
colID,
colName,
new Class[]
{
Date.class, Time.class, Timestamp.class
},
BAD_DATETIME
);
vetNoWrapper
(
wrapper,
colID,
colName,
new Class[]
{
Blob.class, Clob.class, _byteArrayClass, getClass()
}
);
}
private void vetWrappedBinary( Wrapper41 wrapper, int colID, String colName ) throws Exception
{
vetWrapperOK
(
wrapper,
colID,
colName,
_rowOfNulls ? null : "de",
new Class[] { String.class }
);
vetWrapperOK
(
wrapper,
colID,
colName,
_rowOfNulls ? null : BINARY_VALUE,
new Class[] { _byteArrayClass, Object.class }
);
vetNoWrapper
(
wrapper,
colID,
colName,
new Class[]
{
Boolean.class, BigDecimal.class, Byte.class, Short.class, Integer.class, Long.class,
Float.class, Double.class,
Date.class, Time.class, Timestamp.class, Blob.class, Clob.class, getClass()
}
);
}
private void vetWrappedClob( Wrapper41 wrapper ) throws Exception
{
vetWrapperOK
(
wrapper,
6,
"CLOBCOL",
_rowOfNulls ? null : "abc",
new Class[] { String.class, Clob.class, Object.class }
);
vetNoWrapper
(
wrapper,
6,
"CLOBCOL",
new Class[]
{
Boolean.class,
BigDecimal.class, Byte.class, Short.class, Integer.class, Long.class,
Float.class, Double.class,
Date.class, Time.class, Timestamp.class,
_byteArrayClass
}
);
//
// We don't test getting a BLOB because we are only allowed one attempt
// to get a LOB from the column. Using a random class type
// also takes us down that code path, so we don't verify against getClass() either.
//
}
private void vetWrappedDate( Wrapper41 wrapper ) throws Exception
{
vetWrapperOK
(
wrapper,
7,
"DATECOL",
_rowOfNulls ? null : "1994-02-23",
new Class[] { String.class, Date.class, Object.class }
);
vetWrapperOK
(
wrapper,
7,
"DATECOL",
_rowOfNulls ? null : "1994-02-23 00:00:00.0",
new Class[] { Timestamp.class }
);
vetNoWrapper
(
wrapper,
7,
"DATECOL",
new Class[]
{
Boolean.class,
BigDecimal.class, Byte.class, Short.class, Integer.class, Long.class,
Float.class, Double.class,
Time.class,
Blob.class, Clob.class, _byteArrayClass, getClass()
}
);
}
private void vetWrappedFloatingPoint( Wrapper41 wrapper, int colID, String colName ) throws Exception
{
vetWrapperOK
(
wrapper,
colID,
colName,
_rowOfNulls ? null : "1.0",
new Class[] { String.class, Float.class, Double.class, BigDecimal.class, Number.class, Object.class }
);
vetWrapperOK
(
wrapper,
colID,
colName,
_rowOfNulls ? null : "1",
new Class[] { Byte.class, Short.class, Integer.class, Long.class }
);
vetWrapperOK
(
wrapper,
colID,
colName,
_rowOfNulls ? null : "true",
new Class[] { Boolean.class }
);
vetNoWrapper
(
wrapper,
colID,
colName,
new Class[] { Date.class, Time.class, Timestamp.class, Blob.class, Clob.class, _byteArrayClass, getClass() }
);
}
private void vetWrappedTime( Wrapper41 wrapper ) throws Exception
{
Time expectedTime = new Time(TIME_VALUE);
vetWrapperOK
(
wrapper,
16,
"TIMECOL",
_rowOfNulls ? null : expectedTime.toString(),
new Class[] { String.class, Time.class, Object.class }
);
vetWrapperOK
(
wrapper,
16,
"TIMECOL",
_rowOfNulls ? null : timeToTimestamp(expectedTime).toString(),
new Class[] { Timestamp.class }
);
vetNoWrapper
(
wrapper,
16,
"TIMECOL",
new Class[]
{
Boolean.class,
BigDecimal.class, Byte.class, Short.class, Integer.class, Long.class,
Float.class, Double.class,
Date.class,
Blob.class, Clob.class, _byteArrayClass, getClass()
}
);
}
private void vetWrappedTimestamp( Wrapper41 wrapper ) throws Exception
{
String expectedTimestamp = new Timestamp(TIMESTAMP_VALUE).toString();
vetWrapperOK
(
wrapper,
17,
"TIMESTAMPCOL",
_rowOfNulls ? null : expectedTimestamp,
new Class[] { String.class, Timestamp.class, Object.class }
);
String expectedTime = new Time(TIMESTAMP_VALUE).toString();
vetWrapperOK
(
wrapper,
17,
"TIMESTAMPCOL",
_rowOfNulls ? null : expectedTime,
new Class[] { Time.class }
);
String expectedDate = new Date(TIMESTAMP_VALUE).toString();
vetWrapperOK
(
wrapper,
17,
"TIMESTAMPCOL",
_rowOfNulls ? null : expectedDate,
new Class[] { Date.class }
);
vetNoWrapper
(
wrapper,
17,
"TIMESTAMPCOL",
new Class[]
{
Boolean.class,
BigDecimal.class, Byte.class, Short.class, Integer.class, Long.class,
Float.class, Double.class,
Blob.class, Clob.class, _byteArrayClass, getClass()
}
);
}
private void vetWrapperOK
( Wrapper41 wrapper, int colID, String colName, Object expectedValue, Class[] supportedCoercions )
throws Exception
{
int coercionCount = supportedCoercions.length;
for ( int i = 0; i < coercionCount; i++ )
{
Class<?> candidate = supportedCoercions[ i ];
vetCandidate( candidate, expectedValue, wrapper.getObject( colID, candidate ) );
// you can only retrieve a LOB once
if ( (candidate == Blob.class) || (candidate == Clob.class) ) { return; }
// String overloads not implemented for CallableStatement
if ( !(wrapper.getWrappedObject() instanceof CallableStatement) )
{ vetCandidate( candidate, expectedValue, wrapper.getObject( colName, candidate ) ); }
}
}
private void vetCandidate( Class<?> candidate, Object expectedValue, Object actualValue )
throws Exception
{
if ( actualValue != null ) { assertTrue( candidate.getName(), candidate.isAssignableFrom( actualValue.getClass( ) ) ); }
if ( expectedValue == null )
{
assertNull( actualValue );
return;
}
if ( VARIABLE_STRING.equals( expectedValue ) ) { return; }
String actualString;
if ( actualValue instanceof Blob )
{
Blob blob = (Blob) actualValue;
vetBytes( (byte[]) expectedValue, blob.getBytes( 1L, (int) blob.length() ) );
return;
}
else if ( actualValue instanceof byte[] )
{
vetBytes( (byte[]) expectedValue, (byte[]) actualValue );
return;
}
else if ( actualValue instanceof Clob )
{
Clob clob = (Clob) actualValue;
actualString = clob.getSubString( 1L, (int) clob.length() );
}
else { actualString = actualValue.toString(); }
assertEquals( candidate.getName(), (String) expectedValue, actualString );
}
private void vetBytes( byte[] expected, byte[] actual ) throws Exception
{
int count = expected.length;
assertEquals( count, actual.length );
for ( int i = 0; i < count; i++ )
{
assertEquals( expected[ i ], actual[ i ] );
}
}
private void vetNoWrapper
( Wrapper41 wrapper, int colID, String colName, Class[] unsupportedCoercions )
throws Exception
{
vetCoercionError( wrapper, colID, colName, unsupportedCoercions, UNSUPPORTED_COERCION );
}
private void vetCoercionError
( Wrapper41 wrapper, int colID, String colName, Class[] unsupportedCoercions, String expectedSQLState )
throws Exception
{
// null can be coerced to anything
if ( _rowOfNulls ) { return; }
int coercionCount = unsupportedCoercions.length;
for ( int i = 0; i < coercionCount; i++ )
{
Class<?> candidate = unsupportedCoercions[ i ];
try {
wrapper.getObject( colID, candidate );
fail( "Did not expect to get a " + candidate.getName() );
}
catch (SQLException e)
{
assertSQLState( candidate.getName(), expectedSQLState, e );
}
// you can only retrieve a LOB once
if ( (candidate == Blob.class) || (candidate == Clob.class) ) { return; }
// String overloads not implemented for CallableStatements
if ( wrapper.getWrappedObject() instanceof CallableStatement ) { return; }
try {
wrapper.getObject( colName, candidate );
fail( "Did not expect to get a " + candidate.getName() );
}
catch (SQLException e)
{
assertSQLState( candidate.getName(), expectedSQLState, e );
}
}
}
///////////////////////////////////////////////////////////////////////
//
// MINIONS
//
///////////////////////////////////////////////////////////////////////
protected PreparedStatement prepareStatement( Connection conn, String text )
throws Exception
{
println( text );
PreparedStatement ps = conn.prepareStatement( text );
return ps;
}
protected CallableStatement prepareCall( Connection conn, String text )
throws Exception
{
println( text );
CallableStatement cs = conn.prepareCall( text );
return cs;
}
/**
* Convert a Time value to a Timestamp value the same way as when we call
* getTimestamp() on a TIME column. That is, construct a Timestamp value
* with the date component set to the current date and the time component
* set to the specified time of day.
*
* @param time the Time value to convert
* @return a Timestamp value representing the specified time on the
* current date
*/
private static Timestamp timeToTimestamp(Time time) {
// Create a calendar object representing the time value
Calendar timeCal = Calendar.getInstance();
timeCal.setTime(time);
// Create a calendar object for the timestamp, initialized with
// the current time value
Calendar tsCal = Calendar.getInstance();
// Copy all fields, except the date fields, from the time calendar
// to the timestamp calendar
int[] timeFields = {
Calendar.HOUR_OF_DAY,
Calendar.MINUTE,
Calendar.SECOND,
Calendar.MILLISECOND
};
for (int field : timeFields) {
tsCal.set(field, timeCal.get(field));
}
// Return a timestamp based on the current date and the specified time
return new Timestamp(tsCal.getTimeInMillis());
}
}