You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by rh...@apache.org on 2012/10/22 20:25:38 UTC
svn commit: r1400984 - in /db/derby/code/trunk/java:
engine/org/apache/derby/iapi/services/loader/
engine/org/apache/derby/impl/sql/compile/
testing/org/apache/derbyTesting/functionTests/tests/lang/
Author: rhillegas
Date: Mon Oct 22 18:25:37 2012
New Revision: 1400984
URL: http://svn.apache.org/viewvc?rev=1400984&view=rev
Log:
DERBY-672: Tighten up the bounds checking for input and return types of user-defined aggregates.
Modified:
db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/loader/ClassInspector.java
db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/loader/Java5ClassInspector.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UserAggregateDefinition.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GenericMode.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/UserDefinedAggregatesTest.java
Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/loader/ClassInspector.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/loader/ClassInspector.java?rev=1400984&r1=1400983&r2=1400984&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/loader/ClassInspector.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/loader/ClassInspector.java Mon Oct 22 18:25:37 2012
@@ -495,6 +495,17 @@ public class ClassInspector
}
/**
+ * Given an implementation of a parameterized interface, return
+ * the actual types of the interface type variables. This method raises an exception if the
+ * JVM does not support generics. May return null or an array of nulls if type resolution fails.
+ */
+ public Class[] getGenericParameterTypes( Class parameterizedType, Class implementation )
+ throws StandardException
+ {
+ throw StandardException.newException( SQLState.VM_LEVEL_TOO_LOW, "Java 5" );
+ }
+
+ /**
* Get the parameter types for a method described by a Member as a String[].
*
* @param method A Member describing a method
Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/loader/Java5ClassInspector.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/loader/Java5ClassInspector.java?rev=1400984&r1=1400983&r2=1400984&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/loader/Java5ClassInspector.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/loader/Java5ClassInspector.java Mon Oct 22 18:25:37 2012
@@ -62,7 +62,7 @@ public class Java5ClassInspector extends
///////////////////////////////////////////////////////////////////////////////////
//
- // BEHAVIOR
+ // PUBLIC BEHAVIOR
//
///////////////////////////////////////////////////////////////////////////////////
@@ -101,6 +101,36 @@ public class Java5ClassInspector extends
return getTypeBounds( parameterizedInterface, implementation.getSuperclass() );
}
+ @Override
+ public Class[] getGenericParameterTypes( Class parameterizedType, Class implementation )
+ throws StandardException
+ {
+ // construct the inheritance chain stretching from the parameterized type
+ // down to the concrete implemention
+ ArrayList<Class<?>> chain = getTypeChain( parameterizedType, implementation );
+
+ // walk the chain, filling in a map of generic types to their resolved types
+ HashMap<Type,Type> resolvedTypes = getResolvedTypes( chain );
+
+ // compose the resolved types together in order to compute the actual
+ // classes which are plugged into the variables of the parameterized type
+ ArrayList<Class<?>> parameterTypes = getParameterTypes( parameterizedType, resolvedTypes );
+
+ // turn the list into an array
+ if ( parameterTypes == null ) { return null; }
+
+ Class[] result = new Class[ parameterTypes.size() ];
+ parameterTypes.toArray( result );
+
+ return result;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////
+ //
+ // MINIONS FOR getTypeBounds()
+ //
+ ///////////////////////////////////////////////////////////////////////////////////
+
/**
* Get the type bounds for all of the type variables of the given
* parameterized type.
@@ -148,6 +178,119 @@ public class Java5ClassInspector extends
else { return null; }
}
+ ///////////////////////////////////////////////////////////////////////////////////
+ //
+ // MINIONS FOR getGenericParameterTypes()
+ //
+ ///////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Construct an inheritance chain of types stretching from a supertype down
+ * to a concrete implementation.
+ */
+ private ArrayList<Class<?>> getTypeChain( Class<?> chainEnd, Class<?> start )
+ {
+ ArrayList<Class<?>> result = null;
+
+ if ( start == null ) { return null; }
+ if ( !chainEnd.isAssignableFrom( start ) ) { return null; }
+
+ if ( start == chainEnd ) { result = new ArrayList<Class<?>>(); }
+ if ( result == null )
+ {
+ result = getTypeChain( chainEnd, start.getSuperclass() );
+
+ if ( result == null )
+ {
+ for ( Class<?> iface : start.getInterfaces() )
+ {
+ result = getTypeChain( chainEnd, iface );
+ if ( result != null ) { break; }
+ }
+ }
+ }
+
+ if ( result != null ) { result.add( start ); }
+
+ return result;
+ }
+
+ /**
+ * Given an inheritance chain of types, stretching from a superclass down
+ * to a terminal concrete class, construct a map of generic types to their
+ * resolved types.
+ */
+ private HashMap<Type,Type> getResolvedTypes( ArrayList<Class<?>> chain )
+ {
+ if ( chain == null ) { return null; }
+
+ HashMap<Type,Type> resolvedTypes = new HashMap<Type,Type>();
+
+ for ( Class<?> klass : chain )
+ {
+ addResolvedTypes( resolvedTypes, klass.getGenericSuperclass() );
+
+ for ( Type iface : klass.getGenericInterfaces() )
+ {
+ addResolvedTypes( resolvedTypes, iface );
+ }
+ }
+
+ return resolvedTypes;
+ }
+
+ /**
+ * Given a generic type, add its parameter types to an evolving
+ * map of resolved types. Some of the resolved types may be
+ * generic type variables which will need further resolution from
+ * other generic types.
+ */
+ private void addResolvedTypes
+ ( HashMap<Type,Type> resolvedTypes, Type genericType )
+ {
+ if ( genericType == null ) { return; }
+
+ if ( genericType instanceof ParameterizedType )
+ {
+ ParameterizedType pt = (ParameterizedType) genericType;
+ Class rawType = (Class) pt.getRawType();
+
+ Type[] actualTypeArguments = pt.getActualTypeArguments();
+ TypeVariable[] typeParameters = rawType.getTypeParameters();
+ for (int i = 0; i < actualTypeArguments.length; i++)
+ {
+ resolvedTypes.put(typeParameters[i], actualTypeArguments[i]);
+ }
+ }
+ }
+
+ /**
+ * Given a map of resolved types, compose them together in order
+ * to resolve the actual concrete types that are plugged into the
+ * parameterized type.
+ */
+ private ArrayList<Class<?>> getParameterTypes
+ ( Class<?> parameterizedType, HashMap<Type,Type> resolvedTypes )
+ {
+ if ( resolvedTypes == null ) { return null; }
+
+ Type[] actualTypeArguments = parameterizedType.getTypeParameters();
+
+ ArrayList<Class<?>> result = new ArrayList<Class<?>>();
+
+ // resolve types by composing type variables.
+ for (Type baseType: actualTypeArguments)
+ {
+ while ( resolvedTypes.containsKey( baseType ) )
+ {
+ baseType = resolvedTypes.get(baseType);
+ }
+
+ result.add( getRawType( baseType ) );
+ }
+
+ return result;
+ }
}
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UserAggregateDefinition.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UserAggregateDefinition.java?rev=1400984&r1=1400983&r2=1400984&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UserAggregateDefinition.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UserAggregateDefinition.java Mon Oct 22 18:25:37 2012
@@ -136,6 +136,10 @@ public class UserAggregateDefinition imp
);
}
+ Class[] genericParameterTypes = classFactory.getClassInspector().getGenericParameterTypes
+ ( derbyAggregatorInterface, userAggregatorClass );
+ if ( genericParameterTypes == null ) { genericParameterTypes = new Class[ AGGREGATOR_PARAM_COUNT ]; }
+
AggregateAliasInfo aai = (AggregateAliasInfo) _alias.getAliasInfo();
DataTypeDescriptor expectedInputType = DataTypeDescriptor.getType( aai.getForType() );
DataTypeDescriptor expectedReturnType = DataTypeDescriptor.getType( aai.getReturnType() );
@@ -153,19 +157,13 @@ public class UserAggregateDefinition imp
Class[] inputBounds = typeBounds[ INPUT_TYPE ];
for ( int i = 0; i < inputBounds.length; i++ )
{
- Class inputBound = inputBounds[ i ];
-
- if ( !inputBound.isAssignableFrom( expectedInputClass ) )
- {
- throw StandardException.newException
- (
- SQLState.LANG_UDA_WRONG_INPUT_TYPE,
- _alias.getSchemaName(),
- _alias.getName(),
- expectedInputClass.toString(),
- inputBound.toString()
- );
- }
+ vetCompatibility
+ ( inputBounds[ i ], expectedInputClass, SQLState.LANG_UDA_WRONG_INPUT_TYPE );
+ }
+ if ( genericParameterTypes[ INPUT_TYPE ] != null )
+ {
+ vetCompatibility
+ ( genericParameterTypes[ INPUT_TYPE ], expectedInputClass, SQLState.LANG_UDA_WRONG_INPUT_TYPE );
}
//
@@ -175,19 +173,13 @@ public class UserAggregateDefinition imp
Class[] returnBounds = typeBounds[ RETURN_TYPE ];
for ( int i = 0; i < returnBounds.length; i++ )
{
- Class returnBound = returnBounds[ i ];
-
- if ( !returnBound.isAssignableFrom( expectedReturnClass ) )
- {
- throw StandardException.newException
- (
- SQLState.LANG_UDA_WRONG_RETURN_TYPE,
- _alias.getSchemaName(),
- _alias.getName(),
- expectedReturnClass.toString(),
- returnBound.toString()
- );
- }
+ vetCompatibility
+ ( returnBounds[ i ], expectedReturnClass, SQLState.LANG_UDA_WRONG_RETURN_TYPE );
+ }
+ if ( genericParameterTypes[ RETURN_TYPE ] != null )
+ {
+ vetCompatibility
+ ( genericParameterTypes[ RETURN_TYPE ], expectedReturnClass, SQLState.LANG_UDA_WRONG_RETURN_TYPE );
}
aggregatorClass.append( ClassName.UserDefinedAggregator );
@@ -197,6 +189,25 @@ public class UserAggregateDefinition imp
catch (ClassNotFoundException cnfe) { throw aggregatorInstantiation( cnfe ); }
}
+ /**
+ * Verify that an actual type is compatible with the expected type.
+ */
+ private void vetCompatibility( Class actualClass, Class expectedClass, String sqlState )
+ throws StandardException
+ {
+ if ( !actualClass.isAssignableFrom( expectedClass ) )
+ {
+ throw StandardException.newException
+ (
+ sqlState,
+ _alias.getSchemaName(),
+ _alias.getName(),
+ expectedClass.toString(),
+ actualClass.toString()
+ );
+ }
+ }
+
/**
* Wrap the input operand in an implicit CAST node as necessary in order to
* coerce it the correct type for the aggregator. Return null if no cast is necessary.
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GenericMode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GenericMode.java?rev=1400984&r1=1400983&r2=1400984&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GenericMode.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GenericMode.java Mon Oct 22 18:25:37 2012
@@ -32,7 +32,7 @@ import org.apache.derby.agg.Aggregator;
* This is a generic mode aggregator for testing with many types.
* </p>
*/
-public class GenericMode<V extends Comparable<V>> implements Aggregator<V,V,GenericMode<V>>
+public class GenericMode<B extends Comparable<B>> implements Aggregator<B,B,GenericMode<B>>
{
///////////////////////////////////////////////////////////////////////////////////
//
@@ -56,7 +56,7 @@ public class GenericMode<V extends Co
//
///////////////////////////////////////////////////////////////////////////////////
- private HashMap<V,Accumulator<V>> _accumulators;
+ private HashMap<B,Accumulator<B>> _accumulators;
///////////////////////////////////////////////////////////////////////////////////
//
@@ -68,33 +68,33 @@ public class GenericMode<V extends Co
public void init()
{
- _accumulators = new HashMap<V,Accumulator<V>>();
+ _accumulators = new HashMap<B,Accumulator<B>>();
}
- public void accumulate( V value )
+ public void accumulate( B value )
{
getAccumulator( value ).add( 1 );
}
- public void merge( GenericMode<V> otherAggregator )
+ public void merge( GenericMode<B> otherAggregator )
{
- HashMap<V,Accumulator<V>> otherAccumulators = otherAggregator._accumulators;
+ HashMap<B,Accumulator<B>> otherAccumulators = otherAggregator._accumulators;
- for ( V value : otherAccumulators.keySet() )
+ for ( B value : otherAccumulators.keySet() )
{
getAccumulator( value ).add( otherAccumulators.get( value ).getCount() );
}
}
- public V terminate()
+ public B terminate()
{
return _accumulators.isEmpty() ? null : Collections.max( _accumulators.values() ).getValue();
}
- private Accumulator<V> getAccumulator( V value )
+ private Accumulator<B> getAccumulator( B value )
{
- Accumulator<V> retval = _accumulators.get( value );
+ Accumulator<B> retval = _accumulators.get( value );
if ( retval == null )
{
- retval = new Accumulator<V>( value );
+ retval = new Accumulator<B>( value );
_accumulators.put( value, retval );
}
@@ -107,12 +107,12 @@ public class GenericMode<V extends Co
//
///////////////////////////////////////////////////////////////////////////////////
- public static final class Accumulator<V extends Comparable<V>> implements Comparable<Accumulator<V>>
+ public static final class Accumulator<B extends Comparable<B>> implements Comparable<Accumulator<B>>
{
- private V _value;
+ private B _value;
private int _count;
- public Accumulator( V value )
+ public Accumulator( B value )
{
_value = value;
_count = 0;
@@ -120,11 +120,11 @@ public class GenericMode<V extends Co
public void add( int increment ) { _count += increment; }
- public V getValue() { return _value; }
+ public B getValue() { return _value; }
public int getCount() { return _count; }
// Comparable behavior
- public int compareTo( Accumulator<V> that )
+ public int compareTo( Accumulator<B> that )
{
int retval = this._count - that._count;
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/UserDefinedAggregatesTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/UserDefinedAggregatesTest.java?rev=1400984&r1=1400983&r2=1400984&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/UserDefinedAggregatesTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/UserDefinedAggregatesTest.java Mon Oct 22 18:25:37 2012
@@ -2215,4 +2215,47 @@ public class UserDefinedAggregatesTest
);
}
+ /**
+ * <p>
+ * Verify that types fit within the most exact bound possible.
+ * </p>
+ */
+ public void test_16_exactBound() throws Exception
+ {
+ Connection conn = getConnection();
+
+ // input bounds
+ goodStatement
+ (
+ conn,
+ "create derby aggregate bigintMode_16 for bigint\n" +
+ "external name 'org.apache.derbyTesting.functionTests.tests.lang.GenericMode$IntMode'\n"
+ );
+ goodStatement
+ (
+ conn,
+ "create table bigintMode_16_mode_inputs( a int, b bigint )"
+ );
+ expectCompilationError
+ ( INPUT_OUTSIDE_BOUNDS,
+ "select bigintMode_16( b ) from bigintMode_16_mode_inputs" );
+
+ // return bounds
+ goodStatement
+ (
+ conn,
+ "create derby aggregate intMode_16 for int returns varchar( 10 )\n" +
+ "external name 'org.apache.derbyTesting.functionTests.tests.lang.GenericMode$IntMode'\n"
+ );
+ goodStatement
+ (
+ conn,
+ "create table intMode_16_mode_inputs( a int, b int )"
+ );
+ expectCompilationError
+ ( RETURN_OUTSIDE_BOUNDS,
+ "select intMode_16( b ) from intMode_16_mode_inputs" );
+
+ }
+
}