db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rhille...@apache.org
Subject svn commit: r723184 - in /db/derby/code/trunk/java: engine/org/apache/derby/impl/sql/compile/ engine/org/apache/derby/loc/ shared/org/apache/derby/shared/common/reference/ testing/org/apache/derbyTesting/functionTests/tests/lang/
Date Thu, 04 Dec 2008 01:41:26 GMT
Author: rhillegas
Date: Wed Dec  3 17:41:26 2008
New Revision: 723184

URL: http://svn.apache.org/viewvc?rev=723184&view=rev
Log:
DERBY-3969: Fix NPEs when declaring constraints on generated columns without explicit datatypes.

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/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/impl/sql/compile/sqlgrammar.jj
    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/GeneratedColumnsHelper.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=723184&r1=723183&r2=723184&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
Wed Dec  3 17:41:26 2008
@@ -410,12 +410,15 @@
 			/* Now that we've finally goobered stuff up, bind and validate
 			 * the check constraints and generation clauses.
 			 */
-			if  (numCheckConstraints > 0) { tableElementList.bindAndValidateCheckConstraints(fromList);
}
 			if  (numGenerationClauses > 0)
             { tableElementList.bindAndValidateGenerationClauses( schemaDescriptor, fromList,
generatedColumns ); }
+			if  (numCheckConstraints > 0) { tableElementList.bindAndValidateCheckConstraints(fromList);
}
             if ( numReferenceConstraints > 0) { tableElementList.validateForeignKeysOnGenerationClauses(
fromList, generatedColumns ); }
 		}
 
+        // must be done after resolving the datatypes of the generation clauses
+        if (tableElementList != null) { tableElementList.validatePrimaryKeyNullability();
}
+
 		//Check if we are in alter table to update the statistics. If yes, then
 		//check if we are here to update the statistics of a specific index. If
 		//yes, then verify that the indexname provided is a valid one.

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=723184&r1=723183&r2=723184&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
Wed Dec  3 17:41:26 2008
@@ -438,10 +438,12 @@
 			/* Now that we've finally goobered stuff up, bind and validate
 			 * the check constraints and generation clauses.
 			 */
-			if  (numCheckConstraints > 0) { tableElementList.bindAndValidateCheckConstraints(fromList);
}
 			if  (numGenerationClauses > 0) { tableElementList.bindAndValidateGenerationClauses(
sd, fromList, generatedColumns ); }
+			if  (numCheckConstraints > 0) { tableElementList.bindAndValidateCheckConstraints(fromList);
}
             if ( numReferenceConstraints > 0) { tableElementList.validateForeignKeysOnGenerationClauses(
fromList, generatedColumns ); }
 		}
+
+        if ( numPrimaryKeys > 0 ) { tableElementList.validatePrimaryKeyNullability();
}
 	}
 
 	/**

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=723184&r1=723183&r2=723184&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
Wed Dec  3 17:41:26 2008
@@ -278,6 +278,21 @@
 
 	public ResultColumn getResultColumn(String columnName)
 	{
+        return getResultColumn( columnName, true );
+	}
+
+	/**
+	 * Get a ResultColumn that matches the specified columnName. If requested
+	 * to, mark the column as referenced.
+	 *
+	 * @param columnName	The ResultColumn to get from the list
+	 * @param markIfReferenced True if we should mark this column as referenced.
+	 *
+	 * @return	the column that matches that name.
+	 */
+
+	public ResultColumn getResultColumn(String columnName, boolean markIfReferenced )
+	{
 		int size = size();
 		for (int index = 0; index < size; index++)
 		{
@@ -285,8 +300,8 @@
 
 			if (columnName.equals( resultColumn.getName()) )
 			{
-				/* Mark ResultColumn as referenced and return it */
-				resultColumn.setReferenced();
+                /* Mark ResultColumn as referenced and return it */
+                if ( markIfReferenced ) { resultColumn.setReferenced(); }
 				return resultColumn;
 			}
 		}

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=723184&r1=723183&r2=723184&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
Wed Dec  3 17:41:26 2008
@@ -344,21 +344,11 @@
 				}
 			}
 
