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 2008/10/30 19:09:29 UTC
svn commit: r709219 - in /db/derby/code/trunk/java:
engine/org/apache/derby/iapi/sql/dictionary/
engine/org/apache/derby/impl/sql/compile/ engine/org/apache/derby/loc/
shared/org/apache/derby/shared/common/reference/
testing/org/apache/derbyTesting/fun...
Author: rhillegas
Date: Thu Oct 30 11:09:26 2008
New Revision: 709219
URL: http://svn.apache.org/viewvc?rev=709219&view=rev
Log:
DERBY-481: Forbid generation clauses which reference generated columns.
Modified:
db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/TableDescriptor.java
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/ResultColumnList.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableElementList.java
db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml
db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.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/iapi/sql/dictionary/TableDescriptor.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/TableDescriptor.java?rev=709219&r1=709218&r2=709219&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/TableDescriptor.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/TableDescriptor.java Thu Oct 30 11:09:26 2008
@@ -411,6 +411,25 @@
}
/**
+ * Given a list of columns in the table, construct a bit map of those
+ * columns' ids.
+ */
+ public FormatableBitSet makeColumnMap( ColumnDescriptorList cdl )
+ {
+ FormatableBitSet result = new FormatableBitSet( columnDescriptorList.size() + 1 );
+ int count = cdl.size();
+
+ for ( int i = 0; i < count; i++ )
+ {
+ ColumnDescriptor cd = cdl.elementAt( i );
+
+ result.set( cd.getPosition() );
+ }
+
+ return result;
+ }
+
+ /**
* Gets the highest column id in the table. For now this is the same as
* the number of columns. However, in the future, after we implement
* ALTER TABLE DROP COLUMN, this correspondence won't hold any longer.
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=709219&r1=709218&r2=709219&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 Thu Oct 30 11:09:26 2008
@@ -397,7 +397,8 @@
* the check constraints and generation clauses.
*/
if (numCheckConstraints > 0) { tableElementList.bindAndValidateCheckConstraints(fromList); }
- if (numGenerationClauses > 0) { tableElementList.bindAndValidateGenerationClauses(fromList); }
+ if (numGenerationClauses > 0)
+ { tableElementList.bindAndValidateGenerationClauses(fromList, baseTable.makeColumnMap( baseTable.getGeneratedColumns() ) ); }
}
//Check if we are in alter table to update the statistics. If yes, then
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=709219&r1=709218&r2=709219&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 Thu Oct 30 11:09:26 2008
@@ -25,6 +25,7 @@
import org.apache.derby.iapi.reference.SQLState;
import org.apache.derby.iapi.reference.Limits;
+import org.apache.derby.iapi.services.io.FormatableBitSet;
import org.apache.derby.iapi.services.property.PropertyUtil;
import org.apache.derby.iapi.services.sanity.SanityManager;
@@ -438,7 +439,7 @@
* the check constraints and generation clauses.
*/
if (numCheckConstraints > 0) { tableElementList.bindAndValidateCheckConstraints(fromList); }
- if (numGenerationClauses > 0) { tableElementList.bindAndValidateGenerationClauses(fromList); }
+ if (numGenerationClauses > 0) { tableElementList.bindAndValidateGenerationClauses(fromList, new FormatableBitSet() ); }
}
}
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java?rev=709219&r1=709218&r2=709219&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java Thu Oct 30 11:09:26 2008
@@ -3015,6 +3015,28 @@
}
/**
+ * Get the position of first result column with the given name.
+ *
+ * @param name Name of the column
+ * @param basis 0 (for 0-based ids) or 1 (for 1-based ids)
+ */
+ public int getPosition( String name, int basis )
+ {
+ int size = size();
+ for (int index = 0; index < size; index++)
+ {
+ ResultColumn rc = (ResultColumn) elementAt(index);
+
+ if ( name.equals( rc.getName() ) )
+ {
+ return index + basis;
+ }
+ }
+
+ return -1;
+ }
+
+ /**
* Record the top level ColumnReferences in the specified array
* and table map
* This is useful when checking for uniqueness conditions.
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=709219&r1=709218&r2=709219&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 Thu Oct 30 11:09:26 2008
@@ -21,6 +21,7 @@
package org.apache.derby.impl.sql.compile;
+import org.apache.derby.iapi.services.io.FormatableBitSet;
import org.apache.derby.iapi.services.sanity.SanityManager;
import org.apache.derby.iapi.error.StandardException;
@@ -656,16 +657,20 @@
* the specified FromList.
*
* @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.
*
* @exception StandardException Thrown on error
*/
- void bindAndValidateGenerationClauses(FromList fromList)
+ void bindAndValidateGenerationClauses(FromList fromList, FormatableBitSet generatedColumns )
throws StandardException
{
CompilerContext cc;
FromBaseTable table = (FromBaseTable) fromList.elementAt(0);
+ int columnCount = table.getResultColumns().size();
int size = size();
+ generatedColumns.grow( columnCount + 1 );
+
cc = getCompilerContext();
Vector aggregateVector = new Vector();
@@ -689,7 +694,7 @@
continue;
}
- generationClauseNode = cdn.getGenerationClauseNode();
+ generationClauseNode = cdn.getGenerationClauseNode();
// bind the check condition
// verify that it evaluates to a boolean
@@ -763,6 +768,9 @@
int numReferenced = rcl.countReferencedColumns();
int[] generationClauseColumnReferences = new int[numReferenced];
+ int position = rcl.getPosition( cdn.getColumnName(), 1 );
+ generatedColumns.set( position );
+
rcl.recordColumnReferences(generationClauseColumnReferences, 1);
DefaultInfoImpl dii = new DefaultInfoImpl
@@ -774,6 +782,36 @@
*/
rcl.clearColumnReferences();
}
+
+ //
+ // Now verify that none of the generated columns reference other
+ // generated columns.
+ //
+ for (int index = 0; index < size; index++)
+ {
+ ColumnDefinitionNode cdn;
+ TableElementNode element = (TableElementNode) elementAt(index);
+
+ if (! (element instanceof ColumnDefinitionNode)) { continue; }
+
+ cdn = (ColumnDefinitionNode) element;
+
+ if (!cdn.hasGenerationClause()) { continue; }
+
+ int[] referencedColumns = cdn.getDefaultInfo().getReferencedColumnIDs();
+ int count = referencedColumns.length;
+
+ for ( int i = 0; i < count; i++ )
+ {
+ int referencedColumnID = referencedColumns[ i ];
+ if ( generatedColumns.isSet( referencedColumnID ) )
+ {
+ throw StandardException.newException(SQLState.LANG_CANT_REFERENCE_GENERATED_COLUMN, cdn.getColumnName());
+ }
+ } // end of loop through referenced columns
+
+ } // end of loop through generated columns
+
}
/**
Modified: db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml?rev=709219&r1=709218&r2=709219&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml Thu Oct 30 11:09:26 2008
@@ -1982,6 +1982,12 @@
</msg>
<msg>
+ <name>42XA4</name>
+ <text>The generation clause for column '{0}' references other generated columns. This is not allowed.</text>
+ <arg>columnName</arg>
+ </msg>
+
+ <msg>
<name>42Y00</name>
<text>Class '{0}' does not implement org.apache.derby.iapi.db.AggregateDefinition and thus cannot be used as an aggregate expression.</text>
<arg>className</arg>
Modified: db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java?rev=709219&r1=709218&r2=709219&view=diff
==============================================================================
--- db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java (original)
+++ db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java Thu Oct 30 11:09:26 2008
@@ -897,6 +897,7 @@
String LANG_AGGREGATE_IN_GENERATION_CLAUSE = "42XA1";
String LANG_NON_DETERMINISTIC_GENERATION_CLAUSE = "42XA2";
String LANG_CANT_OVERRIDE_GENERATION_CLAUSE = "42XA3";
+ String LANG_CANT_REFERENCE_GENERATED_COLUMN = "42XA4";
String LANG_INVALID_USER_AGGREGATE_DEFINITION2 = "42Y00";
String LANG_INVALID_CHECK_CONSTRAINT = "42Y01";
// String LANG_NO_ALTER_TABLE_COMPRESS_ON_TARGET_TABLE = "42Y02";
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=709219&r1=709218&r2=709219&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 Thu Oct 30 11:09:26 2008
@@ -59,9 +59,12 @@
private static final String REDUNDANT_CLAUSE = "42613";
private static final String UNSTABLE_RESULTS = "42XA2";
private static final String CANT_OVERRIDE_GENERATION_CLAUSE = "42XA3";
+ private static final String CANT_REFERENCE_GENERATED_COLUMN = "42XA4";
private static final String CONSTRAINT_VIOLATION = "23513";
private static final String FOREIGN_KEY_VIOLATION = "23503";
private static final String ILLEGAL_DUPLICATE = "23505";
+ private static final String MISPLACED_SELECT = "42X01";
+ private static final String COLUMN_OUT_OF_SCOPE = "42X04";
///////////////////////////////////////////////////////////////////////////////////
//
@@ -1302,6 +1305,87 @@
}
+ /**
+ * <p>
+ * Verify that generated columns can't refer to one another.
+ * </p>
+ */
+ public void test_012_referencedColumns()
+ throws Exception
+ {
+ Connection conn = getConnection();
+
+ expectCompilationError
+ (
+ CANT_REFERENCE_GENERATED_COLUMN,
+ "create table t_recurse_1( a int, b int generated always as ( -a ), c int generated always as ( b*b) )"
+ );
+ expectCompilationError
+ (
+ CANT_REFERENCE_GENERATED_COLUMN,
+ "create table t_recurse_1( a int, b int generated always as ( -b ) )"
+ );
+
+ goodStatement
+ (
+ conn,
+ "create table t_recurse_1( a int, b int generated always as ( -a ) )"
+ );
+ expectCompilationError
+ (
+ CANT_REFERENCE_GENERATED_COLUMN,
+ "alter table t_recurse_1 add column c int generated always as ( b*b )"
+ );
+ expectCompilationError
+ (
+ CANT_REFERENCE_GENERATED_COLUMN,
+ "alter table t_recurse_1 add column c int generated always as ( -c )"
+ );
+ }
+
+ /**
+ * <p>
+ * Various miscellaneous illegal create/alter table statements.
+ * </p>
+ */
+ public void test_013_badReferences()
+ throws Exception
+ {
+ Connection conn = getConnection();
+
+ goodStatement
+ (
+ conn,
+ "create table t_br_1( a int )"
+ );
+ goodStatement
+ (
+ conn,
+ "create table t_br_3( a int )"
+ );
+
+ expectCompilationError
+ (
+ COLUMN_OUT_OF_SCOPE,
+ "create table t_br_2( a int, b int generated always as ( t_br_1.a ) )"
+ );
+ expectCompilationError
+ (
+ MISPLACED_SELECT,
+ "create table t_br_2( a int, b int generated always as ( select a from t_br_1 ) )"
+ );
+ expectCompilationError
+ (
+ COLUMN_OUT_OF_SCOPE,
+ "alter table t_br_3 add column b int generated always as ( t_br_1.a )"
+ );
+ expectCompilationError
+ (
+ MISPLACED_SELECT,
+ "alter table t_br_3 add column b int generated always as ( select a from t_br_1 )"
+ );
+ }
+
///////////////////////////////////////////////////////////////////////////////////
//
// MINIONS