[fdo-commits] r638 - in branches/3.2.x/Utilities: SchemaMgr/Inc/Sm/Lp SchemaMgr/Nls SchemaMgr/Src/Sm/Lp TestCommon/Inc TestCommon/Src

svn_fdo at osgeo.org svn_fdo at osgeo.org
Fri Jan 19 13:51:21 EST 2007


Author: brentrobinson
Date: 2007-01-19 13:51:20 -0500 (Fri, 19 Jan 2007)
New Revision: 638

Modified:
   branches/3.2.x/Utilities/SchemaMgr/Inc/Sm/Lp/ClassDefinition.h
   branches/3.2.x/Utilities/SchemaMgr/Inc/Sm/Lp/UniqueConstraint.h
   branches/3.2.x/Utilities/SchemaMgr/Nls/SmMessage.mc
   branches/3.2.x/Utilities/SchemaMgr/Src/Sm/Lp/ClassDefinition.cpp
   branches/3.2.x/Utilities/SchemaMgr/Src/Sm/Lp/SchemaCollection.cpp
   branches/3.2.x/Utilities/SchemaMgr/Src/Sm/Lp/UniqueConstraint.cpp
   branches/3.2.x/Utilities/TestCommon/Inc/TestCommonConstraints.h
   branches/3.2.x/Utilities/TestCommon/Src/TestCommonConstraints.cpp
Log:
Handle unique constraints referencing base properties.

Modified: branches/3.2.x/Utilities/SchemaMgr/Inc/Sm/Lp/ClassDefinition.h
===================================================================
--- branches/3.2.x/Utilities/SchemaMgr/Inc/Sm/Lp/ClassDefinition.h	2007-01-18 15:45:41 UTC (rev 637)
+++ branches/3.2.x/Utilities/SchemaMgr/Inc/Sm/Lp/ClassDefinition.h	2007-01-19 18:51:20 UTC (rev 638)
@@ -701,10 +701,14 @@
     );
     void AddForeignNoFeatIdError( const FdoSmLpPropertyDefinition* pFeatId );
     void AddUkeyPropMissingError(FdoDataPropertyDefinition* pProp);
+    void AddUkeyBasePropError(FdoDataPropertyDefinition* pProp);
 
 	void DropUkeys();
 	void CreateUkeysFromFdo();
 	bool MatchUkey( FdoClassDefinitionP pClass, FdoSmPhColumnsP pPhColls );
+
+    // Checks if given unique constraint has a base constraint and sets it if it does.
+    void MatchInheritedUkey( FdoSmLpUniqueConstraintP ukey );
     bool HasUkey(  FdoSmPhColumnsP pPhColls );
 	void DropCkeys();
 	void CreateCkeysFromFdo();

Modified: branches/3.2.x/Utilities/SchemaMgr/Inc/Sm/Lp/UniqueConstraint.h
===================================================================
--- branches/3.2.x/Utilities/SchemaMgr/Inc/Sm/Lp/UniqueConstraint.h	2007-01-18 15:45:41 UTC (rev 637)
+++ branches/3.2.x/Utilities/SchemaMgr/Inc/Sm/Lp/UniqueConstraint.h	2007-01-19 18:51:20 UTC (rev 638)
@@ -33,6 +33,23 @@
 	FdoSmLpDataPropertyDefinitionCollection *GetProperties();
 	const FdoSmLpDataPropertyDefinitionCollection *RefProperties() const;
 
+    // Get the base constraint if constraint actually defined on base class.
+    // Returnes NULL if this constraint does not have a base
+    FdoPtr<FdoSmLpUniqueConstraint> GetBaseConstraint();
+    const FdoSmLpUniqueConstraint* RefBaseConstraint() const;
+
+    // Compare this constraint with another one.
+    // Returns 0 if the two costraints have the same properties by name.
+    // Return -1 otherwise.
+    FdoInt32 Compare( FdoPtr<FdoSmLpUniqueConstraint> other ) const;
+
+    // Create a unique constraint inherited from this constraint.
+    // Returns NULL if not all the constrained properties are in the subClass.
+    FdoPtr<FdoSmLpUniqueConstraint> CreateInherited( FdoSmLpClassBase* pSubClass, FdoSmLpPropertyDefinitionCollection* pSubClassProperties );
+
+    // Sets the base constraint for this constraint.
+    void SetBaseConstraint( FdoPtr<FdoSmLpUniqueConstraint> baseConstraint );
+
     /// Serialize this class to an XML file.
     /// Primarily for unit testing.
 	virtual void XMLSerialize( FILE* xmlFp, int ref ) const;
@@ -45,6 +62,7 @@
 
 private:
 	FdoSmLpDataPropertiesP	mProperties;
+    FdoPtr<FdoSmLpUniqueConstraint> mBaseConstraint;
 
 };
 

