Return-Path: Delivered-To: apmail-db-derby-commits-archive@www.apache.org Received: (qmail 26016 invoked from network); 25 Nov 2009 15:58:16 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 25 Nov 2009 15:58:16 -0000 Received: (qmail 49597 invoked by uid 500); 25 Nov 2009 15:58:16 -0000 Delivered-To: apmail-db-derby-commits-archive@db.apache.org Received: (qmail 49561 invoked by uid 500); 25 Nov 2009 15:58:16 -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 49552 invoked by uid 99); 25 Nov 2009 15:58:16 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 25 Nov 2009 15:58:16 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.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, 25 Nov 2009 15:58:12 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 3C40423889B8; Wed, 25 Nov 2009 15:57:51 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r884163 - in /db/derby/code/trunk/java: engine/org/apache/derby/impl/sql/compile/ testing/org/apache/derbyTesting/functionTests/tests/lang/ Date: Wed, 25 Nov 2009 15:57:51 -0000 To: derby-commits@db.apache.org From: dag@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20091125155751.3C40423889B8@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: dag Date: Wed Nov 25 15:57:50 2009 New Revision: 884163 URL: http://svn.apache.org/viewvc?rev=884163&view=rev Log: DERBY-4451 ArrayIndexOutOfBoundsException or ASSERT FAILED when inserting generated columns out of order This patch fixes this issue as well as DERBY-4448, since they share the same underlying problem: the former way of checking for illegal override of generated columns in the presence of an explicit target column list failed to look below the top level UnionNode in a table constructor. This specialized treatment for the case of an explicit target column list has been removed for INSERT (it was shared with logic for UPDATE), so checking is now done by the code for the case of no explicit targte column list. Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DMLModStatementNode.java db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/InsertNode.java db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UpdateNode.java db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GeneratedColumnsTest.java Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DMLModStatementNode.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DMLModStatementNode.java?rev=884163&r1=884162&r2=884163&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DMLModStatementNode.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DMLModStatementNode.java Wed Nov 25 15:57:50 2009 @@ -408,87 +408,6 @@ } /** - * Do not allow generation clauses to be overriden. Throws an exception - * if the user attempts to override the value of a generated column. - * The only value allowed in a generated column is DEFAULT. If we find - * a generated column which is being explicitly set to DEFAULT in an INSERT, we remove - * it from the column lists--it will be added back in during the enhance - * phase. For an update, addedGeneratedColumns will be non-null and we will - * use this list to pass through the generated columns which have already - * been added to the update list. - * - * @param targetRCL the row in the table being INSERTed or UPDATEd - * @param forUpdate true if this is an UPDATE. false otherwise. - * @param addedGeneratedColumns generated columns which the compiler added earlier on - */ - void forbidGenerationOverrides( ResultColumnList targetRCL, boolean forUpdate, ColumnDescriptorList addedGeneratedColumns ) - throws StandardException - { - int count = targetRCL.size(); - - ResultColumnList resultRCL = resultSet.getResultColumns(); - - for ( int i = 0; i < count; i++ ) - { - ResultColumn rc = (ResultColumn) targetRCL.elementAt( i ); - - if ( rc.hasGenerationClause() ) - { - ValueNode resultExpression = ((ResultColumn) resultRCL.elementAt( i )).getExpression(); - - if ( !( resultExpression instanceof DefaultNode) ) - { - // - // For updates, we may have added the generation clause - // ourselves. Here we forgive ourselves for this pro-active behavior. - // - boolean allIsForgiven = false; - - if ( forUpdate ) - { - String columnName = rc.getTableColumnDescriptor().getColumnName(); - int addedCount = addedGeneratedColumns.size(); - - for ( int j = 0; j < addedCount; j++ ) - { - String addedColumnName = addedGeneratedColumns.elementAt( j ).getColumnName(); - - if ( columnName.equals( addedColumnName ) ) - { - allIsForgiven = true; - break; - } - } - } - if ( allIsForgiven ) { continue; } - - throw StandardException.newException - ( SQLState.LANG_CANT_OVERRIDE_GENERATION_CLAUSE, rc.getName() ); - } - else - { - // skip this step if we're working on an update statement. - // for updates, the target list has already been enhanced. - if ( forUpdate ) { continue; } - - // Prune the generated column and its default. They will be - // added back in during the enhance phase. - targetRCL.removeElementAt( i ); - resultRCL.removeElementAt( i ); - - targetRCL.resetVirtualColumnIds(); - resultRCL.resetVirtualColumnIds(); - - // account for the dropped entries - count--; - i--; - } - } - - } - } - - /** * Parse and bind the generating expressions of computed columns. * * @param dataDictionary metadata Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/InsertNode.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/InsertNode.java?rev=884163&r1=884162&r2=884163&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/InsertNode.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/InsertNode.java Wed Nov 25 15:57:50 2009 @@ -284,9 +284,6 @@ this); } getCompilerContext().popCurrentPrivType(); - - // don't allow overriding of generation clauses - forbidGenerationOverrides( targetColumnList, false, null ); } /* Verify that all underlying ResultSets reclaimed their FromList */ Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UpdateNode.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UpdateNode.java?rev=884163&r1=884162&r2=884163&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UpdateNode.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UpdateNode.java Wed Nov 25 15:57:50 2009 @@ -374,7 +374,8 @@ getCompilerContext().popCurrentPrivType(); // don't allow overriding of generation clauses - forbidGenerationOverrides( resultSet.getResultColumns(), true, addedGeneratedColumns ); + forbidGenerationOverrides( resultSet.getResultColumns(), + addedGeneratedColumns ); LanguageConnectionContext lcc = getLanguageConnectionContext(); if (lcc.getAutoincrementUpdate() == false) @@ -1293,4 +1294,75 @@ super.normalizeSynonymColumns(rcl, tableNameNode); } + /** + * Do not allow generation clauses to be overriden. Throws an exception if + * the user attempts to override the value of a generated column. The only + * value allowed in a generated column is DEFAULT. We will use + * addedGeneratedColumns list to pass through the generated columns which + * have already been added to the update list. + * + * @param targetRCL the row in the table being UPDATEd + * @param addedGeneratedColumns generated columns which the compiler added + * earlier on + * @throws StandardException on error + */ + private void forbidGenerationOverrides( + ResultColumnList targetRCL, + ColumnDescriptorList addedGeneratedColumns) + throws StandardException + { + int count = targetRCL.size(); + + ResultColumnList resultRCL = resultSet.getResultColumns(); + + for ( int i = 0; i < count; i++ ) + { + ResultColumn rc = (ResultColumn) targetRCL.elementAt( i ); + + if ( rc.hasGenerationClause() ) + { + ValueNode resultExpression = + ((ResultColumn) resultRCL.elementAt( i )).getExpression(); + + if ( !( resultExpression instanceof DefaultNode) ) + { + // + // We may have added the generation clause + // ourselves. Here we forgive ourselves for this + // pro-active behavior. + // + boolean allIsForgiven = false; + + String columnName = + rc.getTableColumnDescriptor().getColumnName(); + + int addedCount = addedGeneratedColumns.size(); + + for ( int j = 0; j < addedCount; j++ ) + { + String addedColumnName = addedGeneratedColumns. + elementAt(j).getColumnName(); + + if ( columnName.equals( addedColumnName ) ) + { + allIsForgiven = true; + break; + } + } + if ( allIsForgiven ) { continue; } + + throw StandardException.newException + (SQLState.LANG_CANT_OVERRIDE_GENERATION_CLAUSE, + rc.getName() ); + } + else + { + // Skip this step if we're working on an update + // statement. For updates, the target list has already + // been enhanced. + continue; + } + } + } + } } // end of UpdateNode Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GeneratedColumnsTest.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GeneratedColumnsTest.java?rev=884163&r1=884162&r2=884163&view=diff ============================================================================== --- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GeneratedColumnsTest.java (original) +++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GeneratedColumnsTest.java Wed Nov 25 15:57:50 2009 @@ -122,6 +122,118 @@ /////////////////////////////////////////////////////////////////////////////////// /** + * Test for DERBY-4448 and DERBY-4451: removal of explicitly given values + * for generated column failed if there is more than one row in the VALUES + * clause. + */ + public void testDerby_4448_4451() throws SQLException { + + // DERBY-4451 + + Statement s = createStatement(); + ResultSet rs = null; + setAutoCommit(false); + + s.execute("create table t(a int, b generated always as (-a))"); + s.execute("insert into t(b,a) values (default,1)"); + + + // Trying to override a generation clause + + expectCompilationError + ( + CANT_OVERRIDE_GENERATION_CLAUSE, + "insert into t(b,a) select a,b from t union select a,b from t" + ); + + expectCompilationError + ( + CANT_OVERRIDE_GENERATION_CLAUSE, + "insert into t(a,b) select * from t union select * from t" + ); + + expectCompilationError + ( + CANT_OVERRIDE_GENERATION_CLAUSE, + "insert into t(b,a) select * from t union select * from t" + ); + + expectCompilationError + ( + CANT_OVERRIDE_GENERATION_CLAUSE, + "insert into t(b,a) select * from t intersect select * from t" + ); + expectCompilationError + ( + CANT_OVERRIDE_GENERATION_CLAUSE, + "insert into t(b,a) select * from t except select * from t" + ); + + expectCompilationError + ( + CANT_OVERRIDE_GENERATION_CLAUSE, + "insert into t(b,a) select a,b from t" + ); + + expectCompilationError + ( + CANT_OVERRIDE_GENERATION_CLAUSE, + "insert into t(a,b) values (1,1)" + ); + + expectCompilationError + ( + CANT_OVERRIDE_GENERATION_CLAUSE, + "insert into t(b,a) values (default,1), (2, 2)" + ); + + expectCompilationError + ( + CANT_OVERRIDE_GENERATION_CLAUSE, + "insert into t(b,a) values (default,1), (default, 2),(3,3)" + ); + + expectCompilationError + ( + CANT_OVERRIDE_GENERATION_CLAUSE, + "insert into t(b,a) values (1,1), (default, 2),(default,3)" + ); + + // Originally repro: failed prior to fix with array out of bounds + // (insane), or ASSERT (sane): + s.execute("insert into t(b,a) values (default,1), (default, 2)"); + + rs = s.executeQuery("select * from t"); + JDBC.assertFullResultSet(rs, new String[][]{ + {"1", "-1"}, + {"1", "-1"}, + {"2", "-2"}}); + + // DERBY-4448: + expectCompilationError + ( + CANT_OVERRIDE_GENERATION_CLAUSE, + "insert into t(b) values (2)" + ); + + // Originally repro for DERBY-4448: failed with array out of bounds + // prior to fix: + expectCompilationError + ( + CANT_OVERRIDE_GENERATION_CLAUSE, + "insert into t(b) values (default), (2)" + ); + + expectCompilationError + ( + CANT_OVERRIDE_GENERATION_CLAUSE, + "insert into t(b) values (default), (default), (2)" + ); + + rollback(); + } + + /** *

* Test that the stored system procedures and functions are non-deterministic. If you want * a particular procedure/function to be deterministic, add some logic here. @@ -5323,6 +5435,8 @@ new String[][] { {"1","2"},{"2","4"},{"3","6"}}, false); } + + /////////////////////////////////////////////////////////////////////////////////// // // MINIONS