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/12/09 15:22:48 UTC

svn commit: r888811 - in /db/derby/code/trunk/java: engine/org/apache/derby/catalog/types/ engine/org/apache/derby/iapi/sql/depend/ engine/org/apache/derby/iapi/sql/dictionary/ engine/org/apache/derby/impl/sql/catalog/ engine/org/apache/derby/impl/sql/...

Author: rhillegas
Date: Wed Dec  9 14:22:46 2009
New Revision: 888811

URL: http://svn.apache.org/viewvc?rev=888811&view=rev
Log:
DERBY-651: Add dependency tracking between tables and UDTs.

Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/catalog/types/BaseTypeIdImpl.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/depend/DependencyManager.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/AliasDescriptor.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/DataDictionary.java
    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/catalog/DataDictionaryImpl.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/ColumnDefinitionNode.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/TableElementList.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableElementNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/depend/BasicDependencyManager.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/AlterTableConstantAction.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/CreateTableConstantAction.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DDLConstantAction.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/storeless/org/apache/derby/impl/storeless/EmptyDictionary.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/UDTTest.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/catalog/types/BaseTypeIdImpl.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/catalog/types/BaseTypeIdImpl.java?rev=888811&r1=888810&r2=888811&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/catalog/types/BaseTypeIdImpl.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/catalog/types/BaseTypeIdImpl.java Wed Dec  9 14:22:46 2009
@@ -148,6 +148,9 @@
      */
     public String getUnqualifiedName() { return unqualifiedName; }
 
+    /** Return true if this is this type id describes an ANSI UDT */
+    public boolean isAnsiUDT() { return (schemaName != null); }
+    
     /**
      * Get the jdbc type id for this type.  JDBC type can be
      * found in java.sql.Types. 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/depend/DependencyManager.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/depend/DependencyManager.java?rev=888811&r1=888810&r2=888811&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/depend/DependencyManager.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/depend/DependencyManager.java Wed Dec  9 14:22:46 2009
@@ -337,6 +337,8 @@
 
     public static final int DROP_SEQUENCE = 49;
 
+    public static final int DROP_UDT = 50;
+
     /**
      * Extensions to this interface may use action codes > MAX_ACTION_CODE without fear of
      * clashing with action codes in this base interface.

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/AliasDescriptor.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/AliasDescriptor.java?rev=888811&r1=888810&r2=888811&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/AliasDescriptor.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/AliasDescriptor.java Wed Dec  9 14:22:46 2009
@@ -380,6 +380,10 @@
         case AliasInfo.ALIAS_TYPE_SYNONYM_AS_CHAR:
             invalidationType = DependencyManager.DROP_SYNONYM;
             break;
+            
+        case AliasInfo.ALIAS_TYPE_UDT_AS_CHAR:
+            invalidationType = DependencyManager.DROP_UDT;
+            break;
         }
         
         dm.invalidateFor(this, invalidationType, lcc);

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/DataDictionary.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/DataDictionary.java?rev=888811&r1=888810&r2=888811&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/DataDictionary.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/DataDictionary.java Wed Dec  9 14:22:46 2009
@@ -1475,6 +1475,16 @@
 	 */
 	UUIDFactory getUUIDFactory();
 
+    /**
+     * Get the alias descriptor for an ANSI UDT.
+     *
+     * @param tc The transaction to use: if null, use the compilation transaction
+     * @param dtd The UDT's type descriptor
+     *
+     * @return The UDT's alias descriptor if it is an ANSI UDT; null otherwise.
+     */
+    public AliasDescriptor getAliasDescriptorForUDT( TransactionController tc, DataTypeDescriptor dtd ) throws StandardException;
+    
 	/**
 	 * Get an AliasDescriptor given its UUID.
 	 *

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=888811&r1=888810&r2=888811&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 Wed Dec  9 14:22:46 2009
@@ -30,10 +30,14 @@
 import org.apache.derby.catalog.DependableFinder;
 import org.apache.derby.catalog.UUID;
 import org.apache.derby.iapi.error.StandardException;
+import org.apache.derby.iapi.reference.SQLState;
 import org.apache.derby.iapi.services.io.FormatableBitSet;
 import org.apache.derby.iapi.services.io.StoredFormatIds;
 import org.apache.derby.iapi.services.sanity.SanityManager;
 import org.apache.derby.iapi.sql.StatementType;
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
+import org.apache.derby.iapi.sql.depend.DependencyManager;
+import org.apache.derby.iapi.sql.depend.Dependent;
 import org.apache.derby.iapi.sql.depend.Provider;
 import org.apache.derby.iapi.sql.execute.ExecRow;
 import org.apache.derby.iapi.types.DataValueDescriptor;
@@ -83,7 +87,7 @@
 	*/
 
 public class TableDescriptor extends TupleDescriptor