Modified: branches/3.2.x/Utilities/SchemaMgr/Nls/SmMessage.mc
===================================================================
--- branches/3.2.x/Utilities/SchemaMgr/Nls/SmMessage.mc	2007-01-18 15:45:41 UTC (rev 637)
+++ branches/3.2.x/Utilities/SchemaMgr/Nls/SmMessage.mc	2007-01-19 18:51:20 UTC (rev 638)
@@ -156,6 +156,11 @@
 Language=English
 Collation '%1$ls' does not exist or is inaccessible from current connection.
 .
+MessageId=2234
+SymbolicName=FDOSM_29
+Language=English
+Class '%1$ls' uses Base table mapping; Cannot include base property '%2$ls' in unique constraint
+.
 MessageId=2327
 SymbolicName=FDOSM_122
 Language=English

Modified: branches/3.2.x/Utilities/SchemaMgr/Src/Sm/Lp/ClassDefinition.cpp
===================================================================
--- branches/3.2.x/Utilities/SchemaMgr/Src/Sm/Lp/ClassDefinition.cpp	2007-01-18 15:45:41 UTC (rev 637)
+++ branches/3.2.x/Utilities/SchemaMgr/Src/Sm/Lp/ClassDefinition.cpp	2007-01-19 18:51:20 UTC (rev 638)
@@ -1186,7 +1186,9 @@
                     // Skip the constraint if any of its columns do not correspond
                     // to a property.
                     if ( allFound && (pProps->GetCount() > 0) ) 
-			        {
+			        {   
+                        // If constraint is inherited, match it with its base constraint.
+                        MatchInheritedUkey( pUniqueC );
                         pLpUniqueConstraints->Add(pUniqueC);
 			        }
                 }
@@ -1837,10 +1839,17 @@
 		for ( int j = 0; j < pFdoUniqueCs->GetCount(); j++ ) {
 			FdoDataPropertyP	 pFdoDataProp = pFdoUniqueCs->GetItem(j);
 			FdoSmLpDataPropertyP pLpDataProp = mProperties->FindItem( pFdoDataProp->GetName() )->SmartCast<FdoSmLpDataPropertyDefinition>(true);
-            if ( pLpDataProp ) 
+            if ( pLpDataProp ) {
+                // If class shares table with base class then unique constraints on base properties are not allowed,
+                // since these would prevent multiple objects from being added to base class or 
+                // other classes derived from it. 
+                if ( (Get_TableMapping() == FdoSmOvTableMappingType_BaseTable) && (pLpDataProp->GetBaseProperty()) )
+                    AddUkeyBasePropError( pFdoDataProp );
                 pLpUniqueC->GetProperties()->Add( pLpDataProp );
-            else
+            }
+            else {
                 AddUkeyPropMissingError( pFdoDataProp );
+            }
 		}	
 
 		if ( pFdoUniqueCs->GetCount() != 0 )
@@ -1853,7 +1862,9 @@
 		FdoSmLpUniqueConstraintsP   pLpUniqueConstraintsB = mBaseClass->GetUniqueConstraints();
 		for ( int j = 0; j < pLpUniqueConstraintsB->GetCount(); j++ ) {
 			FdoSmLpUniqueConstraintP		pLpUniqueC = pLpUniqueConstraintsB->GetItem(j);
-			pLpUniqueConstraints->Add( pLpUniqueC );
+            FdoSmLpUniqueConstraintP        pLpInhUniqueC = pLpUniqueC->CreateInherited( this, mProperties );
+			if ( pLpInhUniqueC ) 
+                pLpUniqueConstraints->Add( pLpInhUniqueC );
 		}	
 	}
 }
@@ -1902,6 +1913,26 @@
 	return found;
 }	
 
+void FdoSmLpClassBase::MatchInheritedUkey( FdoSmLpUniqueConstraintP ukey )
+{
+    if ( mBaseClass ) {
+        FdoSmLpUniqueConstraintsP baseUkeys = mBaseClass->GetUniqueConstraints();
+        FdoInt32 idx;
+
+        // Check each constraint from the base class
+        for ( idx = 0; idx < baseUkeys->GetCount(); idx++ ) {
+            FdoSmLpUniqueConstraintP baseUkey = baseUkeys->GetItem(idx);
+
+            if ( ukey->Compare(baseUkey) == 0 ) {
+                // Same as given constraint so given constraint is inherited from base constraint.
+                ukey->SetBaseConstraint( baseUkey );
+                break;
+            }
+        }
+    }
+}
+
+
 bool FdoSmLpClassBase::HasUkey(  FdoSmPhColumnsP pPhColls )
 {
 	FdoSmLpUniqueConstraintsP pLpUniqueConstraints = GetUniqueConstraints();
@@ -3177,6 +3208,19 @@
 	);
 }
 
