db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rhille...@apache.org
Subject svn commit: r1421052 - in /db/derby/code/trunk/java: engine/org/apache/derby/impl/sql/compile/ testing/org/apache/derbyTesting/functionTests/tests/lang/
Date Thu, 13 Dec 2012 00:23:39 GMT
Author: rhillegas
Date: Thu Dec 13 00:23:29 2012
New Revision: 1421052

URL: http://svn.apache.org/viewvc?rev=1421052&view=rev
Log:
DERBY-3069: Fix varargs bugs in handling of primitive args and out/inout args.

Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MethodCallNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/VarargsRoutines.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/VarargsTest.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MethodCallNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MethodCallNode.java?rev=1421052&r1=1421051&r2=1421052&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MethodCallNode.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MethodCallNode.java
Thu Dec 13 00:23:29 2012
@@ -373,17 +373,28 @@ abstract class MethodCallNode extends Ja
 	{
 		/* Put the parameter type names into a single string */
 		StringBuffer	parmTypes = new StringBuffer();
-		for (int i = 0; i < parmTypeNames.length; i++)
+        boolean hasVarargs = hasVarargs();
+        int     firstVarargIdx = getFirstVarargIdx();
+        int     paramCount = signature.length;
+		for (int i = 0; i < paramCount; i++)
 		{
-			if (i != 0)
-				parmTypes.append(", ");
+			if (i != 0) { parmTypes.append(", "); }
+            boolean isVararg = isVararg( i );
+
 			/* RESOLVE - shouldn't be using hard coded strings for output */
-			parmTypes.append( (parmTypeNames[i].length() != 0 ?
-								parmTypeNames[i] :
-								"UNTYPED"));
+            String  parmType = parmTypeNames[ i ];
+            if ( parmTypeNames [i ].length() == 0 ) { parmType = "UNTYPED"; }
+            else if ( isVararg ) { parmType = getVarargTypeName( parmType ); }
+
+            parmTypes.append( parmType );
+
 			if ((primParmTypeNames != null) &&
 				! primParmTypeNames[i].equals(parmTypeNames[i]))  // has primitive
-				parmTypes.append("(" + primParmTypeNames[i] + ")");
+            {
+                String  primTypeName = primParmTypeNames[ i ];
+                if ( isVararg ) { primTypeName = getVarargTypeName( primTypeName ); }
+				parmTypes.append("(" + primTypeName + ")");
+            }
 		}
 
 		throw StandardException.newException(SQLState.LANG_NO_METHOD_FOUND, 
@@ -392,6 +403,12 @@ abstract class MethodCallNode extends Ja
 											 	parmTypes);
 	}
 
