OPENJPA-1083 committing patch provided by Ravi Palacherla

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@781791 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Michael Dick 2009-06-04 16:45:34 +00:00
parent fced775084
commit 8a2210c65a
5 changed files with 258 additions and 16 deletions

View File

@ -19,6 +19,7 @@
package org.apache.openjpa.jdbc.schema; package org.apache.openjpa.jdbc.schema;
import java.sql.DatabaseMetaData; import java.sql.DatabaseMetaData;
import java.sql.Connection;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -28,6 +29,7 @@ import org.apache.commons.lang.ObjectUtils;
import org.apache.openjpa.lib.util.Localizer; import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.lib.util.StringDistance; import org.apache.openjpa.lib.util.StringDistance;
import org.apache.openjpa.util.InvalidStateException; import org.apache.openjpa.util.InvalidStateException;
import org.apache.openjpa.jdbc.sql.DBDictionary;
/** /**
* Represents a database foreign key; may be a logical key with no * Represents a database foreign key; may be a logical key with no
@ -738,4 +740,51 @@ public class ForeignKey
return false; return false;
return true; return true;
} }
/**
* Return the name of the foreignkey constraint as defined in the database.
*/
public String loadNameFromDB(DBDictionary dbdict, Connection conn) {
if( isLogical() || getTable() == null)
return null;
String retVal = null;
try{
Schema schema = getTable().getSchema();
ForeignKey[] fks = dbdict.getImportedKeys(conn.getMetaData(),
conn.getCatalog(), schema.getName(),
getTable().getName(), conn);
for ( int i=0; i< fks.length; i++) {
Table localtable = schema.getTable(fks[i].getTableName());
Table pkTable = schema.getTable(
fks[i].getPrimaryKeyTableName());
boolean addFK = false;
ForeignKey fkTemp = localtable.getForeignKey(
fks[i].getName());
if( fkTemp == null) {
addFK=true;
fkTemp = localtable.addForeignKey(
fks[i].getName());
fkTemp.setDeferred(fks[i].isDeferred());
fkTemp.setDeleteAction(fks[i].getDeleteAction());
}
if( ! fkTemp.containsColumn(
localtable.getColumn(fks[i].getColumnName())))
fkTemp.join(localtable.getColumn(fks[i].getColumnName()),
pkTable.getColumn(fks[i].getPrimaryKeyColumnName()));
if( equalsForeignKey(fkTemp))
{
if(addFK)
localtable.removeForeignKey(fkTemp);
retVal = fks[i].getName();
break;
}
if(addFK)
localtable.removeForeignKey(fkTemp);
}
} catch(Exception ex){
// TO DO -- It would be nice to log a warning here.
}
return retVal;
}
} }

View File

