db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rhille...@apache.org
Subject svn commit: r1398352 - in /db/derby/code/trunk/java: engine/org/apache/derby/impl/sql/compile/ testing/org/apache/derbyTesting/functionTests/tests/lang/
Date Mon, 15 Oct 2012 16:00:09 GMT
Author: rhillegas
Date: Mon Oct 15 16:00:08 2012
New Revision: 1398352

URL: http://svn.apache.org/viewvc?rev=1398352&view=rev
Log:
DERBY-672: Add implicit casts and handle string truncation for user-defined aggregates.

Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/AggregateNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.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/UserDefinedAggregatesTest.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/AggregateNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/AggregateNode.java?rev=1398352&r1=1398351&r2=1398352&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/AggregateNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/AggregateNode.java Mon
Oct 15 16:00:08 2012
@@ -319,7 +319,7 @@ public class AggregateNode extends Unary
 		instantiateAggDef();
 
         // if this is a user-defined aggregate
-        if ( (uad != null) && (uad instanceof UserAggregateDefinition) )
+        if ( isUserDefinedAggregate() )
         {
             AliasDescriptor ad = ((UserAggregateDefinition) uad).getAliasDescriptor();
 
@@ -423,6 +423,19 @@ public class AggregateNode extends Unary
                  );
 		}
 
+        // For user-defined aggregates, the input operand may need to be
+        // coerced to the expected input type of the aggregator.
+        if ( isUserDefinedAggregate() )
+        {
+            ValueNode   castNode = ((UserAggregateDefinition) uad).castInputValue
+                ( operand, getNodeFactory(), getContextManager() );
+
+            if ( castNode != null )
+            {
+                operand = castNode.bindExpression( fromList, subqueryList, aggregateVector
);
+            }
+        }
+
 		checkAggregatorClassName(aggregatorClassName.toString());
 
 		setType(resultType);
@@ -707,10 +720,17 @@ public class AggregateNode extends Unary
     public  String  getSQLName()
         throws StandardException
     {
-        if ( uad instanceof UserAggregateDefinition )
+        if ( isUserDefinedAggregate() )
         {
             return ((UserAggregateDefinition) uad).getAliasDescriptor().getQualifiedName();
         }
         else { return aggregateName; }
     }
+    
+    /** Return true if this is a user-defined aggregate */
+    private boolean isUserDefinedAggregate()
+    {
+        return ( (uad != null) && (uad instanceof UserAggregateDefinition) );
+    }
+
 }

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=1398352&r1=1398351&r2=1398352&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
Mon Oct 15 16:00:08 2012
@@ -22,11 +22,13 @@
 package	org.apache.derby.impl.sql.compile;
 
 import org.apache.derby.iapi.services.compiler.MethodBuilder;
+import org.apache.derby.iapi.services.context.ContextManager;
 
 import org.apache.derby.iapi.services.sanity.SanityManager;
 
 import org.apache.derby.iapi.sql.compile.CompilerContext;
 import org.apache.derby.iapi.sql.compile.C_NodeTypes;
+import org.apache.derby.iapi.sql.compile.NodeFactory;
 import org.apache.derby.iapi.types.JSQLType;
 import org.apache.derby.iapi.types.DataTypeDescriptor;
 import org.apache.derby.iapi.types.StringDataValue;
@@ -627,18 +629,13 @@ public class StaticMethodCallNode extend
 							getContextManager());
 					}
 
-					ValueNode castNode = (ValueNode) getNodeFactory().getNode(
-						C_NodeTypes.CAST_NODE,
-						sqlParamNode, 
-						paramdtd,
-						getContextManager());
-
-                    // Argument type has the same semantics as assignment:
-                    // Section 9.2 (Store assignment). There, General Rule 
-                    // 2.b.v.2 says that the database should raise an exception
-                    // if truncation occurs when stuffing a string value into a
-                    // VARCHAR, so make sure CAST doesn't issue warning only.
-                    ((CastNode)castNode).setAssignmentSemantics();
+					ValueNode castNode = makeCast
+                        (
+                         sqlParamNode,
+                         paramdtd,
+                         getNodeFactory(),
+                         getContextManager()
+                         );
 
 					methodParms[p] = (JavaValueNode) getNodeFactory().getNode(
 							C_NodeTypes.SQL_TO_JAVA_VALUE_NODE,
@@ -690,6 +687,31 @@ public class StaticMethodCallNode extend
         }
 	}
 