-	implements UniqueSQLObjectDescriptor, Provider
+	implements UniqueSQLObjectDescriptor, Provider, Dependent
 {
 	public static final int BASE_TABLE_TYPE = 0;
 	public static final int SYSTEM_TABLE_TYPE = 1;
@@ -1383,4 +1387,79 @@
 	{
 		return (tableType == TableDescriptor.SYNONYM_TYPE) ? "Synonym" : "Table/View";
 	}
+
+	//////////////////////////////////////////////////////
+	//
+	// DEPENDENT INTERFACE
+	//
+	//////////////////////////////////////////////////////
+	/**
+	 * Check that all of the dependent's dependencies are valid.
+	 *
+	 * @return true if the dependent is currently valid
+	 */
+	public synchronized boolean isValid()
+	{
+		return true;
+	}
+
+	/**
+	 * Prepare to mark the dependent as invalid (due to at least one of
+	 * its dependencies being invalid).
+	 *
+	 * @param action	The action causing the invalidation
+	 * @param p		the provider
+	 *
+	 * @exception StandardException thrown if unable to make it invalid
+	 */
+	public void prepareToInvalidate(Provider p, int action,
+					LanguageConnectionContext lcc) 
+		throws StandardException
+	{
+		DependencyManager dm = getDataDictionary().getDependencyManager();
+
+		switch (action)
+		{
+			/*
+			** Currently, the only thing we are dependent
+			** on is an alias descriptor for an ANSI UDT.
+			*/
+		    default:
+
+				throw StandardException.newException(SQLState.LANG_PROVIDER_HAS_DEPENDENT_TABLE, 
+									dm.getActionString(action), 
+									p.getObjectName(),
+									getQualifiedName());
+		}
+	}
+
+	/**
+	 * Mark the dependent as invalid (due to at least one of
+	 * its dependencies being invalid).  Always an error
+	 * for a table -- should never have gotten here.
+	 *
+	 * @param	action	The action causing the invalidation
+	 *
+	 * @exception StandardException thrown if called in sanity mode
+	 */
+	public void makeInvalid(int action, LanguageConnectionContext lcc) 
+		throws StandardException
+	{
+		/* 
+		** We should never get here, we should have barfed on 
+		** prepareToInvalidate().
+		*/
+		if (SanityManager.DEBUG)
+		{
+			DependencyManager dm;
+	
+			dm = getDataDictionary().getDependencyManager();
+
+			SanityManager.THROWASSERT("makeInvalid("+
+				dm.getActionString(action)+
+				") not expected to get called");
+		}
+	}
+    
 }
+

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java?rev=888811&r1=888810&r2=888811&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java Wed Dec  9 14:22:46 2009
@@ -134,6 +134,7 @@
 import org.apache.derby.catalog.DefaultInfo;
 import org.apache.derby.catalog.TypeDescriptor;
 import org.apache.derby.catalog.UUID;
+import org.apache.derby.catalog.types.BaseTypeIdImpl;
 import org.apache.derby.catalog.types.RoutineAliasInfo;
 
 import org.apache.derby.iapi.services.io.FormatableBitSet;
@@ -6675,8 +6676,6 @@
 			ddlList,
 			false);
 
-
-
 		return ddlList;
 	}
 
