use of org.datanucleus.store.rdbms.RDBMSStoreManager in project datanucleus-rdbms by datanucleus.
the class MapContainsValueMethod method containsAsJoin.
/**
* Method to return an expression for Map.containsValue using INNER JOIN to the element.
* This is only for use when there are no "!containsValue" and no "OR" operations.
* Creates SQL by adding INNER JOIN to the join table (where it exists), and also to the value table
* adding an AND condition on the value (with value of the valueExpr).
* Returns a BooleanExpression "TRUE" (since the INNER JOIN will guarantee if the value is contained of not).
* @param stmt SQLStatement
* @param mapExpr Map expression
* @param valExpr Expression for the value
* @param joinType Type of join
* @return Contains expression
*/
protected SQLExpression containsAsJoin(SQLStatement stmt, MapExpression mapExpr, SQLExpression valExpr, JoinType joinType) {
boolean valIsUnbound = (valExpr instanceof UnboundExpression);
String varName = null;
String valAlias = null;
if (valIsUnbound) {
varName = ((UnboundExpression) valExpr).getVariableName();
NucleusLogger.QUERY.debug("map.containsValue(" + valExpr + ") binding unbound variable " + varName + " using INNER JOIN");
// TODO What if the variable is declared as a subtype, handle this see CollectionContainsMethod
} else if (!stmt.getQueryGenerator().hasExplicitJoins()) {
if (stmt.getJoinTypeForTable(valExpr.getSQLTable()) == JoinType.CROSS_JOIN) {
// Value is currently joined via CROSS JOIN, so remove it (and use INNER JOIN below)
valAlias = stmt.removeCrossJoin(valExpr.getSQLTable());
valIsUnbound = true;
NucleusLogger.QUERY.debug("map.containsValue(" + valExpr + ") was previously bound as CROSS JOIN but changing to INNER JOIN");
}
// TODO If owner is joined via CROSS JOIN and value is already present then remove CROSS JOIN
// and join via INNER JOIN
}
RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
SQLExpressionFactory exprFactory = stmt.getSQLExpressionFactory();
ClassLoaderResolver clr = stmt.getQueryGenerator().getClassLoaderResolver();
AbstractMemberMetaData mmd = mapExpr.getJavaTypeMapping().getMemberMetaData();
AbstractClassMetaData valCmd = mmd.getMap().getValueClassMetaData(clr);
if (mmd.getMap().getMapType() == MapType.MAP_TYPE_JOIN) {
// Map formed in join table - add join to join table, then to value table (if present)
MapTable mapTbl = (MapTable) storeMgr.getTable(mmd);
SQLTable joinSqlTbl = stmt.join(joinType, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping(), mapTbl, null, mapTbl.getOwnerMapping(), null, null);
if (valCmd != null) {
if (valIsUnbound) {
DatastoreClass valTbl = storeMgr.getDatastoreClass(valCmd.getFullClassName(), clr);
SQLTable valSqlTbl = stmt.join(joinType, joinSqlTbl, mapTbl.getValueMapping(), valTbl, valAlias, valTbl.getIdMapping(), null, null);
// Bind the variable in the QueryGenerator
valExpr = exprFactory.newExpression(stmt, valSqlTbl, valSqlTbl.getTable().getIdMapping());
stmt.getQueryGenerator().bindVariable(varName, valCmd, valExpr.getSQLTable(), valExpr.getJavaTypeMapping());
} else {
// Add restrict to value
SQLExpression valIdExpr = exprFactory.newExpression(stmt, joinSqlTbl, mapTbl.getValueMapping());
stmt.whereAnd(valIdExpr.eq(valExpr), true);
}
} else {
if (valIsUnbound) {
// Bind the variable in the QueryGenerator
valExpr = exprFactory.newExpression(stmt, joinSqlTbl, mapTbl.getValueMapping());
stmt.getQueryGenerator().bindVariable(varName, null, valExpr.getSQLTable(), valExpr.getJavaTypeMapping());
} else {
// Add restrict to value
SQLExpression valIdExpr = exprFactory.newExpression(stmt, joinSqlTbl, mapTbl.getValueMapping());
stmt.whereAnd(valIdExpr.eq(valExpr), true);
}
}
} else if (mmd.getMap().getMapType() == MapType.MAP_TYPE_KEY_IN_VALUE) {
// Map formed in value table - add join to value table
DatastoreClass valTbl = storeMgr.getDatastoreClass(valCmd.getFullClassName(), clr);
JavaTypeMapping ownerMapping = null;
if (mmd.getMappedBy() != null) {
ownerMapping = valTbl.getMemberMapping(valCmd.getMetaDataForMember(mmd.getMappedBy()));
} else {
ownerMapping = valTbl.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
}
SQLTable valSqlTbl = stmt.join(joinType, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping(), valTbl, valAlias, ownerMapping, null, null);
if (valIsUnbound) {
// Bind the variable in the QueryGenerator
valExpr = exprFactory.newExpression(stmt, valSqlTbl, valTbl.getIdMapping());
stmt.getQueryGenerator().bindVariable(varName, valCmd, valExpr.getSQLTable(), valExpr.getJavaTypeMapping());
} else {
// Add restrict to value
SQLExpression valIdExpr = exprFactory.newExpression(stmt, valSqlTbl, valTbl.getIdMapping());
stmt.whereAnd(valIdExpr.eq(valExpr), true);
}
} else if (mmd.getMap().getMapType() == MapType.MAP_TYPE_VALUE_IN_KEY) {
// Map formed in key table - add join to key table then to value table
AbstractClassMetaData keyCmd = mmd.getMap().getKeyClassMetaData(clr);
DatastoreClass keyTbl = storeMgr.getDatastoreClass(keyCmd.getFullClassName(), clr);
AbstractMemberMetaData keyValMmd = keyCmd.getMetaDataForMember(mmd.getValueMetaData().getMappedBy());
JavaTypeMapping ownerMapping = null;
if (mmd.getMappedBy() != null) {
ownerMapping = keyTbl.getMemberMapping(keyCmd.getMetaDataForMember(mmd.getMappedBy()));
} else {
ownerMapping = keyTbl.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
}
SQLTable keySqlTbl = stmt.join(joinType, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping(), keyTbl, null, ownerMapping, null, null);
if (valCmd != null) {
DatastoreClass valTbl = storeMgr.getDatastoreClass(valCmd.getFullClassName(), clr);
SQLTable valSqlTbl = stmt.join(joinType, keySqlTbl, keyTbl.getMemberMapping(keyValMmd), valTbl, valAlias, valTbl.getIdMapping(), null, null);
if (valIsUnbound) {
// Bind the variable in the QueryGenerator
valExpr = exprFactory.newExpression(stmt, valSqlTbl, valTbl.getIdMapping());
stmt.getQueryGenerator().bindVariable(varName, valCmd, valExpr.getSQLTable(), valExpr.getJavaTypeMapping());
} else {
// Add restrict to value
SQLExpression valIdExpr = exprFactory.newExpression(stmt, valSqlTbl, valTbl.getIdMapping());
stmt.whereAnd(valIdExpr.eq(valExpr), true);
}
} else {
if (valIsUnbound) {
// Bind the variable in the QueryGenerator
valExpr = exprFactory.newExpression(stmt, keySqlTbl, keyTbl.getMemberMapping(keyValMmd));
stmt.getQueryGenerator().bindVariable(varName, null, valExpr.getSQLTable(), valExpr.getJavaTypeMapping());
} else {
// Add restrict to value
SQLExpression valIdExpr = exprFactory.newExpression(stmt, keySqlTbl, keyTbl.getMemberMapping(keyValMmd));
stmt.whereAnd(valIdExpr.eq(valExpr), true);
}
}
}
JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, true));
}
use of org.datanucleus.store.rdbms.RDBMSStoreManager in project datanucleus-rdbms by datanucleus.
the class MapGetMethod method getAsSubquery.
/**
* Implementation of Map.get() using a subquery on the table representing the map,
* adding a condition on the key and returning the value.
* @param stmt SQLStatement
* @param mapExpr The map expression
* @param keyValExpr The key value expression
* @return The value expression
*/
protected SQLExpression getAsSubquery(SQLStatement stmt, MapExpression mapExpr, SQLExpression keyValExpr) {
ClassLoaderResolver clr = stmt.getQueryGenerator().getClassLoaderResolver();
AbstractMemberMetaData mmd = mapExpr.getJavaTypeMapping().getMemberMetaData();
MapMetaData mapmd = mmd.getMap();
RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
JavaTypeMapping ownerMapping = null;
JavaTypeMapping keyMapping = null;
JavaTypeMapping valMapping = null;
Table mapTbl = null;
if (mapmd.getMapType() == MapType.MAP_TYPE_JOIN) {
// JoinTable
mapTbl = storeMgr.getTable(mmd);
ownerMapping = ((MapTable) mapTbl).getOwnerMapping();
keyMapping = ((MapTable) mapTbl).getKeyMapping();
valMapping = ((MapTable) mapTbl).getValueMapping();
} else if (mapmd.getMapType() == MapType.MAP_TYPE_KEY_IN_VALUE) {
// ForeignKey from value table to key
AbstractClassMetaData valCmd = mapmd.getValueClassMetaData(clr);
mapTbl = storeMgr.getDatastoreClass(mmd.getMap().getValueType(), clr);
if (mmd.getMappedBy() != null) {
ownerMapping = mapTbl.getMemberMapping(valCmd.getMetaDataForMember(mmd.getMappedBy()));
} else {
ownerMapping = ((DatastoreClass) mapTbl).getExternalMapping(mmd, MappingType.EXTERNAL_FK);
}
String keyFieldName = mmd.getKeyMetaData().getMappedBy();
AbstractMemberMetaData valKeyMmd = valCmd.getMetaDataForMember(keyFieldName);
keyMapping = mapTbl.getMemberMapping(valKeyMmd);
valMapping = mapTbl.getIdMapping();
} else if (mapmd.getMapType() == MapType.MAP_TYPE_VALUE_IN_KEY) {
// ForeignKey from key table to value
AbstractClassMetaData keyCmd = mapmd.getKeyClassMetaData(clr);
mapTbl = storeMgr.getDatastoreClass(mmd.getMap().getKeyType(), clr);
if (mmd.getMappedBy() != null) {
ownerMapping = mapTbl.getMemberMapping(keyCmd.getMetaDataForMember(mmd.getMappedBy()));
} else {
ownerMapping = ((DatastoreClass) mapTbl).getExternalMapping(mmd, MappingType.EXTERNAL_FK);
}
keyMapping = mapTbl.getIdMapping();
String valFieldName = mmd.getValueMetaData().getMappedBy();
AbstractMemberMetaData keyValMmd = keyCmd.getMetaDataForMember(valFieldName);
valMapping = mapTbl.getMemberMapping(keyValMmd);
} else {
throw new NucleusException("Invalid map for " + mapExpr + " in get() call");
}
SelectStatement subStmt = new SelectStatement(stmt, storeMgr, mapTbl, null, null);
SQLExpressionFactory exprFactory = stmt.getSQLExpressionFactory();
subStmt.setClassLoaderResolver(clr);
SQLExpression valExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), valMapping);
subStmt.select(valExpr, null);
// Link to primary statement
SQLExpression elementOwnerExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), ownerMapping);
SQLExpression ownerIdExpr = exprFactory.newExpression(stmt, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping());
subStmt.whereAnd(elementOwnerExpr.eq(ownerIdExpr), true);
// Condition on key
SQLExpression keyExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), keyMapping);
subStmt.whereAnd(keyExpr.eq(keyValExpr), true);
SubqueryExpression subExpr = new SubqueryExpression(stmt, subStmt);
subExpr.setJavaTypeMapping(valMapping);
return subExpr;
}
use of org.datanucleus.store.rdbms.RDBMSStoreManager in project datanucleus-rdbms by datanucleus.
the class MapValueMethod method getAsJoin.
/**
* Implementation of VALUE(map) using a join to the table representing the map, and returning the value.
* @param stmt SQLStatement
* @param mapExpr The map expression
* @return The value expression
*/
protected SQLExpression getAsJoin(SQLStatement stmt, MapExpression mapExpr) {
JavaTypeMapping m = mapExpr.getJavaTypeMapping();
RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
ClassLoaderResolver clr = stmt.getQueryGenerator().getClassLoaderResolver();
SQLExpressionFactory exprFactory = stmt.getSQLExpressionFactory();
AbstractMemberMetaData mmd = m.getMemberMetaData();
// Use the statement of the table for this Map expression, since it could be in an outer query
stmt = mapExpr.getSQLTable().getSQLStatement();
if (mmd != null) {
MapMetaData mapmd = mmd.getMap();
SQLTable mapSqlTbl = mapExpr.getSQLTable();
// Set alias of "map" table from MapExpression in case it was defined in FROM clause
String mapJoinAlias = mapExpr.getAliasForMapTable();
if (mapJoinAlias == null) {
mapJoinAlias = (mapExpr.getSQLTable().getAlias().toString() + "_" + mmd.getName()).toUpperCase();
}
if (mapmd.getMapType() == MapType.MAP_TYPE_JOIN) {
// Add join to join table
MapTable joinTbl = (MapTable) storeMgr.getTable(mmd);
SQLTable joinSqlTbl = stmt.getTable(mapJoinAlias);
if (joinSqlTbl == null) {
joinSqlTbl = stmt.join(JoinType.INNER_JOIN, mapSqlTbl, mapSqlTbl.getTable().getIdMapping(), joinTbl, mapJoinAlias, joinTbl.getOwnerMapping(), null, null);
}
// Return value expression
if (mapmd.getValueClassMetaData(clr) != null && !mapmd.isEmbeddedValue()) {
// Persistable value so join to its table (default to "{mapJoinAlias}_VALUE")
DatastoreClass valTable = storeMgr.getDatastoreClass(mapmd.getValueType(), clr);
SQLTable valueSqlTbl = stmt.getTable(mapJoinAlias + "_VALUE");
if (valueSqlTbl == null) {
valueSqlTbl = stmt.join(JoinType.INNER_JOIN, joinSqlTbl, joinTbl.getValueMapping(), valTable, mapJoinAlias + "_VALUE", valTable.getIdMapping(), null, null);
}
return exprFactory.newExpression(stmt, valueSqlTbl, valTable.getIdMapping());
}
return exprFactory.newExpression(stmt, joinSqlTbl, joinTbl.getValueMapping());
} else if (mapmd.getMapType() == MapType.MAP_TYPE_KEY_IN_VALUE) {
// Key stored in value table, so join to value table
DatastoreClass valTable = storeMgr.getDatastoreClass(mapmd.getValueType(), clr);
AbstractClassMetaData valCmd = mmd.getMap().getValueClassMetaData(clr);
JavaTypeMapping mapTblOwnerMapping;
if (mmd.getMappedBy() != null) {
mapTblOwnerMapping = valTable.getMemberMapping(valCmd.getMetaDataForMember(mmd.getMappedBy()));
} else {
mapTblOwnerMapping = valTable.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
}
SQLTable valSqlTbl = stmt.join(JoinType.INNER_JOIN, mapSqlTbl, mapSqlTbl.getTable().getIdMapping(), valTable, mapJoinAlias, mapTblOwnerMapping, null, null);
// Return value expression
return exprFactory.newExpression(stmt, valSqlTbl, valTable.getIdMapping());
} else if (mapmd.getMapType() == MapType.MAP_TYPE_VALUE_IN_KEY) {
// Value stored in key table, so join to key table
DatastoreClass keyTable = storeMgr.getDatastoreClass(mapmd.getKeyType(), clr);
AbstractClassMetaData keyCmd = mmd.getMap().getKeyClassMetaData(clr);
JavaTypeMapping mapTblOwnerMapping;
if (mmd.getMappedBy() != null) {
mapTblOwnerMapping = keyTable.getMemberMapping(keyCmd.getMetaDataForMember(mmd.getMappedBy()));
} else {
mapTblOwnerMapping = keyTable.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
}
SQLTable keySqlTbl = stmt.join(JoinType.INNER_JOIN, mapSqlTbl, mapSqlTbl.getTable().getIdMapping(), keyTable, mapJoinAlias, mapTblOwnerMapping, null, null);
// Return value expression
AbstractMemberMetaData valKeyMmd = mapmd.getKeyClassMetaData(clr).getMetaDataForMember(mmd.getValueMetaData().getMappedBy());
JavaTypeMapping valueMapping = keyTable.getMemberMapping(valKeyMmd);
return exprFactory.newExpression(stmt, keySqlTbl, valueMapping);
}
}
throw new NucleusException("KEY(map) for the filter is not supported for " + mapExpr + ". Why not contribute support for it?");
}
use of org.datanucleus.store.rdbms.RDBMSStoreManager in project datanucleus-rdbms by datanucleus.
the class MapValueMethod method getAsSubquery.
/**
* Implementation of VALUE(map) using a subquery on the table representing the map, returning the value.
* @param stmt SQLStatement
* @param mapExpr The map expression
* @return The value expression
*/
protected SQLExpression getAsSubquery(SQLStatement stmt, MapExpression mapExpr) {
AbstractMemberMetaData mmd = mapExpr.getJavaTypeMapping().getMemberMetaData();
MapMetaData mapmd = mmd.getMap();
RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
ClassLoaderResolver clr = stmt.getQueryGenerator().getClassLoaderResolver();
JavaTypeMapping ownerMapping = null;
JavaTypeMapping valMapping = null;
Table mapTbl = null;
if (mapmd.getMapType() == MapType.MAP_TYPE_JOIN) {
// JoinTable
mapTbl = storeMgr.getTable(mmd);
ownerMapping = ((MapTable) mapTbl).getOwnerMapping();
valMapping = ((MapTable) mapTbl).getValueMapping();
} else if (mapmd.getMapType() == MapType.MAP_TYPE_KEY_IN_VALUE) {
// ForeignKey from value table to key
AbstractClassMetaData valCmd = mapmd.getValueClassMetaData(clr);
mapTbl = storeMgr.getDatastoreClass(mmd.getMap().getValueType(), clr);
if (mmd.getMappedBy() != null) {
ownerMapping = mapTbl.getMemberMapping(valCmd.getMetaDataForMember(mmd.getMappedBy()));
} else {
ownerMapping = ((DatastoreClass) mapTbl).getExternalMapping(mmd, MappingType.EXTERNAL_FK);
}
valMapping = mapTbl.getIdMapping();
} else if (mapmd.getMapType() == MapType.MAP_TYPE_VALUE_IN_KEY) {
// ForeignKey from key table to value
AbstractClassMetaData keyCmd = mapmd.getKeyClassMetaData(clr);
mapTbl = storeMgr.getDatastoreClass(mmd.getMap().getKeyType(), clr);
if (mmd.getMappedBy() != null) {
ownerMapping = mapTbl.getMemberMapping(keyCmd.getMetaDataForMember(mmd.getMappedBy()));
} else {
ownerMapping = ((DatastoreClass) mapTbl).getExternalMapping(mmd, MappingType.EXTERNAL_FK);
}
String valFieldName = mmd.getValueMetaData().getMappedBy();
AbstractMemberMetaData keyValMmd = keyCmd.getMetaDataForMember(valFieldName);
valMapping = mapTbl.getMemberMapping(keyValMmd);
} else {
throw new NucleusException("Invalid map for " + mapExpr + " in get() call");
}
SQLExpressionFactory exprFactory = stmt.getSQLExpressionFactory();
SelectStatement subStmt = new SelectStatement(stmt, storeMgr, mapTbl, null, null);
subStmt.setClassLoaderResolver(clr);
SQLExpression valExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), valMapping);
subStmt.select(valExpr, null);
// Link to primary statement
SQLExpression elementOwnerExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), ownerMapping);
SQLExpression ownerIdExpr = exprFactory.newExpression(stmt, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping());
subStmt.whereAnd(elementOwnerExpr.eq(ownerIdExpr), true);
SubqueryExpression subExpr = new SubqueryExpression(stmt, subStmt);
subExpr.setJavaTypeMapping(valMapping);
return subExpr;
}
use of org.datanucleus.store.rdbms.RDBMSStoreManager in project datanucleus-rdbms by datanucleus.
the class ObjectExpression method is.
/**
* An "is" (instanceOf) expression, providing a BooleanExpression whether this expression is an instanceof the provided type.
* @param expr The expression representing the type
* @param not Whether the operator is "!instanceof"
* @return Whether this expression is an instance of the provided type
*/
public BooleanExpression is(SQLExpression expr, boolean not) {
RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
ClassLoaderResolver clr = stmt.getClassLoaderResolver();
// Extract instanceOf type
String instanceofClassName = null;
SQLExpression classExpr = expr;
if (expr instanceof TypeConverterLiteral) {
// For some reason the user has input "TYPE(field) = :param" and param is a type-converted value
classExpr = ((TypeConverterLiteral) expr).getDelegate();
}
if (classExpr instanceof StringLiteral) {
instanceofClassName = (String) ((StringLiteral) classExpr).getValue();
} else if (classExpr instanceof CollectionLiteral) {
// "a instanceof (b1,b2,b3)"
CollectionLiteral typesLiteral = (CollectionLiteral) classExpr;
Collection values = (Collection) typesLiteral.getValue();
if (values.size() == 1) {
Object value = values.iterator().next();
String valueStr = null;
if (value instanceof Class) {
valueStr = ((Class) value).getCanonicalName();
} else if (value instanceof String) {
valueStr = (String) value;
} else {
throw new NucleusUserException("Do not support CollectionLiteral of element type " + value.getClass().getName());
}
return is(new StringLiteral(stmt, typesLiteral.getJavaTypeMapping(), valueStr, typesLiteral.getParameterName()), not);
}
List<BooleanExpression> listExp = new LinkedList<>();
for (Object value : values) {
String valueStr = null;
if (value instanceof Class) {
valueStr = ((Class) value).getCanonicalName();
} else if (value instanceof String) {
valueStr = (String) value;
} else {
throw new NucleusUserException("Do not support CollectionLiteral of element type " + value.getClass().getName());
}
listExp.add(is(new StringLiteral(stmt, typesLiteral.getJavaTypeMapping(), valueStr, typesLiteral.getParameterName()), false));
}
BooleanExpression result = null;
for (BooleanExpression sqlExpression : listExp) {
result = result == null ? sqlExpression : result.ior(sqlExpression);
}
if (result != null) {
return not ? result.not() : result;
}
} else {
throw new NucleusUserException("Do not currently support `instanceof` with class expression of type " + classExpr);
}
Class type = null;
try {
type = stmt.getQueryGenerator().resolveClass(instanceofClassName);
} catch (ClassNotResolvedException cnre) {
type = null;
}
if (type == null) {
throw new NucleusUserException(Localiser.msg("037016", instanceofClassName));
}
// Extract type of member and check obvious conditions
SQLExpressionFactory exprFactory = stmt.getSQLExpressionFactory();
Class memberType = clr.classForName(mapping.getType());
if (!memberType.isAssignableFrom(type) && !type.isAssignableFrom(memberType)) {
// Member type and instanceof type are totally incompatible, so just return false
JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, not));
} else if (memberType == type) {
// instanceof type is the same as the member type therefore must comply (can't store supertypes)
JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, !not));
}
if (mapping instanceof EmbeddedMapping) {
// Don't support embedded instanceof expressions
AbstractClassMetaData fieldCmd = storeMgr.getMetaDataManager().getMetaDataForClass(mapping.getType(), clr);
if (fieldCmd.hasDiscriminatorStrategy()) {
// Embedded field with inheritance so add discriminator restriction
JavaTypeMapping discMapping = ((EmbeddedMapping) mapping).getDiscriminatorMapping();
AbstractClassMetaData typeCmd = storeMgr.getMetaDataManager().getMetaDataForClass(type, clr);
SQLExpression discExpr = stmt.getSQLExpressionFactory().newExpression(stmt, table, discMapping);
SQLExpression discValExpr = stmt.getSQLExpressionFactory().newLiteral(stmt, discMapping, typeCmd.getDiscriminatorValue());
BooleanExpression typeExpr = (not ? discExpr.ne(discValExpr) : discExpr.eq(discValExpr));
Iterator<String> subclassIter = storeMgr.getSubClassesForClass(type.getName(), true, clr).iterator();
while (subclassIter.hasNext()) {
String subclassName = subclassIter.next();
AbstractClassMetaData subtypeCmd = storeMgr.getMetaDataManager().getMetaDataForClass(subclassName, clr);
Object subtypeDiscVal = subtypeCmd.getDiscriminatorValue();
discValExpr = stmt.getSQLExpressionFactory().newLiteral(stmt, discMapping, subtypeDiscVal);
BooleanExpression subtypeExpr = (not ? discExpr.ne(discValExpr) : discExpr.eq(discValExpr));
if (not) {
typeExpr = typeExpr.and(subtypeExpr);
} else {
typeExpr = typeExpr.ior(subtypeExpr);
}
}
return typeExpr;
}
JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, not));
} else if (mapping instanceof PersistableMapping || mapping instanceof ReferenceMapping) {
// Field has its own table, so join to it
AbstractClassMetaData memberCmd = storeMgr.getMetaDataManager().getMetaDataForClass(mapping.getType(), clr);
DatastoreClass memberTable = null;
if (memberCmd.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 = storeMgr.getClassesManagingTableForClass(memberCmd, clr);
if (cmds != null) {
// 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()));
}
memberTable = storeMgr.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
memberTable = storeMgr.getDatastoreClass(mapping.getType(), clr);
}
DiscriminatorMetaData dismd = memberTable.getDiscriminatorMetaData();
DiscriminatorMapping discMapping = (DiscriminatorMapping) memberTable.getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, false);
if (discMapping != null) {
SQLTable targetSqlTbl = null;
if (mapping.getTable() != memberTable) {
// FK is on source table so inner join to target table (holding the discriminator)
targetSqlTbl = stmt.getTable(memberTable, null);
if (targetSqlTbl == null) {
targetSqlTbl = stmt.join(JoinType.INNER_JOIN, getSQLTable(), mapping, memberTable, null, memberTable.getIdMapping(), null, null);
}
} else {
// FK is on target side and already joined
targetSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(stmt, getSQLTable(), discMapping);
}
// Add restrict to discriminator for the instanceOf type and subclasses
SQLTable discSqlTbl = targetSqlTbl;
BooleanExpression discExpr = null;
if (!Modifier.isAbstract(type.getModifiers())) {
discExpr = SQLStatementHelper.getExpressionForDiscriminatorForClass(stmt, type.getName(), dismd, discMapping, discSqlTbl, clr);
}
Iterator<String> subclassIter = storeMgr.getSubClassesForClass(type.getName(), true, clr).iterator();
boolean multiplePossibles = false;
while (subclassIter.hasNext()) {
String subclassName = subclassIter.next();
Class subclass = clr.classForName(subclassName);
if (Modifier.isAbstract(subclass.getModifiers())) {
continue;
}
BooleanExpression discExprSub = SQLStatementHelper.getExpressionForDiscriminatorForClass(stmt, subclassName, dismd, discMapping, discSqlTbl, clr);
if (discExpr != null) {
multiplePossibles = true;
discExpr = discExpr.ior(discExprSub);
} else {
discExpr = discExprSub;
}
}
if (multiplePossibles && discExpr != null) {
discExpr.encloseInParentheses();
}
return ((not && discExpr != null) ? discExpr.not() : discExpr);
}
// No discriminator, so the following is likely incomplete.
// Join to member table
DatastoreClass table = null;
if (memberCmd.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 = storeMgr.getClassesManagingTableForClass(memberCmd, clr);
if (cmds != null) {
// 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 = storeMgr.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 = storeMgr.getDatastoreClass(mapping.getType(), clr);
}
if (table.managesClass(type.getName())) {
// This type is managed in this table so must be an instance TODO Is this correct, what if member is using discrim?
JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, !not));
}
if (table == stmt.getPrimaryTable().getTable()) {
// This is member table, so just need to restrict to the instanceof type now
JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
if (stmt instanceof SelectStatement) {
SelectStatement selectStmt = (SelectStatement) stmt;
if (selectStmt.getNumberOfUnions() == 0) {
// No UNIONs so just check the main statement and return according to whether it is allowed
Class mainCandidateCls = clr.classForName(stmt.getCandidateClassName());
if (type.isAssignableFrom(mainCandidateCls) == not) {
SQLExpression returnExpr = exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, false));
return (BooleanExpression) returnExpr;
}
SQLExpression returnExpr = exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, true));
return (BooleanExpression) returnExpr;
}
NucleusLogger.QUERY.warn("TYPE/INSTANCEOF operator for class=" + memberCmd.getFullClassName() + " on table=" + memberTable + " for type=" + instanceofClassName + " but there is no discriminator and using UNIONs. Any subsequent handling is likely incorrect TODO");
// a). we have unions for the member, so restrict to just the applicable unions
// Note that this is only really valid is wanting "a instanceof SUB1".
// It fails when we want to do "a instanceof SUB1 || a instanceof SUB2"
// TODO What if this "OP_IS" is in the SELECT clause??? Need to update QueryToSQLMapper.compileResult
Class mainCandidateCls = clr.classForName(stmt.getCandidateClassName());
if (type.isAssignableFrom(mainCandidateCls) == not) {
SQLExpression unionClauseExpr = exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, false));
stmt.whereAnd((BooleanExpression) unionClauseExpr, false);
}
List<SelectStatement> unionStmts = selectStmt.getUnions();
for (SelectStatement unionStmt : unionStmts) {
Class unionCandidateCls = clr.classForName(unionStmt.getCandidateClassName());
if (type.isAssignableFrom(unionCandidateCls) == not) {
SQLExpression unionClauseExpr = exprFactory.newLiteral(unionStmt, m, true).eq(exprFactory.newLiteral(unionStmt, m, false));
// TODO Avoid using whereAnd
unionStmt.whereAnd((BooleanExpression) unionClauseExpr, false);
}
}
// Just return true since we applied the condition direct to the unions
SQLExpression returnExpr = exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, true));
return (BooleanExpression) returnExpr;
}
// b). The member table doesn't manage the instanceof type, so do inner join to
// the table of the instanceof to impose the instanceof condition
DatastoreClass instanceofTable = storeMgr.getDatastoreClass(type.getName(), clr);
stmt.join(JoinType.INNER_JOIN, this.table, this.table.getTable().getIdMapping(), instanceofTable, null, instanceofTable.getIdMapping(), null, this.table.getGroupName());
return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, !not));
}
// Do inner join to this table to impose the instanceOf
DatastoreClass instanceofTable = storeMgr.getDatastoreClass(type.getName(), clr);
stmt.join(JoinType.INNER_JOIN, this.table, this.table.getTable().getIdMapping(), instanceofTable, null, instanceofTable.getIdMapping(), null, this.table.getGroupName());
JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, !not));
} else {
// TODO Implement instanceof for other types
throw new NucleusException("Dont currently support " + this + " instanceof " + type.getName());
}
}
Aggregations