Author: tomdz Date: Thu Mar 2 14:46:16 2006 New Revision: 382539 URL: http://svn.apache.org/viewcvs?rev=382539&view=rev Log: Enhanced foreign key change detection when altering tables
Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/model/ForeignKey.java db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Reference.java db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Table.java db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/SqlBuilder.java Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/model/ForeignKey.java URL: http://svn.apache.org/viewcvs/db/ddlutils/trunk/src/java/org/apache/ddlutils/model/ForeignKey.java?rev=382539&r1=382538&r2=382539&view=diff ============================================================================== --- db/ddlutils/trunk/src/java/org/apache/ddlutils/model/ForeignKey.java (original) +++ db/ddlutils/trunk/src/java/org/apache/ddlutils/model/ForeignKey.java Thu Mar 2 14:46:16 2006 @@ -16,6 +16,7 @@ * limitations under the License. */ +import java.util.HashSet; import java.util.Iterator; import org.apache.commons.collections.set.ListOrderedSet; @@ -247,6 +248,48 @@ .append(_foreignTableName, other._foreignTableName) .append(_references, other._references) .isEquals(); + } + else + { + return false; + } + } + + /** + * Compares this foreign key to the given one while ignoring the case of identifiers. + * + * @param otherFk The other foreign key + */ + public boolean equalsIgnoreCase(ForeignKey otherFk) + { + if (_name.equalsIgnoreCase(otherFk._name) && + _foreignTableName.equalsIgnoreCase(otherFk._foreignTableName)) + { + HashSet otherRefs = new HashSet(); + + otherRefs.addAll(otherFk._references); + for (Iterator it = _references.iterator(); it.hasNext();) + { + Reference curLocalRef = (Reference)it.next(); + boolean found = false; + + for (Iterator otherIt = otherRefs.iterator(); otherIt.hasNext();) + { + Reference curOtherRef = (Reference)otherIt.next(); + + if (curLocalRef.equalsIgnoreCase(curOtherRef)) + { + otherIt.remove(); + found = true; + break; + } + } + if (!found) + { + return false; + } + } + return otherRefs.isEmpty(); } else { Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Reference.java URL: http://svn.apache.org/viewcvs/db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Reference.java?rev=382539&r1=382538&r2=382539&view=diff ============================================================================== --- db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Reference.java (original) +++ db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Reference.java Thu Mar 2 14:46:16 2006 @@ -208,6 +208,18 @@ } /** + * Compares this reference to the given one while ignoring the case of identifiers. + * + * @param otherRef The other reference + */ + public boolean equalsIgnoreCase(Reference otherRef) + { + return (otherRef != null) && + _localColumnName.equalsIgnoreCase(otherRef._localColumnName) && + _foreignColumnName.equalsIgnoreCase(otherRef._foreignColumnName); + } + + /** * [EMAIL PROTECTED] */ public int hashCode() Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Table.java URL: http://svn.apache.org/viewcvs/db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Table.java?rev=382539&r1=382538&r2=382539&view=diff ============================================================================== --- db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Table.java (original) +++ db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Table.java Thu Mar 2 14:46:16 2006 @@ -604,6 +604,28 @@ } /** + * Finds the foreign key in this table that is equal to the supplied foreign key. + * + * @param key The foreign key to search for + * @param caseSensitive Whether case matters for the names + * @return The found foreign key + */ + public ForeignKey findForeignKey(ForeignKey key, boolean caseSensitive) + { + for (int idx = 0; idx < getForeignKeyCount(); idx++) + { + ForeignKey fk = getForeignKey(idx); + + if ((caseSensitive && fk.equals(key)) || + (!caseSensitive && fk.equalsIgnoreCase(key))) + { + return fk; + } + } + return null; + } + + /** * Returns the primary key columns of this table. * * @return The primary key columns Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/SqlBuilder.java URL: http://svn.apache.org/viewcvs/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/SqlBuilder.java?rev=382539&r1=382538&r2=382539&view=diff ============================================================================== --- db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/SqlBuilder.java (original) +++ db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/SqlBuilder.java Thu Mar 2 14:46:16 2006 @@ -26,6 +26,7 @@ import java.util.Locale; import java.util.Map; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.map.ListOrderedMap; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; @@ -37,6 +38,7 @@ import org.apache.ddlutils.model.ForeignKey; import org.apache.ddlutils.model.Index; import org.apache.ddlutils.model.IndexColumn; +import org.apache.ddlutils.model.Reference; import org.apache.ddlutils.model.Table; import org.apache.ddlutils.model.TypeMap; @@ -429,7 +431,7 @@ for (int columnIdx = 0; columnIdx < desiredTable.getColumnCount(); columnIdx++) { Column desiredColumn = desiredTable.getColumn(columnIdx); - Column currentColumn = currentTable.findColumn(desiredColumn.getName()); + Column currentColumn = currentTable.findColumn(desiredColumn.getName(), getPlatformInfo().isUseDelimitedIdentifiers()); if (null == currentColumn) { @@ -468,7 +470,7 @@ for (int fkIdx = 0; fkIdx < desiredTable.getForeignKeyCount(); fkIdx++) { ForeignKey desiredFk = desiredTable.getForeignKey(fkIdx); - ForeignKey currentFk = currentTable.findForeignKey(desiredFk); + ForeignKey currentFk = findCorrespondingForeignKey(currentTable, desiredFk); if (currentFk == null) { @@ -485,7 +487,7 @@ for (int indexIdx = 0; indexIdx < desiredTable.getIndexCount(); indexIdx++) { Index desiredIndex = desiredTable.getIndex(indexIdx); - Index currentIndex = currentTable.findIndex(desiredIndex.getName()); + Index currentIndex = currentTable.findIndex(desiredIndex.getName(), getPlatformInfo().isUseDelimitedIdentifiers()); if (currentIndex == null) { @@ -501,7 +503,7 @@ for (int fkIdx = 0; fkIdx < currentTable.getForeignKeyCount(); fkIdx++) { ForeignKey currentFk = currentTable.getForeignKey(fkIdx); - ForeignKey desiredFk = desiredTable.findForeignKey(currentFk); + ForeignKey desiredFk = findCorrespondingForeignKey(desiredTable, currentFk); if (desiredFk == null) { @@ -521,7 +523,7 @@ for (int columnIdx = 0; columnIdx < currentTable.getColumnCount(); columnIdx++) { Column currentColumn = currentTable.getColumn(columnIdx); - Column desiredColumn = desiredTable.findColumn(currentColumn.getName()); + Column desiredColumn = desiredTable.findColumn(currentColumn.getName(), getPlatformInfo().isUseDelimitedIdentifiers()); if (desiredColumn == null) { @@ -550,7 +552,7 @@ for (int indexIdx = 0; indexIdx < currentTable.getIndexCount(); indexIdx++) { Index currentIndex = currentTable.getIndex(indexIdx); - Index desiredIndex = desiredTable.findIndex(currentIndex.getName()); + Index desiredIndex = desiredTable.findIndex(currentIndex.getName(), getPlatformInfo().isUseDelimitedIdentifiers()); if (desiredIndex == null) { @@ -582,8 +584,80 @@ } } + } + + /** + * Searches in the given table for a corresponding foreign key. If the given key + * has no name, then a foreign key to the same table with the same columns in the + * same order is searched. If the given key has a name, then the a corresponding + * key also needs to have the same name, or no name at all, but not a different one. + * + * @param table The table to search in + * @param fk The original foreign key + * @return The corresponding foreign key if found + */ + protected ForeignKey findCorrespondingForeignKey(Table table, ForeignKey fk) + { + boolean caseMatters = getPlatformInfo().isUseDelimitedIdentifiers(); + boolean checkFkName = (fk.getName() != null) && (fk.getName().length() > 0); + Reference[] refs = fk.getReferences(); + ArrayList curRefs = new ArrayList(); + + for (int fkIdx = 0; fkIdx < table.getForeignKeyCount(); fkIdx++) + { + ForeignKey curFk = table.getForeignKey(fkIdx); + boolean checkCurFkName = checkFkName && + (curFk.getName() != null) && (curFk.getName().length() > 0); + + if ((!checkCurFkName || areEqual(fk.getName(), curFk.getName(), caseMatters)) && + areEqual(fk.getForeignTableName(), curFk.getForeignTableName(), caseMatters)) + { + curRefs.clear(); + CollectionUtils.addAll(curRefs, curFk.getReferences()); + + // the order is not fixed, so we have to take this long way + if (curRefs.size() == refs.length) + { + for (int refIdx = 0; refIdx < refs.length; refIdx++) + { + boolean found = false; + + for (int curRefIdx = 0; !found && (curRefIdx < curRefs.size()); curRefIdx++) + { + Reference curRef = (Reference)curRefs.get(curRefIdx); + + if ((caseMatters && refs[refIdx].equals(curRef)) || + (!caseMatters && refs[refIdx].equalsIgnoreCase(curRef))) + { + curRefs.remove(curRefIdx); + found = true; + } + } + } + if (curRefs.isEmpty()) + { + return curFk; + } + } + } + } + return null; } - + + /** + * Compares the two strings. + * + * @param string1 The first string + * @param string2 The second string + * @param caseMatters Whether case matters in the comparison + * @return <code>true</code> if the string are equal + */ + protected boolean areEqual(String string1, String string2, boolean caseMatters) + { + return (caseMatters && string1.equals(string2)) || + (!caseMatters && string1.equalsIgnoreCase(string2)); + } + /** * Outputs the DDL to create the table along with any non-external constraints as well * as with external primary keys and indices (but not foreign keys). @@ -1364,7 +1438,8 @@ String desiredDefault = desiredColumn.getDefaultValue(); String currentDefault = currentColumn.getDefaultValue(); boolean defaultsEqual = (desiredDefault == null) || desiredDefault.equals(currentDefault); - boolean sizeMatters = getPlatformInfo().hasSize(currentColumn.getTypeCode()); + boolean sizeMatters = getPlatformInfo().hasSize(currentColumn.getTypeCode()) && + (desiredColumn.getSize() != null); // We're comparing the jdbc type that corresponds to the native type for the // desired type, in order to avoid repeated altering of a perfectly valid column