@@ -6827,6 +6826,30 @@
 		return uuidFactory;
 	}
 
+    /**
+     * Get the alias descriptor for an ANSI UDT.
+     *
+     * @param tc The transaction to use: if null, use the compilation transaction
+     * @param dtd The UDT's type descriptor
+     *
+     * @return The UDT's alias descriptor if it is an ANSI UDT; null otherwise.
+     */
+    public AliasDescriptor getAliasDescriptorForUDT( TransactionController tc, DataTypeDescriptor dtd ) throws StandardException
+    {
+        if ( tc == null ) { tc = getTransactionCompile(); }
+
+        if ( dtd == null ) { return null; }
+
+        BaseTypeIdImpl btii = dtd.getTypeId().getBaseTypeId();
+        if ( !btii.isAnsiUDT() ) { return null; }
+
+        SchemaDescriptor sd = getSchemaDescriptor( btii.getSchemaName(), tc, true );
+        AliasDescriptor ad = getAliasDescriptor
+            ( sd.getUUID().toString(), btii.getUnqualifiedName(), AliasInfo.ALIAS_NAME_SPACE_UDT_AS_CHAR );
+
+        return ad;
+    }
+    
 	/**
 	 * Get a AliasDescriptor given its UUID.
 	 *
@@ -8310,7 +8333,7 @@
 		else
 		{
 			if (SanityManager.DEBUG)
-			{
+ 			{
 				SanityManager.ASSERT(! booting, "booting is expected to be false");
 			}
 			{

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=888811&r1=888810&r2=888811&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  9 14:22:46 2009
@@ -30,6 +30,8 @@
 import org.apache.derby.iapi.error.StandardException;
 
 import org.apache.derby.iapi.sql.compile.C_NodeTypes;
+import org.apache.derby.iapi.sql.compile.Visitable;
+import org.apache.derby.iapi.sql.compile.Visitor;
 
 import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
 import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptorList;
@@ -566,6 +568,24 @@
 	}
 
 
+	/**
+	 * Accept the visitor for all visitable children of this node.
+	 * 
+	 * @param v the visitor
+	 *
+	 * @exception StandardException on error
+	 */
+	void acceptChildren(Visitor v)
+		throws StandardException
+	{
+		super.acceptChildren(v);
+
+		if (tableElementList != null)
+		{
+			tableElementList.accept(v);
+		}
+	}
+
 	/*
 	 * class interface
 	 */

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ColumnDefinitionNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ColumnDefinitionNode.java?rev=888811&r1=888810&r2=888811&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ColumnDefinitionNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ColumnDefinitionNode.java Wed Dec  9 14:22:46 2009
@@ -199,7 +199,7 @@
 	{
 		if (SanityManager.DEBUG)
 		{
-			return "type: " + getType().toString() + "\n" +
+			return "type: " + getType() + "\n" +
 				"defaultValue: " + defaultValue + "\n" +
 				super.toString();
 		}

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=888811&r1=888810&r2=888811&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  9 14:22:46 2009
@@ -38,6 +38,8 @@
 
 import org.apache.derby.iapi.sql.compile.C_NodeTypes;
 import org.apache.derby.iapi.sql.compile.CompilerContext;
+import org.apache.derby.iapi.sql.compile.Visitable;
+import org.apache.derby.iapi.sql.compile.Visitor;
 import org.apache.derby.iapi.sql.conn.Authorizer;
 
 import org.apache.derby.iapi.error.StandardException;
@@ -563,4 +565,23 @@
                 onCommitDeleteRows,
                 onRollbackDeleteRows));
 	}
+
+	/**
+	 * Accept the visitor for all visitable children of this node.
+	 * 
+	 * @param v the visitor
+	 *
+	 * @exception StandardException on error
+	 */
+	void acceptChildren(Visitor v)
+		throws StandardException
+	{
+		super.acceptChildren(v);
+
+		if (tableElementList != null)
+		{
+			tableElementList.accept(v);
+		}
+	}
+    
 }

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=888811&r1=888810&r2=888811&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  9 14:22:46 2009
@@ -224,8 +224,9 @@
 					ModifyColumnNode mcdn = (ModifyColumnNode)cdn;
 					mcdn.checkExistingConstraints(td);
 					mcdn.useExistingCollation(td);
