*/
protected void compileFromClassExpression(ClassExpression clsExpr)
{
Symbol clsExprSym = clsExpr.getSymbol();
Class baseCls = (clsExprSym != null ? clsExprSym.getValueType() : null);
SQLTable candSqlTbl = stmt.getPrimaryTable();
MetaDataManager mmgr = storeMgr.getMetaDataManager();
AbstractClassMetaData cmd = mmgr.getMetaDataForClass(baseCls, clr);
if (baseCls != null && baseCls != compilation.getCandidateClass())
{
// Not candidate class so must be cross join (JPA spec 4.4.5)
DatastoreClass candTbl = storeMgr.getDatastoreClass(baseCls.getName(), clr);
candSqlTbl = stmt.crossJoin(candTbl, clsExpr.getAlias(), null);
SQLTableMapping tblMapping = new SQLTableMapping(candSqlTbl, cmd, candTbl.getIdMapping());
setSQLTableMappingForAlias(clsExpr.getAlias(), tblMapping);
}
if (clsExpr.getCandidateExpression() != null && parentMapper != null)
{
// User defined the candidate of the subquery as an implied join to the outer query
// e.g SELECT c FROM Customer c WHERE EXISTS (SELECT o FROM c.orders o ...)
// so add the join(s) to the outer query
String[] tokens = StringUtils.split(clsExpr.getCandidateExpression(), ".");
String leftAlias = tokens[0];
SQLTableMapping outerSqlTblMapping = parentMapper.getSQLTableMappingForAlias(leftAlias);
AbstractClassMetaData leftCmd = outerSqlTblMapping.cmd;
// Get array of the left-right sides of this expression so we can work back from the subquery candidate
AbstractMemberMetaData[] leftMmds = new AbstractMemberMetaData[tokens.length-1];
AbstractMemberMetaData[] rightMmds = new AbstractMemberMetaData[tokens.length-1];
for (int i=0;i<tokens.length-1;i++)
{
String joinedField = tokens[i+1];
AbstractMemberMetaData leftMmd = leftCmd.getMetaDataForMember(joinedField);
AbstractMemberMetaData rightMmd = null;
AbstractClassMetaData rightCmd = null;
int relationType = leftMmd.getRelationType(clr);
switch (relationType)
{
case Relation.ONE_TO_ONE_BI :
case Relation.ONE_TO_MANY_BI :
case Relation.MANY_TO_ONE_BI :
case Relation.MANY_TO_MANY_BI :
rightMmd = leftMmd.getRelatedMemberMetaData(clr)[0]; // Take first possible
rightCmd = rightMmd.getAbstractClassMetaData();
break;
case Relation.ONE_TO_ONE_UNI :
rightCmd = mmgr.getMetaDataForClass(leftMmd.getType(), clr);
rightMmd = null;
break;
case Relation.ONE_TO_MANY_UNI :
if (leftMmd.hasCollection())
{
rightCmd = mmgr.getMetaDataForClass(leftMmd.getCollection().getElementType(), clr);
}
else if (leftMmd.hasMap())
{
rightCmd = mmgr.getMetaDataForClass(leftMmd.getMap().getValueType(), clr);
}
break;
default :
throw new NucleusUserException(
"Subquery has been specified with a candidate-expression that" +
" includes \"" + tokens[i] + "\" that isnt a relation field!!");
}
leftMmds[i] = leftMmd;
rightMmds[i] = rightMmd;
leftCmd = rightCmd;
}
// Work from subquery candidate back to outer query table, adding joins and where clause as appropriate
SQLTable rSqlTbl = candSqlTbl;
SQLTable outerSqlTbl = outerSqlTblMapping.table;
for (int i=leftMmds.length-1;i>=0;i--)
{
AbstractMemberMetaData leftMmd = leftMmds[i];
AbstractMemberMetaData rightMmd = rightMmds[i];
DatastoreClass leftTbl = storeMgr.getDatastoreClass(leftMmd.getClassName(true), clr);
SQLTable lSqlTbl = null;
int relationType = leftMmd.getRelationType(clr);
switch (relationType)
{
case Relation.ONE_TO_ONE_UNI:
{
// 1-1 with FK in left table
if (i == 0)
{
// Add where clause right table to outer table
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(),
outerSqlTbl, outerSqlTbl.getTable().getMemberMapping(leftMmd));
SQLExpression rightExpr = exprFactory.newExpression(stmt,
rSqlTbl, rSqlTbl.getTable().getIdMapping());
stmt.whereAnd(outerExpr.eq(rightExpr), false);
}
else
{
// Join to left table
JavaTypeMapping leftMapping = leftTbl.getMemberMapping(leftMmd);
lSqlTbl = stmt.innerJoin(rSqlTbl, rSqlTbl.getTable().getIdMapping(),
leftTbl, null, leftMapping, null, null);
}
break;
}
case Relation.ONE_TO_ONE_BI:
{
if (leftMmd.getMappedBy() != null)
{
// 1-1 with FK in right table
JavaTypeMapping rightMapping = rSqlTbl.getTable().getMemberMapping(rightMmd);
if (i == 0)
{
// Add where clause right table to outer table
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(),
outerSqlTbl, outerSqlTbl.getTable().getIdMapping());
SQLExpression rightExpr = exprFactory.newExpression(stmt,
rSqlTbl, rightMapping);
stmt.whereAnd(outerExpr.eq(rightExpr), false);
}
else
{
// Join to left table
lSqlTbl = stmt.innerJoin(rSqlTbl, rightMapping,
leftTbl, null, leftTbl.getIdMapping(), null, null);
}
}
else
{
// 1-1 with FK in left table
if (i == 0)
{
// Add where clause right table to outer table
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(),
outerSqlTbl, outerSqlTbl.getTable().getMemberMapping(leftMmd));
SQLExpression rightExpr = exprFactory.newExpression(stmt,
rSqlTbl, rSqlTbl.getTable().getIdMapping());
stmt.whereAnd(outerExpr.eq(rightExpr), false);
}
else
{
// Join to left table
lSqlTbl = stmt.innerJoin(rSqlTbl, rSqlTbl.getTable().getIdMapping(),
leftTbl, null, leftTbl.getMemberMapping(leftMmd), null, null);
}
}
break;
}
case Relation.ONE_TO_MANY_UNI:
{
if (leftMmd.getJoinMetaData() != null || rightMmd.getJoinMetaData() != null)
{
// 1-N with join table to right table, so join from right to join table
ElementContainerTable joinTbl =
(ElementContainerTable)storeMgr.getDatastoreContainerObject(leftMmd);
SQLTable joinSqlTbl = stmt.innerJoin(rSqlTbl, rSqlTbl.getTable().getIdMapping(),
joinTbl, null, joinTbl.getElementMapping(), null, null);
if (i == 0)
{
// Add where clause join table to outer table
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(),
outerSqlTbl, outerSqlTbl.getTable().getMemberMapping(leftMmd));
SQLExpression joinExpr = exprFactory.newExpression(stmt,
joinSqlTbl, joinTbl.getOwnerMapping());
stmt.whereAnd(outerExpr.eq(joinExpr), false);
}
else
{
// Join to left table
lSqlTbl = stmt.innerJoin(joinSqlTbl, joinTbl.getOwnerMapping(),
leftTbl, null, leftTbl.getIdMapping(), null, null);
}
}
else
{
// 1-N with FK in right table
if (i == 0)
{
// Add where clause right table to outer table
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(),
outerSqlTbl, outerSqlTbl.getTable().getMemberMapping(leftMmd));
SQLExpression rightExpr = exprFactory.newExpression(stmt,
rSqlTbl, rSqlTbl.getTable().getMemberMapping(rightMmd));
stmt.whereAnd(outerExpr.eq(rightExpr), false);
}
else
{
// Join to left table
lSqlTbl = stmt.innerJoin(rSqlTbl, rSqlTbl.getTable().getMemberMapping(rightMmd),
leftTbl, null, leftTbl.getIdMapping(), null, null);
}
}
break;
}
case Relation.ONE_TO_MANY_BI:
{
if (leftMmd.getJoinMetaData() != null || rightMmd.getJoinMetaData() != null)
{
// 1-N with join table to right table, so join from right to join table
ElementContainerTable joinTbl =
(ElementContainerTable)storeMgr.getDatastoreContainerObject(leftMmd);
SQLTable joinSqlTbl = stmt.innerJoin(rSqlTbl, rSqlTbl.getTable().getIdMapping(),
joinTbl, null, joinTbl.getElementMapping(), null, null);
if (i == 0)
{
// Add where clause join table to outer table
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(),
outerSqlTbl, outerSqlTbl.getTable().getMemberMapping(leftMmd));
SQLExpression joinExpr = exprFactory.newExpression(stmt,
joinSqlTbl, joinTbl.getOwnerMapping());
stmt.whereAnd(outerExpr.eq(joinExpr), false);
}
else
{
// Join to left table
lSqlTbl = stmt.innerJoin(joinSqlTbl, joinTbl.getOwnerMapping(),
leftTbl, null, leftTbl.getIdMapping(), null, null);
}
}
else
{
// 1-N with FK in right table
if (i == 0)
{
// Add where clause right table to outer table
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(),
outerSqlTbl, outerSqlTbl.getTable().getIdMapping());
SQLExpression rightExpr = exprFactory.newExpression(stmt,
rSqlTbl, rSqlTbl.getTable().getMemberMapping(rightMmd));
stmt.whereAnd(outerExpr.eq(rightExpr), false);
}
else
{
// Join to left table
lSqlTbl = stmt.innerJoin(rSqlTbl, rSqlTbl.getTable().getMemberMapping(rightMmd),
leftTbl, null, leftTbl.getIdMapping(), null, null);
}
}
break;
}
case Relation.MANY_TO_ONE_BI:
{
if (leftMmd.getJoinMetaData() != null || rightMmd.getJoinMetaData() != null)
{
// 1-N with join table to right table, so join from right to join table
ElementContainerTable joinTbl =
(ElementContainerTable)storeMgr.getDatastoreContainerObject(leftMmd);
SQLTable joinSqlTbl = stmt.innerJoin(rSqlTbl, rSqlTbl.getTable().getIdMapping(),
joinTbl, null, joinTbl.getOwnerMapping(), null, null);
if (i == 0)
{
// Add where clause join table to outer table
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(),
outerSqlTbl, outerSqlTbl.getTable().getMemberMapping(leftMmd));
SQLExpression joinExpr = exprFactory.newExpression(stmt,
joinSqlTbl, joinTbl.getElementMapping());
stmt.whereAnd(outerExpr.eq(joinExpr), false);
}
else
{
// Join to left table
lSqlTbl = stmt.innerJoin(joinSqlTbl, joinTbl.getElementMapping(),
leftTbl, null, leftTbl.getIdMapping(), null, null);
}
}
else
{
if (i == 0)
{
// Add where clause right table to outer table
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(),
outerSqlTbl, outerSqlTbl.getTable().getMemberMapping(leftMmd));
SQLExpression rightExpr = exprFactory.newExpression(stmt,
rSqlTbl, rSqlTbl.getTable().getIdMapping());
stmt.whereAnd(outerExpr.eq(rightExpr), false);
}
else
{
// Join to left table
lSqlTbl = stmt.innerJoin(rSqlTbl, rSqlTbl.getTable().getIdMapping(),
leftTbl, null, leftTbl.getMemberMapping(leftMmd), null, null);
}
}
}
default:
break;
}
rSqlTbl = lSqlTbl;
}
}
// Process all join expressions
Expression rightExpr = clsExpr.getRight();
SQLTable sqlTbl = candSqlTbl;
while (rightExpr != null)
{
if (rightExpr instanceof JoinExpression)
{
JoinExpression joinExpr = (JoinExpression)rightExpr;
JoinType joinType = joinExpr.getType();
String joinAlias = joinExpr.getAlias();
PrimaryExpression joinPrimExpr = joinExpr.getPrimaryExpression();
Iterator<String> iter = joinPrimExpr.getTuples().iterator();
String rootId = iter.next();
String joinTableGroupName = null;
if (rootId.equalsIgnoreCase(candidateAlias))
{
// Join relative to the candidate
// Name table group of joined-to as per the relation
// Note : this will only work for one level out from the candidate TODO Extend this
joinTableGroupName = joinPrimExpr.getId();
}
else
{
// Join relative to some other alias
SQLTableMapping sqlTblMapping = getSQLTableMappingForAlias(rootId);
if (sqlTblMapping != null)
{
cmd = sqlTblMapping.cmd;
joinTableGroupName = sqlTblMapping.table.getGroupName();
sqlTbl = sqlTblMapping.table;
}
else
{
throw new NucleusUserException("Query has " + joinPrimExpr.getId() + " yet the first component "+
rootId + " is unknown!");
}
}
while (iter.hasNext())
{
String id = iter.next();
AbstractMemberMetaData mmd = cmd.getMetaDataForMember(id);
int relationType = mmd.getRelationType(clr);
DatastoreClass relTable = null;
AbstractMemberMetaData relMmd = null;
// TODO Cater for map in 1-N relations?
switch (relationType)
{
case Relation.ONE_TO_ONE_UNI:
relTable = storeMgr.getDatastoreClass(mmd.getTypeName(), clr);
cmd = mmgr.getMetaDataForClass(mmd.getType(), clr);
if (joinType == JoinType.JOIN_INNER || joinType == JoinType.JOIN_INNER_FETCH)
{
sqlTbl = stmt.innerJoin(sqlTbl, sqlTbl.getTable().getMemberMapping(mmd),
relTable, null, relTable.getIdMapping(), null, joinTableGroupName);
}
else
{
sqlTbl = stmt.leftOuterJoin(sqlTbl, sqlTbl.getTable().getMemberMapping(mmd),
relTable, null, relTable.getIdMapping(), null, joinTableGroupName);
}
break;
case Relation.ONE_TO_ONE_BI:
relTable = storeMgr.getDatastoreClass(mmd.getTypeName(), clr);
cmd = storeMgr.getMetaDataManager().getMetaDataForClass(mmd.getType(), clr);
if (mmd.getMappedBy() != null)
{
relMmd = mmd.getRelatedMemberMetaData(clr)[0];
if (joinType == JoinType.JOIN_INNER || joinType == JoinType.JOIN_INNER_FETCH)
{
sqlTbl = stmt.innerJoin(sqlTbl, sqlTbl.getTable().getIdMapping(),
relTable, null, relTable.getMemberMapping(relMmd), null, joinTableGroupName);
}
else
{
sqlTbl = stmt.leftOuterJoin(sqlTbl, sqlTbl.getTable().getIdMapping(),
relTable, null, relTable.getMemberMapping(relMmd), null, joinTableGroupName);
}
}
else
{
if (joinType == JoinType.JOIN_INNER || joinType == JoinType.JOIN_INNER_FETCH)
{
sqlTbl = stmt.innerJoin(sqlTbl, sqlTbl.getTable().getMemberMapping(mmd), relTable, null,
relTable.getIdMapping(), null, joinTableGroupName);
}
else
{
sqlTbl = stmt.leftOuterJoin(sqlTbl, sqlTbl.getTable().getMemberMapping(mmd), relTable, null,
relTable.getIdMapping(), null, joinTableGroupName);
}
}
break;
case Relation.ONE_TO_MANY_BI:
relTable = storeMgr.getDatastoreClass(mmd.getCollection().getElementType(), clr);
cmd = mmd.getCollection().getElementClassMetaData(clr, mmgr);
relMmd = mmd.getRelatedMemberMetaData(clr)[0];
if (mmd.getJoinMetaData() != null || relMmd.getJoinMetaData() != null)
{
// Join to join table, then to related table
ElementContainerTable joinTbl = (ElementContainerTable)storeMgr.getDatastoreContainerObject(mmd);
if (joinType == JoinType.JOIN_INNER || joinType == JoinType.JOIN_INNER_FETCH)
{
SQLTable joinSqlTbl = stmt.innerJoin(sqlTbl, sqlTbl.getTable().getIdMapping(),
joinTbl, null, joinTbl.getOwnerMapping(), null, null);
sqlTbl = stmt.innerJoin(joinSqlTbl, joinTbl.getElementMapping(),
relTable, null, relTable.getIdMapping(), null, joinTableGroupName);
}
else
{
SQLTable joinSqlTbl = stmt.leftOuterJoin(sqlTbl, sqlTbl.getTable().getIdMapping(),
joinTbl, null, joinTbl.getOwnerMapping(), null, null);
sqlTbl = stmt.leftOuterJoin(joinSqlTbl, joinTbl.getElementMapping(),
relTable, null, relTable.getIdMapping(), null, joinTableGroupName);
}
}
else
{
// Join to related table
if (joinType == JoinType.JOIN_INNER || joinType == JoinType.JOIN_INNER_FETCH)
{
sqlTbl = stmt.innerJoin(sqlTbl, sqlTbl.getTable().getIdMapping(),
relTable, null, relTable.getMemberMapping(relMmd), null, joinTableGroupName);
}
else
{
sqlTbl = stmt.leftOuterJoin(sqlTbl, sqlTbl.getTable().getIdMapping(),
relTable, null, relTable.getMemberMapping(relMmd), null, joinTableGroupName);
}
}
break;
case Relation.ONE_TO_MANY_UNI:
relTable = storeMgr.getDatastoreClass(mmd.getCollection().getElementType(), clr);
cmd = mmd.getCollection().getElementClassMetaData(clr, mmgr);
if (mmd.getJoinMetaData() != null)
{
// Join to join table, then to related table
ElementContainerTable joinTbl = (ElementContainerTable)storeMgr.getDatastoreContainerObject(mmd);
if (joinType == JoinType.JOIN_INNER || joinType == JoinType.JOIN_INNER_FETCH)
{
SQLTable joinSqlTbl = stmt.innerJoin(sqlTbl, sqlTbl.getTable().getIdMapping(),
joinTbl, null, joinTbl.getOwnerMapping(), null, null);
sqlTbl = stmt.innerJoin(joinSqlTbl, joinTbl.getElementMapping(),
relTable, null, relTable.getIdMapping(), null, joinTableGroupName);
}
else
{
SQLTable joinSqlTbl = stmt.leftOuterJoin(sqlTbl, sqlTbl.getTable().getIdMapping(),
joinTbl, null, joinTbl.getOwnerMapping(), null, null);
sqlTbl = stmt.leftOuterJoin(joinSqlTbl, joinTbl.getElementMapping(),
relTable, null, relTable.getIdMapping(), null, joinTableGroupName);
}
}
else
{
// Join to related table
JavaTypeMapping relMapping = relTable.getExternalMapping(mmd, MappingConsumer.MAPPING_TYPE_EXTERNAL_FK);
if (joinType == JoinType.JOIN_INNER || joinType == JoinType.JOIN_INNER_FETCH)
{
sqlTbl = stmt.innerJoin(sqlTbl, sqlTbl.getTable().getIdMapping(),
relTable, null, relMapping, null, joinTableGroupName);
}
else
{
sqlTbl = stmt.leftOuterJoin(sqlTbl, sqlTbl.getTable().getIdMapping(),
relTable, null, relMapping, null, joinTableGroupName);
}
}
break;
case Relation.MANY_TO_MANY_BI:
relTable = storeMgr.getDatastoreClass(mmd.getCollection().getElementType(), clr);
cmd = mmd.getCollection().getElementClassMetaData(clr, mmgr);
relMmd = mmd.getRelatedMemberMetaData(clr)[0];
// Join to join table, then to related table
CollectionTable joinTbl = (CollectionTable)storeMgr.getDatastoreContainerObject(mmd);
if (joinType == JoinType.JOIN_INNER || joinType == JoinType.JOIN_INNER_FETCH)
{
SQLTable joinSqlTbl = stmt.innerJoin(sqlTbl, sqlTbl.getTable().getIdMapping(),
joinTbl, null, joinTbl.getOwnerMapping(), null, null);
sqlTbl = stmt.innerJoin(joinSqlTbl, joinTbl.getElementMapping(),
relTable, null, relTable.getIdMapping(), null, joinTableGroupName);
}
else
{
SQLTable joinSqlTbl = stmt.leftOuterJoin(sqlTbl, sqlTbl.getTable().getIdMapping(),
joinTbl, null, joinTbl.getOwnerMapping(), null, null);
sqlTbl = stmt.leftOuterJoin(joinSqlTbl, joinTbl.getElementMapping(),
relTable, null, relTable.getIdMapping(), null, joinTableGroupName);
}
break;
case Relation.MANY_TO_ONE_BI:
relTable = storeMgr.getDatastoreClass(mmd.getTypeName(), clr);
cmd = storeMgr.getMetaDataManager().getMetaDataForClass(mmd.getType(), clr);
relMmd = mmd.getRelatedMemberMetaData(clr)[0];
if (mmd.getJoinMetaData() != null || relMmd.getJoinMetaData() != null)
{
// Join to join table, then to related table
joinTbl = (CollectionTable)storeMgr.getDatastoreContainerObject(relMmd);
if (joinType == JoinType.JOIN_INNER || joinType == JoinType.JOIN_INNER_FETCH)
{
SQLTable joinSqlTbl = stmt.innerJoin(sqlTbl, sqlTbl.getTable().getIdMapping(),
joinTbl, null, joinTbl.getElementMapping(), null, null);
sqlTbl = stmt.innerJoin(joinSqlTbl, joinTbl.getOwnerMapping(),
relTable, null, relTable.getIdMapping(), null, joinTableGroupName);
}
else
{
SQLTable joinSqlTbl = stmt.leftOuterJoin(sqlTbl, sqlTbl.getTable().getIdMapping(),
joinTbl, null, joinTbl.getElementMapping(), null, null);
sqlTbl = stmt.leftOuterJoin(joinSqlTbl, joinTbl.getOwnerMapping(),
relTable, null, relTable.getIdMapping(), null, joinTableGroupName);
}
}