private void mergeJoinColumn(MetaDataContext context, String prefix,
Column given, Object[][] joins, int idx, Table table, ClassMapping cls,
ClassMapping rel, ForeignKeyDefaults def, boolean inversable,
boolean adapt, boolean fill) {
// default to the primary key column name if this is a pk join
DBIdentifier name = given.getIdentifier();
if (DBIdentifier.isNull(name) && given.getFlag(Column.FLAG_PK_JOIN) && cls != null) {
Column[] pks = cls.getPrimaryKeyColumns();
if (pks.length == 1)
name = pks[0].getIdentifier();
}
// if we can't adapt, then the user must at least give a column name
if (DBIdentifier.isNull(name) && !adapt && !fill)
throw new MetaDataException(_loc.get(prefix + "-no-fkcol-name",
context));
// check to see if the column isn't in the expected table; it might
// be an inverse join or a join to a base class of the target type
Table local = table;
Table foreign = rel.getTable();
boolean fullName = false;
boolean inverse = false;
if (!DBIdentifier.isNull(name)) {
QualifiedDBIdentifier path = QualifiedDBIdentifier.getPath(name);
if (!DBIdentifier.isNull(path.getObjectTableName())) {
if (DBIdentifier.isEmpty(path.getObjectTableName()))
local = foreign;
else
local = findTable(context, path.getObjectTableName(),
local, foreign, null);
fullName = true;
name = path.getIdentifier().getUnqualifiedName();
// if inverse join, then swap local and foreign tables
if (local != table) {
foreign = table;
inverse = true;
}
}
}
boolean forceInverse = !fullName && _join == JOIN_INVERSE;
if (forceInverse) {
local = foreign;
foreign = table;
inverse = true;
}
// determine target
DBIdentifier targetName = given.getTargetIdentifier();
Object target = null;
Table ttable = null;
boolean constant = false;
boolean fullTarget = false;
if (DBIdentifier.isNull(targetName) && given.getTargetField() != null) {
ClassMapping tcls = (inverse) ? cls : rel;
String fieldName = given.getTargetField();
String[] names = Normalizer.splitName(fieldName);
fullTarget = names.length > 1;
if (names.length > 1 && StringUtils.isEmpty(names[0])) {
// allow use of '.' without prefix to mean "use expected local
// cls"; but if we already inversed no need to switch again
if (!inverse)
tcls = cls;
fieldName = names[1];
} else if (names.length > 1) {
// must be class + field name
tcls = findClassMapping(context, names[0], cls, rel);
fieldName = names[1];
}
if (tcls == null)
throw new MetaDataException(_loc.get(prefix
+ "-bad-fktargetcls", context, fieldName, name));
FieldMapping field = tcls.getFieldMapping(fieldName);
if (field == null)
throw new MetaDataException(_loc.get(prefix
+ "-bad-fktargetfield", new Object[]{ context, fieldName,
name, tcls }));
if (field.getColumns().length != 1)
throw new MetaDataException(_loc.get(prefix
+ "-fktargetfield-cols", context, fieldName, name));
ttable = (field.getJoinForeignKey() != null) ? field.getTable()
: field.getDefiningMapping().getTable();
targetName = field.getColumns()[0].getIdentifier();
} else if (!DBIdentifier.isNull(targetName)) {
String targetNameStr = targetName.getName();
if (targetNameStr.charAt(0) == '\'') {
constant = true;
target = targetNameStr.substring(1, targetNameStr.length() - 1);
} else if (targetNameStr.charAt(0) == '-'
|| targetNameStr.charAt(0) == '.'