+    /**
+     * Wrap a parameter in a CAST node.
+     */
+    public  static  ValueNode   makeCast
+        ( ValueNode parameterNode, DataTypeDescriptor targetType, NodeFactory nodeFactory,
ContextManager cm )
+        throws StandardException
+    {
+        ValueNode castNode = (ValueNode) nodeFactory.getNode
+            (
+             C_NodeTypes.CAST_NODE,
+             parameterNode, 
+             targetType,
+             cm
+             );
+
+        // Argument type has the same semantics as assignment:
+        // Section 9.2 (Store assignment). There, General Rule 
+        // 2.b.v.2 says that the database should raise an exception
+        // if truncation occurs when stuffing a string value into a
+        // VARCHAR, so make sure CAST doesn't issue warning only.
+        ((CastNode)castNode).setAssignmentSemantics();
+
+        return castNode;
+    }
+
 	/**
 	 * Add code to set up the SQL session context for a stored
 	 * procedure or function which needs a nested SQL session

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=1398352&r1=1398351&r2=1398352&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 15 16:00:08 2012
@@ -25,6 +25,7 @@ import java.lang.reflect.Method;
 
 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
 import org.apache.derby.iapi.reference.SQLState;
+import org.apache.derby.iapi.services.context.ContextManager;
 import org.apache.derby.iapi.services.context.ContextService;
 import org.apache.derby.iapi.services.loader.ClassFactory;
 import org.apache.derby.iapi.services.sanity.SanityManager;
@@ -36,7 +37,9 @@ import org.apache.derby.iapi.types.JSQLT
 import org.apache.derby.iapi.types.DataTypeDescriptor;
 
 import org.apache.derby.iapi.sql.compile.CompilerContext;
+import org.apache.derby.iapi.sql.compile.NodeFactory;
 import org.apache.derby.iapi.sql.dictionary.AliasDescriptor;
+import org.apache.derby.iapi.sql.compile.TypeCompilerFactory;
 
 import org.apache.derby.iapi.error.StandardException;
 import org.apache.derby.iapi.reference.ClassName;
@@ -109,6 +112,7 @@ public class UserAggregateDefinition imp
 			CompilerContext cc = (CompilerContext)
 				ContextService.getContext(CompilerContext.CONTEXT_ID);
             ClassFactory    classFactory = cc.getClassFactory();
+            TypeCompilerFactory tcf = cc.getTypeCompilerFactory();
 
             Class   userAggregatorClass = classFactory.loadApplicationClass( _alias.getJavaClassName()
);
             Class   derbyAggregatorInterface = classFactory.loadApplicationClass( "org.apache.derby.agg.Aggregator"
);
@@ -138,8 +142,9 @@ public class UserAggregateDefinition imp
             Class       expectedInputClass = getJavaClass( classFactory, expectedInputType
);
             Class       expectedReturnClass = getJavaClass( classFactory, expectedReturnType
);
 
-            // the input operand must be the expected input type of the aggregate
-            if ( !inputType.getTypeId().equals( expectedInputType.getTypeId() ) ) { return
null; }
+            // the input operand must be coercible to the expected input type of the aggregate
+            if ( !tcf.getTypeCompiler( expectedInputType.getTypeId() ).storable( inputType.getTypeId(),
classFactory ) )
+            { return null; }
             
             //
             // Make sure that the declared input type of the UDA actually falls within
@@ -192,6 +197,26 @@ public class UserAggregateDefinition imp
 		catch (ClassNotFoundException cnfe) { throw aggregatorInstantiation( cnfe ); }
 	}
 
+	/**
+	 * 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.
+	 */
+	public final ValueNode	castInputValue
+        ( ValueNode inputValue, NodeFactory nodeFactory, ContextManager cm )
+        throws StandardException
+	{
+        AggregateAliasInfo  aai = (AggregateAliasInfo) _alias.getAliasInfo();
+        DataTypeDescriptor  expectedInputType = DataTypeDescriptor.getType( aai.getForType()
);
+        DataTypeDescriptor  actualInputType = inputValue.getTypeServices();
+
+        // no cast needed if the types match exactly
+        if ( expectedInputType.isExactTypeAndLengthMatch( actualInputType ) ) { return null;
}
+        else
+        {
+            return StaticMethodCallNode.makeCast( inputValue, expectedInputType, nodeFactory,
cm );
+        }
+    }
+    
     /**
      * Get the Java class corresponding to a Derby datatype.
      */