+    /** Turn an array type name into the corresponding vararg type name */
+    private String  getVarargTypeName( String arrayTypeName )
+    {
+        return stripOneArrayLevel( arrayTypeName ) + "...";
+    }
+
 	/**
 	 * Preprocess an expression tree.  We do a number of transformations
 	 * here (including subqueries, IN lists, LIKE and BETWEEN) plus
@@ -519,7 +536,20 @@ abstract class MethodCallNode extends Ja
     public  boolean hasVarargs()
     {
         return (routineInfo == null ) ? false : routineInfo.hasVarargs();
-    }   
+    }
+
+    /** Get the index of the first vararg if this is a varargs method */
+    public  int getFirstVarargIdx() { return signature.length - 1; }
+
+    /** Return true if the parameter is a vararg */
+    public  boolean isVararg( int parameterNumber )
+    {
+        if ( !hasVarargs() ) { return false; }
+        else
+        {
+            return ( parameterNumber >= getFirstVarargIdx() );
+        }
+    }
 
 	/**
 	 * Generate the parameters to the given method call
@@ -616,17 +646,27 @@ abstract class MethodCallNode extends Ja
         // an array type. right now we only support vararg static methods.
         // if we have to support vararg constructors in the future, then this code
         // will need adjustment.
-        Class[]     parameterTypes = ((Method) method).getParameterTypes();
-        int         firstVarargIdx = parameterTypes.length - 1;
-        Class       varargType = parameterTypes[ firstVarargIdx ].getComponentType();
-        
+        int         firstVarargIdx = getFirstVarargIdx();
+        String      arrayType = methodParameterTypes[ firstVarargIdx ];
+        String      cellType = stripOneArrayLevel( arrayType );
+        String      varargType = cellType;
+
+        // must strip another array level off of out and in/out parameters
+        if ( routineInfo != null )
+        {
+            if ( routineInfo.getParameterModes()[ firstVarargIdx ] != JDBC30Translation.PARAMETER_MODE_IN
)
+            {
+                varargType = stripOneArrayLevel( varargType );
+            }
+        }
+
         int         varargCount = methodParms.length - firstVarargIdx;
         if ( varargCount < 0 ) { varargCount = 0; }
 
         // allocate an array to hold the varargs
-		LocalField arrayField = acb.newFieldDeclaration( Modifier.PRIVATE, varargType.getName()
+ "[]" );
+		LocalField arrayField = acb.newFieldDeclaration( Modifier.PRIVATE, arrayType );
 		MethodBuilder cb = acb.getConstructor();
-		cb.pushNewArray( varargType.getName(), varargCount );
+		cb.pushNewArray( cellType, varargCount );
 		cb.setField( arrayField );
 
         // now put the arguments into the array
@@ -634,7 +674,7 @@ abstract class MethodCallNode extends Ja
         {
 			mb.getField( arrayField ); // push the array onto the stack
             // evaluate the parameter and push it onto the stack
-            generateAndCastOneParameter( acb, mb, i + firstVarargIdx, methodParameterTypes[
firstVarargIdx ] );
+            generateAndCastOneParameter( acb, mb, i + firstVarargIdx, cellType );
             mb.setArrayElement( i ); // move the parameter into the array, pop the stack
         }
         
@@ -654,10 +694,14 @@ abstract class MethodCallNode extends Ja
     protected   int getRoutineArgIdx( int invocationArgIdx )
     {
         if ( routineInfo == null ) { return invocationArgIdx; }
-        if ( !routineInfo.hasVarargs() ) { return invocationArgIdx; }
+        else { return getRoutineArgIdx( routineInfo, invocationArgIdx ); }
+    }
+    protected   int getRoutineArgIdx( RoutineAliasInfo rai, int invocationArgIdx )
+    {
+        if ( !rai.hasVarargs() ) { return invocationArgIdx; }
 
         // ok, this is a varargs routine
-        int         firstVarargIdx = routineInfo.getParameterCount() - 1;
+        int         firstVarargIdx = rai.getParameterCount() - 1;
 
         return (firstVarargIdx < invocationArgIdx) ? firstVarargIdx : invocationArgIdx;
     }
@@ -929,13 +973,15 @@ abstract class MethodCallNode extends Ja
                 
 		methodParameterTypes = classInspector.getParameterTypes(method);
 
+        String methodParameter = null;
+        
 		for (int i = 0; i < methodParameterTypes.length; i++)
 		{
-			String methodParameter = methodParameterTypes[i];
+			methodParameter = methodParameterTypes[i];
 
 			if (routineInfo != null) {
 				if (i < routineInfo.getParameterCount()) {
-					int parameterMode = routineInfo.getParameterModes()[i];
+					int parameterMode = routineInfo.getParameterModes()[ getRoutineArgIdx( i ) ];
 
 					switch (parameterMode) {
 					case JDBC30Translation.PARAMETER_MODE_IN:
@@ -943,7 +989,7 @@ abstract class MethodCallNode extends Ja
 					case JDBC30Translation.PARAMETER_MODE_IN_OUT:
 						// we need to see if the type of the array is
 						// primitive, not the array itself.
-						methodParameter = methodParameter.substring(0, methodParameter.length() - 2);
+						methodParameter = stripOneArrayLevel( methodParameter );
 						break;
 
 					case JDBC30Translation.PARAMETER_MODE_OUT:
@@ -953,10 +999,43 @@ abstract class MethodCallNode extends Ja
 				}
 			}
 
+            //
+            // Strip off the array type if this is a varargs arg. We are only interested
in
+            // whether we need to cast to the cell type.
+            //
+            if ( hasVarargs() && (i >= getFirstVarargIdx()) )
+            {
+                methodParameter = stripOneArrayLevel( methodParameter );
+            }
+
 			if (ClassInspector.primitiveType(methodParameter))
-				methodParms[i].castToPrimitive(true);
+            {
+                // varargs may be omitted, so there may not be an invocation argument
+                // corresponding to the vararg
+                if ( i < methodParms.length )
+                {
+                    methodParms[i].castToPrimitive(true);
+                }
+            }
 		}
 
+        // the last routine parameter may have been a varargs. if so,
+        // casting may be needed on the trailing varargs
+        if ( hasVarargs() )
+        {
+            int     firstVarargIdx = getFirstVarargIdx();
+            int     trailingVarargCount = methodParms.length - firstVarargIdx;
+
+            // the first vararg was handled in the preceding loop
+            for ( int i = 1; i < trailingVarargCount; i++ )
+            {
+                if (ClassInspector.primitiveType(methodParameter))
+                {
+                    methodParms[ i + firstVarargIdx ].castToPrimitive(true);
+                }
+            }
+        }
+
 		/* Set type info for any null parameters */
 		if ( someParametersAreNull() )
 		{
@@ -976,7 +1055,13 @@ abstract class MethodCallNode extends Ja
 		if (getCompilerContext().getReturnParameterFlag()) {
 			getCompilerContext().getParameterTypes()[0] = dts;
 		}
-  }
+    }
+
+    /** Strip the trailing [] from a type name */
+    protected String  stripOneArrayLevel( String typeName )
+    {
+        return typeName.substring( 0, typeName.length() - 2 );
+    }
 	
 	/**
 	 * Parse the user supplied signature for a method and validate

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java?rev=1421052&r1=1421051&r2=1421052&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java
Thu Dec 13 00:23:29 2012
@@ -494,7 +494,7 @@ public class StaticMethodCallNode extend
 
 
 				// if it's an OUT or INOUT parameter we need an array.
-				int parameterMode = routineInfo.getParameterModes()[p];
+				int parameterMode = routineInfo.getParameterModes()[ getRoutineArgIdx( routineInfo, p
) ];
 
 				if (parameterMode != JDBC30Translation.PARAMETER_MODE_IN) {
 
@@ -556,7 +556,7 @@ public class StaticMethodCallNode extend
                         coerceMethodParameter
                             (
                              fromList, subqueryList, aggregateVector,
-                             parameterCount,
+                             methodParms.length,
                              paramdtd, parameterTypeId, parameterMode,
                              idx
                              );
@@ -567,7 +567,7 @@ public class StaticMethodCallNode extend
                     coerceMethodParameter
                         (
                          fromList, subqueryList, aggregateVector,
-                         parameterCount,
+                         methodParms.length,
                          paramdtd, parameterTypeId, parameterMode,
                          p
                          );
@@ -868,7 +868,7 @@ public class StaticMethodCallNode extend
 					// applicationParameterNumbers is only set up for a procedure.
 					int applicationParameterNumber = pn.getParameterNumber();
 
-					String parameterType = methodParameterTypes[parameterNumber];
+					String parameterType = methodParameterTypes[ getRoutineArgIdx( parameterNumber ) ];
 
 					if (parameterType.endsWith("[]")) {
 
@@ -916,12 +916,20 @@ public class StaticMethodCallNode extend
 			// application could retain a reference to it and corrupt
 			// future calls with the same CallableStatement object.
 
-			String methodParameterType = methodParameterTypes[parameterNumber];
+			String methodParameterType = methodParameterTypes[ getRoutineArgIdx( parameterNumber )
];
 			String arrayType = methodParameterType.substring(0, methodParameterType.length() - 2);
+
+            // if a varargs arg, then strip off the extra array dimension added by varargs
+            if ( isVararg( parameterNumber ) )
+            {
+                methodParameterType = stripOneArrayLevel( methodParameterType );
+                arrayType = stripOneArrayLevel( arrayType );
+            }
+            
 			LocalField lf = acb.newFieldDeclaration(Modifier.PRIVATE, methodParameterType);
 
 			if (outParamArrays == null)
-				outParamArrays = new LocalField[methodParms.length];
+            { outParamArrays = new LocalField[methodParms.length]; }
 
 			outParamArrays[parameterNumber] = lf;
 
@@ -1292,7 +1300,8 @@ public class StaticMethodCallNode extend
 				int[] parameterModes = routineInfo.getParameterModes();
 				for (int i = 0; i < outParamArrays.length; i++) {
 
-					int parameterMode = parameterModes[i];
+					int parameterMode = parameterModes[ getRoutineArgIdx( i ) ];
+                    
 					if (parameterMode != JDBC30Translation.PARAMETER_MODE_IN) {
 
 						// must be a parameter if it is INOUT or OUT.
@@ -1323,7 +1332,11 @@ public class StaticMethodCallNode extend
 						boolean isAnsiUDT = paramdtd.getTypeId().getBaseTypeId().isAnsiUDT();
 
 						// is the underlying type for the OUT/INOUT parameter primitive.
-						boolean isPrimitive = ((java.lang.reflect.Method) method).getParameterTypes()[i].getComponentType().isPrimitive();
+                        // if this is a varargs arg then we have to strip off another array
level
+                        Class   cellType = ((java.lang.reflect.Method) method).getParameterTypes()[
getRoutineArgIdx( i ) ].
+                            getComponentType();
+                        if ( isVararg( i ) ) { cellType = cellType.getComponentType(); }
+						boolean isPrimitive = cellType.isPrimitive();
 
 						if (isNumericType) {
 							// need to up-cast as the setValue(Number) method only exists on NumberDataValue

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/VarargsRoutines.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/VarargsRoutines.java?rev=1421052&r1=1421051&r2=1421052&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/VarargsRoutines.java
(original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/VarargsRoutines.java
Thu Dec 13 00:23:29 2012
@@ -48,6 +48,12 @@ public  class   VarargsRoutines
     //
     ///////////////////////////////////////////////////////////////////////////////////
 
+    //////////////////
+    //
+    // SIMPLE ROUTINES
+    //
+    //////////////////
+
     /** Compute the maximum of a series of ints */
     public  static  Integer max( Integer... values )
     {
@@ -71,4 +77,116 @@ public  class   VarargsRoutines
         return MessageFormat.format( message, args );
     }
 
