This fixes OPENJPA-2795 in that generation of indizes for @ManyToOne relations that are also foreign keys can optionally be turned on if so desired. Default behaviour of OpenJPA is unchanged.

This commit contains two new features:
1) A new DB-specific flag DBDictionary#indexPhysicalForeignKeys so that indices for foreign keys will be generated for
database systems that don't automatically create an index for foreign keys.
2) A new boolean property MappingDefaults.IndexPhysicalForeignKeys that will turn the feature from 1) on or off.
By default MappingDefaults.IndexPhysicalForeignKeys is false so that the feature from 1) is disabled.

Note: DBDictionary#indexPhysicalForeignKeys works similar to the pre-existing flag DBDictionary#indexLogicalForeignKeys.

Note: this commit enables FK indices for Oracle and MS SQLServer. Other database systems may benefit, too, and should also be changed.
This commit is contained in:
Robert Mayer 2020-07-06 15:52:27 +02:00 committed by Mark Struberg
parent 119df603b8
commit c13f0b0e13
4 changed files with 46 additions and 8 deletions

View File

@ -61,7 +61,8 @@ public class MappingDefaultsImpl
private int _joinFKAction = ForeignKey.ACTION_NONE; private int _joinFKAction = ForeignKey.ACTION_NONE;
private int _fkAction = ForeignKey.ACTION_NONE; private int _fkAction = ForeignKey.ACTION_NONE;
private boolean _defer = false; private boolean _defer = false;
private boolean _indexFK = true; private boolean _indexLogicalFK = true;
private boolean _indexPhysicalFK = false;
private boolean _indexDisc = true; private boolean _indexDisc = true;
private boolean _indexVers = false; private boolean _indexVers = false;
private boolean _orderLists = true; private boolean _orderLists = true;
@ -248,14 +249,30 @@ public class MappingDefaultsImpl
* Whether to index logical foreign keys by default. Defaults to true. * Whether to index logical foreign keys by default. Defaults to true.
*/ */
public boolean getIndexLogicalForeignKeys() { public boolean getIndexLogicalForeignKeys() {
return _indexFK; return _indexLogicalFK;
} }
/** /**
* Whether to index logical foreign keys by default. Defaults to true. * Whether to index logical foreign keys by default. Defaults to true.
*/ */
public void setIndexLogicalForeignKeys(boolean indexFK) { public void setIndexLogicalForeignKeys(boolean indexFK) {
_indexFK = indexFK; _indexLogicalFK = indexFK;
}
/**
* Whether to use DbDictionary specific index on real foreign keys by default.
* Defaults to false i.e. old compatibility behaviour (i.e. no foreign key indices for FKs)
*/
public boolean getIndexPhysicalForeignKeys() {
return _indexPhysicalFK;
}
/**
* Whether to use DbDictionary specific index on real foreign keys by default.
* Defaults to false i.e. old compatibility behaviour (i.e. no foreign key indices for FKs)
*/
public void setIndexPhysicalForeignKeys(boolean indexPhysFKCompat) {
_indexPhysicalFK = indexPhysFKCompat;
} }
/** /**
@ -812,17 +829,25 @@ public class MappingDefaultsImpl
@Override @Override
public Index getJoinIndex(FieldMapping fm, Table table, Column[] cols) { public Index getJoinIndex(FieldMapping fm, Table table, Column[] cols) {
if (!_indexFK || fm.getJoinForeignKey() == null if (!needsFkIndex(fm.getJoinForeignKey())) {
|| !fm.getJoinForeignKey().isLogical())
return null; return null;
if (areAllPrimaryKeyColumns(cols)) }
if (areAllPrimaryKeyColumns(cols)) {
return null; return null;
}
Index idx = new Index(); Index idx = new Index();
idx.setIdentifier(getIndexName(DBIdentifier.NULL, table, cols)); idx.setIdentifier(getIndexName(DBIdentifier.NULL, table, cols));
return idx; return idx;
} }
private boolean needsFkIndex(ForeignKey fk) {
if (fk == null)
return false;
boolean fkIsLogical = fk.isLogical();
return (_indexLogicalFK && fkIsLogical) || (_indexPhysicalFK && !fkIsLogical && dict.indexPhysicalForeignKeys);
}
/** /**
* Return whether all the given columns are primary key columns. * Return whether all the given columns are primary key columns.
*/ */
@ -868,9 +893,9 @@ public class MappingDefaultsImpl
@Override @Override
public Index getIndex(ValueMapping vm, DBIdentifier name, Table table, public Index getIndex(ValueMapping vm, DBIdentifier name, Table table,
Column[] cols) { Column[] cols) {
if (!_indexFK || vm.getForeignKey() == null if (!needsFkIndex(vm.getForeignKey())) {
|| !vm.getForeignKey().isLogical())
return null; return null;
}
if (areAllPrimaryKeyColumns(cols)) if (areAllPrimaryKeyColumns(cols))
return null; return null;

View File

@ -345,6 +345,16 @@ public class DBDictionary
*/ */
protected BooleanRepresentation booleanRepresentation = BooleanRepresentationFactory.INT_10; protected BooleanRepresentation booleanRepresentation = BooleanRepresentationFactory.INT_10;
/**
* Whether an index is generated for a relation that is also a foreign key.
* Some database systems (e.g. MySQL) will automatically create an index for a foreign key,
* others (e.g. Oracle, MS-SQL-Server) do not.
*
* See also {@link org.apache.openjpa.jdbc.meta.MappingDefaultsImpl#_indexPhysicalFK}
* which may disable this feature for backwards compatibility.
*/
public boolean indexPhysicalForeignKeys = false;
public int characterColumnSize = 255; public int characterColumnSize = 255;
public String arrayTypeName = "ARRAY"; public String arrayTypeName = "ARRAY";
public String bigintTypeName = "BIGINT"; public String bigintTypeName = "BIGINT";

View File

@ -251,6 +251,7 @@ public class OracleDictionary
oracleBlob_empty_lob_Method = getMethodByReflection("oracle.sql.BLOB", "getEmptyBLOB"); oracleBlob_empty_lob_Method = getMethodByReflection("oracle.sql.BLOB", "getEmptyBLOB");
oracleClob_isEmptyLob_Method = getMethodByReflection("oracle.sql.CLOB", "isEmptyLob"); oracleClob_isEmptyLob_Method = getMethodByReflection("oracle.sql.CLOB", "isEmptyLob");
indexPhysicalForeignKeys = true; // Oracle does not automatically create an index for a foreign key so we will
} }
private Method getMethodByReflection(String className, String methodName, Class<?>... paramTypes) { private Method getMethodByReflection(String className, String methodName, Class<?>... paramTypes) {

View File

@ -80,6 +80,8 @@ public class SQLServerDictionary extends AbstractSQLServerDictionary {
timeWithZoneTypeName = "TIME"; timeWithZoneTypeName = "TIME";
timestampWithZoneTypeName = "DATETIMEOFFSET"; timestampWithZoneTypeName = "DATETIMEOFFSET";
indexPhysicalForeignKeys = true; // MS-SQLServer does not automatically create an index for a foreign key so we will
} }
@Override @Override