{
// Field type and instanceof type are totally incompatible, so just return false
return new BooleanLiteral(qs, mapping, true).eq(new BooleanLiteral(qs, mapping, false));
}
DatastoreContainerObject table;
try
{
if (mapping instanceof EmbeddedMapping)
{
// Field is embedded in this table
// TODO Enable instanceof on non-PC fields (currently just return "true")
return new BooleanLiteral(qs, mapping, true).eq(new BooleanLiteral(qs, mapping, true));
}
else if (mapping instanceof PersistenceCapableMapping || mapping instanceof ReferenceMapping)
{
// Field has its own table, so join to it
AbstractClassMetaData fieldCmd = qs.getStoreManager().getOMFContext().getMetaDataManager().getMetaDataForClass(
mapping.getType(), clr);
if (fieldCmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.SUBCLASS_TABLE)
{
// Field is a PC class that uses "subclass-table" inheritance strategy (and so has multiple possible tables to join to)
AbstractClassMetaData[] cmds = qs.getStoreManager().getClassesManagingTableForClass(fieldCmd, clr);
if (cmds != null)
{
// Join to the first table
// TODO Allow for all possible tables. Can we do an OR of the tables ? How ?
if (cmds.length > 1)
{
NucleusLogger.QUERY.warn(LOCALISER.msg("037006",
mapping.getMemberMetaData().getFullFieldName(), cmds[0].getFullClassName()));
}
table = qs.getStoreManager().getDatastoreClass(cmds[0].getFullClassName(), clr);
}
else
{
// No subclasses with tables to join to, so throw a user error
throw new NucleusUserException(LOCALISER.msg("037005",
mapping.getMemberMetaData().getFullFieldName()));
}
}
else
{
// Class of the field will have its own table
table = qs.getStoreManager().getDatastoreClass(mapping.getType(), clr);
}
}
else
{
table = qs.getStoreManager().getDatastoreClass(mapping.getType(), clr);
}
}
catch (ClassNotPersistenceCapableException cnpce)
{
// Field is not PersistenceCapable
// TODO Enable instanceof on non-PC fields (currently just return "true")
return new BooleanLiteral(qs, mapping, true).eq(new BooleanLiteral(qs, mapping, true));
}
// Check if the table of the field has a discriminator
IdentifierFactory idFactory = qs.getStoreManager().getIdentifierFactory();
DiscriminatorMetaData dismd = table.getDiscriminatorMetaData();
DiscriminatorMapping discriminatorMapping = (DiscriminatorMapping)table.getDiscriminatorMapping(false);
if (discriminatorMapping != null)
{
// Has a discriminator so do a join to the table of the field and apply a constraint on its discriminator
LogicSetExpression fieldTblExpr = null;
if (fieldName == null)
{
// Get the table expression for this alias
fieldTblExpr = qs.getTableExpression(te.getAlias());
}
else
{
// Using field, so our real table will have an identifier of "THIS_{fieldName}" via INNER JOIN
String fieldIdentifier = te.getAlias().getIdentifierName();
fieldIdentifier += '.' + fieldName;
DatastoreIdentifier fieldRangeVar = idFactory.newIdentifier(IdentifierType.TABLE, fieldIdentifier);
fieldTblExpr = qs.getTableExpression(fieldRangeVar);
if (fieldTblExpr == null)
{
fieldTblExpr = qs.newTableExpression(table, fieldRangeVar);
}
ScalarExpression fieldExpr = table.getIDMapping().newScalarExpression(qs, fieldTblExpr);
expr = mapping.newScalarExpression(qs, te);
qs.innerJoin(fieldExpr, expr, fieldTblExpr, true, true);
}
// Return a constraint on the discriminator for this table to get the right instances
// This allows all discriminator values for the instanceof class and all of its subclasses
// DISCRIM = 'baseVal' OR DISCRIM = 'sub1Val' OR DISCRIM = 'sub2Val' ... etc
BooleanExpression discrExpr =
booleanConditionForClassInDiscriminator(qs, instanceofClass.getName(), dismd,
discriminatorMapping, fieldTblExpr);
Iterator subclassIter = qs.getStoreManager().getSubClassesForClass(instanceofClass.getName(),
true, clr).iterator();
while (subclassIter.hasNext())
{
String subCandidateType = (String)subclassIter.next();
discrExpr.ior(booleanConditionForClassInDiscriminator(qs, subCandidateType, dismd,
discriminatorMapping, fieldTblExpr));
}
discrExpr.encloseWithInParentheses();
return discrExpr;
}
else
{
// No discriminator so maybe union, or just a SELECT
// Need to join to the instanceof class (where appropriate)
// TODO RDBMS-71 Only join on the UNION select that it is applicable to
if (table instanceof DatastoreClass)
{
DatastoreClass ct = (DatastoreClass)table;
if (ct.managesClass(instanceofClass.getName()))
{
// This type is managed in this table so must be an instance
return new BooleanLiteral(qs, mapping, true).eq(new BooleanLiteral(qs, mapping, true));
}
else
{
// The instanceof type is not managed here
DatastoreClass instanceofTable = qs.getStoreManager().getDatastoreClass(
instanceofClass.getName(), clr);
String fieldIdentifier = te.getAlias().getIdentifierName();
if (fieldName == null)
{
// Using THIS, so our real table will have an identifier of "THIS_INST"
fieldIdentifier += ".INST";
}
else
{
// Using field, so our real table will have an identifier of "THIS_{fieldName}"
fieldIdentifier += '.' + fieldName;
}
DatastoreIdentifier fieldRangeVar = idFactory.newIdentifier(IdentifierType.TABLE, fieldIdentifier);
LogicSetExpression fieldTblExpr = qs.newTableExpression(instanceofTable, fieldRangeVar);
ScalarExpression fieldExpr = table.getIDMapping().newScalarExpression(qs, te);
if (fieldName == null)
{
expr = instanceofTable.getIDMapping().newScalarExpression(qs, fieldTblExpr);
}
else