+    //////////////////////////
+    //
+    // PRIMITIVES VS OBJECTS
+    //
+    //////////////////////////
+
+    public  static  String  ambiguousTypes( int... a )    { return "primitive";}
+    public  static  String  ambiguousTypes( Integer... a )    { return "wrapper";}
+
+    public  static  Integer maxInts( int... values )
+    {
+        if ( values == null ) { return null; }
+        if ( values.length == 0 ) { return null; }
+
+        int     result = Integer.MIN_VALUE;
+
+        for ( int value : values )  { result = Math.max( result, value ); }
+
+        return result;
+    }
+
+    //////////////////////////
+    //
+    // NON-VARARGS METHODS
+    //
+    //////////////////////////
+
+    public  static  String  nonVarargsMethod( int a )    { return "shouldn't be resolved";}
+    public  static  String  nonVarargsMethod( int[] a )    { return "shouldn't be resolved";}
+
+    //////////////////////////
+    //
+    // VARARGS & NON-VARARGS RESOLUTIONS
+    //
+    //////////////////////////
+
+    public  static  Integer vnvr( int a )    { return -a;}
+    public  static  Integer vnvr( int... a )    { return maxInts( a );}
+
+    //////////////////////////
+    //
+    // LEADING NON-VARARGS
+    //
+    //////////////////////////
+
+    public  static  Integer lnv( int... a ) { return maxInts( a );}
+    public  static  Integer lnv( int first, int...a ) { return maxInts( a );}
+    public  static  Integer lnv( int first, int second, int...a ) { return maxInts( a );}
+
+    //////////////////////////
+    //
+    // IN, OUT, IN/OUT PARAMETERS
+    //
+    //////////////////////////
+
+    public  static  void    inVarargs( String[] result, int... values )
+    {
+        String  retval;
+        if ( values == null ) { retval = null; }
+        else if ( values.length == 0 ) { retval = null; }
+        else
+        {
+            StringBuilder   buffer = new StringBuilder();
+
+            buffer.append( "RESULT: " );
+            
+            for ( int value : values )
+            {
+                buffer.append( " " + Integer.toString( value ) );
+            }
+
+            retval = buffer.toString();
+        }
+
+        result[ 0 ] = retval;
+    }
+
+    public  static  void    outVarargs( int seed, int[]... values )
+        throws Exception
+    {
+        String  retval;
+        if ( values == null ) { return; }
+        else
+        {
+            for ( int i = 0; i < values.length; i++ )
+            {
+                values[ i ][ 0 ] = seed + i;
+            }
+        }
+    }
+
+    public  static  void    inoutVarargs( int seed, int[]... values )
+        throws Exception
+    {
+        String  retval;
+        if ( values == null ) { return; }
+        else
+        {
+            for ( int i = 0; i < values.length; i++ )
+            {
+                values[ i ][ 0 ] += seed;
+            }
+        }
+    }
+
+    ////////////////////////
+    //
+    // DATATYPE COVERAGE
+    //
+    ////////////////////////
+
+
 }

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/VarargsTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/VarargsTest.java?rev=1421052&r1=1421051&r2=1421052&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/VarargsTest.java
(original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/VarargsTest.java
Thu Dec 13 00:23:29 2012
@@ -21,6 +21,7 @@
 
 package org.apache.derbyTesting.functionTests.tests.lang;
 
+import java.sql.CallableStatement;
 import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.PreparedStatement;
@@ -48,6 +49,8 @@ public class VarargsTest  extends Genera
     private static  final   String  NEEDS_DERBY_STYLE = "42ZC9";
     private static  final   String  NEEDS_JAVA_STYLE = "42ZCA";
     private static  final   String  RETURNS_RESULT_SETS = "42ZCB";
+    private static  final   String  AMBIGUOUS = "42X73";
+    private static  final   String  NO_SUCH_METHOD = "42X50";
 
     ///////////////////////////////////////////////////////////////////////////////////
     //
@@ -271,6 +274,278 @@ public class VarargsTest  extends Genera
              );
     }
 