+void FdoSmLpClassBase::AddUkeyBasePropError(FdoDataPropertyDefinition* pProp)
+{
+	GetErrors()->Add( FdoSmErrorType_Other, 
+        FdoSchemaException::Create(
+            FdoSmError::NLSGetMessage(
+				FDO_NLSID(FDOSM_29),
+				(FdoString*)(GetQName()),
+				(FdoString*)(pProp->GetName())
+			)
+		)
+	);
+}
+
 void FdoSmLpClassBase::XMLSerialize( FILE* xmlFp, int ref  ) const
 {
 	if ( ref == 0 ) {

Modified: branches/3.2.x/Utilities/SchemaMgr/Src/Sm/Lp/SchemaCollection.cpp
===================================================================
--- branches/3.2.x/Utilities/SchemaMgr/Src/Sm/Lp/SchemaCollection.cpp	2007-01-18 15:45:41 UTC (rev 637)
+++ branches/3.2.x/Utilities/SchemaMgr/Src/Sm/Lp/SchemaCollection.cpp	2007-01-19 18:51:20 UTC (rev 638)
@@ -796,30 +796,51 @@
 	// UNIQUE() constraints : Load from the database
 	///////////////////////////////////////////////////////////////////////////
 
-	FdoSmLpUniqueConstraintCollection*			uLpUKeys = (FdoSmLpUniqueConstraintCollection *)((FdoSmLpClassBase *)pLpClassDef)->RefUniqueConstraints();
-	FdoPtr<FdoUniqueConstraintCollection>		pFdoUKeys = pFdoClassDef->GetUniqueConstraints();
-	FdoPropertiesP								pFdoProps = pFdoClassDef->GetProperties();
+	FdoSmLpUniqueConstraintCollection*			    uLpUKeys = (FdoSmLpUniqueConstraintCollection *)((FdoSmLpClassBase *)pLpClassDef)->RefUniqueConstraints();
+	FdoPtr<FdoUniqueConstraintCollection>		    pFdoUKeys = pFdoClassDef->GetUniqueConstraints();
+	FdoPropertiesP								    pFdoProps = pFdoClassDef->GetProperties();
+	FdoPtr<FdoReadOnlyPropertyDefinitionCollection>	pFdoBaseProps = pFdoClassDef->GetBaseProperties();
 
 	for ( int i = 0; i < uLpUKeys->GetCount(); i++ ) {
 		FdoSmLpUniqueConstraintP	pLpUniqueC = uLpUKeys->GetItem(i);
-		FdoSmLpDataPropertiesP		pLpProps = pLpUniqueC->GetProperties();
 
-		// New constraints
-		FdoPtr<FdoUniqueConstraint>	pFdoUniqueC = FdoUniqueConstraint::Create();
-		FdoDataPropertiesP			pFdoUniqueProps = pFdoUniqueC->GetProperties();
+        // Skip inherited constraints since already defined on base class.
+        if ( !pLpUniqueC->GetBaseConstraint() ) {
+		    FdoSmLpDataPropertiesP		pLpProps = pLpUniqueC->GetProperties();
 
-		for ( int j = 0; j < pLpProps->GetCount(); j++ ) {
-			FdoSmLpDataPropertyP	pLpProp = pLpProps->GetItem(j);
-			
-			// Find the Fdo data property
-			FdoDataPropertyP   pFdoProp = (FdoDataPropertyDefinition *)pFdoProps->FindItem(pLpProp->GetName());
-					
-			// Match the names and add to collection
-			if ( pFdoProp && ( wcscmp(pLpProp->GetName(), pFdoProp->GetName()) == 0 ) )
-				pFdoUniqueProps->Add( pFdoProp );
-		}
-		if ( pFdoUniqueProps->GetCount() != 0 )
-			pFdoUKeys->Add(pFdoUniqueC);
+		    // New constraints
+		    FdoPtr<FdoUniqueConstraint>	pFdoUniqueC = FdoUniqueConstraint::Create();
+		    FdoDataPropertiesP			pFdoUniqueProps = pFdoUniqueC->GetProperties();
+    	    bool                        constraintOk = true;	
+    		
+            for ( int j = 0; j < pLpProps->GetCount(); j++ ) {
+			    FdoSmLpDataPropertyP	pLpProp = pLpProps->GetItem(j);
+    			
+			    // Find the Fdo data property
+			    FdoDataPropertyP   pFdoProp = (FdoDataPropertyDefinition *)pFdoProps->FindItem(pLpProp->GetName());
+
+			    // Match the names and add to collection
+                if ( pFdoProp && ( wcscmp(pLpProp->GetName(), pFdoProp->GetName()) == 0 ) ) {
+				    pFdoUniqueProps->Add( pFdoProp );
+                }
+                else {
+                    try { 
+                        pFdoProp = (FdoDataPropertyDefinition *)pFdoBaseProps->GetItem(pLpProp->GetName());
+                    }
+                    catch (...) {
+                    }
+
+                    if ( pFdoProp && ( wcscmp(pLpProp->GetName(), pFdoProp->GetName()) == 0 ) ) {
+				        pFdoUniqueProps->Add( pFdoProp );
+                    }
+                    else {
+                        constraintOk = false;
+                    }
+                }
+		    }
+		    if ( constraintOk && (pFdoUniqueProps->GetCount() != 0) )
+			    pFdoUKeys->Add(pFdoUniqueC);
+        }
 	}
 
 	///////////////////////////////////////////////////////////////////////////

Modified: branches/3.2.x/Utilities/SchemaMgr/Src/Sm/Lp/UniqueConstraint.cpp
===================================================================
--- branches/3.2.x/Utilities/SchemaMgr/Src/Sm/Lp/UniqueConstraint.cpp	2007-01-18 15:45:41 UTC (rev 637)
+++ branches/3.2.x/Utilities/SchemaMgr/Src/Sm/Lp/UniqueConstraint.cpp	2007-01-19 18:51:20 UTC (rev 638)
@@ -22,6 +22,37 @@
 	mProperties = new FdoSmLpDataPropertyDefinitionCollection();
 }
 
+FdoPtr<FdoSmLpUniqueConstraint> FdoSmLpUniqueConstraint::CreateInherited( FdoSmLpClassBase* pSubClass, FdoSmLpPropertyDefinitionCollection* pSubClassProperties )
+{
+    // Create the inherited constaint, making this constraint the base
+    FdoPtr<FdoSmLpUniqueConstraint> inheritedConstraint = new FdoSmLpUniqueConstraint();
+    inheritedConstraint->SetBaseConstraint( FDO_SAFE_ADDREF(this) );
+
+    // Set the inherited constaint's properties to the sub-class equivalents of the base constraint
+    // properties.
+    FdoSmLpDataPropertiesP baseProperties = GetProperties();
+    FdoSmLpDataPropertiesP subProperties = inheritedConstraint->GetProperties();
+
+    FdoInt32 idx;
+    bool propNotFound = false;
+
+    for ( idx = 0; idx < baseProperties->GetCount(); idx++ ) {
+        FdoSmLpDataPropertyP baseProperty = baseProperties->GetItem( idx );
+        FdoSmLpPropertyP subProperty = pSubClassProperties->FindItem( baseProperty->GetName() );
+
+        if ( subProperty && (subProperty->GetPropertyType() == FdoPropertyType_DataProperty) )
+            subProperties->Add( (FdoSmLpDataPropertyDefinition*)(subProperty.p) );
+        else
+            // Property not in subclass so can't inherit constraint.
+            propNotFound = true;
+    }
+
+    if ( propNotFound )
+        inheritedConstraint = NULL;
+
+    return inheritedConstraint;
+}
+
 FdoSmLpDataPropertyDefinitionCollection *FdoSmLpUniqueConstraint::GetProperties()
 {
 	return FDO_SAFE_ADDREF(mProperties.p);
@@ -32,6 +63,44 @@
 	return mProperties.p;
 }
 
+FdoPtr<FdoSmLpUniqueConstraint> FdoSmLpUniqueConstraint::GetBaseConstraint()
+{
+    return mBaseConstraint;
+}
+
+FdoInt32 FdoSmLpUniqueConstraint::Compare( FdoPtr<FdoSmLpUniqueConstraint> other ) const
+{
+    FdoInt32 result = -1;
+
+    const FdoSmLpDataPropertyDefinitionCollection* myProps = RefProperties();
+    const FdoSmLpDataPropertyDefinitionCollection* otherProps = other->RefProperties();
+    
+    if ( myProps->GetCount() == otherProps->GetCount() ) {
+        FdoInt32 idx;
+        result = 0;
+
+        for ( idx = 0; idx < myProps->GetCount(); idx++ ) {
+            const FdoSmLpDataPropertyDefinition* myProp = myProps->RefItem(idx);
+            if ( !otherProps->RefItem(myProp->GetName()) ) {
+                result = -1;
+                break;
+            }
+        }
+    }
+
+    return result;
+}
+
+const FdoSmLpUniqueConstraint* FdoSmLpUniqueConstraint::RefBaseConstraint() const
+{
+    return ( ((FdoSmLpUniqueConstraint*) this)->GetBaseConstraint().p );
+}
+
+void FdoSmLpUniqueConstraint::SetBaseConstraint( FdoPtr<FdoSmLpUniqueConstraint> baseConstraint )
+{
+    mBaseConstraint = baseConstraint;
+}
+
 void FdoSmLpUniqueConstraint::Dispose()
 {
 	delete this;

Modified: branches/3.2.x/Utilities/TestCommon/Inc/TestCommonConstraints.h
===================================================================
--- branches/3.2.x/Utilities/TestCommon/Inc/TestCommonConstraints.h	2007-01-18 15:45:41 UTC (rev 637)
+++ branches/3.2.x/Utilities/TestCommon/Inc/TestCommonConstraints.h	2007-01-19 18:51:20 UTC (rev 638)
@@ -31,6 +31,7 @@
 	CPPUNIT_TEST( TestDescribeUpdatedConstraints );
     CPPUNIT_TEST( TestRestrictCheckConstraints );
 	CPPUNIT_TEST( TestDateTimeConstraints );
+    CPPUNIT_TEST( TestBaseReferences );
 
 	CPPUNIT_TEST_SUITE_END();
 
@@ -43,6 +44,9 @@
 	virtual void TestRestrictCheckConstraints(void);
 	virtual void TestDateTimeConstraints(void);
 
+    // Tests unique constraints that reference base properties.
+	virtual void TestBaseReferences(void);
+
     void CreateConstraintsSchema(FdoIConnection * connection);
 	void DescribeConstraintsSchema(FdoIConnection * connection, FdoString *className, int numUkeys, int numCkeys, bool afterUpdate);
 	void UpdateCheckConstraints(FdoIConnection * connection);

Modified: branches/3.2.x/Utilities/TestCommon/Src/TestCommonConstraints.cpp
===================================================================
--- branches/3.2.x/Utilities/TestCommon/Src/TestCommonConstraints.cpp	2007-01-18 15:45:41 UTC (rev 637)
+++ branches/3.2.x/Utilities/TestCommon/Src/TestCommonConstraints.cpp	2007-01-19 18:51:20 UTC (rev 638)
@@ -27,6 +27,7 @@
 #define            SCHEMA_NAME            L"constraints"
 #define            CLASS_NAME             L"cdataclass"    // lower case to compensate for MySQl on Linux
 #define            CLASS_NAME_BASE        L"CDataBaseClass"
+#define            CLASS_NAME_SUB        L"CDataSubClass"
 
 #define            PROP_FEATID            L"FeatureId"
 
@@ -431,6 +432,338 @@
     }
 }
 