+
 				} else if (cdn.isAutoincrementColumn())
-					numAutoCols ++;
+                { numAutoCols ++; }
 			}
 			else if (tableElement.getElementType() == TableElementNode.AT_DROP_COLUMN)
 			{
@@ -483,9 +484,12 @@
 		{
 			if (((TableElementNode) elementAt(index)).getElementType() == TableElementNode.AT_DROP_COLUMN)
 			{
+                String columnName = ((TableElementNode) elementAt(index)).getName();
+
 				colInfos[index] = new ColumnInfo(
-								((TableElementNode) elementAt(index)).getName(),
-								null, null, null, null, null, null,
+								columnName,
+								td.getColumnDescriptor( columnName ).getType(),
+                                null, null, null, null, null,
 								ColumnInfo.DROP, 0, 0, 0);
 				break;
 			}
@@ -521,7 +525,7 @@
                 DependencyManager dm = getDataDictionary().getDependencyManager();
                 providerInfos = dm.getPersistentProviderInfos(apl);
             }
-            
+
 			colInfos[index - numConstraints] = 
 				new ColumnInfo(coldef.getColumnName(),
 							   coldef.getType(),

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableElementNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableElementNode.java?rev=888811&r1=888810&r2=888811&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableElementNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableElementNode.java Wed Dec  9 14:22:46 2009
@@ -22,6 +22,7 @@
 package	org.apache.derby.impl.sql.compile;
 
 import org.apache.derby.iapi.services.sanity.SanityManager;
+import org.apache.derby.iapi.sql.compile.C_NodeTypes;
 
 /**
  * A TableElementNode is an item in a TableElementList, and represents
@@ -101,6 +102,7 @@
 		if (SanityManager.DEBUG)
 		{
 			return "name: " + name + "\n" +
+                "elementType: " + getElementType() + "\n" +
 				super.toString();
 		}
 		else
@@ -181,7 +183,11 @@
 		else if ( hasUniqueKeyConstraint() ) { return AT_ADD_UNIQUE_CONSTRAINT; }
 		else if ( hasCheckConstraint() ) { return AT_ADD_CHECK_CONSTRAINT; }
 		else if ( this instanceof ConstraintDefinitionNode ) { return AT_DROP_CONSTRAINT; }
-		else if ( this instanceof ModifyColumnNode ) { return AT_MODIFY_COLUMN; }
+		else if ( this instanceof ModifyColumnNode )
+        {
+            if ( getNodeType() == C_NodeTypes.DROP_COLUMN_NODE ) { return AT_DROP_COLUMN; }
+            else { return AT_MODIFY_COLUMN; }
+        }
 		else { return elementType; }
 	}
 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/depend/BasicDependencyManager.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/depend/BasicDependencyManager.java?rev=888811&r1=888810&r2=888811&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/depend/BasicDependencyManager.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/depend/BasicDependencyManager.java Wed Dec  9 14:22:46 2009
@@ -264,6 +264,7 @@
 		throws StandardException
 	{
 		List list = getDependents(p);
+
 		if (list == null)
 		{
 			return;
@@ -889,6 +890,9 @@
             case DROP_SEQUENCE:
 				return "DROP SEQUENCE";
 
+            case DROP_UDT:
+				return "DROP TYPE";
+
             default:
 				if (SanityManager.DEBUG)
 				{

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/AlterTableConstantAction.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/AlterTableConstantAction.java?rev=888811&r1=888810&r2=888811&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/AlterTableConstantAction.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/AlterTableConstantAction.java Wed Dec  9 14:22:46 2009
@@ -510,6 +510,9 @@
 			}
 		}
 
+        // adjust dependencies on user defined types
+        adjustUDTDependencies( lcc, dd, td, columnInfo );
+
 		/* Create/Drop any constraints */
 		if (constraintActions != null)
 		{

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/CreateTableConstantAction.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/CreateTableConstantAction.java?rev=888811&r1=888810&r2=888811&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/CreateTableConstantAction.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/CreateTableConstantAction.java Wed Dec  9 14:22:46 2009
@@ -366,6 +366,11 @@
 		{
             addColumnDependencies( lcc, dd, td, columnInfo[ ix ] );
         }
+
+        //
+        // The table itself can depend on the user defined types of its columns.
+        //
+        adjustUDTDependencies( lcc, dd, td, columnInfo );
         
 		if ( tableType == TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE )
 		{

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DDLConstantAction.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DDLConstantAction.java?rev=888811&r1=888810&r2=888811&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DDLConstantAction.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DDLConstantAction.java Wed Dec  9 14:22:46 2009
@@ -21,9 +21,12 @@
 
 package org.apache.derby.impl.sql.execute;
 
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 
+import org.apache.derby.catalog.AliasInfo;
 import org.apache.derby.catalog.DependableFinder;
 import org.apache.derby.catalog.UUID;
 import org.apache.derby.iapi.error.StandardException;
@@ -37,9 +40,12 @@
 import org.apache.derby.iapi.sql.depend.Dependent;
 import org.apache.derby.iapi.sql.depend.Provider;
 import org.apache.derby.iapi.sql.depend.ProviderInfo;
+import org.apache.derby.iapi.sql.dictionary.AliasDescriptor;
 import org.apache.derby.iapi.sql.dictionary.ColPermsDescriptor;
 import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor;
+import org.apache.derby.iapi.sql.dictionary.ColumnDescriptorList;
 import org.apache.derby.iapi.sql.dictionary.DefaultDescriptor;
+import org.apache.derby.iapi.sql.dictionary.DependencyDescriptor;
 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
 import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
 import org.apache.derby.iapi.sql.dictionary.PermissionsDescriptor;
@@ -56,6 +62,7 @@
 import org.apache.derby.iapi.store.access.ConglomerateController;
 import org.apache.derby.iapi.store.access.TransactionController;
 import org.apache.derby.iapi.services.sanity.SanityManager;
+import org.apache.derby.iapi.types.DataTypeDescriptor;
 
 /**
  * Abstract class that has actions that are across
@@ -805,6 +812,122 @@
         }
     }
 
+    /**
+     * Adjust dependencies of a table on ANSI UDTs. We only add one dependency
+     * between a table and a UDT. If the table already depends on the UDT, we don't add
+     * a redundant dependency.
+     */
+    protected   void    adjustUDTDependencies
+        (
+         LanguageConnectionContext  lcc,
+         DataDictionary     dd,
+         TableDescriptor    td,
+         ColumnInfo[]        columnInfos
+         )
+        throws StandardException
+    {
+        if ( columnInfos == null ) { return; }
+
+		TransactionController tc = lcc.getTransactionExecute();
+
+        int changedColumnCount = columnInfos.length;
+        HashMap addUdtMap = new HashMap();
+        HashMap dropUdtMap = new HashMap();
+        HashSet addColumnNames = new HashSet();
+        HashSet dropColumnNames = new HashSet();
+
+        // first find all of the new ansi udts which the table must depend on
+        // and the old ones which are candidates for removal
+        for ( int i = 0; i < changedColumnCount; i++ )
+        {
+            ColumnInfo ci = columnInfos[ i ];
+
+            // skip this column if it is not a UDT
+            AliasDescriptor ad = dd.getAliasDescriptorForUDT( tc, columnInfos[ i ].dataType );
+            if ( ad == null ) { continue; }
+
+            String key = ad.getObjectID().toString();
+
+            if ( ci.action == ColumnInfo.CREATE )
+            {
+                addColumnNames.add( ci.name);
+
+                // no need to add the descriptor if it is already on the list
+                if ( addUdtMap.get( key ) != null ) { continue; }
+
+                addUdtMap.put( key, ad );
+            }
+            else if ( ci.action == ColumnInfo.DROP )
+            {
+                dropColumnNames.add( ci.name );
+                dropUdtMap.put( key, ad );
+            }
+        }
+
+        // nothing to do if there are no columns of udt type
+        if ( (addUdtMap.size() == 0) && (dropUdtMap.size() == 0) ) { return; }
+
+        //
+        // Now prune from the add list all udt descriptors for which we already have dependencies.
+        // These are the udts for old columns. This supports the ALTER TABLE ADD COLUMN
+        // case.
+        //
+        // Also prune from the drop list add udt descriptors which will still be
+        // referenced by the remaining columns.
+        //
+        ColumnDescriptorList cdl = td.getColumnDescriptorList();
+        int totalColumnCount = cdl.size();
+
+        for ( int i = 0; i < totalColumnCount; i++ )
+        {
+            ColumnDescriptor cd = cdl.elementAt( i );
+
+            // skip columns that are being added and dropped. we only want the untouched columns
+            if (
+                addColumnNames.contains( cd.getColumnName() ) ||
+                dropColumnNames.contains( cd.getColumnName() )
+                ) { continue; }
+
+            // nothing to do if the old column isn't a UDT
+            AliasDescriptor ad = dd.getAliasDescriptorForUDT( tc, cd.getType() );
+            if ( ad == null ) { continue; }
+
+            String key = ad.getObjectID().toString();
+
+            // ha, it is a UDT. remove the UDT from the list of dependencies to
+            // add and drop
+            if ( addUdtMap.get( key ) != null ) { addUdtMap.remove( key ); }
+            if ( dropUdtMap.get( key ) != null ) { dropUdtMap.remove( key ); }
+        }
+
+        // again, nothing to do if there are no columns of udt type
+        if ( (addUdtMap.size() == 0) && (dropUdtMap.size() == 0) ) { return; }
+
+        DependencyManager   dm = dd.getDependencyManager();
+        ContextManager      cm = lcc.getContextManager();
+
+        // add new dependencies
+        Iterator            addIterator = addUdtMap.values().iterator();
+        while( addIterator.hasNext() )
+        {
+            AliasDescriptor ad = (AliasDescriptor) addIterator.next();
+
+            dm.addDependency( td, ad, cm );
+        }
+
+        // drop dependencies that are orphaned
+        Iterator            dropIterator = dropUdtMap.values().iterator();
+        while( dropIterator.hasNext() )
+        {
+            AliasDescriptor ad = (AliasDescriptor) dropIterator.next();
+
+            DependencyDescriptor dependency = new DependencyDescriptor( td, ad );
+
+            dd.dropStoredDependency( dependency, tc );
+        }
+    }
+
+    
 	/**
 	 * Mutable Boolean wrapper, initially false
 	 */

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=888811&r1=888810&r2=888811&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  9 14:22:46 2009
@@ -3136,6 +3136,14 @@
             </msg>
 
             <msg>
+                <name>X0Y29.S</name>
+                <text>Operation '{0}' cannot be performed on object '{1}' because TABLE '{2}' is dependent on that object.</text>
+                <arg>operationName</arg>
+                <arg>objectName</arg>
+                <arg>viewName</arg>
+            </msg>
+
+            <msg>
                 <name>X0Y32.S</name>
                 <text>{0} '{1}' already exists in {2} '{3}'.</text>
                 <arg>value</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=888811&r1=888810&r2=888811&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  9 14:22:46 2009
@@ -1321,6 +1321,7 @@
 	String LANG_PROVIDER_HAS_DEPENDENT_OBJECT                          = "X0Y25.S";
 	String LANG_INDEX_AND_TABLE_IN_DIFFERENT_SCHEMAS                   = "X0Y26.S";
 	String LANG_CREATE_SYSTEM_INDEX_ATTEMPTED                          = "X0Y28.S";
+	String LANG_PROVIDER_HAS_DEPENDENT_TABLE                            = "X0Y29.S";
 	String LANG_OBJECT_ALREADY_EXISTS_IN_OBJECT						   = "X0Y32.S";
 	String LANG_CREATE_INDEX_NO_TABLE                                  = "X0Y38.S";
 	String LANG_INVALID_FK_NO_PK                                       = "X0Y41.S";

Modified: db/derby/code/trunk/java/storeless/org/apache/derby/impl/storeless/EmptyDictionary.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/storeless/org/apache/derby/impl/storeless/EmptyDictionary.java?rev=888811&r1=888810&r2=888811&view=diff
==============================================================================
--- db/derby/code/trunk/java/storeless/org/apache/derby/impl/storeless/EmptyDictionary.java (original)
+++ db/derby/code/trunk/java/storeless/org/apache/derby/impl/storeless/EmptyDictionary.java Wed Dec  9 14:22:46 2009
@@ -614,6 +614,12 @@
 		return null;
 	}
 
+    public AliasDescriptor getAliasDescriptorForUDT( TransactionController tc, DataTypeDescriptor dtd )
+        throws StandardException {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
 	public AliasDescriptor getAliasDescriptor(UUID uuid)
 			throws StandardException {
 		// TODO Auto-generated method stub

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/UDTTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/UDTTest.java?rev=888811&r1=888810&r2=888811&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/UDTTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/UDTTest.java Wed Dec  9 14:22:46 2009
@@ -51,6 +51,7 @@
     public static final String OBJECT_EXISTS = "X0Y68";
     public static final String NONEXISTENT_OBJECT = "42Y55";
     public static final String SYNTAX_ERROR = "42X01";
+    public static final String TABLE_DEPENDS_ON_TYPE = "X0Y29";
 
     ///////////////////////////////////////////////////////////////////////////////////
     //
@@ -226,10 +227,159 @@
              );
     }
 
+    /**
+     * <p>
+     * Adding and dropping udt columns.
+     * </p>
+     */
+    public void test_03_addDropColumn() throws Exception
+    {
+        Connection conn = getConnection();
+        String tableName1 = "UDTCOLUMNS";
+        String tableName2 = "UDTCOLUMNS2";
+
+        goodStatement
+            ( conn,
+              "create type price_03 external name 'org.apache.derbyTesting.functionTests.tests.lang.Price' language java\n" );
+
+        // even though there are 2 price_03 columns, we only create 1 dependency
+        goodStatement
+            ( conn,
+              "create table " + tableName1 + "\n" +
+              "(\n" +
+              "    a int, b int,\n" +
+              "    price1 price_03,\n" +
+              "    price2 price_03\n" +
+              ")\n"
+              );
+        assertEquals( 1, countTableDependencies( conn, tableName1 ) );
+
+        // verify that we can't drop the type while the table depends on it
+        expectExecutionError( conn, TABLE_DEPENDS_ON_TYPE, "drop type Price_03 restrict\n" );
+
+        // add another price_03 column. should not add another dependency
+        goodStatement
+            ( conn,
+              "alter table udtColumns add column price3 price_03\n" );
+        assertEquals( 1, countTableDependencies( conn, tableName1 ) );
+        expectExecutionError( conn, TABLE_DEPENDS_ON_TYPE, "drop type Price_03 restrict\n" );
+
+        // drop one of the price_03 column. there should still be a dependency
+        goodStatement
+            ( conn,
+              "alter table udtColumns drop column price3\n" );
+        assertEquals( 1, countTableDependencies( conn, tableName1 ) );
+        expectExecutionError( conn, TABLE_DEPENDS_ON_TYPE, "drop type Price_03 restrict\n" );
+
+        // drop another column. same story.
+        goodStatement
+            ( conn,
+              "alter table udtColumns drop column price2\n" );
+        assertEquals( 1, countTableDependencies( conn, tableName1 ) );
+        expectExecutionError( conn, TABLE_DEPENDS_ON_TYPE, "drop type Price_03 restrict\n" );
+
+        // drop the last udt column. dependency should disappear
+        goodStatement
+            ( conn,
+              "alter table udtColumns drop column price1\n" );
+        assertEquals( 0, countTableDependencies( conn, tableName1 ) );
+        goodStatement
+            ( conn,
+              "drop type Price_03 restrict\n" );
+
+        // similar experiments with more types
+        goodStatement
+            ( conn,
+              "create type price_03_a external name 'org.apache.derbyTesting.functionTests.tests.lang.Price' language java\n" );
+        goodStatement
+            ( conn,
+              "create type price_03_b external name 'org.apache.derbyTesting.functionTests.tests.lang.Price' language java\n" );
+        goodStatement
+            ( conn,
+              "create type price_03_c external name 'org.apache.derbyTesting.functionTests.tests.lang.Price' language java\n" );
+
+        goodStatement
+            ( conn,
+              "create table udtColumns2\n" +
+              "(\n" +
+              "    a int, b int,\n" +
+              "    price1 price_03_a,\n" +
+              "    price2 price_03_b\n" +
+              ")\n"
+              );
+        assertEquals( 2, countTableDependencies( conn, tableName2 ) );
+        expectExecutionError( conn, TABLE_DEPENDS_ON_TYPE, "drop type Price_03_a restrict\n" );
+        expectExecutionError( conn, TABLE_DEPENDS_ON_TYPE, "drop type Price_03_b restrict\n" );
+        
+        goodStatement
+            ( conn,
+              "alter table udtColumns2 add column price3 price_03_c\n" );
+        assertEquals( 3, countTableDependencies( conn, tableName2 ) );
+        expectExecutionError( conn, TABLE_DEPENDS_ON_TYPE, "drop type Price_03_a restrict\n" );
+        expectExecutionError( conn, TABLE_DEPENDS_ON_TYPE, "drop type Price_03_b restrict\n" );
+        expectExecutionError( conn, TABLE_DEPENDS_ON_TYPE, "drop type Price_03_c restrict\n" );
+
+        goodStatement
+            ( conn,
+              "alter table udtColumns2 drop column b\n" );
+        assertEquals( 3, countTableDependencies( conn, tableName2 ) );
+        expectExecutionError( conn, TABLE_DEPENDS_ON_TYPE, "drop type Price_03_a restrict\n" );
+        expectExecutionError( conn, TABLE_DEPENDS_ON_TYPE, "drop type Price_03_b restrict\n" );
+        expectExecutionError( conn, TABLE_DEPENDS_ON_TYPE, "drop type Price_03_c restrict\n" );
+
+        goodStatement
+            ( conn,
+              "alter table udtColumns2 drop column price3\n" );
+        assertEquals( 2, countTableDependencies( conn, tableName2 ) );
+        goodStatement
+            ( conn,
+              "drop type Price_03_c restrict\n" );
+
+        goodStatement
+            ( conn,
+              "alter table udtColumns2 drop column price2\n" );
+        assertEquals( 1, countTableDependencies( conn, tableName2 ) );
+        goodStatement
+            ( conn,
+              "drop type Price_03_b restrict\n" );
+
+        goodStatement
+            ( conn,
+              "alter table udtColumns2 drop column price1\n" );
+        assertEquals( 0, countTableDependencies( conn, tableName2 ) );
+        goodStatement
+            ( conn,
+              "drop type Price_03_a restrict\n" );
+
+    }
+
     ///////////////////////////////////////////////////////////////////////////////////
     //
     // MINIONS
     //
     ///////////////////////////////////////////////////////////////////////////////////
 
+    /** Get the number of dependencies that a table has */
+    private int countTableDependencies( Connection conn, String tableName ) throws Exception
+    {
+        PreparedStatement ps = chattyPrepare
+            ( conn, "select count(*) from sys.sysdepends d, sys.systables t where d.dependentid = t.tableid and t.tablename = ?" );
+        ps.setString( 1, tableName );
+
+        return getScalarInteger( ps );
+    }
+
+    /** Get a scalar integer result from a query */
+    private int getScalarInteger( PreparedStatement ps ) throws Exception
+    {
+        ResultSet rs = ps.executeQuery();
+        rs.next();
+        int retval = rs.getInt( 1 );
+
+        rs.close();
+        ps.close();
+
+        return retval;
+    }
+
 }