+    /**
+     * <p>
+     * Misc tests for varargs routines.
+     * </p>
+     */
+    public void test_03_misc() throws Exception
+    {
+        if ( !vmSupportsVarargs() ) { return; }
+
+        Connection conn = getConnection();
+
+        // primitive and wrapper overloads make method resolution ambiguous
+
+        goodStatement
+            ( conn,
+              "create function ambiguousTypes( a int ... ) returns int\n" +
+              "language java parameter style derby no sql deterministic\n" +
+              "external name 'org.apache.derbyTesting.functionTests.tests.lang.VarargsRoutines.ambiguousTypes'\n"
+              );
+        expectCompilationError( AMBIGUOUS, "values ambiguousTypes( 1, 2, 3 )" );
+
+        // can resolve to a primitive-typed vararg
+        goodStatement
+            ( conn,
+              "create function maxInts( a int ... ) returns int\n" +
+              "language java parameter style derby no sql deterministic\n" +
+              "external name 'org.apache.derbyTesting.functionTests.tests.lang.VarargsRoutines.maxInts'\n"
+              );
+        assertResults
+            (
+             conn,
+             "values maxInts( 3 )",
+             new String[][]
+             {
+                 { "3" },
+             },
+             false
+             );
+        assertResults
+            (
+             conn,
+             "values maxInts( 1, 2, 5, 4, 3 )",
+             new String[][]
+             {
+                 { "5" },
+             },
+             false
+             );
+
+        // error if the matching method isn't varargs
+        goodStatement
+            ( conn,
+              "create function nonVarargsMethod( a int ... ) returns int\n" +
+              "language java parameter style derby no sql deterministic\n" +
+              "external name 'org.apache.derbyTesting.functionTests.tests.lang.VarargsRoutines.nonVarargsMethod'\n"
+              );
+        expectCompilationError( NO_SUCH_METHOD, "values nonVarargsMethod( 3 )" );
+        
+        // correctly disambiguate similar varargs and non-varargs methods
+        goodStatement
+            ( conn,
+              "create function vnvr_vararg( a int ... ) returns int\n" +
+              "language java parameter style derby no sql deterministic\n" +
+              "external name 'org.apache.derbyTesting.functionTests.tests.lang.VarargsRoutines.vnvr'\n"
+              );
+        goodStatement
+            ( conn,
+              "create function vnvr_nonvararg( a int ) returns int\n" +
+              "language java parameter style java no sql deterministic\n" +
+              "external name 'org.apache.derbyTesting.functionTests.tests.lang.VarargsRoutines.vnvr'\n"
+              );
+        assertResults
+            (
+             conn,
+             "values vnvr_vararg( 3 )",
+             new String[][]
+             {
+                 { "3" },
+             },
+             false
+             );
+        assertResults
+            (
+             conn,
+             "values vnvr_nonvararg( 3 )",
+             new String[][]
+             {
+                 { "-3" },
+             },
+             false
+             );
+        
+        // correctly disambiguate overloads with different numbers of leading non-vararg
arguments
+        goodStatement
+            ( conn,
+              "create function lnv( a int ... ) returns int\n" +
+              "language java parameter style derby no sql deterministic\n" +
+              "external name 'org.apache.derbyTesting.functionTests.tests.lang.VarargsRoutines.lnv'\n"
+              );
+        goodStatement
+            ( conn,
+              "create function lnv_1( a int, b int ... ) returns int\n" +
+              "language java parameter style derby no sql deterministic\n" +
+              "external name 'org.apache.derbyTesting.functionTests.tests.lang.VarargsRoutines.lnv'\n"
+              );
+        goodStatement
+            ( conn,
+              "create function lnv_2( a int, b int, c int ... ) returns int\n" +
+              "language java parameter style derby no sql deterministic\n" +
+              "external name 'org.apache.derbyTesting.functionTests.tests.lang.VarargsRoutines.lnv'\n"
+              );
+        assertResults
+            (
+             conn,
+             "values lnv( 5, 4, 3, 2, 1 )",
+             new String[][]
+             {
+                 { "5" },
+             },
+             false
+             );
+        assertResults
+            (
+             conn,
+             "values lnv_1( 5, 4, 3, 2, 1 )",
+             new String[][]
+             {
+                 { "4" },
+             },
+             false
+             );
+        assertResults
+            (
+             conn,
+             "values lnv_2( 5, 4, 3, 2, 1 )",
+             new String[][]
+             {
+                 { "3" },
+             },
+             false
+             );
+    }
+    
+    /**
+     * <p>
+     * Test in, out, and in/out procedure arguments which are varargs.
+     * </p>
+     */
+    public void test_04_inOut() throws Exception
+    {
+        if ( !vmSupportsVarargs() ) { return; }
+
+        Connection conn = getConnection();
+        CallableStatement   cs =  null;
+
+        // one input vararg
+        goodStatement
+            ( conn,
+              "create procedure inVarargs( out result varchar( 32672 ), b int ... )\n" +
+              "language java parameter style derby no sql deterministic\n" +
+              "external name 'org.apache.derbyTesting.functionTests.tests.lang.VarargsRoutines.inVarargs'\n"
+              );
+        cs = chattyPrepareCall
+            ( conn, "call inVarargs( ?, ? )" );
+        cs.registerOutParameter( 1, java.sql.Types.VARCHAR );
+        cs.setInt( 2, 5 );
+        cs.execute();
+        assertEquals( "RESULT:  5", cs.getString( 1 ) );
+
+        cs = chattyPrepareCall
+            ( conn, "call inVarargs( ?, ?, ? )" );
+        cs.registerOutParameter( 1, java.sql.Types.VARCHAR );
+        cs.setInt( 2, 5 );
+        cs.setInt( 3, 4 );
+        cs.execute();
+        assertEquals( "RESULT:  5 4", cs.getString( 1 ) );
+
+        cs = chattyPrepareCall
+            ( conn, "call inVarargs( ?, ?, ?, ? )" );
+        cs.registerOutParameter( 1, java.sql.Types.VARCHAR );
+        cs.setInt( 2, 5 );
+        cs.setInt( 3, 4 );
+        cs.setInt( 4, 3 );
+        cs.execute();
+        assertEquals( "RESULT:  5 4 3", cs.getString( 1 ) );
+
+        // output vararg
+        goodStatement
+            ( conn,
+              "create procedure outVarargs( seed int, out b int ... )\n" +
+              "language java parameter style derby no sql deterministic\n" +
+              "external name 'org.apache.derbyTesting.functionTests.tests.lang.VarargsRoutines.outVarargs'\n"
+              );
+        cs = chattyPrepareCall
+            ( conn, "call outVarargs( ? )" );
+        cs.setInt( 1, 5 );
+        cs.execute();
+
+        cs = chattyPrepareCall
+            ( conn, "call outVarargs( ?, ? )" );
+        cs.registerOutParameter( 2, java.sql.Types.INTEGER );
+        cs.setInt( 1, 5 );
+        cs.execute();
+        assertEquals( 5, cs.getInt( 2 ) );
+
+        cs = chattyPrepareCall
+            ( conn, "call outVarargs( ?, ?, ? )" );
+        cs.registerOutParameter( 2, java.sql.Types.INTEGER );
+        cs.registerOutParameter( 3, java.sql.Types.INTEGER );
+        cs.setInt( 1, 5 );
+        cs.execute();
+        assertEquals( 5, cs.getInt( 2 ) );
+        assertEquals( 6, cs.getInt( 3 ) );
+
+        cs = chattyPrepareCall
+            ( conn, "call outVarargs( ?, ?, ?, ? )" );
+        cs.registerOutParameter( 2, java.sql.Types.INTEGER );
+        cs.registerOutParameter( 3, java.sql.Types.INTEGER );
+        cs.registerOutParameter( 4, java.sql.Types.INTEGER );
+        cs.setInt( 1, 5 );
+        cs.execute();
+        assertEquals( 5, cs.getInt( 2 ) );
+        assertEquals( 6, cs.getInt( 3 ) );
+        assertEquals( 7, cs.getInt( 4 ) );
+
+        // in/out vararg
+        goodStatement
+            ( conn,
+              "create procedure inoutVarargs( seed int, inout b int ... )\n" +
+              "language java parameter style derby no sql deterministic\n" +
+              "external name 'org.apache.derbyTesting.functionTests.tests.lang.VarargsRoutines.inoutVarargs'\n"
+              );
+        cs = chattyPrepareCall
+            ( conn, "call inoutVarargs( ? )" );
+        cs.setInt( 1, 5 );
+        cs.execute();
+
+        cs = chattyPrepareCall
+            ( conn, "call inoutVarargs( ?, ? )" );
+        cs.registerOutParameter( 2, java.sql.Types.INTEGER );
+        cs.setInt( 1, 5 );
+        cs.setInt( 2, 3 );
+        cs.execute();
+        assertEquals( 8, cs.getInt( 2 ) );
+
+        cs = chattyPrepareCall
+            ( conn, "call inoutVarargs( ?, ?, ? )" );
+        cs.registerOutParameter( 2, java.sql.Types.INTEGER );
+        cs.registerOutParameter( 3, java.sql.Types.INTEGER );
+        cs.setInt( 1, 5 );
+        cs.setInt( 2, 3 );
+        cs.setInt( 3, 10 );
+        cs.execute();
+        assertEquals( 8, cs.getInt( 2 ) );
+        assertEquals( 15, cs.getInt( 3 ) );
+
+        cs = chattyPrepareCall
+            ( conn, "call inoutVarargs( ?, ?, ?, ? )" );
+        cs.registerOutParameter( 2, java.sql.Types.INTEGER );
+        cs.registerOutParameter( 3, java.sql.Types.INTEGER );
+        cs.registerOutParameter( 4, java.sql.Types.INTEGER );
+        cs.setInt( 1, 5 );
+        cs.setInt( 2, 3 );
+        cs.setInt( 3, 10 );
+        cs.setInt( 4, 100 );
+        cs.execute();
+        assertEquals( 8, cs.getInt( 2 ) );
+        assertEquals( 15, cs.getInt( 3 ) );
+        assertEquals( 105, cs.getInt( 4 ) );
+
+    }
+    
     ///////////////////////////////////////////////////////////////////////////////////
     //
     // MINIONS



Mime
View raw message