+void TestCommonConstraints::TestBaseReferences ()
+{
+    FdoPtr<FdoIConnection> connection;
+
+    try
+    {
+        // delete, re-create and open the datastore
+        printf( "Initializing Connection ... \n" );
+        connection = CreateConnection( true );
+
+        printf( "Creating Constraints Schema ... \n" );
+            
+        FdoPtr<FdoISchemaCapabilities>    schemaCap = connection->GetSchemaCapabilities();
+
+        if ( schemaCap->SupportsUniqueValueConstraints() && schemaCap->SupportsCompositeUniqueValueConstraints() ) {
+            FdoPtr<FdoIApplySchema>            pCmd = (FdoIApplySchema*) connection->CreateCommand(FdoCommandType_ApplySchema);
+
+            FdoFeatureSchemasP pSchemas = FdoFeatureSchemaCollection::Create(NULL);
+
+            FdoPtr<FdoFeatureSchema> pSchema = FdoFeatureSchema::Create( SCHEMA_NAME, L"AutoCAD schema" );
+            pSchemas->Add( pSchema );
+
+            FdoPtr<FdoFeatureClass> pCData = FdoFeatureClass::Create( CLASS_NAME_BASE, L"Constraints" );
+            pCData->SetIsAbstract(false);
+
+            FdoPtr<FdoDataPropertyDefinition> pProp = FdoDataPropertyDefinition::Create( PROP_FEATID, L"" );
+            pProp->SetDataType( FdoDataType_Int32 );
+            pProp->SetNullable(false);
+            FdoPropertiesP(pCData->GetProperties())->Add( pProp );
+            FdoDataPropertiesP(pCData->GetIdentityProperties())->Add( pProp );
+
+            //// Add the class to schema
+            FdoClassesP(pSchema->GetClasses())->Add( pCData );
+
+            FdoClassDefinitionP pClass = FdoClassesP( pSchema->GetClasses() )->GetItem( CLASS_NAME_BASE );
+
+            //////////////  1st unique property - single ///////////////
+            FdoPtr<FdoDataPropertyDefinition> pUnique1Int = FdoDataPropertyDefinition::Create( PROP_UNIQUE1, L"" );
+            pUnique1Int->SetDataType( FdoDataType_Int32 );
+            pUnique1Int->SetNullable(true);
+            FdoPropertiesP(pCData->GetProperties())->Add( pUnique1Int  );
+
+            //////////////  2nd unique property - Composite ///////////////
+            FdoPtr<FdoDataPropertyDefinition> pUnique21Int = FdoDataPropertyDefinition::Create( PROP_UNIQUE2_1, L"" );
+            pUnique21Int->SetDataType( FdoDataType_Int32 );
+            pUnique21Int->SetNullable(true);
+            FdoPropertiesP(pCData->GetProperties())->Add( pUnique21Int  );
+
+            // Create a new class based on the previous ...
+            FdoPtr<FdoFeatureClass> pCDataDerived = FdoFeatureClass::Create( CLASS_NAME, L"Constraits" );
+            pCDataDerived->SetBaseClass( pCData );
+            pCDataDerived->SetIsAbstract(false);
+            FdoPtr<FdoUniqueConstraintCollection> constraints = pCDataDerived->GetUniqueConstraints();
+
+            //// Add the class to schema
+            FdoClassesP(pSchema->GetClasses())->Add( pCDataDerived );
+
+            // Create constaint on base property
+            FdoPtr<FdoUniqueConstraint>  newUniqueConstr1 = FdoUniqueConstraint::Create();
+            FdoPtr<FdoDataPropertyDefinitionCollection> pDataPropColl = newUniqueConstr1->GetProperties();
+            pDataPropColl->Add( pUnique1Int );
+            constraints->Add( newUniqueConstr1 );
+
+            FdoPtr<FdoDataPropertyDefinition> pUnique22Int = FdoDataPropertyDefinition::Create( PROP_UNIQUE2_2, L"" );
+            pUnique22Int->SetDataType( FdoDataType_Int32 );
+            pUnique22Int->SetNullable(true);
+            FdoPropertiesP(pCDataDerived->GetProperties())->Add( pUnique22Int  );
+
+            // Create composite constraint on property and base property.
+            FdoPtr<FdoUniqueConstraint>  newUniqueConstr2 = FdoUniqueConstraint::Create();
+            pDataPropColl = newUniqueConstr2->GetProperties();
+            pDataPropColl->Add( pUnique21Int );
+            pDataPropColl->Add( pUnique22Int );
+            constraints->Add( newUniqueConstr2 );
+
+            // Create a new class based on the previous ...
+            FdoPtr<FdoFeatureClass> pCDataSubDerived = FdoFeatureClass::Create( CLASS_NAME_SUB, L"Constraits" );
+            pCDataSubDerived->SetBaseClass( pCDataDerived);
+            pCDataSubDerived->SetIsAbstract(false);
+            constraints = pCDataSubDerived->GetUniqueConstraints();
+
+            //// Add the class to schema
+            FdoClassesP(pSchema->GetClasses())->Add( pCDataSubDerived );
+
+            // Create duplicate constaint on base property (should disappear on DescribeSchema)
+            newUniqueConstr1 = FdoUniqueConstraint::Create();
+            pDataPropColl = newUniqueConstr1->GetProperties();
+            pDataPropColl->Add( pUnique1Int );
+            constraints->Add( newUniqueConstr1 );
+
+            // Create constraint on subset of properties from a base class constraint - OK.
+            newUniqueConstr2 = FdoUniqueConstraint::Create();
+            pDataPropColl = newUniqueConstr2->GetProperties();
+            pDataPropColl->Add( pUnique22Int );
+            constraints->Add( newUniqueConstr2 );
+
+            ///////// Done.
+            pCmd->SetFeatureSchema( pSchema );
+            pCmd->Execute();
+
+            FdoPtr<FdoIInsert> insertCmd;
+
+            // This should succeed
+            TestCommonMiscUtil::InsertObject(
+                connection,
+                insertCmd,
+                SCHEMA_NAME,
+                CLASS_NAME_BASE,
+                PROP_FEATID, FdoDataType_Int32, GetNextFeatId(connection,CLASS_NAME_BASE),
+                PROP_UNIQUE1,  FdoDataType_Int32,  (FdoInt32) 1000,
+                (FdoString*) NULL
+            );
+
+            // Unique constraint not on base class so should succeed.
+            TestCommonMiscUtil::InsertObject(
+                connection,
+                insertCmd,
+                SCHEMA_NAME,
+                CLASS_NAME_BASE,
+                PROP_FEATID, FdoDataType_Int32, GetNextFeatId(connection, CLASS_NAME_BASE),
+                PROP_UNIQUE1,  FdoDataType_Int32,  (FdoInt32) 1000,
+                (FdoString*) NULL
+            );
+
+            // This should succeed
+            TestCommonMiscUtil::InsertObject(
+                connection,
+                insertCmd,
+                SCHEMA_NAME,
+                CLASS_NAME,
+                PROP_FEATID, FdoDataType_Int32, GetNextFeatId(connection, CLASS_NAME),
+                PROP_UNIQUE1,  FdoDataType_Int32,  (FdoInt32) 2000,
+                (FdoString*) NULL
+            );
+
+            bool    uniqueSuccess1 = true;
+            try {
+                TestCommonMiscUtil::InsertObject(
+                    connection,
+                    insertCmd,
+                    SCHEMA_NAME,
+                    CLASS_NAME,
+                    PROP_FEATID, FdoDataType_Int32, GetNextFeatId(connection, CLASS_NAME),
+                    PROP_UNIQUE1,  FdoDataType_Int32,  (FdoInt32) 2000,
+                    (FdoString*) NULL
+                );
+            } catch (FdoException *ex) {
+                DBG(printf("Expected unique constraint violation exception: %ls", (FdoString* )ex->GetExceptionMessage()));
+                ex->Release();
+                uniqueSuccess1 = false;
+            }
+            CPPUNIT_ASSERT_MESSAGE("Should get unique constraint violation prop #4", uniqueSuccess1 == false );
+
+            // This should succeed
+            TestCommonMiscUtil::InsertObject(
+                connection,
+                insertCmd,
+                SCHEMA_NAME,
+                CLASS_NAME_BASE,
+                PROP_FEATID, FdoDataType_Int32, GetNextFeatId(connection, CLASS_NAME_BASE),
+                PROP_UNIQUE2_1,  FdoDataType_Int32,  (FdoInt32) 1000,
+                (FdoString*) NULL
+            );
+
+            // Unique constraint not on base class so should succeed.
+            TestCommonMiscUtil::InsertObject(
+                connection,
+                insertCmd,
+                SCHEMA_NAME,
+                CLASS_NAME_BASE,
+                PROP_FEATID, FdoDataType_Int32, GetNextFeatId(connection, CLASS_NAME_BASE),
+                PROP_UNIQUE2_1,  FdoDataType_Int32,  (FdoInt32) 1000,
+                (FdoString*) NULL
+                );
+
+            // This should succeed
+            TestCommonMiscUtil::InsertObject(
+                connection,
+                insertCmd,
+                SCHEMA_NAME,
+                CLASS_NAME,
+                PROP_FEATID, FdoDataType_Int32, GetNextFeatId(connection, CLASS_NAME),
+                PROP_UNIQUE2_1,  FdoDataType_Int32,  (FdoInt32) 1000,
+                PROP_UNIQUE2_2,  FdoDataType_Int32,  (FdoInt32) 2000,
+                (FdoString*) NULL
+                );
+
+            bool    uniqueSuccess2 = true;
+
+            try {
+                TestCommonMiscUtil::InsertObject(
+                    connection,
+                    insertCmd,
+                    SCHEMA_NAME,
+                    CLASS_NAME,
+                    PROP_FEATID, FdoDataType_Int32, GetNextFeatId(connection, CLASS_NAME),
+                    PROP_UNIQUE2_1,  FdoDataType_Int32,  (FdoInt32) 1000,
+                    PROP_UNIQUE2_2,  FdoDataType_Int32,  (FdoInt32) 2000,
+                    (FdoString*) NULL
+                    );
+
+            } catch (FdoException *ex) {
+                DBG(printf("Expected unique constraint violationexception: %ls", (FdoString* )ex->GetExceptionMessage()));
+                ex->Release();
+                uniqueSuccess2 = false;
+            }
+
+            CPPUNIT_ASSERT_MESSAGE("Should get unique constraint violation prop #[5,6]", uniqueSuccess2 == false ); 
+            
+            // This should succeed
+
+            TestCommonMiscUtil::InsertObject(
+                connection,
+                insertCmd,
+                SCHEMA_NAME,
+                CLASS_NAME,
+                PROP_FEATID, FdoDataType_Int32, GetNextFeatId(connection, CLASS_NAME),
+                PROP_UNIQUE1,  FdoDataType_Int32,  (FdoInt32) 3000,
+                PROP_UNIQUE2_1,  FdoDataType_Int32,  (FdoInt32) 2000,
+                PROP_UNIQUE2_2,  FdoDataType_Int32,  (FdoInt32) 2000,
+                (FdoString*) NULL
+                );
+           
+            // This should succeed
+
+            TestCommonMiscUtil::InsertObject(
+                connection,
+                insertCmd,
+                SCHEMA_NAME,
+                CLASS_NAME,
+                PROP_FEATID, FdoDataType_Int32, GetNextFeatId(connection, CLASS_NAME),
+                PROP_UNIQUE1,  FdoDataType_Int32,  (FdoInt32) 4000,
+                PROP_UNIQUE2_1,  FdoDataType_Int32,  (FdoInt32) 1000,
+                PROP_UNIQUE2_2,  FdoDataType_Int32,  (FdoInt32) 3000,
+                (FdoString*) NULL
+                );
+            
+            FdoPtr<FdoIDescribeSchema>  pDescCmd = (FdoIDescribeSchema*) connection->CreateCommand(FdoCommandType_DescribeSchema);
+
+            pDescCmd->SetSchemaName( SCHEMA_NAME );
+            FdoPtr<FdoFeatureSchemaCollection> pSchemas2 = pDescCmd->Execute();
+            FdoPtr<FdoFeatureSchema> pSchema2 = pSchemas2->GetItem( SCHEMA_NAME );
+            FdoPtr<FdoClassCollection> pClasses2 = pSchema2->GetClasses();
+            FdoPtr<FdoClassDefinition> pClass2 = pClasses2->GetItem( CLASS_NAME );
+            FdoPtr<FdoClassDefinition> pClassBase2 = pClass2->GetBaseClass();
+            FdoPtr<FdoClassDefinition> pClassSub2 = pClasses2->GetItem( CLASS_NAME_SUB );
+
+            ///////////////// UNIQUE() CONSTRAINTS //////////////////////////////////////////
+            FdoPtr<FdoUniqueConstraintCollection> pUniqueCs = pClass2->GetUniqueConstraints();
+
+            int     count = 0;
+            bool    found_unique1 = false;
+            bool    found_unique2 = false;
+            bool    found_unique3 = false;
+
+            for ( int i = 0; i < pUniqueCs->GetCount(); i++ ) {
+                FdoPtr<FdoUniqueConstraint>  pUniqueC = pUniqueCs->GetItem(i);
+                FdoDataPropertiesP             pProps = pUniqueC->GetProperties();
+                    
+                printf("Unique key #%d:\n", i);
+
+                for ( int j = 0; j < pProps->GetCount(); j++ ) {
+                    FdoDataPropertyP    pProp = pProps->GetItem(j);
+
+                    printf("\t%d %ls\n", j, pProp->GetName());
+                    count++;
+                    
+                    if ( wcscmp(pProp->GetName(), PROP_UNIQUE1 ) == 0 )
+                        found_unique1 = true;
+                    else if ( wcscmp(pProp->GetName(), PROP_UNIQUE2_1 ) == 0 )
+                        found_unique2 = true;
+                    else if ( wcscmp(pProp->GetName(), PROP_UNIQUE2_2 ) == 0 )
+                        found_unique3 = true;
+                }    
+            }
+
+            CPPUNIT_ASSERT_MESSAGE("Wrong number of unique keys", count == 3 );
+            CPPUNIT_ASSERT_MESSAGE("Unique keys properties not found", found_unique1 && found_unique2 && found_unique3);
+
+            // None of the unique constraints on derived class should find their way to the base
+            // class.
+            pUniqueCs = pClassBase2->GetUniqueConstraints();
+            CPPUNIT_ASSERT_MESSAGE("Base class has unique keys", pUniqueCs->GetCount() == 0 );
+
+            // Sub class should have on 1 constraint (one with subset of properties). Duplicate
+            // constraint should disappear
+            pUniqueCs = pClassSub2->GetUniqueConstraints();
+            CPPUNIT_ASSERT_MESSAGE("Sub class does not have 1 unique key", pUniqueCs->GetCount() == 1 );
+            FdoPtr<FdoUniqueConstraint>  pUniqueC = pUniqueCs->GetItem(0);
+            FdoDataPropertiesP             pProps = pUniqueC->GetProperties();
+            CPPUNIT_ASSERT_MESSAGE("Sub class unique key does not have 1 property ", pProps->GetCount() == 1 );
+            pProp = pProps->GetItem(0);
+            CPPUNIT_ASSERT( wcscmp(pProp->GetName(), PROP_UNIQUE2_2) == 0);
+
+            printf( "Closing Connection ... \n" );
+            
+            connection->Close();
+        }
+    }
+    catch ( FdoException* e ) 
+    {
+        try {
+            if ( connection) connection->Close(); 
+        }
+        catch ( ... ) 
+        {
+        }
+        TestCommonFail( e );
+    }
+    catch ( CppUnit::Exception e ) 
+    {
+        try {
+            if ( connection) connection->Close(); 
+        }
+        catch ( ... ) 
+        {
+        }
+        throw;
+    }
+    catch (...)
+    {
+        try {
+            if ( connection) connection->Close(); 
+        }
+        catch ( ... ) 
+        {
+        }
+
+        CPPUNIT_FAIL ("caught unexpected exception");
+    }
+}
+
 void TestCommonConstraints::CreateConstraintsSchema( FdoIConnection* connection )
 {
     FdoPtr<FdoISchemaCapabilities>    schemaCap = connection->GetSchemaCapabilities();
@@ -951,7 +1284,6 @@
 
     pDescCmd->SetSchemaName( SCHEMA_NAME );
     FdoPtr<FdoFeatureSchemaCollection> pSchemas2 = pDescCmd->Execute();
-pSchemas2->WriteXml( L"constraints.xml" );
     FdoPtr<FdoFeatureSchema> pSchema2 = pSchemas2->GetItem( SCHEMA_NAME );
     FdoPtr<FdoClassCollection> pClasses2 = pSchema2->GetClasses();
     FdoPtr<FdoClassDefinition> pClass2 = pClasses2->GetItem( className );



More information about the fdo-commits mailing list