Return-Path: X-Original-To: apmail-db-derby-commits-archive@www.apache.org Delivered-To: apmail-db-derby-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 3C91510C99 for ; Wed, 5 Feb 2014 12:15:16 +0000 (UTC) Received: (qmail 61093 invoked by uid 500); 5 Feb 2014 12:15:15 -0000 Delivered-To: apmail-db-derby-commits-archive@db.apache.org Received: (qmail 61005 invoked by uid 500); 5 Feb 2014 12:15:09 -0000 Mailing-List: contact derby-commits-help@db.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: List-Post: Reply-To: "Derby Development" List-Id: Delivered-To: mailing list derby-commits@db.apache.org Received: (qmail 60997 invoked by uid 99); 5 Feb 2014 12:15:07 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 05 Feb 2014 12:15:07 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 05 Feb 2014 12:15:06 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 35BCD238883D; Wed, 5 Feb 2014 12:14:46 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1564730 - in /db/derby/code/branches/10.10: ./ java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java java/testing/org/apache/derbyTesting/functionTests/tests/lang/InsertTest.java Date: Wed, 05 Feb 2014 12:14:46 -0000 To: derby-commits@db.apache.org From: kahatlen@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20140205121446.35BCD238883D@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: kahatlen Date: Wed Feb 5 12:14:45 2014 New Revision: 1564730 URL: http://svn.apache.org/r1564730 Log: DERBY-6443: ArrayIndexOutOfBoundsException when calling function from trigger Merged revision 1556809 from trunk. Modified: db/derby/code/branches/10.10/ (props changed) db/derby/code/branches/10.10/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java db/derby/code/branches/10.10/java/testing/org/apache/derbyTesting/functionTests/tests/lang/InsertTest.java Propchange: db/derby/code/branches/10.10/ ------------------------------------------------------------------------------ Merged /db/derby/code/trunk:r1556809 Modified: db/derby/code/branches/10.10/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.10/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java?rev=1564730&r1=1564729&r2=1564730&view=diff ============================================================================== --- db/derby/code/branches/10.10/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java (original) +++ db/derby/code/branches/10.10/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java Wed Feb 5 12:14:45 2014 @@ -113,7 +113,12 @@ public class StaticMethodCallNode extend private int[] applicationParameterNumbers; private boolean isSystemCode; - private boolean alreadyBound; + + /** + * This flag is true while bindExpression() is executing. It is used to + * avoid infinite recursion when bindExpression() is reentered. + */ + private boolean isInsideBind; /** * Generated boolean field to hold the indicator @@ -182,10 +187,24 @@ public class StaticMethodCallNode extend throws StandardException { // for a function we can get called recursively - if (alreadyBound) - return this; + if (isInsideBind) { + return this; + } + isInsideBind = true; + try { + return bindExpressionMinion(fromList, subqueryList, aggregateVector); + } finally { + isInsideBind = false; + } + } + private JavaValueNode bindExpressionMinion( + FromList fromList, + SubqueryList subqueryList, + List aggregateVector) + throws StandardException + { bindParameters(fromList, subqueryList, aggregateVector); @@ -345,7 +364,6 @@ public class StaticMethodCallNode extend resolveMethodCall( javaClassName, true ); - alreadyBound = true; if (isPrivilegeCollectionRequired()) getCompilerContext().addRequiredRoutinePriv(ad); Modified: db/derby/code/branches/10.10/java/testing/org/apache/derbyTesting/functionTests/tests/lang/InsertTest.java URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.10/java/testing/org/apache/derbyTesting/functionTests/tests/lang/InsertTest.java?rev=1564730&r1=1564729&r2=1564730&view=diff ============================================================================== --- db/derby/code/branches/10.10/java/testing/org/apache/derbyTesting/functionTests/tests/lang/InsertTest.java (original) +++ db/derby/code/branches/10.10/java/testing/org/apache/derbyTesting/functionTests/tests/lang/InsertTest.java Wed Feb 5 12:14:45 2014 @@ -207,4 +207,75 @@ public class InsertTest extends BaseJDBC TOO_MANY_RESULT_COLUMNS, "insert into derby4449 (x) values (default, default)"); } + + /** + * Regression test case for DERBY-6443. INSERT statements bind the + * source SELECT statement twice, and the second time it would miss + * aggregates and subqueries if they were wrapped in a function call. + * This led to inconsistencies in the query tree that caused errors + * during execution (or assertion failures during compilation in sane + * builds). + */ + public void testDerby6443() throws SQLException { + Statement s = createStatement(); + + // Disable auto-commit for easy cleanup of test tables (automatically + // rolled back in tearDown()), and create a separate schema to avoid + // name conflicts with other test cases. + setAutoCommit(false); + s.execute("CREATE SCHEMA d6443"); + s.execute("SET SCHEMA d6443"); + + // This is the original test case provided in the bug report. It + // used to fail with an assert failure when compiling the trigger + // (in sane builds), or with an ArrayIndexOutOfBoundsException when + // the trigger fired (in insane builds). + s.execute("CREATE TABLE foo (name VARCHAR(20), val DOUBLE)"); + s.execute("CREATE TABLE summary " + + "(name VARCHAR(20), aver DOUBLE, size INT)"); + s.execute("CREATE TRIGGER trg_foo AFTER INSERT ON foo " + + "REFERENCING NEW TABLE AS changed FOR EACH STATEMENT " + + "INSERT INTO summary (name, aver, size) " + + "SELECT name, FLOOR(AVG(LOG10(val))), COUNT(*) " + + "FROM changed " + + "GROUP BY name"); + s.execute("INSERT INTO foo (name, val) " + + "VALUES ('A', 10), ('A', 20), ('B', 30), ('C', 40)"); + JDBC.assertFullResultSet( + s.executeQuery("select * from foo order by val"), + new String[][] { + { "A", "10.0" }, + { "A", "20.0" }, + { "B", "30.0" }, + { "C", "40.0" }, + }); + JDBC.assertFullResultSet( + s.executeQuery("select * from summary order by name"), + new String[][] { + { "A", "1.0", "2" }, + { "B", "1.0", "1" }, + { "C", "1.0", "1" }, + }); + + // Some other problematic queries... + + s.execute("create table t1(x int)"); + s.execute("insert into t1 values 1"); + s.execute("create table t2(x int)"); + + // Used to fail with assert or ArrayIndexOutOfBoundsException. + s.execute("insert into t2 select floor(avg(x)) from t1"); + + // Same here... + s.execute("create function f(x int) returns int language java " + + "parameter style java external name 'java.lang.Math.abs'"); + s.execute("insert into t2 select f(avg(x)) from t1"); + + // This query used to fail with a NullPointerException. + s.execute("insert into t2 select f((select x from t1)) from t1"); + + JDBC.assertFullResultSet( + s.executeQuery("select * from t2"), + new String[][] {{"1"}, {"1"}, {"1"}}); + } }