@@ -227,5 +252,6 @@ public class UserAggregateDefinition imp
              t.getMessage()
              );
     }
+
     
 }

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=1398352&r1=1398351&r2=1398352&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 15 16:00:08 2012
@@ -64,6 +64,8 @@ public class UserDefinedAggregatesTest  
     public static final String INPUT_OUTSIDE_BOUNDS = "42ZC6";
     public static final String RETURN_OUTSIDE_BOUNDS = "42ZC7";
     public static final String XML_TYPE = "42ZB3";
+    public static final String INT_TRUNCATION = "22003";
+    public static final String CAST_FAILURE = "22018";
 
     ///////////////////////////////////////////////////////////////////////////////////
     //
@@ -1770,4 +1772,194 @@ public class UserDefinedAggregatesTest  
         return new HarmonySerialClob( contents );
     }
 
+    /**
+     * <p>
+     * Test implicit casts of input types.
+     * </p>
+     */
+    public void test_12_coercion() throws Exception
+    {
+        Connection conn = getConnection();
+
+        goodStatement
+            (
+             conn,
+             "create derby aggregate charMode_12 for char( 4 )\n" +
+             "external name 'org.apache.derbyTesting.functionTests.tests.lang.GenericMode$StringMode'\n"
+             );
+        goodStatement
+            (
+             conn,
+             "create table charMode_12_mode_inputs_small( a int, b char( 3 ) )"
+             );
+        goodStatement
+            (
+             conn,
+             "insert into charMode_12_mode_inputs_small( a, b ) values ( 1, 'aaa' ), ( 1,
'aba' ), ( 1, 'aaa' ), ( 2, 'aba' ), ( 2, 'aba' ), ( 2, 'aba' ), ( 3, 'aba' ), ( 3, 'aba'
), ( 3, 'abc' )"
+             );
+        goodStatement
+            (
+             conn,
+             "create table charMode_12_mode_inputs_big( a int, b char( 5 ) )"
+             );
+        goodStatement
+            (
+             conn,
+             "insert into charMode_12_mode_inputs_big( a, b ) values ( 1, 'aaaaa' ), ( 1,
'abaaa' ), ( 1, 'aaaaa' ), ( 2, 'abaaa' ), ( 2, 'abaaa' ), ( 2, 'abcaa' ), ( 3, 'abaaa' ),
( 3, 'abaaa' ), ( 3, 'abcde' )"
+             );
+
+        // undersized char values are space-padded at the end
+        assertResults
+            (
+             conn,
+             "select charMode_12( b ) from charMode_12_mode_inputs_small",
+             new String[][]
+             {
+                 { "aba " },
+             },
+             false
+             );
+        assertResults
+            (
+             conn,
+             "select a, charMode_12( b ) from charMode_12_mode_inputs_small group by a",
+             new String[][]
+             {
+                 { "1", "aaa " },
+                 { "2", "aba " },
+                 { "3", "aba " },
+             },
+             false
+             );
+        assertResults
+            (
+             conn,
+             "select charMode_12( distinct b ) from charMode_12_mode_inputs_small",
+             new String[][]
+             {
+                 { "abc " },
+             },
+             false
+             );
+        assertResults
+            (
+             conn,
+             "select a, charMode_12( distinct b ) from charMode_12_mode_inputs_small group
by a",
+             new String[][]
+             {
+                 { "1", "aba " },
+                 { "2", "aba " },
+                 { "3", "abc " },
+             },
+             false
+             );
+
+        // oversized char values raise truncation errors
+        expectExecutionError
+            ( conn, STRING_TRUNCATION, "select charMode_12( b ) from charMode_12_mode_inputs_big"
);
+        expectExecutionError
+            ( conn, STRING_TRUNCATION, "select a, charMode_12( b ) from charMode_12_mode_inputs_big
group by a" );
+        expectExecutionError
+            ( conn, STRING_TRUNCATION, "select charMode_12( distinct b ) from charMode_12_mode_inputs_big"
);
+        expectExecutionError
+            ( conn, STRING_TRUNCATION, "select a, charMode_12( distinct b ) from charMode_12_mode_inputs_big
group by a" );
+
+        // no problem running a BIGINT aggregator on INTs
+        goodStatement
+            (
+             conn,
+             "create derby aggregate bigintMode_12 for bigint\n" +
+             "external name 'org.apache.derbyTesting.functionTests.tests.lang.GenericMode$BigintMode'\n"
+             );
+        goodStatement
+            (
+             conn,
+             "create table ints_12( a int, b int )"
+             );
+        goodStatement
+            (
+             conn,
+             "insert into ints_12( a, b ) values ( 1, 1 ), ( 1, 2 ), (1, 2 ), ( 2, 2 ), (
2, 3 ), ( 3, 3 ), ( 3, 4 ), ( 3, 5 )"
+             );
+        assertResults
+            (
+             conn,
+             "select bigintMode_12( b ) from ints_12",
+             new String[][]
+             {
+                 { "2" },
+             },
+             false
+             );
+        assertResults
+            (
+             conn,
+             "select a, bigintMode_12( b ) from ints_12 group by a",
+             new String[][]
+             {
+                 { "1", "2" },
+                 { "2", "3" },
+                 { "3", "5" },
+             },
+             false
+             );
+        assertResults
+            (
+             conn,
+             "select bigintMode_12( distinct b ) from ints_12",
+             new String[][]
+             {
+                 { "5" },
+             },
+             false
+             );
+        assertResults
+            (
+             conn,
+             "select a, bigintMode_12( distinct b ) from ints_12 group by a",
+             new String[][]
+             {
+                 { "1", "2" },
+                 { "2", "3" },
+                 { "3", "5" },
+             },
+             false
+             );
+
+        // but you can get runtime errors if you run an INT aggregate on oversized BIGINTs
+        goodStatement
+            (
+             conn,
+             "create derby aggregate intMode_12 for int\n" +
+             "external name 'org.apache.derbyTesting.functionTests.tests.lang.GenericMode$IntMode'\n"
+             );
+        goodStatement
+            (
+             conn,
+             "create table bigints_12( a int, b bigint )"
+             );
+        goodStatement
+            (
+             conn,
+             "insert into bigints_12( a, b ) values ( 1, 1000000000001 ), ( 1, 1000000000002
), (1, 1000000000002 ), ( 2, 1000000000002 ), ( 2, 1000000000003 ), ( 3, 1000000000003 ),
( 3, 1000000000004 ), ( 3, 1000000000005 )"
+             );
+        expectExecutionError
+            ( conn, INT_TRUNCATION, "select intMode_12( b ) from bigints_12" );
+        expectExecutionError
+            ( conn, INT_TRUNCATION, "select a, intMode_12( b ) from bigints_12 group by a"
);
+        expectExecutionError
+            ( conn, INT_TRUNCATION, "select intMode_12( distinct b ) from bigints_12" );
+        expectExecutionError
+            ( conn, INT_TRUNCATION, "select a, intMode_12( distinct b ) from bigints_12 group
by a" );
+
+        // implicit cast from char to int fails
+        expectCompilationError( INPUT_MISMATCH, "select intMode_12( b ) from charMode_12_mode_inputs_small"
);
+
+        // explict cast from char to int can fail at runtime
+        expectExecutionError
+            ( conn, CAST_FAILURE, "select intMode_12( cast (b as int) ) from charMode_12_mode_inputs_small"
);
+        
+    }
+
+
 }



Mime
View raw message