+            // validation of primary key nullability moved to validatePrimaryKeyNullability().
             if (cdn.hasPrimaryKeyConstraint())
             {
                 // for PRIMARY KEY, check that columns are unique
                 verifyUniqueColumnList(ddlStmt, cdn);
-
-                if (td == null)
-                {
-                    // in CREATE TABLE so set PRIMARY KEY columns to NOT NULL
-                    setColumnListToNotNull(cdn);
-                }
-                else
-                {
-                    // in ALTER TABLE so raise error if any columns are nullable
-                    checkForNullColumns(cdn, td);
-                }
             }
             else if (cdn.hasUniqueKeyConstraint())
             {
@@ -387,6 +377,44 @@
 	}
 
     /**
+	 * Validate nullability of primary keys. This logic was moved out of the main validate
+	 * method so that it can be called after binding generation clauses. We need
+	 * to perform the nullability checks later on because the datatype may be
+	 * omitted on the generation clause--we can't set/vet the nullability of the
+	 * datatype until we determine what the datatype is.
+	 */
+    public  void    validatePrimaryKeyNullability()
+        throws StandardException
+    {
+		int			size = size();
+		for (int index = 0; index < size; index++)
+		{
+			TableElementNode tableElement = (TableElementNode) elementAt(index);
+
+			if (! (tableElement.hasConstraint()))
+			{
+				continue;
+			}
+            
+			ConstraintDefinitionNode cdn = (ConstraintDefinitionNode) tableElement;
+
+            if (cdn.hasPrimaryKeyConstraint())
+            {
+                if (td == null)
+                {
+                    // in CREATE TABLE so set PRIMARY KEY columns to NOT NULL
+                    setColumnListToNotNull(cdn);
+                }
+                else
+                {
+                    // in ALTER TABLE so raise error if any columns are nullable
+                    checkForNullColumns(cdn, td);
+                }
+            }
+        }
+    }
+    
+    /**
 	 * Count the number of constraints of the specified type.
 	 *
 	 * @param constraintType	The constraint type to search for.
@@ -721,6 +749,7 @@
 	{
 		CompilerContext cc;
 		FromBaseTable				table = (FromBaseTable) fromList.elementAt(0);
+        ResultColumnList            tableColumns = table.getResultColumns();
         int                                 columnCount = table.getResultColumns().size();
 		int						  size = size();
 
@@ -788,6 +817,12 @@
                     cdn.setType( generationClauseType );
 
                     //
+                    // Poke the type into the FromTable so that constraints will
+                    // compile.
+                    //
+                    tableColumns.getResultColumn( cdn.getColumnName(), false ).setType( generationClauseType
);
+
+                    //
                     // We skipped these steps earlier on because we didn't have
                     // a datatype. Now that we have a datatype, revisit these
                     // steps.

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj?rev=723184&r1=723183&r2=723184&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj Wed Dec
 3 17:41:26 2008
@@ -12195,6 +12195,10 @@
 		//throw an exception
 		if (explicitNull) 
                    throw StandardException.newException(SQLState.LANG_ADDING_COLUMN_WITH_NULL_AND_NOT_NULL_CONSTRAINT,
columnName); 
+
+		// columns with generation clauses can omit the datatype
+		if ( dataTypeDescriptor[0] == null ) { throw StandardException.newException(SQLState.LANG_NOT_NULL_NEEDS_DATATYPE);
}
+
 		dataTypeDescriptor[0] = dataTypeDescriptor[0].getNullabilityType(false);
 		return null;
 	}

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=723184&r1=723183&r2=723184&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 Wed Dec  3 17:41:26
2008
@@ -2032,6 +2032,11 @@
             </msg>
 
             <msg>
+                <name>42XAB</name>
+                <text>NOT NULL is allowed only if you explicitly declare a datatype.</text>
+            </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=723184&r1=723183&r2=723184&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
Wed Dec  3 17:41:26 2008
@@ -905,6 +905,7 @@
     String LANG_GEN_COL_BAD_RENAME                                           = "42XA8";
     String LANG_NEEDS_DATATYPE                                                      = "42XA9";
     String LANG_GEN_COL_BEFORE_TRIG                                             = "42XAA";
+    String LANG_NOT_NULL_NEEDS_DATATYPE                                    = "42XAB";
 	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/GeneratedColumnsHelper.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GeneratedColumnsHelper.java?rev=723184&r1=723183&r2=723184&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GeneratedColumnsHelper.java
(original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GeneratedColumnsHelper.java
Wed Dec  3 17:41:26 2008
@@ -57,6 +57,7 @@
     ///////////////////////////////////////////////////////////////////////////////////
 
     protected static  final   String  REDUNDANT_CLAUSE = "42613";
+    protected static  final   String  CANT_CONTAIN_NULLS = "42831";
     protected static  final   String  ILLEGAL_AGGREGATE = "42XA1";
     protected static  final   String  UNSTABLE_RESULTS = "42XA2";
     protected static  final   String  CANT_OVERRIDE_GENERATION_CLAUSE = "42XA3";
@@ -67,6 +68,7 @@
     protected static  final   String  ILLEGAL_RENAME = "42XA8";
     protected static  final   String  NEED_EXPLICIT_DATATYPE = "42XA9";
     protected static  final   String  BAD_BEFORE_TRIGGER = "42XAA";
+    protected static  final   String  NOT_NULL_NEEDS_DATATYPE = "42XAB";
     
     protected static  final   String  NOT_NULL_VIOLATION = "23502";
     protected static  final   String  CONSTRAINT_VIOLATION = "23513";

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=723184&r1=723183&r2=723184&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 Dec  3 17:41:26 2008
@@ -4644,6 +4644,387 @@
              );
     }
     
+    /**
+     * <p>
+     * Test that we can put constraints on generated columns when we omit the datatype.
+     * DERBY-3969.
+     * </p>
+     */
+    public  void    test_027_constraintsNoDatatype()
+        throws Exception
+    {
+        Connection  conn = getConnection();
+
+        //
+        // Verify that we can declare check constraints on generated columns
+        // which omit the datatype.
+        //
+        goodStatement
+            (
+             conn,
+             "create table t_ccnd_1( a int, b generated always as ( -a ) check ( b < 0
) )"
+             );
+        goodStatement
+            (
+             conn,
+             "insert into t_ccnd_1( a ) values ( 1 )"
+             );
+        expectExecutionError
+            (
+             conn,
+             CONSTRAINT_VIOLATION,
+             "insert into t_ccnd_1( a ) values ( -1 )"
+             );
+        goodStatement
+            (
+             conn,
+             "alter table t_ccnd_1 add column c generated always as ( -a ) check ( c >
-10 )"
+             );
+        goodStatement
+            (
+             conn,
+             "insert into t_ccnd_1( a ) values ( 2 )"
+             );
+        expectExecutionError
+            (
+             conn,
+             CONSTRAINT_VIOLATION,
+             "insert into t_ccnd_1( a ) values ( 20 )"
+             );
+        assertResults
+            (
+             conn,
+             "select * from t_ccnd_1 order by a",
+             new String[][]
+             {
+                 { "1", "-1", "-1" },
+                 { "2", "-2", "-2" },
+             },
+             false
+             );
+
+        //
+        // Verify that we can declare foreign keys on generated columns
+        // which omit the datatype.
+        //
+        goodStatement
+            (
+             conn,
+             "create table t_ccnd_2( b int primary key )"
+             );
+        goodStatement
+            (
+             conn,
+             "create table t_ccnd_3( a int, b generated always as ( -a ) references t_ccnd_2(
b ) )"
+             );
+        goodStatement
+            (
+             conn,
+             "create table t_ccnd_4( a int )"
+             );
+        goodStatement
+            (
+             conn,
+             "insert into t_ccnd_2( b ) values ( 1 )"
+             );
+        goodStatement
+            (
+             conn,
+             "insert into t_ccnd_3( a ) values ( -1 )"
+             );
+        expectExecutionError
+            (
+             conn,
+             FOREIGN_KEY_VIOLATION,
+             "insert into t_ccnd_3( a ) values ( -2 )"
+             );
+        goodStatement
+            (
+             conn,
+             "alter table t_ccnd_4 add column b generated always as ( -a ) references t_ccnd_2(
b )"
+             );
+        goodStatement
+            (
+             conn,
+             "insert into t_ccnd_4( a ) values ( -1 )"
+             );
+        expectExecutionError
+            (
+             conn,
+             FOREIGN_KEY_VIOLATION,
+             "insert into t_ccnd_4( a ) values ( -2 )"
+             );
+        assertResults
+            (
+             conn,
+             "select * from t_ccnd_3 order by a",
+             new String[][]
+             {
+                 { "-1", "1", },
+             },
+             false
+             );
+        assertResults
+            (
+             conn,
+             "select * from t_ccnd_4 order by a",
+             new String[][]
+             {
+                 { "-1", "1", },
+             },
+             false
+             );
+
+        //
+        // Verify that we can declare primary keys on generated columns
+        // which omit the datatype.
+        //
+        goodStatement
+            (
+             conn,
+             "create table t_ccnd_5( a int, b generated always as ( -a ) primary key )"
+             );
+        goodStatement
+            (
+             conn,
+             "insert into t_ccnd_5( a ) values ( 1 )"
+             );
+        expectExecutionError
+            (
+             conn,
+             ILLEGAL_DUPLICATE,
+             "insert into t_ccnd_5( a ) values ( 1 )"
+             );
+        assertResults
+            (
+             conn,
+             "select * from t_ccnd_5 order by a",
+             new String[][]
+             {
+                 { "1", "-1", },
+             },
+             false
+             );
+        
+        //
+        // Verify that you CANNOT declare a generated column to be NOT NULL
+        // if you omit the datatype.
+        //
+        expectCompilationError
+            (
+             NOT_NULL_NEEDS_DATATYPE,
+             "create table t_ccnd_6( a int, b generated always as ( -a ) not null )"
+             );
+        goodStatement
+            (
+             conn,
+             "create table t_ccnd_6( a int )"
+             );
+        expectCompilationError
+            (
+             NOT_NULL_NEEDS_DATATYPE,
+             "alter table t_ccnd_6 add column b generated always as ( -a ) not null"
+             );
+        
+        //
+        // Verify that you CAN declare a generated column to be NOT NULL
+        // if you include the datatype.
+        //
+        goodStatement
+            (
+             conn,
+             "create table t_ccnd_7( a int, b int generated always as ( -a ) not null )"
+             );
+        goodStatement
+            (
+             conn,
+             "insert into t_ccnd_7( a ) values ( 1 )"
+             );
+        expectExecutionError
+            (
+             conn,
+             NOT_NULL_VIOLATION,
+             "insert into t_ccnd_7( a ) values ( null )"
+             );
+        assertResults
+            (
+             conn,
+             "select * from t_ccnd_7 order by a",
+             new String[][]
+             {
+                 { "1", "-1", },
+             },
+             false
+             );
+        
+        //
+        // Verify that we can add generated columns with primary keys
+        // but only if you include the datatype or if the resolved datatype
+        // is not nullable.
+        //
+        goodStatement
+            (
+             conn,
+             "create table t_ccnd_8( a int )"
+             );
+        goodStatement
+            (
+             conn,
+             "create table t_ccnd_9( a int not null )"
+             );
+        expectCompilationError
+            (
+             CANT_CONTAIN_NULLS,
+             "alter table t_ccnd_8 add column b generated always as ( -a ) primary key"
+             );
+        goodStatement
+            (
+             conn,
+             "alter table t_ccnd_8 add column b int not null generated always as ( -a ) primary
key"
+             );
+        goodStatement
+            (
+             conn,
+             "insert into t_ccnd_8( a ) values ( 1 )"
+             );
+        expectExecutionError
+            (
+             conn,
+             NOT_NULL_VIOLATION,
+             "insert into t_ccnd_8( a ) values ( null )"
+             );
+        expectExecutionError
+            (
+             conn,
+             ILLEGAL_DUPLICATE,
+             "insert into t_ccnd_8( a ) values ( 1 )"
+             );
+        assertResults
+            (
+             conn,
+             "select * from t_ccnd_8 order by a",
+             new String[][]
+             {
+                 { "1", "-1", },
+             },
+             false
+             );
+
+        goodStatement
+            (
+             conn,
+             "alter table t_ccnd_9 add column b generated always as ( -a ) primary key"
+             );
+        goodStatement
+            (
+             conn,
+             "insert into t_ccnd_9( a ) values ( 1 )"
+             );
+        expectExecutionError
+            (
+             conn,
+             ILLEGAL_DUPLICATE,
+             "insert into t_ccnd_9( a ) values ( 1 )"
+             );
+        assertResults
+            (
+             conn,
+             "select * from t_ccnd_9 order by a",
+             new String[][]
+             {
+                 { "1", "-1", },
+             },
+             false
+             );
+        
+        //
+        // Verify that we can create generated columns with unique constraints.
+        //
+        goodStatement
+            (
+             conn,
+             "create table t_ccnd_10( a int, b generated always as ( -a ) unique )"
+             );
+        goodStatement
+            (
+             conn,
+             "create table t_ccnd_11( a int )"
+             );
+        goodStatement
+            (
+             conn,
+             "insert into t_ccnd_10( a ) values ( 1 )"
+             );
+        goodStatement
+            (
+             conn,
+             "insert into t_ccnd_10( a ) values ( null )"
+             );
+        goodStatement
+            (
+             conn,
+             "insert into t_ccnd_10( a ) values ( null )"
+             );
+        expectExecutionError
+            (
+             conn,
+             ILLEGAL_DUPLICATE,
+             "insert into t_ccnd_10( a ) values ( 1 )"
+             );
+        assertResults
+            (
+             conn,
+             "select * from t_ccnd_10 order by a",
+             new String[][]
+             {
+                 { "1", "-1", },
+                 { null, null, },
+                 { null, null, },
+             },
+             false
+             );
+
+        goodStatement
+            (
+             conn,
+             "alter table t_ccnd_11 add column b generated always as ( -a ) unique"
+             );
+        goodStatement
+            (
+             conn,
+             "insert into t_ccnd_11( a ) values ( 1 )"
+             );
+        goodStatement
+            (
+             conn,
+             "insert into t_ccnd_11( a ) values ( null )"
+             );
+        goodStatement
+            (
+             conn,
+             "insert into t_ccnd_11( a ) values ( null )"
+             );
+        expectExecutionError
+            (
+             conn,
+             ILLEGAL_DUPLICATE,
+             "insert into t_ccnd_11( a ) values ( 1 )"
+             );
+        assertResults
+            (
+             conn,
+             "select * from t_ccnd_11 order by a",
+             new String[][]
+             {
+                 { "1", "-1", },
+                 { null, null, },
+                 { null, null, },
+             },
+             false
+             );
+
+    }
+    
     ///////////////////////////////////////////////////////////////////////////////////
     //
     // MINIONS



Mime
View raw message