You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by jr...@apache.org on 2009/11/03 23:49:30 UTC
svn commit: r832587 - in /openjpa/trunk/openjpa-jdbc/src/main:
java/org/apache/openjpa/jdbc/schema/ java/org/apache/openjpa/jdbc/sql/
resources/org/apache/openjpa/jdbc/schema/
Author: jrbauer
Date: Tue Nov 3 22:48:43 2009
New Revision: 832587
URL: http://svn.apache.org/viewvc?rev=832587&view=rev
Log:
OPENJPA-1083 Fixed a mapping tool failure caused by the inability to discover and drop multi-column foreign key constraints. Multi-column FK's were not getting dropped, but got added after clearing out the tables. Trying to add an existing FK caused an exception when using Oracle.
Modified:
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/ForeignKey.java
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/OracleDictionary.java
openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/schema/localizer.properties
Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/ForeignKey.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/ForeignKey.java?rev=832587&r1=832586&r2=832587&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/ForeignKey.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/ForeignKey.java Tue Nov 3 22:48:43 2009
@@ -26,6 +26,7 @@
import java.util.List;
import org.apache.commons.lang.ObjectUtils;
+import org.apache.commons.lang.StringUtils;
import org.apache.openjpa.jdbc.sql.DBDictionary;
import org.apache.openjpa.lib.log.Log;
import org.apache.openjpa.lib.util.Localizer;
@@ -753,7 +754,7 @@
Schema schema = getTable().getSchema();
ForeignKey[] fks = dbdict.getImportedKeys(conn.getMetaData(),
conn.getCatalog(), schema.getName(),
- getTable().getName(), conn);
+ getTable().getName(), conn, false);
for ( int i=0; i< fks.length; i++) {
Table localtable = schema.getTable(fks[i].getTableName());
Table pkTable = schema.getTable(
@@ -768,10 +769,33 @@
fkTemp.setDeferred(fks[i].isDeferred());
fkTemp.setDeleteAction(fks[i].getDeleteAction());
}
- if( ! fkTemp.containsColumn(
- localtable.getColumn(fks[i].getColumnName(), dbdict)))
- fkTemp.join(localtable.getColumn(fks[i].getColumnName(), dbdict),
- pkTable.getColumn(fks[i].getPrimaryKeyColumnName(), dbdict));
+ if (fks[i].getColumns() == null || fks[i].getColumns().length == 0) {
+ // Singular column foreign key
+ if( ! fkTemp.containsColumn(
+ localtable.getColumn(fks[i].getColumnName(), dbdict)))
+ fkTemp.join(localtable.getColumn(fks[i].getColumnName(), dbdict),
+ pkTable.getColumn(fks[i].getPrimaryKeyColumnName(), dbdict));
+ } else {
+ // Add the multi-column foreign key, joining local and pk columns in
+ // the temporary key
+ Column[] locCols = fks[i].getColumns();
+ Column[] pkCols = fks[i].getPrimaryKeyColumns();
+ // Column counts must match
+ if (locCols != null && pkCols != null &
+ locCols.length != pkCols.length) {
+ Log log = dbdict.getLog();
+ if (log.isTraceEnabled()) {
+ log.trace(_loc.get("fk-column-mismatch"));
+ }
+ }
+ for (int j = 0; j < locCols.length; j++) {
+ if( ! fkTemp.containsColumn(
+ localtable.getColumn(locCols[j].getName(), dbdict))) {
+ fkTemp.join(localtable.getColumn(locCols[j].getName(), dbdict),
+ pkTable.getColumn(pkCols[j].getName(), dbdict));
+ }
+ }
+ }
if( equalsForeignKey(fkTemp))
{
if(addFK)
@@ -790,5 +814,96 @@
}
return retVal;
}
+
+ /**
+ * Joins the column of a single column FK to this FK.
+ * @param fk
+ */
+ public void addColumn(ForeignKey fk) {
+ // Convert simple name based fk to a multi-column FK if necessary.
+ if (getColumns() == null || getColumns().length == 0) {
+ // If this FK is single column key, covert to a multi-column key
+ Column[] keyCols = createKeyColumns(this);
+ if (keyCols[0] != null && keyCols[1] != null) {
+ setPrimaryKeyColumnName(null);
+ setColumnName(null);
+ join(keyCols[0], keyCols[1]);
+ }
+ }
+ // Create the local and primary key columns from the fk and add them
+ // to this fk.
+ Column[] keyCols = createKeyColumns(fk);
+ if (keyCols[0] != null && keyCols[1] != null) {
+ join(keyCols[0], keyCols[1]);
+ }
+ }
+ /*
+ * Creates the local and primary key columns for a name-based fk.
+ * @return Column[] element 0 is local column
+ * element 1 is the primary key in another table.
+ */
+ private static Column[] createKeyColumns(ForeignKey fk) {
+ Column fkCol = null;
+ if (!StringUtils.isEmpty(fk.getColumnName())) {
+ fkCol = new Column();
+ fkCol.setName(fk.getColumnName());
+ fkCol.setTableName(fk.getTableName());
+ fkCol.setSchemaName(fk.getSchemaName());
+ }
+
+ Column pkCol = null;
+ if (!StringUtils.isEmpty(fk.getPrimaryKeyColumnName())) {
+ pkCol = new Column();
+ pkCol.setName(fk.getPrimaryKeyColumnName());
+ pkCol.setTableName(fk.getPrimaryKeyTableName());
+ pkCol.setSchemaName(fk.getPrimaryKeySchemaName());
+ }
+ return new Column[] { fkCol, pkCol };
+ }
+
+ /*
+ * ForeignKey utility class which determines equality based upon the
+ * non-column state of the keys.
+ */
+ public static class FKMapKey {
+
+ private ForeignKey _fk;
+
+ public FKMapKey(ForeignKey fk) {
+ _fk = fk;
+ }
+ public ForeignKey getFk() {
+ return _fk;
+ }
+
+ public int hashCode() {
+ return getFk().getName() != null ? getFk().getName().hashCode() : getFk().hashCode();
+ }
+
+ public boolean equals(Object fkObj) {
+ if (fkObj == this) {
+ return true;
+ }
+ if (fkObj == null || !(fkObj instanceof FKMapKey)) {
+ return false;
+ }
+ ForeignKey fk = ((FKMapKey)fkObj).getFk();
+ if (getFk().getDeleteAction() != fk.getDeleteAction())
+ return false;
+ if (getFk().isDeferred() != fk.isDeferred())
+ return false;
+ if (!getFk().getName().equals(fk.getName())) {
+ return false;
+ }
+ // Assert PK table name and schema
+ if (!StringUtils.equals(getFk().getPrimaryKeySchemaName(), fk.getPrimaryKeySchemaName()) ||
+ !StringUtils.equals(getFk().getPrimaryKeyTableName(), fk.getPrimaryKeyTableName()) ||
+ !StringUtils.equals(getFk().getSchemaName(), fk.getSchemaName()) ||
+ !StringUtils.equals(getFk().getTableName(), fk.getTableName())) {
+ return false;
+ }
+ return true;
+ }
+ }
}
Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java?rev=832587&r1=832586&r2=832587&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java Tue Nov 3 22:48:43 2009
@@ -86,6 +86,7 @@
import org.apache.openjpa.jdbc.schema.Sequence;
import org.apache.openjpa.jdbc.schema.Table;
import org.apache.openjpa.jdbc.schema.Unique;
+import org.apache.openjpa.jdbc.schema.ForeignKey.FKMapKey;
import org.apache.openjpa.kernel.Filters;
import org.apache.openjpa.kernel.OpenJPAStateManager;
import org.apache.openjpa.kernel.Seq;
@@ -4118,6 +4119,16 @@
public ForeignKey[] getImportedKeys(DatabaseMetaData meta, String catalog,
String schemaName, String tableName, Connection conn)
throws SQLException {
+ return getImportedKeys(meta, catalog, schemaName, tableName, conn, true);
+ }
+
+ /**
+ * Reflect on the schema to return full foreign keys imported by the given
+ * table pattern.
+ */
+ public ForeignKey[] getImportedKeys(DatabaseMetaData meta, String catalog,
+ String schemaName, String tableName, Connection conn, boolean partialKeys)
+ throws SQLException {
if (!supportsForeignKeys)
return null;
if (tableName == null && !supportsNullTableForGetImportedKeys)
@@ -4130,19 +4141,50 @@
getSchemaNameForMetadata(schemaName),
getTableNameForMetadata(tableName));
- List importedKeyList = new ArrayList();
- while (keys != null && keys.next())
- importedKeyList.add(newForeignKey(keys));
+ List<ForeignKey> importedKeyList = new ArrayList<ForeignKey>();
+ Map<FKMapKey, ForeignKey> fkMap = new HashMap<FKMapKey, ForeignKey>();
+
+ while (keys != null && keys.next()) {
+ ForeignKey nfk = newForeignKey(keys);
+ if (!partialKeys) {
+ ForeignKey fk = combineForeignKey(fkMap, nfk);
+ // If the key returned != new key, fk col was combined
+ // with existing fk.
+ if (fk != nfk) {
+ continue;
+ }
+ }
+ importedKeyList.add(nfk);
+ }
return (ForeignKey[]) importedKeyList.toArray
(new ForeignKey[importedKeyList.size()]);
} finally {
- if (keys != null)
+ if (keys != null) {
try {
keys.close();
} catch (Exception e) {
}
+ }
}
}
+
+ /*
+ * Combines partial foreign keys into singular key
+ */
+ protected ForeignKey combineForeignKey(Map<FKMapKey, ForeignKey> fkMap,
+ ForeignKey fk) {
+
+ FKMapKey fkmk = new FKMapKey(fk);
+ ForeignKey baseKey = fkMap.get(fkmk);
+ // Found the FK, add the additional column
+ if (baseKey != null) {
+ baseKey.addColumn(fk);
+ return baseKey;
+ }
+ // fkey is new
+ fkMap.put(fkmk, fk);
+ return fk;
+ }
/**
* Create a new foreign key from the information in the schema metadata.
Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/OracleDictionary.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/OracleDictionary.java?rev=832587&r1=832586&r2=832587&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/OracleDictionary.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/OracleDictionary.java Tue Nov 3 22:48:43 2009
@@ -34,6 +34,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -49,6 +50,7 @@
import org.apache.openjpa.jdbc.schema.PrimaryKey;
import org.apache.openjpa.jdbc.schema.Sequence;
import org.apache.openjpa.jdbc.schema.Table;
+import org.apache.openjpa.jdbc.schema.ForeignKey.FKMapKey;
import org.apache.openjpa.lib.jdbc.DelegatingDatabaseMetaData;
import org.apache.openjpa.lib.jdbc.DelegatingPreparedStatement;
import org.apache.openjpa.lib.util.J2DoPrivHelper;
@@ -756,7 +758,7 @@
}
public ForeignKey[] getImportedKeys(DatabaseMetaData meta, String catalog,
- String schemaName, String tableName, Connection conn)
+ String schemaName, String tableName, Connection conn, boolean partialKeys)
throws SQLException {
StringBuffer delAction = new StringBuffer("DECODE(t1.DELETE_RULE").
append(", 'NO ACTION', ").append(meta.importedKeyNoAction).
@@ -805,9 +807,20 @@
setString(stmnt, idx++, tableName.toUpperCase(), null);
setTimeouts(stmnt, conf, false);
rs = stmnt.executeQuery();
- List fkList = new ArrayList();
- while (rs != null && rs.next())
- fkList.add(newForeignKey(rs));
+ List<ForeignKey> fkList = new ArrayList<ForeignKey>();
+ Map<FKMapKey, ForeignKey> fkMap = new HashMap<FKMapKey, ForeignKey>();
+
+ while (rs != null && rs.next()) {
+ ForeignKey nfk = newForeignKey(rs);
+ if (!partialKeys) {
+ ForeignKey fk = combineForeignKey(fkMap, nfk);
+ // Only add the fk to the import list if it is new
+ if (fk != nfk) {
+ continue;
+ }
+ }
+ fkList.add(nfk);
+ }
return (ForeignKey[]) fkList.toArray
(new ForeignKey[fkList.size()]);
} finally {
Modified: openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/schema/localizer.properties
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/schema/localizer.properties?rev=832587&r1=832586&r2=832587&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/schema/localizer.properties (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/schema/localizer.properties Tue Nov 3 22:48:43 2009
@@ -154,3 +154,5 @@
no-column: Can not find column "{0}" in table "{1}"
except-read-fk-name: An exception occurred when obtaining the foreign key \
names from the database.
+fk-column-mismatch: Unable to create multi-column foreign key. The key \
+ columns do not match primary keys in foreign table.