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 2009/04/06 23:41:45 UTC
svn commit: r762520 - in /db/derby/code/trunk/java:
engine/org/apache/derby/impl/sql/compile/
testing/org/apache/derbyTesting/functionTests/tests/lang/
Author: rhillegas
Date: Mon Apr 6 21:41:44 2009
New Revision: 762520
URL: http://svn.apache.org/viewvc?rev=762520&view=rev
Log:
DERBY-4145: Look for illegal references in generation clauses before binding the clauses.
Modified:
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/AlterTableNode.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CreateTableNode.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/GenerationClauseNode.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableElementList.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/AlterTableNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/AlterTableNode.java?rev=762520&r1=762519&r2=762520&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/AlterTableNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/AlterTableNode.java Mon Apr 6 21:41:44 2009
@@ -411,7 +411,7 @@
* the check constraints and generation clauses.
*/
if (numGenerationClauses > 0)
- { tableElementList.bindAndValidateGenerationClauses( schemaDescriptor, fromList, generatedColumns ); }
+ { tableElementList.bindAndValidateGenerationClauses( schemaDescriptor, fromList, generatedColumns, baseTable ); }
if (numCheckConstraints > 0) { tableElementList.bindAndValidateCheckConstraints(fromList); }
if ( numReferenceConstraints > 0) { tableElementList.validateForeignKeysOnGenerationClauses( fromList, generatedColumns ); }
}
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CreateTableNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CreateTableNode.java?rev=762520&r1=762519&r2=762520&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CreateTableNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CreateTableNode.java Mon Apr 6 21:41:44 2009
@@ -438,7 +438,7 @@
/* Now that we've finally goobered stuff up, bind and validate
* the check constraints and generation clauses.
*/
- if (numGenerationClauses > 0) { tableElementList.bindAndValidateGenerationClauses( sd, fromList, generatedColumns ); }
+ if (numGenerationClauses > 0) { tableElementList.bindAndValidateGenerationClauses( sd, fromList, generatedColumns, null ); }
if (numCheckConstraints > 0) { tableElementList.bindAndValidateCheckConstraints(fromList); }
if ( numReferenceConstraints > 0) { tableElementList.validateForeignKeysOnGenerationClauses( fromList, generatedColumns ); }
}
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/GenerationClauseNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/GenerationClauseNode.java?rev=762520&r1=762519&r2=762520&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/GenerationClauseNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/GenerationClauseNode.java Mon Apr 6 21:41:44 2009
@@ -144,6 +144,25 @@
return this._generationExpression.isEquivalent( that._generationExpression );
}
+ /**
+ * Return a vector of columns referenced in the generation expression.
+ *
+ * @exception StandardException Thrown on error
+ */
+ public Vector findReferencedColumns()
+ throws StandardException
+ {
+ CollectNodesVisitor visitor = new CollectNodesVisitor( ColumnReference.class );
+
+ _generationExpression.accept( visitor );
+
+ Vector result = visitor.getList();
+
+ if ( result == null ) { result = new Vector(); }
+
+ return result;
+ }
+
/*
Stringify.
*/
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableElementList.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableElementList.java?rev=762520&r1=762519&r2=762520&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableElementList.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableElementList.java Mon Apr 6 21:41:44 2009
@@ -36,6 +36,7 @@
import org.apache.derby.catalog.types.DefaultInfoImpl;
+import org.apache.derby.iapi.sql.dictionary.ColumnDescriptorList;
import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor;
import org.apache.derby.iapi.sql.dictionary.DataDictionary;
import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
@@ -57,7 +58,9 @@
import org.apache.derby.catalog.UUID;
+import java.util.ArrayList;
import java.util.Hashtable;
+import java.util.HashSet;
import java.util.Vector;
/**
@@ -741,10 +744,11 @@
* @param sd Schema where the table lives.
* @param fromList The FromList in question.
* @param generatedColumns Bitmap of generated columns in the table. Vacuous for CREATE TABLE, but may be non-trivial for ALTER TABLE. This routine may set bits for new generated columns.
+ * @param baseTable Table descriptor if this is an ALTER TABLE statement.
*
* @exception StandardException Thrown on error
*/
- void bindAndValidateGenerationClauses( SchemaDescriptor sd, FromList fromList, FormatableBitSet generatedColumns )
+ void bindAndValidateGenerationClauses( SchemaDescriptor sd, FromList fromList, FormatableBitSet generatedColumns, TableDescriptor baseTable )
throws StandardException
{
CompilerContext cc;
@@ -753,6 +757,9 @@
int columnCount = table.getResultColumns().size();
int size = size();
+ // complain if a generation clause references another generated column
+ findIllegalGenerationReferences( fromList, baseTable );
+
generatedColumns.grow( columnCount + 1 );
cc = getCompilerContext();
@@ -892,15 +899,40 @@
rcl.clearColumnReferences();
}
- //
- // Now verify that none of the generated columns reference other
- // generated columns.
- //
- ResultColumnList rcl = table.getResultColumns();
+
+ }
+
+ /**
+ * Complain if a generation clause references other generated columns. This
+ * is required by the SQL Standard, part 2, section 4.14.8.
+ *
+ * @param fromList The FromList in question.
+ * @param baseTable Table descriptor if this is an ALTER TABLE statement.
+ * @exception StandardException Thrown on error
+ */
+ void findIllegalGenerationReferences( FromList fromList, TableDescriptor baseTable )
+ throws StandardException
+ {
+ ArrayList generatedColumns = new ArrayList();
+ HashSet names = new HashSet();
+ int size = size();
+
+ // add in existing generated columns if this is an ALTER TABLE statement
+ if ( baseTable != null )
+ {
+ ColumnDescriptorList cdl = baseTable.getGeneratedColumns();
+ int count = cdl.size();
+ for ( int i = 0; i < count; i++ )
+ {
+ names.add( cdl.elementAt( i ).getColumnName() );
+ }
+ }
+
+ // find all of the generated columns
for (int index = 0; index < size; index++)
{
ColumnDefinitionNode cdn;
- TableElementNode element = (TableElementNode) elementAt(index);
+ TableElementNode element = (TableElementNode) elementAt(index);
if (! (element instanceof ColumnDefinitionNode)) { continue; }
@@ -908,24 +940,35 @@
if (!cdn.hasGenerationClause()) { continue; }
- String[] referencedColumnNames = cdn.getDefaultInfo().getReferencedColumnNames();
- int count = referencedColumnNames.length;
+ generatedColumns.add( cdn );
+ names.add( cdn.getColumnName() );
+ }
- for ( int i = 0; i < count; i++ )
+ // now look at their generation clauses to see if they reference one
+ // another
+ int count = generatedColumns.size();
+ for ( int i = 0; i < count; i++ )
+ {
+ ColumnDefinitionNode cdn = (ColumnDefinitionNode) generatedColumns.get( i );
+ GenerationClauseNode generationClauseNode = cdn.getGenerationClauseNode();
+ Vector referencedColumns = generationClauseNode.findReferencedColumns();
+ int refCount = referencedColumns.size();
+ for ( int j = 0; j < refCount; j++ )
{
- String name = referencedColumnNames[ i ];
- int referencedColumnID = rcl.getPosition( name, 1 );
+ String name = ((ColumnReference) referencedColumns.elementAt( j ) ).getColumnName();
- if ( generatedColumns.isSet( referencedColumnID ) )
+ if ( name != null )
{
- throw StandardException.newException(SQLState.LANG_CANT_REFERENCE_GENERATED_COLUMN, cdn.getColumnName());
+ if ( names.contains( name ) )
+ {
+ throw StandardException.newException(SQLState.LANG_CANT_REFERENCE_GENERATED_COLUMN, cdn.getColumnName());
+ }
}
- } // end of loop through referenced columns
-
- } // end of loop through generated columns
-
- }
+ }
+ }
+ }
+
/**
* Prevent foreign keys on generated columns from violating the SQL spec,
* part 2, section 11.8 (<column definition>), syntax rule 12: the
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=762520&r1=762519&r2=762520&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 Mon Apr 6 21:41:44 2009
@@ -5101,6 +5101,23 @@
);
}
+ /**
+ * <p>
+ * Test that we don't get a null pointer exception when generation clauses
+ * have forward references to other generated columns.
+ * </p>
+ */
+ public void test_029_derby_4145()
+ throws Exception
+ {
+ expectCompilationError
+ (
+ CANT_REFERENCE_GENERATED_COLUMN,
+ "create table t_4145(c1 int, c2 int, c3 generated always as (c1 + c4), c4 generated always as (-c1))"
+ );
+ }
+
+
///////////////////////////////////////////////////////////////////////////////////
//
// MINIONS