blob: 70668e1a70c1a493da1f1f99ae882d2ef7cd3885 [file] [log] [blame]
/*
* 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.schema;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Objects;
import org.apache.openjpa.jdbc.identifier.DBIdentifier;
import org.apache.openjpa.jdbc.sql.DBDictionary;
import org.apache.openjpa.lib.log.Log;
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.lib.util.StringDistance;
import org.apache.openjpa.util.InvalidStateException;
/**
* Represents a database foreign key; may be a logical key with no
* database representation. This class can also represent a partial key,
* aligning with {@link DatabaseMetaData}.
*
* @author Abe White
*/
public class ForeignKey extends Constraint {
private static final long serialVersionUID = 1L;
/**
* Logical foreign key; links columns, but does not perform any action
* when the joined primary key columns are modified.
*/
public static final int ACTION_NONE = 1;
/**
* Throw an exception if joined primary key columns are modified.
*/
public static final int ACTION_RESTRICT = 2;
/**
* Cascade any modification of the joined primary key columns to
* this table. If the joined primary key row is deleted, the row in this
* table will also be deleted.
*/
public static final int ACTION_CASCADE = 3;
/**
* Null the local columns if the joined primary key columns are modified.
*/
public static final int ACTION_NULL = 4;
/**
* Set the local columns to their default values if the primary key
* columns are modified.
*/
public static final int ACTION_DEFAULT = 5;
private static final Localizer _loc =
Localizer.forPackage(ForeignKey.class);
private DBIdentifier _pkTableName = DBIdentifier.NULL;
private DBIdentifier _pkSchemaName = DBIdentifier.NULL;
private DBIdentifier _pkColumnName = DBIdentifier.NULL;
private int _seq = 0;
private LinkedHashMap _joins = null;
private LinkedHashMap _joinsPK = null;
private LinkedHashMap _consts = null;
private LinkedHashMap _constsPK = null;
private int _delAction = ACTION_NONE;
private int _upAction = ACTION_NONE;
private int _index = 0;
// cached items
private Column[] _locals = null;
private Column[] _pks = null;
private Object[] _constVals = null;
private Column[] _constCols = null;
private Object[] _constValsPK = null;
private Column[] _constColsPK = null;
private Table _pkTable = null;
private Boolean _autoAssign = null;
/**
* Return the foreign key action constant for the given action name.
*/
public static int getAction(String name) {
if (name == null || "none".equalsIgnoreCase(name))
return ACTION_NONE;
if ("cascade".equalsIgnoreCase(name))
return ACTION_CASCADE;
if ("default".equalsIgnoreCase(name))
return ACTION_DEFAULT;
if ("restrict".equalsIgnoreCase(name)
|| "exception".equalsIgnoreCase(name))
return ACTION_RESTRICT;
if ("null".equalsIgnoreCase(name))
return ACTION_NULL;
// not a recognized action; check for typo
List recognized = Arrays.asList(new String[]{ "none", "exception",
"restrict", "cascade", "null", "default", });
String closest = StringDistance.getClosestLevenshteinDistance(name,
recognized, .5F);
String msg;
if (closest != null)
msg = _loc.get("bad-fk-action-hint", name, closest, recognized)
.getMessage();
else
msg = _loc.get("bad-fk-action", name, recognized).getMessage();
throw new IllegalArgumentException(msg);
}
/**
* Return the foreign key action name for the given action constant.
*/
public static String getActionName(int action) {
switch (action) {
case ACTION_NONE:
return "none";
case ACTION_RESTRICT:
return "restrict";
case ACTION_CASCADE:
return "cascade";
case ACTION_DEFAULT:
return "default";
case ACTION_NULL:
return "null";
default:
throw new IllegalArgumentException(String.valueOf(action));
}
}
/**
* Default constructor.
*/
public ForeignKey() {
}
/**
* Constructor.
*
* @param name the foreign key name, if any
* @param table the local table of the foreign key
* @deprecated
*/
@Deprecated
public ForeignKey(String name, Table table) {
super(name, table);
}
public ForeignKey(DBIdentifier name, Table table) {
super(name, table);
}
@Override
public boolean isLogical() {
return _delAction == ACTION_NONE;
}
/**
* Whether the primary key columns of this key are auto-incrementing, or
* whether they themselves are members of a foreign key who's primary key
* is auto-incrementing (recursing to arbitrary depth).
*/
public boolean isPrimaryKeyAutoAssigned() {
if (_autoAssign != null)
return _autoAssign;
return isPrimaryKeyAutoAssigned(new ArrayList(3));
}
/**
* Helper to calculate whether this foreign key depends on auto-assigned
* columns. Recurses appropriately if the primary key columns this key
* joins to are themselves members of a foreign key that is dependent on
* auto-assigned columns. Caches calculated auto-assign value as a side
* effect.
*
* @param seen track seen foreign keys to prevent infinite recursion in
* the case of foreign key cycles
*/
private boolean isPrimaryKeyAutoAssigned(List seen) {
if (_autoAssign != null)
return _autoAssign;
Column[] cols = getPrimaryKeyColumns();
if (cols.length == 0) {
_autoAssign = Boolean.FALSE;
return false;
}
for (Column column : cols) {
if (column.isAutoAssigned()) {
_autoAssign = Boolean.TRUE;
return true;
}
}
ForeignKey[] fks = _pkTable.getForeignKeys();
seen.add(this);
for (Column col : cols) {
for (ForeignKey fk : fks) {
if (!fk.containsColumn(col))
continue;
if (!seen.contains(fk)
&& fk.isPrimaryKeyAutoAssigned(seen)) {
_autoAssign = Boolean.TRUE;
return true;
}
}
}
_autoAssign = Boolean.FALSE;
return false;
}
/**
* The name of the primary key table.
* @deprecated
*/
@Deprecated
public String getPrimaryKeyTableName() {
return getPrimaryKeyTableIdentifier().getName();
}
public DBIdentifier getPrimaryKeyTableIdentifier() {
Table table = getPrimaryKeyTable();
if (table != null)
return table.getIdentifier();
return _pkTableName == null ? DBIdentifier.NULL : _pkTableName;
}
/**
* The name of the primary key table. You can only set the primary
* key table name on foreign keys that have not already been joined.
* @deprecated
*/
@Deprecated
public void setPrimaryKeyTableName(String pkTableName) {
setPrimaryKeyTableIdentifier(DBIdentifier.newTable(pkTableName));
}
public void setPrimaryKeyTableIdentifier(DBIdentifier pkTableName) {
if (getPrimaryKeyTable() != null)
throw new IllegalStateException();
_pkTableName = pkTableName;
}
/**
* The name of the primary key table's schema.
* @deprecated
*/
@Deprecated
public String getPrimaryKeySchemaName() {
return getPrimaryKeySchemaIdentifier().getName();
}
public DBIdentifier getPrimaryKeySchemaIdentifier() {
Table table = getPrimaryKeyTable();
if (table != null)
return table.getSchemaIdentifier();
return _pkSchemaName;
}
/**
* The name of the primary key table's schema. You can only set the
* primary key schema name on foreign keys that have not already been
* joined.
* @deprecated
*/
@Deprecated
public void setPrimaryKeySchemaName(String pkSchemaName) {
setPrimaryKeySchemaIdentifier(DBIdentifier.newSchema(pkSchemaName));
}
public void setPrimaryKeySchemaIdentifier(DBIdentifier pkSchemaName) {
if (getPrimaryKeyTable() != null)
throw new IllegalStateException();
_pkSchemaName = pkSchemaName;
}
/**
* The name of the primary key column.
* @deprecated
*/
@Deprecated
public String getPrimaryKeyColumnName() {
return getPrimaryKeyColumnIdentifier().getName();
}
public DBIdentifier getPrimaryKeyColumnIdentifier() {
return _pkColumnName == null ? DBIdentifier.NULL : _pkColumnName;
}
/**
* The name of the primary key column. You can only set the
* primary key column name on foreign keys that have not already been
* joined.
* @deprecated
*/
@Deprecated
public void setPrimaryKeyColumnName(String pkColumnName) {
setPrimaryKeyColumnIdentifier(DBIdentifier.newColumn(pkColumnName));
}
public void setPrimaryKeyColumnIdentifier(DBIdentifier pkColumnName) {
if (getPrimaryKeyTable() != null)
throw new IllegalStateException();
_pkColumnName = pkColumnName;
}
/**
* The sequence of this join in the foreign key.
*/
public int getKeySequence() {
return _seq;
}
/**
* The sequence of this join in the foreign key.
*/
public void setKeySequence(int seq) {
_seq = seq;
}
/**
* Return the delete action for the key. Will be one of:
* {@link #ACTION_NONE}, {@link #ACTION_RESTRICT},
* {@link #ACTION_CASCADE}, {@link #ACTION_NULL}, {@link #ACTION_DEFAULT}.
*/
public int getDeleteAction() {
return _delAction;
}
/**
* Set the delete action for the key. Must be one of:
* {@link #ACTION_NONE}, {@link #ACTION_RESTRICT},
* {@link #ACTION_CASCADE}, {@link #ACTION_NULL}, {@link #ACTION_DEFAULT}.
*/
public void setDeleteAction(int action) {
_delAction = action;
if (action == ACTION_NONE)
_upAction = ACTION_NONE;
else if (_upAction == ACTION_NONE)
_upAction = ACTION_RESTRICT;
}
/**
* Return the update action for the key. Will be one of:
* {@link #ACTION_NONE}, {@link #ACTION_RESTRICT},
* {@link #ACTION_CASCADE}, {@link #ACTION_NULL}, {@link #ACTION_DEFAULT}.
*/
public int getUpdateAction() {
return _upAction;
}
/**
* Set the update action for the key. Must be one of:
* {@link #ACTION_NONE}, {@link #ACTION_RESTRICT},
* {@link #ACTION_CASCADE}, {@link #ACTION_NULL}, {@link #ACTION_DEFAULT}.
*/
public void setUpdateAction(int action) {
_upAction = action;
if (action == ACTION_NONE)
_delAction = ACTION_NONE;
else if (_delAction == ACTION_NONE)
_delAction = ACTION_RESTRICT;
}
/**
* Return the foreign key's 0-based index in the owning table.
*/
public int getIndex() {
Table table = getTable();
if (table != null)
table.indexForeignKeys();
return _index;
}
/**
* Set the foreign key's 0-based index in the owning table.
*/
void setIndex(int index) {
_index = index;
}
/**
* Return the primary key column joined to the given local column.
*/
public Column getPrimaryKeyColumn(Column local) {
return (_joins == null) ? null : (Column) _joins.get(local);
}
/**
* Return the local column joined to the given primary key column.
*/
public Column getColumn(Column pk) {
return (_joinsPK == null) ? null : (Column) _joinsPK.get(pk);
}
/**
* Return the constant value assigned to the given local column.
*/
public Object getConstant(Column local) {
return (_consts == null) ? null : _consts.get(local);
}
/**
* Return the constant value assigned to the given primary key column.
*/
public Object getPrimaryKeyConstant(Column pk) {
return (_constsPK == null) ? null : _constsPK.get(pk);
}
/**
* Return the local columns in the foreign key local table order.
*/
public Column[] getColumns() {
if (_locals == null)
_locals = (_joins == null) ? Schemas.EMPTY_COLUMNS : (Column[])
_joins.keySet().toArray(new Column[_joins.size()]);
return _locals;
}
/**
* Return the constant values assigned to the local columns
* returned by {@link #getConstantColumns}.
*/
public Object[] getConstants() {
if (_constVals == null)
_constVals = (_consts == null) ? Schemas.EMPTY_VALUES
: _consts.values().toArray();
return _constVals;
}
/**
* Return the constant values assigned to the primary key columns
* returned by {@link #getConstantPrimaryKeyColumns}.
*/
public Object[] getPrimaryKeyConstants() {
if (_constValsPK == null)
_constValsPK = (_constsPK == null) ? Schemas.EMPTY_VALUES
: _constsPK.values().toArray();
return _constValsPK;
}
/**
* Return true if the fk includes the given local column.
*/
public boolean containsColumn(Column col) {
return _joins != null && _joins.containsKey(col);
}
/**
* Return true if the fk includes the given primary key column.
*/
public boolean containsPrimaryKeyColumn(Column col) {
return _joinsPK != null && _joinsPK.containsKey(col);
}
/**
* Return true if the fk includes the given local column.
*/
public boolean containsConstantColumn(Column col) {
return _consts != null && _consts.containsKey(col);
}
/**
* Return true if the fk includes the given primary key column.
*/
public boolean containsConstantPrimaryKeyColumn(Column col) {
return _constsPK != null && _constsPK.containsKey(col);
}
/**
* Return the foreign columns in the foreign key, in join-order with
* the result of {@link #getColumns}.
*/
public Column[] getPrimaryKeyColumns() {
if (_pks == null)
_pks = (_joins == null) ? Schemas.EMPTY_COLUMNS : (Column[])
_joins.values().toArray(new Column[_joins.size()]);
return _pks;
}
/**
* Return the local columns that we link to using constant values.
*/
public Column[] getConstantColumns() {
if (_constCols == null)
_constCols = (_consts == null) ? Schemas.EMPTY_COLUMNS : (Column[])
_consts.keySet().toArray(new Column[_consts.size()]);
return _constCols;
}
/**
* Return the primary key columns that we link to using constant values.
*/
public Column[] getConstantPrimaryKeyColumns() {
if (_constColsPK == null)
_constColsPK = (_constsPK == null) ? Schemas.EMPTY_COLUMNS :
(Column[]) _constsPK.keySet().toArray
(new Column[_constsPK.size()]);
return _constColsPK;
}
/**
* Set the foreign key's joins.
*/
public void setJoins(Column[] cols, Column[] pkCols) {
Column[] cur = getColumns();
for (Column column : cur) {
removeJoin(column);
}
if (cols != null)
for (int i = 0; i < cols.length; i++)
join(cols[i], pkCols[i]);
}
/**
* Set the foreign key's constant joins.
*/
public void setConstantJoins(Object[] consts, Column[] pkCols) {
Column[] cur = getConstantPrimaryKeyColumns();
for (Column column : cur) {
removeJoin(column);
}
if (consts != null)
for (int i = 0; i < consts.length; i++)
joinConstant(consts[i], pkCols[i]);
}
/**
* Set the foreign key's constant joins.
*/
public void setConstantJoins(Column[] cols, Object[] consts) {
Column[] cur = getConstantColumns();
for (Column column : cur) {
removeJoin(column);
}
if (consts != null)
for (int i = 0; i < consts.length; i++)
joinConstant(cols[i], consts[i]);
}
/**
* Join a local column to a primary key column of another table.
*/
public void join(Column local, Column toPK) {
if (!Objects.equals(local.getTable(), getTable()))
throw new InvalidStateException(_loc.get("table-mismatch",
local.getTable(), getTable()));
Table pkTable = toPK.getTable();
if (_pkTable != null && !_pkTable.equals(pkTable))
throw new InvalidStateException(_loc.get("fk-mismatch",
pkTable, _pkTable));
_pkTable = pkTable;
if (_joins == null)
_joins = new LinkedHashMap();
_joins.put(local, toPK);
local.addConstraint(this);
if (_joinsPK == null)
_joinsPK = new LinkedHashMap();
_joinsPK.put(toPK, local);
// force re-cache
_locals = null;
_pks = null;
if (Boolean.FALSE.equals(_autoAssign))
_autoAssign = null;
}
/**
* Join a constant value to a primary key column of another table. The
* constant must be either a string or a number.
*/
public void joinConstant(Object val, Column toPK) {
Table pkTable = toPK.getTable();
if (_pkTable != null && !_pkTable.equals(pkTable))
throw new InvalidStateException(_loc.get("fk-mismatch",
pkTable, _pkTable));
_pkTable = pkTable;
if (_constsPK == null)
_constsPK = new LinkedHashMap();
_constsPK.put(toPK, val);
// force re-cache
_constValsPK = null;
_constColsPK = null;
}
/**
* Join a constant value to a local column of this table. The
* constant must be either a string or a number.
*/
public void joinConstant(Column col, Object val) {
if (_consts == null)
_consts = new LinkedHashMap();
_consts.put(col, val);
// force re-cache
_constVals = null;
_constCols = null;
}
/**
* Remove any joins inolving the given column.
*
* @return true if the join was removed, false if not part of the key
*/
public boolean removeJoin(Column col) {
boolean remd = false;
Object rem;
if (_joins != null) {
rem = _joins.remove(col);
col.removeConstraint(this);
if (rem != null) {
_locals = null;
_pks = null;
_joinsPK.remove(rem);
remd = true;
}
}
if (_joinsPK != null) {
rem = _joinsPK.remove(col);
if (rem != null) {
_locals = null;
_pks = null;
_joins.remove(rem);
remd = true;
}
}
if (_consts != null) {
if (_consts.remove(col) != null) {
_constVals = null;
_constCols = null;
remd = true;
}
}
if (_constsPK != null) {
if (_constsPK.containsKey(col)) {
_constsPK.remove(col);
_constValsPK = null;
_constColsPK = null;
remd = true;
}
}
if ((_joins == null || _joins.isEmpty())
&& (_constsPK == null || _constsPK.isEmpty()))
_pkTable = null;
if (remd && Boolean.TRUE.equals(_autoAssign))
_autoAssign = null;
return remd;
}
/**
* Returns the table this foreign key is linking to, if it is known yet.
*/
public Table getPrimaryKeyTable() {
return _pkTable;
}
/**
* Ref all columns in this key.
*/
public void refColumns() {
Column[] cols = getColumns();
for (Column column : cols) {
column.ref();
}
cols = getConstantColumns();
for (Column col : cols) {
col.ref();
}
}
/**
* Deref all columns in this key.
*/
public void derefColumns() {
Column[] cols = getColumns();
for (Column column : cols) {
column.deref();
}
cols = getConstantColumns();
for (Column col : cols) {
col.deref();
}
}
/**
* Foreign keys are equal if the satisfy the equality constraints of
* {@link Constraint} and they have the same local and primary key
* columns and action.
*/
public boolean equalsForeignKey(ForeignKey fk) {
if (fk == this)
return true;
if (fk == null)
return false;
if (getDeleteAction() != fk.getDeleteAction())
return false;
if (isDeferred() != fk.isDeferred())
return false;
if (!columnsMatch(fk.getColumns(), fk.getPrimaryKeyColumns()))
return false;
if (!match(getConstantColumns(), fk.getConstantColumns()))
return false;
if (!match(getConstants(), fk.getConstants()))
return false;
if (!match(getConstantPrimaryKeyColumns(),
fk.getConstantPrimaryKeyColumns()))
return false;
if (!match(getPrimaryKeyConstants(), fk.getPrimaryKeyConstants()))
return false;
return true;
}
/**
* Return true if the given local and foreign columns match those
* on this key. This can be used to find foreign keys given only
* column linking information.
*/
public boolean columnsMatch(Column[] fkCols, Column[] fkPKCols) {
return match(getColumns(), fkCols)
&& match(getPrimaryKeyColumns(), fkPKCols);
}
/**
* Checks for non-nullable local columns.
*/
public boolean hasNotNullColumns() {
Column[] columns = getColumns();
for (Column column : columns) {
if (column.isNotNull()) {
return true;
}
}
return false;
}
private static boolean match(Column[] cols, Column[] fkCols) {
if (cols.length != fkCols.length)
return false;
for (Column fkCol : fkCols)
if (!hasColumn(cols, fkCol))
return false;
return true;
}
private static boolean hasColumn(Column[] cols, Column col) {
for (Column column : cols)
if (column.getQualifiedPath().equals(col.getQualifiedPath()))
return true;
return false;
}
private static boolean match(Object[] vals, Object[] fkVals) {
if (vals.length != fkVals.length)
return false;
for (int i = 0; i < vals.length; i++)
if (!Objects.equals(vals[i], fkVals[i]))
return false;
return true;
}
/**
* Return the name of the foreignkey constraint as defined in the database.
* @deprecated
*/
@Deprecated
public String loadNameFromDB(DBDictionary dbdict, Connection conn) {
return loadIdentifierFromDB(dbdict, conn).getName();
}
public DBIdentifier loadIdentifierFromDB(DBDictionary dbdict, Connection conn) {
if( isLogical() || getTable() == null)
return DBIdentifier.NULL;
DBIdentifier retVal = DBIdentifier.NULL;
try{
Schema schema = getTable().getSchema();
ForeignKey[] fks = dbdict.getImportedKeys(conn.getMetaData(),
DBIdentifier.newCatalog(conn.getCatalog()), schema.getIdentifier(),
getTable().getIdentifier(), conn, false);
for (ForeignKey fk : fks) {
Table localtable = schema.getTable(fk.getTableIdentifier());
Table pkTable = schema.getTable(
fk.getPrimaryKeyTableIdentifier());
boolean addFK = false;
ForeignKey fkTemp = localtable.getForeignKey(
fk.getIdentifier());
if (fkTemp == null) {
addFK = true;
fkTemp = localtable.addForeignKey(
fk.getIdentifier());
fkTemp.setDeferred(fk.isDeferred());
fkTemp.setDeleteAction(fk.getDeleteAction());
}
if (fk.getColumns() == null || fk.getColumns().length == 0) {
// Singular column foreign key
if (!fkTemp.containsColumn(
localtable.getColumn(fk.getColumnIdentifier())))
fkTemp.join(localtable.getColumn(fk.getColumnIdentifier()),
pkTable.getColumn(fk.getPrimaryKeyColumnIdentifier()));
}
else {
// Add the multi-column foreign key, joining local and pk columns in
// the temporary key
Column[] locCols = fk.getColumns();
Column[] pkCols = fk.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].getIdentifier()))) {
fkTemp.join(localtable.getColumn(locCols[j].getIdentifier()),
pkTable.getColumn(pkCols[j].getIdentifier()));
}
}
}
if (equalsForeignKey(fkTemp)) {
if (addFK)
localtable.removeForeignKey(fkTemp);
retVal = fk.getIdentifier();
break;
}
if (addFK)
localtable.removeForeignKey(fkTemp);
}
} catch(Exception ex){
Log log = dbdict.getLog();
if (log.isTraceEnabled()) {
log.trace(_loc.get("except-read-fk-name"), ex);
}
}
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) {
setPrimaryKeyColumnIdentifier(DBIdentifier.NULL);
setColumnIdentifier(DBIdentifier.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 (!DBIdentifier.isEmpty(fk.getColumnIdentifier())) {
fkCol = new Column();
fkCol.setIdentifier(fk.getColumnIdentifier());
fkCol.setTableIdentifier(fk.getTableIdentifier());
fkCol.setSchemaIdentifier(fk.getSchemaIdentifier());
}
Column pkCol = null;
if (!DBIdentifier.isEmpty(fk.getPrimaryKeyColumnIdentifier())) {
pkCol = new Column();
pkCol.setIdentifier(fk.getPrimaryKeyColumnIdentifier());
pkCol.setTableIdentifier(fk.getPrimaryKeyTableIdentifier());
pkCol.setSchemaIdentifier(fk.getPrimaryKeySchemaIdentifier());
}
return new Column[] { fkCol, pkCol };
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
ForeignKey that = (ForeignKey) o;
if (_seq != that._seq) return false;
if (_delAction != that._delAction) return false;
if (_upAction != that._upAction) return false;
if (_index != that._index) return false;
if (_pkTableName != null ? !_pkTableName.equals(that._pkTableName) : that._pkTableName != null) return false;
if (_pkSchemaName != null ? !_pkSchemaName.equals(that._pkSchemaName) : that._pkSchemaName != null) return false;
if (_pkColumnName != null ? !_pkColumnName.equals(that._pkColumnName) : that._pkColumnName != null) return false;
if (_joins != null ? !_joins.equals(that._joins) : that._joins != null) return false;
if (_joinsPK != null ? !_joinsPK.equals(that._joinsPK) : that._joinsPK != null) return false;
if (_consts != null ? !_consts.equals(that._consts) : that._consts != null) return false;
if (_constsPK != null ? !_constsPK.equals(that._constsPK) : that._constsPK != null) return false;
// Probably incorrect - comparing Object[] arrays with Arrays.equals
if (!Arrays.equals(_locals, that._locals)) return false;
// Probably incorrect - comparing Object[] arrays with Arrays.equals
if (!Arrays.equals(_pks, that._pks)) return false;
// Probably incorrect - comparing Object[] arrays with Arrays.equals
if (!Arrays.equals(_constVals, that._constVals)) return false;
// Probably incorrect - comparing Object[] arrays with Arrays.equals
if (!Arrays.equals(_constCols, that._constCols)) return false;
// Probably incorrect - comparing Object[] arrays with Arrays.equals
if (!Arrays.equals(_constValsPK, that._constValsPK)) return false;
// Probably incorrect - comparing Object[] arrays with Arrays.equals
if (!Arrays.equals(_constColsPK, that._constColsPK)) return false;
if (_pkTable != null ? !_pkTable.equals(that._pkTable) : that._pkTable != null) return false;
return _autoAssign != null ? _autoAssign.equals(that._autoAssign) : that._autoAssign == null;
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (_pkTableName != null ? _pkTableName.hashCode() : 0);
result = 31 * result + (_pkSchemaName != null ? _pkSchemaName.hashCode() : 0);
result = 31 * result + (_pkColumnName != null ? _pkColumnName.hashCode() : 0);
result = 31 * result + _seq;
result = 31 * result + (_joins != null ? _joins.hashCode() : 0);
result = 31 * result + (_joinsPK != null ? _joinsPK.hashCode() : 0);
result = 31 * result + (_consts != null ? _consts.hashCode() : 0);
result = 31 * result + (_constsPK != null ? _constsPK.hashCode() : 0);
result = 31 * result + _delAction;
result = 31 * result + _upAction;
result = 31 * result + _index;
result = 31 * result + Arrays.hashCode(_locals);
result = 31 * result + Arrays.hashCode(_pks);
result = 31 * result + Arrays.hashCode(_constVals);
result = 31 * result + Arrays.hashCode(_constCols);
result = 31 * result + Arrays.hashCode(_constValsPK);
result = 31 * result + Arrays.hashCode(_constColsPK);
result = 31 * result + (_pkTable != null ? _pkTable.hashCode() : 0);
result = 31 * result + (_autoAssign != null ? _autoAssign.hashCode() : 0);
return result;
}
/*
* 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;
}
@Override
public int hashCode() {
return getFk().getIdentifier() != null ? getFk().getIdentifier().hashCode() : getFk().hashCode();
}
@Override
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().getIdentifier().equals(fk.getIdentifier())) {
return false;
}
// Assert PK table name and schema
if (!getFk().getPrimaryKeySchemaIdentifier().equals(fk.getPrimaryKeySchemaIdentifier()) ||
!getFk().getPrimaryKeyTableIdentifier().equals(fk.getPrimaryKeyTableIdentifier()) ||
!getFk().getSchemaIdentifier().equals(fk.getSchemaIdentifier()) ||
!getFk().getTableIdentifier().equals(fk.getTableIdentifier())) {
return false;
}
return true;
}
}
}