mirror of https://github.com/apache/openjpa.git
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:
parent
fced775084
commit
8a2210c65a
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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 <table name> DROP CONSTRAINT
|
* Returns <code>ALTER TABLE <table name> DROP CONSTRAINT
|
||||||
* <fk name></code> by default.
|
* <fk name></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() };
|
||||||
|
|
|
@ -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 ");
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue