use of org.datanucleus.store.rdbms.sql.SQLJoin.JoinType in project datanucleus-rdbms by datanucleus.
the class QueryToSQLMapper method processFromClauseSubquery.
/**
* Method to process a ClassExpression where it represents a subquery.
* User defined the candidate of the subquery as an implied join to the outer query, for example "SELECT c FROM Customer c WHERE EXISTS (SELECT o FROM c.orders o ...)"
* so this method will add the join(s) to the outer query.
* @param clsExpr The ClassExpression
* @param candSqlTbl Candidate SQL Table
* @param mmgr MetaData Manager
*/
protected void processFromClauseSubquery(ClassExpression clsExpr, SQLTable candSqlTbl, MetaDataManager mmgr) {
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;
RelationType relationType = leftMmd.getRelationType(clr);
if (RelationType.isBidirectional(relationType)) {
// Take first possible
rightMmd = leftMmd.getRelatedMemberMetaData(clr)[0];
rightCmd = rightMmd.getAbstractClassMetaData();
} else if (relationType == RelationType.ONE_TO_ONE_UNI) {
rightCmd = mmgr.getMetaDataForClass(leftMmd.getType(), clr);
} else if (relationType == RelationType.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);
}
} else {
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;
JoinType joinType = JoinType.INNER_JOIN;
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;
RelationType relationType = leftMmd.getRelationType(clr);
if (relationType == RelationType.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.join(joinType, rSqlTbl, rSqlTbl.getTable().getIdMapping(), leftTbl, null, leftMapping, null, null, true);
}
} else if (relationType == RelationType.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.join(joinType, rSqlTbl, rightMapping, leftTbl, null, leftTbl.getIdMapping(), null, null, true);
}
} 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.join(joinType, rSqlTbl, rSqlTbl.getTable().getIdMapping(), leftTbl, null, leftTbl.getMemberMapping(leftMmd), null, null, true);
}
}
} else if (relationType == RelationType.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
JoinTable joinTbl = (JoinTable) storeMgr.getTable(leftMmd);
SQLTable joinSqlTbl = null;
if (leftMmd.hasCollection()) {
joinSqlTbl = stmt.join(joinType, rSqlTbl, rSqlTbl.getTable().getIdMapping(), joinTbl, null, ((ElementContainerTable) joinTbl).getElementMapping(), null, null, true);
} else if (leftMmd.hasMap()) {
joinSqlTbl = stmt.join(joinType, rSqlTbl, rSqlTbl.getTable().getIdMapping(), joinTbl, null, ((MapTable) joinTbl).getValueMapping(), null, null, true);
}
if (i == 0) {
// Add where clause join table (owner) to outer table (id)
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(), outerSqlTbl, outerSqlTbl.getTable().getIdMapping());
SQLExpression joinExpr = exprFactory.newExpression(stmt, joinSqlTbl, joinTbl.getOwnerMapping());
stmt.whereAnd(outerExpr.eq(joinExpr), false);
} else {
// Join to left table
lSqlTbl = stmt.join(joinType, joinSqlTbl, joinTbl.getOwnerMapping(), leftTbl, null, leftTbl.getIdMapping(), null, null, true);
}
} 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.join(joinType, rSqlTbl, rSqlTbl.getTable().getMemberMapping(rightMmd), leftTbl, null, leftTbl.getIdMapping(), null, null, true);
}
}
} else if (relationType == RelationType.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
JoinTable joinTbl = (JoinTable) storeMgr.getTable(leftMmd);
SQLTable joinSqlTbl = null;
if (leftMmd.hasCollection()) {
joinSqlTbl = stmt.join(joinType, rSqlTbl, rSqlTbl.getTable().getIdMapping(), joinTbl, null, ((ElementContainerTable) joinTbl).getElementMapping(), null, null, true);
} else if (leftMmd.hasMap()) {
joinSqlTbl = stmt.join(joinType, rSqlTbl, rSqlTbl.getTable().getIdMapping(), joinTbl, null, ((MapTable) joinTbl).getValueMapping(), null, null, true);
}
if (i == 0) {
// Add where clause join table (owner) to outer table (id)
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(), outerSqlTbl, outerSqlTbl.getTable().getIdMapping());
SQLExpression joinExpr = exprFactory.newExpression(stmt, joinSqlTbl, joinTbl.getOwnerMapping());
stmt.whereAnd(outerExpr.eq(joinExpr), false);
} else {
// Join to left table
lSqlTbl = stmt.join(joinType, joinSqlTbl, joinTbl.getOwnerMapping(), leftTbl, null, leftTbl.getIdMapping(), null, null, true);
}
} 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.join(joinType, rSqlTbl, rSqlTbl.getTable().getMemberMapping(rightMmd), leftTbl, null, leftTbl.getIdMapping(), null, null, true);
}
}
} else if (relationType == RelationType.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
JoinTable joinTbl = (JoinTable) storeMgr.getTable(leftMmd);
SQLTable joinSqlTbl = stmt.join(joinType, rSqlTbl, rSqlTbl.getTable().getIdMapping(), joinTbl, null, joinTbl.getOwnerMapping(), null, null, true);
if (leftMmd.hasCollection()) {
if (i == 0) {
// Add where clause join table (element) to outer table (id)
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(), outerSqlTbl, outerSqlTbl.getTable().getIdMapping());
SQLExpression joinExpr = exprFactory.newExpression(stmt, joinSqlTbl, ((ElementContainerTable) joinTbl).getElementMapping());
stmt.whereAnd(outerExpr.eq(joinExpr), false);
} else {
// Join to left table
lSqlTbl = stmt.join(joinType, joinSqlTbl, ((ElementContainerTable) joinTbl).getElementMapping(), leftTbl, null, leftTbl.getIdMapping(), null, null, true);
}
} else if (leftMmd.hasMap()) {
if (i == 0) {
// Add where clause join table (value) to outer table (id)
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(), outerSqlTbl, outerSqlTbl.getTable().getIdMapping());
SQLExpression joinExpr = exprFactory.newExpression(stmt, joinSqlTbl, ((MapTable) joinTbl).getValueMapping());
stmt.whereAnd(outerExpr.eq(joinExpr), false);
} else {
// Join to left table
lSqlTbl = stmt.join(joinType, joinSqlTbl, ((MapTable) joinTbl).getValueMapping(), leftTbl, null, leftTbl.getIdMapping(), null, null, true);
}
}
} 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.join(joinType, rSqlTbl, rSqlTbl.getTable().getIdMapping(), leftTbl, null, leftTbl.getMemberMapping(leftMmd), null, null, true);
}
}
}
rSqlTbl = lSqlTbl;
}
}
use of org.datanucleus.store.rdbms.sql.SQLJoin.JoinType in project datanucleus-rdbms by datanucleus.
the class QueryToSQLMapper method getSQLTableMappingForPrimaryExpression.
/**
* Method to take in a PrimaryExpression and return the SQLTable mapping info that it signifies.
* If the primary expression implies joining to other objects then adds the joins to the statement.
* Only adds joins if necessary; so if there is a further component after the required join, or if
* the "forceJoin" flag is set.
* @param theStmt SQLStatement to use when looking for tables etc
* @param exprName Name for an expression that this primary is relative to (optional)
* If not specified then the tuples are relative to the candidate.
* If specified then should have an entry in sqlTableByPrimary under this name.
* @param primExpr The primary expression
* @param forceJoin Whether to force a join if a relation member (or null if leaving to this method to decide)
* @return The SQL table mapping information for the specified primary
*/
private SQLTableMapping getSQLTableMappingForPrimaryExpression(SQLStatement theStmt, String exprName, PrimaryExpression primExpr, Boolean forceJoin) {
if (forceJoin == null && primExpr.getParent() != null) {
if (primExpr.getParent().getOperator() == Expression.OP_IS || primExpr.getParent().getOperator() == Expression.OP_ISNOT) {
// "instanceOf" needs to be in the table of the primary expression
forceJoin = Boolean.TRUE;
}
}
SQLTableMapping sqlMapping = null;
List<String> tuples = primExpr.getTuples();
// Find source object
ListIterator<String> iter = tuples.listIterator();
String first = tuples.get(0);
boolean mapKey = false;
boolean mapValue = false;
if (first.endsWith("#KEY")) {
first = first.substring(0, first.length() - 4);
mapKey = true;
} else if (first.endsWith("#VALUE")) {
first = first.substring(0, first.length() - 6);
mapValue = true;
}
String primaryName = null;
if (exprName != null) {
// Primary relative to some object etc
sqlMapping = getSQLTableMappingForAlias(exprName);
primaryName = exprName;
} else {
if (hasSQLTableMappingForAlias(first)) {
// Start from a candidate (e.g JPQL alias)
sqlMapping = getSQLTableMappingForAlias(first);
primaryName = first;
// Skip first tuple
iter.next();
}
if (sqlMapping != null && first.equals(candidateAlias) && candidateCmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.COMPLETE_TABLE) {
// Special case of using COMPLETE_TABLE for candidate and picked wrong table
// TODO Use OPTION_CASE_INSENSITIVE
SQLTable firstSqlTbl = stmt.getTable(first.toUpperCase());
if (firstSqlTbl != null && firstSqlTbl.getTable() != sqlMapping.table.getTable()) {
// Cached the SQLTableMapping for one of the other inherited classes, so create our own
sqlMapping = new SQLTableMapping(firstSqlTbl, sqlMapping.cmd, firstSqlTbl.getTable().getIdMapping());
}
}
if (sqlMapping == null) {
if (parentMapper != null) {
QueryToSQLMapper theParentMapper = parentMapper;
while (theParentMapper != null) {
if (theParentMapper.hasSQLTableMappingForAlias(first)) {
// Try parent query
sqlMapping = theParentMapper.getSQLTableMappingForAlias(first);
primaryName = first;
// Skip first tuple
iter.next();
// This expression is for the parent statement so any joins need to go on that statement
theStmt = sqlMapping.table.getSQLStatement();
break;
}
theParentMapper = theParentMapper.parentMapper;
}
}
}
if (sqlMapping == null) {
// Field of candidate, so use candidate
sqlMapping = getSQLTableMappingForAlias(candidateAlias);
primaryName = candidateAlias;
}
}
AbstractClassMetaData cmd = sqlMapping.cmd;
JavaTypeMapping mapping = sqlMapping.mapping;
if (sqlMapping.mmd != null && (mapKey || mapValue)) {
// Special case of MAP#KEY or MAP#VALUE, so navigate from the Map "table" to the key or value
SQLTable sqlTbl = sqlMapping.table;
AbstractMemberMetaData mmd = sqlMapping.mmd;
MapMetaData mapmd = mmd.getMap();
// Find the table forming the Map. This may be a join table, or the key or value depending on the type
if (mapKey) {
// Cater for all case possibilities of table name/alias
// TODO Use OPTION_CASE_INSENSITIVE
SQLTable mapSqlTbl = stmt.getTable(first + "_MAP");
if (mapSqlTbl == null) {
mapSqlTbl = stmt.getTable((first + "_MAP").toUpperCase());
if (mapSqlTbl == null) {
mapSqlTbl = stmt.getTable((first + "_MAP").toLowerCase());
}
}
if (mapSqlTbl != null) {
sqlTbl = mapSqlTbl;
}
}
if (mapmd.getMapType() == MapType.MAP_TYPE_JOIN) {
if (sqlTbl.getTable() instanceof MapTable) {
MapTable mapTable = (MapTable) sqlTbl.getTable();
if (mapKey) {
cmd = mapmd.getKeyClassMetaData(clr);
if (!mapmd.isEmbeddedKey() && !mapmd.isSerializedKey()) {
// Join to key table
DatastoreClass keyTable = storeMgr.getDatastoreClass(mapmd.getKeyType(), clr);
sqlTbl = stmt.join(getDefaultJoinTypeForNavigation(), sqlMapping.table, mapTable.getKeyMapping(), keyTable, null, keyTable.getIdMapping(), null, null, true);
mapping = keyTable.getIdMapping();
} else {
mapping = mapTable.getKeyMapping();
}
} else {
cmd = mapmd.getValueClassMetaData(clr);
if (!mapmd.isEmbeddedValue() && !mapmd.isSerializedValue()) {
// Join to value table
DatastoreClass valueTable = storeMgr.getDatastoreClass(mapmd.getValueType(), clr);
sqlTbl = stmt.join(getDefaultJoinTypeForNavigation(), sqlMapping.table, mapTable.getValueMapping(), valueTable, null, valueTable.getIdMapping(), null, null, true);
mapping = valueTable.getIdMapping();
} else {
mapping = mapTable.getValueMapping();
}
}
} else {
// TODO Document exactly which situation this is
if (!mapmd.isEmbeddedValue() && !mapmd.isSerializedValue()) {
mapping = sqlTbl.getTable().getIdMapping();
}
}
} else if (mapmd.getMapType() == MapType.MAP_TYPE_KEY_IN_VALUE) {
if (mapKey) {
AbstractClassMetaData keyCmd = mapmd.getKeyClassMetaData(clr);
String keyMappedBy = mmd.getKeyMetaData().getMappedBy();
mapping = ((DatastoreClass) sqlTbl.getTable()).getMemberMapping(keyMappedBy);
if (keyCmd != null) {
// Join to key table
DatastoreClass keyTable = storeMgr.getDatastoreClass(mapmd.getKeyType(), clr);
sqlTbl = stmt.join(getDefaultJoinTypeForNavigation(), sqlMapping.table, mapping, keyTable, null, keyTable.getIdMapping(), null, null, true);
mapping = keyTable.getIdMapping();
}
} else {
}
} else if (mapmd.getMapType() == MapType.MAP_TYPE_VALUE_IN_KEY) {
// TODO We maybe already have the VALUE TABLE from the original join
if (!mapKey) {
AbstractClassMetaData valCmd = mapmd.getValueClassMetaData(clr);
String valMappedBy = mmd.getValueMetaData().getMappedBy();
mapping = ((DatastoreClass) sqlTbl.getTable()).getMemberMapping(valMappedBy);
if (valCmd != null) {
// Join to value table
DatastoreClass valueTable = storeMgr.getDatastoreClass(mapmd.getValueType(), clr);
sqlTbl = stmt.join(getDefaultJoinTypeForNavigation(), sqlMapping.table, mapping, valueTable, null, valueTable.getIdMapping(), null, null, true);
mapping = valueTable.getIdMapping();
}
}
}
sqlMapping = new SQLTableMapping(sqlTbl, cmd, mapping);
}
while (iter.hasNext()) {
String component = iter.next();
// fully-qualified primary name
primaryName += "." + component;
// Derive SQLTableMapping for this component
SQLTableMapping sqlMappingNew = getSQLTableMappingForAlias(primaryName);
if (sqlMappingNew == null) {
// Table not present for this primary
AbstractMemberMetaData mmd = cmd.getMetaDataForMember(component);
if (mmd == null) {
// Not valid member name
throw new NucleusUserException(Localiser.msg("021062", component, cmd.getFullClassName()));
} else if (mmd.getPersistenceModifier() != FieldPersistenceModifier.PERSISTENT) {
throw new NucleusUserException("Field " + mmd.getFullFieldName() + " is not marked as persistent so cannot be queried");
}
RelationType relationType = mmd.getRelationType(clr);
// Find the table and the mapping for this field in the table
SQLTable sqlTbl = null;
if (mapping instanceof EmbeddedMapping) {
// Embedded into the current table
sqlTbl = sqlMapping.table;
mapping = ((EmbeddedMapping) mapping).getJavaTypeMapping(component);
} else if (mapping instanceof PersistableMapping && cmd.isEmbeddedOnly()) {
// JPA EmbeddedId into current table
sqlTbl = sqlMapping.table;
JavaTypeMapping[] subMappings = ((PersistableMapping) mapping).getJavaTypeMapping();
if (subMappings.length == 1 && subMappings[0] instanceof EmbeddedPCMapping) {
mapping = ((EmbeddedPCMapping) subMappings[0]).getJavaTypeMapping(component);
} else {
// TODO What situation is this?
}
} else {
DatastoreClass table = storeMgr.getDatastoreClass(cmd.getFullClassName(), clr);
if (table == null) {
if (cmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.COMPLETE_TABLE && candidateCmd.getFullClassName().equals(cmd.getFullClassName())) {
// Special case of a candidate having no table of its own and using COMPLETE_TABLE, so we use the candidate class for this statement (or UNION)
table = storeMgr.getDatastoreClass(stmt.getCandidateClassName(), clr);
}
}
if (table == null) {
AbstractClassMetaData[] subCmds = storeMgr.getClassesManagingTableForClass(cmd, clr);
if (subCmds.length == 1) {
table = storeMgr.getDatastoreClass(subCmds[0].getFullClassName(), clr);
} else {
// all of UNIONs, and this primary expression refers to a mapping in each of subclass tables
throw new NucleusUserException("Unable to find table for primary " + primaryName + " since the class " + cmd.getFullClassName() + " is managed in multiple tables");
}
}
if (table == null) {
throw new NucleusUserException("Unable to find table for primary " + primaryName + ". Table for class=" + cmd.getFullClassName() + " is null : is the field correct? or using some inheritance pattern?");
}
mapping = table.getMemberMapping(mmd);
sqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(theStmt, sqlMapping.table, mapping);
}
if (relationType == RelationType.NONE) {
sqlMappingNew = new SQLTableMapping(sqlTbl, cmd, mapping);
cmd = sqlMappingNew.cmd;
setSQLTableMappingForAlias(primaryName, sqlMappingNew);
} else if (relationType == RelationType.ONE_TO_ONE_UNI || relationType == RelationType.ONE_TO_ONE_BI) {
if (mmd.getMappedBy() != null) {
// FK in other table so join to that first
AbstractMemberMetaData relMmd = mmd.getRelatedMemberMetaData(clr)[0];
if (relMmd.getAbstractClassMetaData().isEmbeddedOnly()) {
// Member is embedded, so keep same SQL table mapping
sqlMappingNew = sqlMapping;
cmd = relMmd.getAbstractClassMetaData();
} else {
// Member is in own table, so move to that SQL table mapping
DatastoreClass relTable = storeMgr.getDatastoreClass(mmd.getTypeName(), clr);
JavaTypeMapping relMapping = relTable.getMemberMapping(relMmd);
// Join to related table unless we already have the join in place
sqlTbl = theStmt.getTable(relTable, primaryName);
if (sqlTbl == null) {
sqlTbl = SQLStatementHelper.addJoinForOneToOneRelation(theStmt, sqlMapping.table.getTable().getIdMapping(), sqlMapping.table, relMapping, relTable, null, null, primaryName, getDefaultJoinTypeForNavigation());
}
if (iter.hasNext()) {
sqlMappingNew = new SQLTableMapping(sqlTbl, relMmd.getAbstractClassMetaData(), relTable.getIdMapping());
cmd = sqlMappingNew.cmd;
} else {
sqlMappingNew = new SQLTableMapping(sqlTbl, cmd, relTable.getIdMapping());
cmd = sqlMappingNew.cmd;
}
}
} else {
// FK is at this side
if (forceJoin == null) {
if (!iter.hasNext()) {
// Further component provided, so check if we should force a join to the other side
if (primExpr.getParent() != null && primExpr.getParent().getOperator() == Expression.OP_CAST) {
// Cast and not an interface field, so do a join to the table of the persistable object
if (mapping instanceof ReferenceMapping) {
// Don't join with interface field since represents multiple implementations
// and the cast will be a restrict on which implementation to join to
} else {
AbstractClassMetaData relCmd = ec.getMetaDataManager().getMetaDataForClass(mmd.getType(), clr);
if (relCmd != null && !relCmd.isEmbeddedOnly()) {
DatastoreClass relTable = storeMgr.getDatastoreClass(relCmd.getFullClassName(), clr);
if (relTable == null) {
} else {
forceJoin = Boolean.TRUE;
}
} else {
forceJoin = Boolean.TRUE;
}
}
}
} else {
// TODO Add optimisation to omit join if the FK is at this side and only selecting PK of the related object
if (iter.hasNext()) {
// Peek ahead to see if just selecting "id" of the related (i.e candidate.related.id with related FK in candidate table, so don't join)
String next = iter.next();
if (!iter.hasNext()) {
AbstractClassMetaData relCmd = storeMgr.getMetaDataManager().getMetaDataForClass(mmd.getType(), clr);
if (relCmd != null) {
AbstractMemberMetaData mmdOfRelCmd = relCmd.getMetaDataForMember(next);
if (mmdOfRelCmd != null && mmdOfRelCmd.isPrimaryKey() && relCmd.getNoOfPrimaryKeyMembers() == 1 && !storeMgr.getMetaDataManager().isClassPersistable(mmdOfRelCmd.getTypeName())) {
// We have something like "a.b.id" and have the FK to the "B" table in the "A" table, so just refer to A.FK rather than joining and using B.ID
NucleusLogger.QUERY.debug("Found implicit join to member=" + mmdOfRelCmd.getFullFieldName() + " which is PK of the other type but FK is in this table so avoiding the join");
JavaTypeMapping subMapping = ((PersistableMapping) mapping).getJavaTypeMapping()[0];
// Component mappings of a PersistableMapping sometimes don't have table set, so fix it
subMapping.setTable(mapping.getTable());
return new SQLTableMapping(sqlMapping.table, relCmd, subMapping);
}
}
}
iter.previous();
}
}
}
if (iter.hasNext() || Boolean.TRUE.equals(forceJoin)) {
AbstractClassMetaData relCmd = null;
JavaTypeMapping relMapping = null;
DatastoreClass relTable = null;
if (relationType == RelationType.ONE_TO_ONE_BI) {
AbstractMemberMetaData relMmd = mmd.getRelatedMemberMetaData(clr)[0];
relCmd = relMmd.getAbstractClassMetaData();
} else {
String typeName = mmd.isSingleCollection() ? mmd.getCollection().getElementType() : mmd.getTypeName();
relCmd = ec.getMetaDataManager().getMetaDataForClass(typeName, clr);
}
if (relCmd != null && relCmd.isEmbeddedOnly()) {
// Member is embedded so use same table but embedded mapping
sqlMappingNew = new SQLTableMapping(sqlTbl, relCmd, mapping);
cmd = relCmd;
} else {
// Member is in own table, so move to that SQL table mapping
relTable = storeMgr.getDatastoreClass(relCmd.getFullClassName(), clr);
if (relTable == null) {
// No table for the related type (subclass-table), so see if this class has a single subclass with its own table
Collection<String> relSubclassNames = storeMgr.getSubClassesForClass(relCmd.getFullClassName(), false, clr);
if (relSubclassNames != null && relSubclassNames.size() == 1) {
String relSubclassName = relSubclassNames.iterator().next();
relTable = storeMgr.getDatastoreClass(relSubclassName, clr);
// TODO Cater for this having no table and next level yes etc
if (relTable != null) {
relCmd = ec.getMetaDataManager().getMetaDataForClass(relSubclassName, clr);
}
}
if (relTable == null) {
// No table as such, so likely using subclass-table at other side and we don't know where to join to
throw new NucleusUserException("Reference to PrimaryExpression " + primExpr + " yet this needs to join relation " + mmd.getFullFieldName() + " and the other type has no table (subclass-table?). Maybe use a CAST to the appropriate subclass?");
}
}
relMapping = relTable.getIdMapping();
// Join to other table unless we already have the join in place
sqlTbl = theStmt.getTable(relTable, primaryName);
if (sqlTbl == null) {
sqlTbl = SQLStatementHelper.addJoinForOneToOneRelation(theStmt, mapping, sqlMapping.table, relMapping, relTable, null, null, primaryName, getDefaultJoinTypeForNavigation());
}
sqlMappingNew = new SQLTableMapping(sqlTbl, relCmd, relMapping);
cmd = sqlMappingNew.cmd;
setSQLTableMappingForAlias(primaryName, sqlMappingNew);
}
} else {
sqlMappingNew = new SQLTableMapping(sqlTbl, cmd, mapping);
cmd = sqlMappingNew.cmd;
// Don't register the SQLTableMapping for this alias since only using FK
}
}
} else if (relationType == RelationType.MANY_TO_ONE_BI) {
AbstractMemberMetaData relMmd = mmd.getRelatedMemberMetaData(clr)[0];
DatastoreClass relTable = storeMgr.getDatastoreClass(mmd.getTypeName(), clr);
if (mmd.getJoinMetaData() != null || relMmd.getJoinMetaData() != null) {
// Has join table so use that
sqlTbl = theStmt.getTable(relTable, primaryName);
if (sqlTbl == null) {
// Join to the join table
CollectionTable joinTbl = (CollectionTable) storeMgr.getTable(relMmd);
JoinType defJoinType = getDefaultJoinTypeForNavigation();
if (defJoinType == JoinType.INNER_JOIN) {
SQLTable joinSqlTbl = theStmt.join(JoinType.INNER_JOIN, sqlMapping.table, sqlMapping.table.getTable().getIdMapping(), joinTbl, null, joinTbl.getElementMapping(), null, null, true);
sqlTbl = theStmt.join(JoinType.INNER_JOIN, joinSqlTbl, joinTbl.getOwnerMapping(), relTable, null, relTable.getIdMapping(), null, primaryName, true);
} else if (defJoinType == JoinType.LEFT_OUTER_JOIN || defJoinType == null) {
SQLTable joinSqlTbl = theStmt.join(JoinType.LEFT_OUTER_JOIN, sqlMapping.table, sqlMapping.table.getTable().getIdMapping(), joinTbl, null, joinTbl.getElementMapping(), null, null, true);
sqlTbl = theStmt.join(JoinType.LEFT_OUTER_JOIN, joinSqlTbl, joinTbl.getOwnerMapping(), relTable, null, relTable.getIdMapping(), null, primaryName, true);
}
}
sqlMappingNew = new SQLTableMapping(sqlTbl, relMmd.getAbstractClassMetaData(), relTable.getIdMapping());
cmd = sqlMappingNew.cmd;
setSQLTableMappingForAlias(primaryName, sqlMappingNew);
} else {
// FK in this table
sqlTbl = theStmt.getTable(relTable, primaryName);
if (sqlTbl == null) {
if (mmd.getMappedBy() == null) {
// FK at this side so check for optimisations
if (iter.hasNext()) {
// Peek ahead to see if just selecting "id" of the related (i.e candidate.related.id with related FK in candidate table, so don't join)
String next = iter.next();
if (!iter.hasNext()) {
AbstractClassMetaData relCmd = relMmd.getAbstractClassMetaData();
AbstractMemberMetaData mmdOfRelCmd = relCmd.getMetaDataForMember(next);
if (mmdOfRelCmd != null && mmdOfRelCmd.isPrimaryKey() && relCmd.getNoOfPrimaryKeyMembers() == 1 && !storeMgr.getMetaDataManager().isClassPersistable(mmdOfRelCmd.getTypeName())) {
// We have something like "a.b.id" and have the FK to the "B" table in the "A" table, so just refer to A.FK rather than joining and using B.ID
NucleusLogger.QUERY.debug("Found implicit join to member=" + mmdOfRelCmd.getFullFieldName() + " which is PK of the other type but FK is in this table so avoiding the join");
JavaTypeMapping subMapping = ((PersistableMapping) mapping).getJavaTypeMapping()[0];
// Component mappings of a PersistableMapping sometimes don't have table set, so fix it
subMapping.setTable(mapping.getTable());
return new SQLTableMapping(sqlMapping.table, relCmd, subMapping);
}
}
iter.previous();
}
}
Operator op = (primExpr.getParent() != null ? primExpr.getParent().getOperator() : null);
if (!iter.hasNext() && (op == Expression.OP_EQ || op == Expression.OP_GT || op == Expression.OP_LT || op == Expression.OP_GTEQ || op == Expression.OP_LTEQ || op == Expression.OP_NOTEQ)) {
// Just return the FK mapping since in a "a.b == c.d" type expression and not needing to go further than the FK
sqlMappingNew = new SQLTableMapping(sqlMapping.table, relMmd.getAbstractClassMetaData(), mapping);
} else {
// Join to the related table
JoinType defJoinType = getDefaultJoinTypeForNavigation();
if (defJoinType == JoinType.INNER_JOIN) {
sqlTbl = theStmt.join(JoinType.INNER_JOIN, sqlMapping.table, mapping, relTable, null, relTable.getIdMapping(), null, primaryName, true);
} else if (defJoinType == JoinType.LEFT_OUTER_JOIN || defJoinType == null) {
sqlTbl = theStmt.join(JoinType.LEFT_OUTER_JOIN, sqlMapping.table, mapping, relTable, null, relTable.getIdMapping(), null, primaryName, true);
}
sqlMappingNew = new SQLTableMapping(sqlTbl, relMmd.getAbstractClassMetaData(), relTable.getIdMapping());
cmd = sqlMappingNew.cmd;
setSQLTableMappingForAlias(primaryName, sqlMappingNew);
}
} else {
sqlMappingNew = new SQLTableMapping(sqlTbl, relMmd.getAbstractClassMetaData(), relTable.getIdMapping());
cmd = sqlMappingNew.cmd;
setSQLTableMappingForAlias(primaryName, sqlMappingNew);
}
}
} else if (RelationType.isRelationMultiValued(relationType)) {
// Can't reference further than a collection/map so just return its mapping here
sqlMappingNew = new SQLTableMapping(sqlTbl, cmd, mapping);
cmd = sqlMappingNew.cmd;
setSQLTableMappingForAlias(primaryName, sqlMappingNew);
}
} else {
cmd = sqlMappingNew.cmd;
}
sqlMapping = sqlMappingNew;
}
return sqlMapping;
}
use of org.datanucleus.store.rdbms.sql.SQLJoin.JoinType in project datanucleus-rdbms by datanucleus.
the class MapContainsKeyMethod method getExpression.
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.sql.method.SQLMethod#getExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression, java.util.List)
*/
public SQLExpression getExpression(SQLStatement stmt, SQLExpression expr, List<SQLExpression> args) {
if (args == null || args.size() == 0 || args.size() > 1) {
throw new NucleusException(Localiser.msg("060016", "containsKey", "MapExpression", 1));
}
MapExpression mapExpr = (MapExpression) expr;
SQLExpression keyExpr = args.get(0);
if (keyExpr.isParameter()) {
// Key is a parameter so make sure its type is set
AbstractMemberMetaData mmd = mapExpr.getJavaTypeMapping().getMemberMetaData();
if (mmd != null && mmd.getMap() != null) {
Class keyCls = stmt.getQueryGenerator().getClassLoaderResolver().classForName(mmd.getMap().getKeyType());
stmt.getQueryGenerator().bindParameter(keyExpr.getParameterName(), keyCls);
}
}
SQLExpressionFactory exprFactory = stmt.getSQLExpressionFactory();
ClassLoaderResolver clr = stmt.getQueryGenerator().getClassLoaderResolver();
if (expr instanceof MapLiteral) {
// Literal Map
MapLiteral lit = (MapLiteral) expr;
Map map = (Map) lit.getValue();
JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
if (map == null || map.size() == 0) {
return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, false));
}
boolean useInExpression = false;
List<SQLExpression> mapKeyExprs = lit.getKeyLiteral().getKeyExpressions();
if (mapKeyExprs != null && !mapKeyExprs.isEmpty()) {
// Make sure the the map key(s) are compatible with the keyExpr
boolean incompatible = true;
Class elemtype = clr.classForName(keyExpr.getJavaTypeMapping().getType());
Iterator<SQLExpression> mapKeyExprIter = mapKeyExprs.iterator();
while (mapKeyExprIter.hasNext()) {
SQLExpression mapKeyExpr = mapKeyExprIter.next();
Class mapKeyType = clr.classForName(mapKeyExpr.getJavaTypeMapping().getType());
if (keyTypeCompatible(elemtype, mapKeyType)) {
incompatible = false;
break;
}
}
if (incompatible) {
// The provided element type isn't assignable to any of the input collection elements!
return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, false));
}
// Check if we should compare using an "IN (...)" expression
SQLExpression mapKeyExpr = mapKeyExprs.get(0);
if (mapKeyExpr instanceof StringExpression || mapKeyExpr instanceof NumericExpression || mapKeyExpr instanceof TemporalExpression || mapKeyExpr instanceof CharacterExpression || mapKeyExpr instanceof EnumExpression) {
useInExpression = true;
}
}
if (useInExpression) {
// Return "key IN (val1, val2, ...)"
SQLExpression[] exprs = (mapKeyExprs != null ? mapKeyExprs.toArray(new SQLExpression[mapKeyExprs.size()]) : null);
return new InExpression(keyExpr, exprs);
}
// TODO If keyExpr is a parameter and mapExpr is derived from a parameter ?
MapKeyLiteral mapKeyLiteral = lit.getKeyLiteral();
BooleanExpression bExpr = null;
List<SQLExpression> elementExprs = mapKeyLiteral.getKeyExpressions();
for (int i = 0; i < elementExprs.size(); i++) {
if (bExpr == null) {
bExpr = (elementExprs.get(i)).eq(keyExpr);
} else {
bExpr = bExpr.ior((elementExprs.get(i)).eq(keyExpr));
}
}
if (bExpr != null) {
bExpr.encloseInParentheses();
}
return bExpr;
}
if (stmt.getQueryGenerator().getCompilationComponent() == CompilationComponent.FILTER) {
boolean useSubquery = getNeedsSubquery(stmt);
JoinType joinType = JoinType.INNER_JOIN;
if (keyExpr instanceof UnboundExpression) {
// See if the user has defined what should be used
String varName = ((UnboundExpression) keyExpr).getVariableName();
String extensionName = "datanucleus.query.jdoql." + varName + ".join";
String extensionValue = (String) stmt.getQueryGenerator().getValueForExtension(extensionName);
if (extensionValue != null) {
if (extensionValue.equalsIgnoreCase("SUBQUERY")) {
useSubquery = true;
} else if (extensionValue.equalsIgnoreCase("INNERJOIN")) {
useSubquery = false;
} else if (extensionValue.equalsIgnoreCase("LEFTOUTERJOIN")) {
joinType = JoinType.LEFT_OUTER_JOIN;
}
}
}
// TODO Check if *this* "containsKey" is negated, not any of them (and remove above check)
if (useSubquery) {
return containsAsSubquery(stmt, mapExpr, keyExpr);
}
return containsAsJoin(stmt, mapExpr, keyExpr, joinType);
}
return containsAsSubquery(stmt, mapExpr, keyExpr);
}
use of org.datanucleus.store.rdbms.sql.SQLJoin.JoinType in project datanucleus-rdbms by datanucleus.
the class QueryToSQLMapper method processEqExpression.
/* (non-Javadoc)
* @see org.datanucleus.query.evaluator.AbstractExpressionEvaluator#processEqExpression(org.datanucleus.query.expression.Expression)
*/
protected Object processEqExpression(Expression expr) {
SQLExpression right = stack.pop();
SQLExpression left = stack.pop();
if (left instanceof ParameterLiteral && !(right instanceof ParameterLiteral)) {
left = replaceParameterLiteral((ParameterLiteral) left, right.getJavaTypeMapping());
} else if (right instanceof ParameterLiteral && !(left instanceof ParameterLiteral)) {
right = replaceParameterLiteral((ParameterLiteral) right, left.getJavaTypeMapping());
}
if (left.isParameter() && right.isParameter()) {
if (left.isParameter() && left instanceof SQLLiteral && ((SQLLiteral) left).getValue() != null) {
// Change this parameter to a plain literal
useParameterExpressionAsLiteral((SQLLiteral) left);
}
if (right.isParameter() && right instanceof SQLLiteral && ((SQLLiteral) right).getValue() != null) {
// Change this parameter to a plain literal
useParameterExpressionAsLiteral((SQLLiteral) right);
}
}
ExpressionUtils.checkAndCorrectExpressionMappingsForBooleanComparison(left, right);
if (left instanceof UnboundExpression) {
processUnboundExpression((UnboundExpression) left);
left = stack.pop();
}
if (right instanceof UnboundExpression) {
processUnboundExpression((UnboundExpression) right);
right = stack.pop();
}
// Logic for when one side is cross-joined (variable) and other side not, so transfer to a left outer join
if (!options.contains(OPTION_EXPLICIT_JOINS)) {
boolean leftIsCrossJoin = (stmt.getJoinTypeForTable(left.getSQLTable()) == JoinType.CROSS_JOIN);
boolean rightIsCrossJoin = (stmt.getJoinTypeForTable(right.getSQLTable()) == JoinType.CROSS_JOIN);
if (leftIsCrossJoin && !rightIsCrossJoin && !(right instanceof SQLLiteral)) {
// "a == b" and a is cross-joined currently (includes variable) so change to left outer join
String varName = getAliasForSQLTable(left.getSQLTable());
JoinType joinType = getRequiredJoinTypeForAlias(varName);
if (joinType != null) {
NucleusLogger.QUERY.debug("QueryToSQL.eq variable " + varName + " is mapped to table " + left.getSQLTable() + " was previously bound as CROSS JOIN but changing to " + joinType);
String leftTblAlias = stmt.removeCrossJoin(left.getSQLTable());
if (joinType == JoinType.LEFT_OUTER_JOIN) {
stmt.join(JoinType.LEFT_OUTER_JOIN, right.getSQLTable(), right.getJavaTypeMapping(), left.getSQLTable().getTable(), leftTblAlias, left.getJavaTypeMapping(), null, left.getSQLTable().getGroupName(), true);
} else {
stmt.join(JoinType.INNER_JOIN, right.getSQLTable(), right.getJavaTypeMapping(), left.getSQLTable().getTable(), leftTblAlias, left.getJavaTypeMapping(), null, left.getSQLTable().getGroupName(), true);
}
JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
SQLExpression opExpr = exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, true));
stack.push(opExpr);
return opExpr;
}
} else if (!leftIsCrossJoin && rightIsCrossJoin && !(left instanceof SQLLiteral)) {
// "a == b" and b is cross-joined currently (includes variable) so change to left outer join
String varName = getAliasForSQLTable(right.getSQLTable());
JoinType joinType = getRequiredJoinTypeForAlias(varName);
if (joinType != null) {
NucleusLogger.QUERY.debug("QueryToSQL.eq variable " + varName + " is mapped to table " + right.getSQLTable() + " was previously bound as CROSS JOIN but changing to " + joinType);
String rightTblAlias = stmt.removeCrossJoin(right.getSQLTable());
if (joinType == JoinType.LEFT_OUTER_JOIN) {
stmt.join(JoinType.LEFT_OUTER_JOIN, left.getSQLTable(), left.getJavaTypeMapping(), right.getSQLTable().getTable(), rightTblAlias, right.getJavaTypeMapping(), null, right.getSQLTable().getGroupName(), true);
} else {
stmt.join(JoinType.INNER_JOIN, left.getSQLTable(), left.getJavaTypeMapping(), right.getSQLTable().getTable(), rightTblAlias, right.getJavaTypeMapping(), null, right.getSQLTable().getGroupName(), true);
}
JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
SQLExpression opExpr = exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, true));
stack.push(opExpr);
return opExpr;
}
}
}
BooleanExpression opExpr = left.eq(right);
stack.push(opExpr);
return opExpr;
}
use of org.datanucleus.store.rdbms.sql.SQLJoin.JoinType in project datanucleus-rdbms by datanucleus.
the class SQLStatementHelper method selectMemberOfSourceInStatement.
/**
* Method to select the specified member (field/property) of the source table in the passed SQL
* statement. This populates the mappingDefinition with the column details for this member.
* @param stmt The SQL statement
* @param mappingDefinition Mapping definition for the results (will be populated by any
* selected mappings if provided as input)
* @param fetchPlan FetchPlan
* @param sourceSqlTbl Table that has the member (or a super-table/secondary-table of this table)
* @param mmd Meta-data for the field/property in the source that we are selecting
* @param clr ClassLoader resolver
* @param maxFetchPlanLimit Max fetch depth from this point to select (0 implies no other objects)
* @param inputJoinType Optional join type to use for subobjects (otherwise decide join type internally)
*/
public static void selectMemberOfSourceInStatement(SelectStatement stmt, StatementClassMapping mappingDefinition, FetchPlan fetchPlan, SQLTable sourceSqlTbl, AbstractMemberMetaData mmd, ClassLoaderResolver clr, int maxFetchPlanLimit, JoinType inputJoinType) {
boolean selectSubobjects = false;
if (maxFetchPlanLimit > 0) {
selectSubobjects = true;
}
// Set table-group name for any related object we join to (naming based on member name)
String tableGroupName = sourceSqlTbl.getGroupName() + "." + mmd.getName();
JavaTypeMapping m = sourceSqlTbl.getTable().getMemberMapping(mmd);
if (m != null && m.includeInFetchStatement()) {
RelationType relationType = mmd.getRelationType(clr);
RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
DatastoreAdapter dba = storeMgr.getDatastoreAdapter();
if (!dba.validToSelectMappingInStatement(stmt, m)) {
// Not valid to select this mapping for this statement so return
return;
}
MetaDataManager mmgr = storeMgr.getMetaDataManager();
StatementMappingIndex stmtMapping = new StatementMappingIndex(m);
if (m.getNumberOfDatastoreMappings() > 0) {
// Select of fields with columns in source table(s)
// Adds inner/outer join to any required superclass/secondary tables
SQLTable sqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(stmt, sourceSqlTbl, m);
boolean selectFK = true;
if (selectSubobjects && (relationType == RelationType.ONE_TO_ONE_UNI || (relationType == RelationType.ONE_TO_ONE_BI && mmd.getMappedBy() == null)) && !mmd.isSerialized() && !mmd.isEmbedded()) {
// Related object with FK at this side
selectFK = selectFetchPlanFieldsOfFKRelatedObject(stmt, mappingDefinition, fetchPlan, sourceSqlTbl, mmd, clr, maxFetchPlanLimit, m, tableGroupName, stmtMapping, sqlTbl, inputJoinType);
} else if (selectSubobjects && (!mmd.isEmbedded() && !mmd.isSerialized()) && relationType == RelationType.MANY_TO_ONE_BI) {
AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
if (mmd.getJoinMetaData() != null || relatedMmds[0].getJoinMetaData() != null) {
// N-1 bidirectional join table relation
// TODO Add left outer join from {sourceTable}.ID to {joinTable}.ELEM_FK
Table joinTable = storeMgr.getTable(relatedMmds[0]);
DatastoreElementContainer collTable = (DatastoreElementContainer) joinTable;
JavaTypeMapping selectMapping = collTable.getOwnerMapping();
SQLTable joinSqlTbl = null;
if (stmt.getPrimaryTable().getTable() != joinTable) {
// Join to the join table
JavaTypeMapping referenceMapping = collTable.getElementMapping();
joinSqlTbl = stmt.join(JoinType.LEFT_OUTER_JOIN, sourceSqlTbl, sourceSqlTbl.getTable().getIdMapping(), collTable, null, referenceMapping, null, tableGroupName, true);
} else {
// Main table of the statement is the join table so no need to join
joinSqlTbl = stmt.getPrimaryTable();
}
// Select the owner mapping of the join table
int[] colNumbers = stmt.select(joinSqlTbl, selectMapping, null);
stmtMapping.setColumnPositions(colNumbers);
// TODO Join to 1 side from join table?
} else {
// N-1 bidirectional FK relation
// Related object with FK at this side, so join/select related object as required
selectFK = selectFetchPlanFieldsOfFKRelatedObject(stmt, mappingDefinition, fetchPlan, sourceSqlTbl, mmd, clr, maxFetchPlanLimit, m, tableGroupName, stmtMapping, sqlTbl, inputJoinType);
}
}
if (selectFK) {
int[] colNumbers = stmt.select(sqlTbl, m, null);
stmtMapping.setColumnPositions(colNumbers);
}
} else {
// Select of related objects with FK in other table
if (relationType == RelationType.ONE_TO_ONE_BI && mmd.getMappedBy() != null) {
// 1-1 bidirectional relation with FK in related table
AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
AbstractMemberMetaData relatedMmd = relatedMmds[0];
String[] clsNames = null;
if (mmd.getType().isInterface()) {
if (mmd.getFieldTypes() != null && mmd.getFieldTypes().length == 1) {
// Use field-type since only one class specified
Class fldTypeCls = clr.classForName(mmd.getFieldTypes()[0]);
if (fldTypeCls.isInterface()) {
// User has specified an interface, so find its implementations
clsNames = mmgr.getClassesImplementingInterface(mmd.getFieldTypes()[0], clr);
} else {
// Use user-provided field-type
clsNames = new String[] { mmd.getFieldTypes()[0] };
}
}
if (clsNames == null) {
clsNames = mmgr.getClassesImplementingInterface(mmd.getTypeName(), clr);
}
} else {
String typeName = mmd.isSingleCollection() ? mmd.getCollection().getElementType() : mmd.getTypeName();
clsNames = new String[] { typeName };
}
DatastoreClass relatedTbl = storeMgr.getDatastoreClass(clsNames[0], clr);
JavaTypeMapping relatedMapping = relatedTbl.getMemberMapping(relatedMmd);
JavaTypeMapping relatedDiscrimMapping = relatedTbl.getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, true);
Object[] discrimValues = null;
JavaTypeMapping relatedTypeMapping = null;
AbstractClassMetaData relatedCmd = relatedMmd.getAbstractClassMetaData();
if (relatedDiscrimMapping != null && (relatedCmd.getSuperAbstractClassMetaData() != null || !relatedCmd.getFullClassName().equals(mmd.getTypeName()))) {
// Related table has a discriminator and the field can store other types
List discValueList = null;
for (String clsName : clsNames) {
List values = getDiscriminatorValuesForMember(clsName, relatedDiscrimMapping, storeMgr, clr);
if (discValueList == null) {
discValueList = values;
} else {
discValueList.addAll(values);
}
}
if (discValueList != null) {
discrimValues = discValueList.toArray(new Object[discValueList.size()]);
}
} else if (relatedTbl != relatedMapping.getTable()) {
// The relation is to a base class table, and the type stored is a sub-class
relatedTypeMapping = relatedTbl.getIdMapping();
}
SQLTable relatedSqlTbl = null;
if (relatedTypeMapping == null) {
// Join the 1-1 relation
JoinType joinType = getJoinTypeForOneToOneRelationJoin(sourceSqlTbl.getTable().getIdMapping(), sourceSqlTbl, inputJoinType);
if (joinType == JoinType.LEFT_OUTER_JOIN || joinType == JoinType.RIGHT_OUTER_JOIN) {
inputJoinType = joinType;
}
relatedSqlTbl = addJoinForOneToOneRelation(stmt, sourceSqlTbl.getTable().getIdMapping(), sourceSqlTbl, relatedMapping, relatedTbl, null, discrimValues, tableGroupName, joinType);
// Select the id mapping in the related table
int[] colNumbers = stmt.select(relatedSqlTbl, relatedTbl.getIdMapping(), null);
stmtMapping.setColumnPositions(colNumbers);
} else {
DatastoreClass relationTbl = (DatastoreClass) relatedMapping.getTable();
if (relatedTbl != relatedMapping.getTable()) {
if (relatedMapping.isNullable()) {
// Nullable - left outer join from {sourceTable}.ID to {relatedBaseTable}.FK
// and inner join from {relatedBaseTable}.ID to {relatedTable}.ID
// (joins the relation and restricts to the right type)
relatedSqlTbl = stmt.join(JoinType.LEFT_OUTER_JOIN, sourceSqlTbl, sourceSqlTbl.getTable().getIdMapping(), relatedMapping.getTable(), null, relatedMapping, null, tableGroupName, true);
relatedSqlTbl = stmt.join(JoinType.INNER_JOIN, relatedSqlTbl, relatedMapping.getTable().getIdMapping(), relatedTbl, null, relatedTbl.getIdMapping(), null, tableGroupName, true);
} else {
// Not nullable - inner join from {sourceTable}.ID to {relatedBaseTable}.FK
// and inner join from {relatedBaseTable}.ID to {relatedTable}.ID
// (joins the relation and restricts to the right type)
relatedSqlTbl = stmt.join(JoinType.INNER_JOIN, sourceSqlTbl, sourceSqlTbl.getTable().getIdMapping(), relatedMapping.getTable(), null, relatedMapping, null, tableGroupName, true);
relatedSqlTbl = stmt.join(JoinType.INNER_JOIN, relatedSqlTbl, relatedMapping.getTable().getIdMapping(), relatedTbl, null, relatedTbl.getIdMapping(), null, tableGroupName, true);
}
} else {
// Join the 1-1 relation
JoinType joinType = getJoinTypeForOneToOneRelationJoin(sourceSqlTbl.getTable().getIdMapping(), sourceSqlTbl, inputJoinType);
if (joinType == JoinType.LEFT_OUTER_JOIN || joinType == JoinType.RIGHT_OUTER_JOIN) {
inputJoinType = joinType;
}
relatedSqlTbl = addJoinForOneToOneRelation(stmt, sourceSqlTbl.getTable().getIdMapping(), sourceSqlTbl, relatedMapping, relationTbl, null, null, tableGroupName, joinType);
}
// Select the id mapping in the subclass of the related table
// Note this adds an inner join from relatedTable to its subclass
relatedSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(stmt, relatedSqlTbl, relatedTbl.getIdMapping());
int[] colNumbers = stmt.select(relatedSqlTbl, relatedTbl.getIdMapping(), null);
stmtMapping.setColumnPositions(colNumbers);
}
if (selectSubobjects && !mmd.isSerialized() && !mmd.isEmbedded()) {
// Select the fetch-plan fields of the related object
StatementClassMapping subMappingDefinition = new StatementClassMapping(null, mmd.getName());
selectFetchPlanOfSourceClassInStatement(stmt, subMappingDefinition, fetchPlan, relatedSqlTbl, relatedMmd.getAbstractClassMetaData(), maxFetchPlanLimit - 1, inputJoinType);
if (mappingDefinition != null) {
mappingDefinition.addMappingDefinitionForMember(mmd.getAbsoluteFieldNumber(), subMappingDefinition);
}
}
} else if (relationType == RelationType.MANY_TO_ONE_BI) {
AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
if (mmd.getJoinMetaData() != null || relatedMmds[0].getJoinMetaData() != null) {
// N-1 bidirectional join table relation
// Add left outer join from {sourceTable}.ID to {joinTable}.ELEM_FK
Table joinTable = storeMgr.getTable(relatedMmds[0]);
DatastoreElementContainer collTable = (DatastoreElementContainer) joinTable;
JavaTypeMapping selectMapping = collTable.getOwnerMapping();
SQLTable joinSqlTbl = null;
if (stmt.getPrimaryTable().getTable() != joinTable) {
// Join to the join table
JavaTypeMapping referenceMapping = collTable.getElementMapping();
if (referenceMapping instanceof ReferenceMapping) {
// Join table has a reference mapping pointing to our table, so get the submapping for the implementation
ReferenceMapping refMap = (ReferenceMapping) referenceMapping;
Class implType = clr.classForName(mmd.getClassName(true));
referenceMapping = refMap.getJavaTypeMappingForType(implType);
}
joinSqlTbl = stmt.join(JoinType.LEFT_OUTER_JOIN, sourceSqlTbl, sourceSqlTbl.getTable().getIdMapping(), collTable, null, referenceMapping, null, tableGroupName + "_JOIN", true);
} else {
// Main table of the statement is the join table so no need to join
joinSqlTbl = stmt.getPrimaryTable();
}
// Select the owner mapping of the join table
int[] colNumbers = stmt.select(joinSqlTbl, selectMapping, null);
stmtMapping.setColumnPositions(colNumbers);
}
// TODO Select fetch plan fields of this related object
} else if (relationType == RelationType.MANY_TO_ONE_UNI) {
// Add left outer join from {sourceTable}.ID to {joinTable}.OWNER_FK
PersistableJoinTable joinTable = (PersistableJoinTable) storeMgr.getTable(mmd);
SQLTable joinSqlTbl = stmt.join(JoinType.LEFT_OUTER_JOIN, sourceSqlTbl, sourceSqlTbl.getTable().getIdMapping(), joinTable, null, joinTable.getOwnerMapping(), null, tableGroupName + "_JOIN", true);
int[] colNumbers = stmt.select(joinSqlTbl, joinTable.getRelatedMapping(), null);
stmtMapping.setColumnPositions(colNumbers);
// TODO Select fetch plan fields of this related object
}
}
if (mappingDefinition != null) {
mappingDefinition.addMappingForMember(mmd.getAbsoluteFieldNumber(), stmtMapping);
}
}
}
Aggregations