@ -423,7 +423,7 @@ public class SchemaTool {
} }
Table[] tableArray = (Table[]) tables.toArray(new Table[tables.size()]); Table[] tableArray = (Table[]) tables.toArray(new Table[tables.size()]);
String[] sql = _conf.getDBDictionaryInstance() String[] sql = _conf.getDBDictionaryInstance()
.getDeleteTableContentsSQL(tableArray); .getDeleteTableContentsSQL(tableArray,_ds.getConnection());
if (!executeSQL(sql)) if (!executeSQL(sql))
_log.warn(_loc.get("delete-table-contents")); _log.warn(_loc.get("delete-table-contents"));
} }
@ -1083,7 +1083,7 @@ public class SchemaTool {
*/ */
public boolean dropForeignKey(ForeignKey fk) public boolean dropForeignKey(ForeignKey fk)
throws SQLException { throws SQLException {
return executeSQL(_dict.getDropForeignKeySQL(fk)); return executeSQL(_dict.getDropForeignKeySQL(fk,_ds.getConnection()));
} }
/** /**

View File

@ -2173,33 +2173,36 @@ public class DBDictionary
* Databases with more optimal ways of deleting the contents of several * Databases with more optimal ways of deleting the contents of several
* tables should override this method. * tables should override this method.
*/ */
public String[] getDeleteTableContentsSQL(Table[] tables) { public String[] getDeleteTableContentsSQL(Table[] tables,Connection conn) {
Collection sql = new ArrayList(); Collection<String> sql = new ArrayList<String>();
// collect and drop non-deferred physical restrict constraints, and // collect and drop non-deferred physical restrict constraints, and
// collect the DELETE FROM statements // collect the DELETE FROM statements
Collection deleteSQL = new ArrayList(tables.length); Collection<String> deleteSQL = new ArrayList<String>(tables.length);
Collection restrictConstraints = new LinkedHashSet(); Collection<ForeignKey> restrictConstraints =
new LinkedHashSet<ForeignKey>();
for (int i = 0; i < tables.length; i++) { for (int i = 0; i < tables.length; i++) {
ForeignKey[] fks = tables[i].getForeignKeys(); ForeignKey[] fks = tables[i].getForeignKeys();
for (int j = 0; j < fks.length; j++) { for (int j = 0; j < fks.length; j++) {
if (!fks[j].isLogical() && !fks[j].isDeferred() if (!fks[j].isLogical() && !fks[j].isDeferred()
&& fks[j].getDeleteAction() == ForeignKey.ACTION_RESTRICT) && fks[j].getDeleteAction() == ForeignKey.ACTION_RESTRICT)
restrictConstraints.add(fks[j]); restrictConstraints.add(fks[j]);
String[] constraintSQL = getDropForeignKeySQL(fks[j]);
sql.addAll(Arrays.asList(constraintSQL));
} }
deleteSQL.add("DELETE FROM " + tables[i].getFullName()); deleteSQL.add("DELETE FROM " + tables[i].getFullName());
} }
for(ForeignKey fk : restrictConstraints) {
String[] constraintSQL = getDropForeignKeySQL(fk,conn);
sql.addAll(Arrays.asList(constraintSQL));
}
// add the delete statements after all the constraint mutations // add the delete statements after all the constraint mutations
sql.addAll(deleteSQL); sql.addAll(deleteSQL);
// add the deleted constraints back to the schema // add the deleted constraints back to the schema
for (Iterator iter = restrictConstraints.iterator(); iter.hasNext(); ) { for (ForeignKey fk : restrictConstraints) {
String[] constraintSQL = String[] constraintSQL = getAddForeignKeySQL(fk);
getAddForeignKeySQL((ForeignKey) iter.next());
sql.addAll(Arrays.asList(constraintSQL)); sql.addAll(Arrays.asList(constraintSQL));
} }
@ -3448,9 +3451,16 @@ public class DBDictionary
* Returns <code>ALTER TABLE &lt;table name&gt; DROP CONSTRAINT * Returns <code>ALTER TABLE &lt;table name&gt; DROP CONSTRAINT
* &lt;fk name&gt;</code> by default. * &lt;fk name&gt;</code> by default.
*/ */
public String[] getDropForeignKeySQL(ForeignKey fk) { public String[] getDropForeignKeySQL(ForeignKey fk, Connection conn) {
if (fk.getName() == null) if (fk.getName() == null) {
return new String[0]; String[] retVal;
String fkName = fk.loadNameFromDB(this,conn);
retVal = (fkName == null) ? new String[0] :
new String[]{ "ALTER TABLE "
+ getFullName(fk.getTable(), false)
+ " DROP CONSTRAINT " + fkName };
return retVal;
}
return new String[]{ "ALTER TABLE " return new String[]{ "ALTER TABLE "
+ getFullName(fk.getTable(), false) + getFullName(fk.getTable(), false)
+ " DROP CONSTRAINT " + fk.getName() }; + " DROP CONSTRAINT " + fk.getName() };

View File

@ -222,10 +222,10 @@ public class MySQLDictionary
return ret; return ret;
} }
public String[] getDeleteTableContentsSQL(Table[] tables) { public String[] getDeleteTableContentsSQL(Table[] tables,Connection conn) {
// mysql >= 4 supports more-optimal delete syntax // mysql >= 4 supports more-optimal delete syntax
if (!optimizeMultiTableDeletes) if (!optimizeMultiTableDeletes)
return super.getDeleteTableContentsSQL(tables); return super.getDeleteTableContentsSQL(tables,conn);
else { else {
StringBuffer buf = new StringBuffer(tables.length * 8); StringBuffer buf = new StringBuffer(tables.length * 8);
buf.append("DELETE FROM "); buf.append("DELETE FROM ");

View File

@ -0,0 +1,183 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.openjpa.jdbc.kernel;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.sql.DataSource;
import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
import org.apache.openjpa.jdbc.schema.ForeignKey;
import org.apache.openjpa.jdbc.schema.Table;
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
/**
* Test that makes sure the number of foreign keys are same on a table after
* calling loadNameFromDB method of ForeignKey class.
*
*/
public class TestForeignKeyCountViolation extends SingleEMFTestCase {
private JDBCConfiguration _conf;
public void setUp() {
super.setUp(EntityF.class, EntityG.class);
Map props = new HashMap(System.getProperties());
_conf = (JDBCConfiguration) emf.getConfiguration();
}
public void testFKCount() throws SQLException {
EntityManager em = emf.createEntityManager();
Table tableG = getMapping(EntityG.class).getTable();
tableG.addForeignKey();
int b4Count = tableG.getForeignKeys().length;
EntityF f = new EntityF();
f.setId(1);
List<EntityG> listG = new ArrayList<EntityG>();
EntityG g1 = new EntityG();
g1.setId(1);
listG.add(g1);
g1.setEntityF(f);
EntityG g2 = new EntityG();
g2.setId(2);
listG.add(g2);
g2.setEntityF(f);
EntityG g3 = new EntityG();
g3.setId(3);
listG.add(g3);
g3.setEntityF(f);
EntityG g4 = new EntityG();
g4.setId(4);
listG.add(g4);
g4.setEntityF(f);
f.setListG(listG);
em.getTransaction().begin();
em.persist(f);
em.persist(g1);
em.persist(g2);
em.persist(g3);
em.persist(g4);
em.getTransaction().commit();
ForeignKey fks[] = tableG.getForeignKeys();
DataSource ds = (DataSource) _conf.getConnectionFactory();
Connection c = ds.getConnection(_conf.getConnectionUserName(),
_conf.getConnectionPassword());
for (int i=0; i< fks.length; i++) {
fks[i].loadNameFromDB(
_conf.getDBDictionaryInstance(), c);
}
assertEquals(b4Count, tableG.getForeignKeys().length);
em.close();
}
public void testFKNamefromDB()throws SQLException {
EntityManager em = emf.createEntityManager();
Table tableG = getMapping(EntityG.class).getTable();
tableG.addForeignKey();
EntityF f = new EntityF();
f.setId(1);
List<EntityG> listG = new ArrayList<EntityG>();
EntityG g1 = new EntityG();
g1.setId(1);
listG.add(g1);
g1.setEntityF(f);
EntityG g2 = new EntityG();
g2.setId(2);
listG.add(g2);
g2.setEntityF(f);
EntityG g3 = new EntityG();
g3.setId(3);
listG.add(g3);
g3.setEntityF(f);
EntityG g4 = new EntityG();
g4.setId(4);
listG.add(g4);
g4.setEntityF(f);
f.setListG(listG);
em.getTransaction().begin();
em.persist(f);
em.persist(g1);
em.persist(g2);
em.persist(g3);
em.persist(g4);
em.getTransaction().commit();
DataSource ds = (DataSource) _conf.getConnectionFactory();
Connection c = ds.getConnection(_conf.getConnectionUserName(),
_conf.getConnectionPassword());
ForeignKey fkfromDB[] = _conf.getDBDictionaryInstance().getImportedKeys(
c.getMetaData(), c.getCatalog() , tableG.getSchemaName()
, tableG.getName(), c);
ArrayList<String> fkListfromDB = new ArrayList<String>();
ArrayList<String> fkListfromTable = new ArrayList<String>();
for (int i=0; i< fkfromDB.length; i++) {
fkListfromDB.add(fkfromDB[i].getName());
}
ForeignKey fks[] = tableG.getForeignKeys();
for (int i=0; i< fks.length; i++) {
String fkNamefromDB =fks[i].loadNameFromDB(
_conf.getDBDictionaryInstance(), c);
if( fkNamefromDB != null)
fkListfromTable.add(fkNamefromDB);
}
assertEquals(fkListfromDB.toArray().length,
fkListfromTable.toArray().length);
Collections.sort(fkListfromTable);
Collections.sort(fkListfromDB);
for(int i=0; i< fkListfromDB.size(); i++)
{
assertEquals(fkListfromDB.get(i),fkListfromTable.get(i));
}
em.close();
}
}