use of org.datanucleus.metadata.DiscriminatorMetaData in project datanucleus-rdbms by datanucleus.
the class EmbeddedMapping method initialize.
/**
* Initialize for the specified member.
* @param mmd metadata for the embedded member
* @param table Table for persisting this field
* @param clr The ClassLoaderResolver
* @param emd Embedded MetaData for the object being embedded
* @param typeName type of the embedded PC object being stored
* @param objectType Object type of the PC object being embedded (see StateManagerImpl object types)
*/
public void initialize(AbstractMemberMetaData mmd, Table table, ClassLoaderResolver clr, EmbeddedMetaData emd, String typeName, int objectType) {
super.initialize(mmd, table, clr);
this.clr = clr;
this.emd = emd;
this.typeName = typeName;
this.objectType = (short) objectType;
// Find the MetaData for the embedded PC class
MetaDataManager mmgr = table.getStoreManager().getMetaDataManager();
AbstractClassMetaData rootEmbCmd = mmgr.getMetaDataForClass(typeName, clr);
if (rootEmbCmd == null) {
// Not found so must be an interface
// Try using the fieldTypes on the field/property - we support it if only 1 implementation
String[] fieldTypes = mmd.getFieldTypes();
if (fieldTypes != null && fieldTypes.length == 1) {
rootEmbCmd = mmgr.getMetaDataForClass(fieldTypes[0], clr);
} else if (fieldTypes != null && fieldTypes.length > 1) {
// TODO Cater for multiple implementations
throw new NucleusUserException("Field " + mmd.getFullFieldName() + " is a reference field that is embedded with multiple possible implementations. " + "DataNucleus doesnt support embedded reference fields that have more than 1 implementation");
}
if (rootEmbCmd == null) {
// Try a persistent interface
rootEmbCmd = mmgr.getMetaDataForInterface(clr.classForName(typeName), clr);
if (rootEmbCmd == null && mmd.getFieldTypes() != null && mmd.getFieldTypes().length == 1) {
// No MetaData for the type so try "fieldType" specified on the field
rootEmbCmd = mmgr.getMetaDataForInterface(clr.classForName(mmd.getFieldTypes()[0]), clr);
}
}
}
if (rootEmbCmd == null) {
throw new NucleusUserException("Unable to find root class embedded metadata for field=" + mmd.getFullFieldName());
}
embCmd = rootEmbCmd;
AbstractMemberMetaData[] embFmds = null;
if (emd == null && rootEmbCmd.isEmbeddedOnly()) {
// No <embedded> block yet the class is defined as embedded-only so just use its own definition of fields
embFmds = rootEmbCmd.getManagedMembers();
} else if (emd != null) {
// <embedded> block so use those field definitions
embFmds = emd.getMemberMetaData();
}
String[] subclasses = mmgr.getSubclassesForClass(rootEmbCmd.getFullClassName(), true);
if (subclasses != null && subclasses.length > 0) {
if (rootEmbCmd.hasDiscriminatorStrategy()) {
// Fabricate a DiscriminatorMetaData to use for the embedded object
discrimMetaData = new DiscriminatorMetaData();
InheritanceMetaData embInhMd = new InheritanceMetaData();
embInhMd.setParent(rootEmbCmd);
discrimMetaData.setParent(embInhMd);
// Set strategy based on the inheritance of the embedded object, otherwise class name.
DiscriminatorMetaData dismd = rootEmbCmd.getDiscriminatorMetaDataRoot();
if (dismd.getStrategy() != null && dismd.getStrategy() != DiscriminatorStrategy.NONE) {
discrimMetaData.setStrategy(dismd.getStrategy());
} else {
// Fallback to class name
discrimMetaData.setStrategy(DiscriminatorStrategy.CLASS_NAME);
}
// Set column for discriminator
ColumnMetaData disColmd = new ColumnMetaData();
disColmd.setAllowsNull(Boolean.TRUE);
DiscriminatorMetaData embDismd = (emd != null) ? emd.getDiscriminatorMetaData() : null;
if (embDismd != null && embDismd.getColumnMetaData() != null) {
disColmd.setName(embDismd.getColumnMetaData().getName());
} else {
ColumnMetaData colmd = dismd.getColumnMetaData();
if (colmd != null && colmd.getName() != null) {
disColmd.setName(colmd.getName());
}
}
discrimMetaData.setColumnMetaData(disColmd);
discrimMapping = DiscriminatorMapping.createDiscriminatorMapping(table, discrimMetaData);
addDatastoreMapping(discrimMapping.getDatastoreMapping(0));
} else {
NucleusLogger.PERSISTENCE.info("Member " + mmd.getFullFieldName() + " is embedded and the type " + "(" + rootEmbCmd.getFullClassName() + ") has potential subclasses." + " Impossible to detect which is stored embedded. Add a discriminator to the embedded type");
}
}
// Add all fields of the embedded class (that are persistent)
int[] pcFieldNumbers = rootEmbCmd.getAllMemberPositions();
for (int i = 0; i < pcFieldNumbers.length; i++) {
AbstractMemberMetaData rootEmbMmd = rootEmbCmd.getMetaDataForManagedMemberAtAbsolutePosition(pcFieldNumbers[i]);
if (rootEmbMmd.getPersistenceModifier() == FieldPersistenceModifier.PERSISTENT) {
addMappingForMember(rootEmbCmd, rootEmbMmd, embFmds);
}
}
// Add fields for any subtypes (that are persistent)
if (discrimMapping != null && subclasses != null && subclasses.length > 0) {
for (int i = 0; i < subclasses.length; i++) {
AbstractClassMetaData subEmbCmd = storeMgr.getMetaDataManager().getMetaDataForClass(subclasses[i], clr);
AbstractMemberMetaData[] subEmbMmds = subEmbCmd.getManagedMembers();
if (subEmbMmds != null) {
for (int j = 0; j < subEmbMmds.length; j++) {
if (subEmbMmds[j].getPersistenceModifier() == FieldPersistenceModifier.PERSISTENT) {
addMappingForMember(subEmbCmd, subEmbMmds[j], embFmds);
}
}
}
}
}
}
use of org.datanucleus.metadata.DiscriminatorMetaData in project datanucleus-rdbms by datanucleus.
the class DiscriminatorStatementGenerator method getStatement.
/**
* Accessor for the SelectStatement.
* @param ec ExecutionContext
* @return The SelectStatement for iterating through objects with a discriminator column
*/
public SelectStatement getStatement(ExecutionContext ec) {
SelectStatement stmt = null;
SQLTable discrimSqlTbl = null;
if (joinTable == null) {
// Select of candidate table
stmt = new SelectStatement(parentStmt, storeMgr, candidateTable, candidateTableAlias, candidateTableGroupName);
stmt.setClassLoaderResolver(clr);
discrimSqlTbl = stmt.getPrimaryTable();
} else {
// Select of join table, with join to element table
stmt = new SelectStatement(parentStmt, storeMgr, joinTable, joinTableAlias, candidateTableGroupName);
stmt.setClassLoaderResolver(clr);
JavaTypeMapping candidateIdMapping = candidateTable.getIdMapping();
if (hasOption(OPTION_ALLOW_NULLS)) {
// Put element table in same table group since all relates to the elements
discrimSqlTbl = stmt.join(JoinType.LEFT_OUTER_JOIN, null, joinElementMapping, candidateTable, null, candidateIdMapping, null, stmt.getPrimaryTable().getGroupName(), true);
} else {
// Put element table in same table group since all relates to the elements
discrimSqlTbl = stmt.join(JoinType.INNER_JOIN, null, joinElementMapping, candidateTable, null, candidateIdMapping, null, stmt.getPrimaryTable().getGroupName(), true);
}
}
JavaTypeMapping discMapping = candidateTable.getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, true);
if (discMapping != null) {
// Allow for discriminator being in super-table of the candidate table
discrimSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(stmt, discrimSqlTbl, discMapping);
}
DiscriminatorMetaData dismd = discrimSqlTbl.getTable().getDiscriminatorMetaData();
boolean hasDiscriminator = (discMapping != null && dismd != null && dismd.getStrategy() != DiscriminatorStrategy.NONE);
// Check if we can omit the discriminator restriction
boolean restrictDiscriminator = hasOption(OPTION_RESTRICT_DISCRIM);
if (hasDiscriminator && restrictDiscriminator) {
// Add the discriminator expression to restrict accepted values
boolean multipleCandidates = false;
BooleanExpression discExpr = null;
if (candidates != null) {
// Multiple candidates
if (candidates.length > 1) {
multipleCandidates = true;
}
for (int i = 0; i < candidates.length; i++) {
if (Modifier.isAbstract(candidates[i].getModifiers())) {
// No point selecting this candidate since can't be instantiated
continue;
}
BooleanExpression discExprCandidate = SQLStatementHelper.getExpressionForDiscriminatorForClass(stmt, candidates[i].getName(), dismd, discMapping, discrimSqlTbl, clr);
if (discExpr != null) {
discExpr = discExpr.ior(discExprCandidate);
} else {
discExpr = discExprCandidate;
}
if (includeSubclasses) {
Collection<String> subclassNames = storeMgr.getSubClassesForClass(candidateType.getName(), true, clr);
Iterator<String> subclassIter = subclassNames.iterator();
if (!multipleCandidates) {
multipleCandidates = (subclassNames.size() > 0);
}
while (subclassIter.hasNext()) {
String subclassName = subclassIter.next();
BooleanExpression discExprSub = SQLStatementHelper.getExpressionForDiscriminatorForClass(stmt, subclassName, dismd, discMapping, discrimSqlTbl, clr);
discExpr = discExpr.ior(discExprSub);
}
}
}
} else {
// Single candidate
if (!Modifier.isAbstract(candidateType.getModifiers())) {
discExpr = SQLStatementHelper.getExpressionForDiscriminatorForClass(stmt, candidateType.getName(), dismd, discMapping, discrimSqlTbl, clr);
}
if (includeSubclasses) {
Collection<String> subclassNames = storeMgr.getSubClassesForClass(candidateType.getName(), true, clr);
Iterator<String> subclassIter = subclassNames.iterator();
multipleCandidates = (subclassNames.size() > 0);
while (subclassIter.hasNext()) {
String subclassName = subclassIter.next();
Class subclass = clr.classForName(subclassName);
if ((Modifier.isAbstract(subclass.getModifiers()))) {
continue;
}
BooleanExpression discExprCandidate = SQLStatementHelper.getExpressionForDiscriminatorForClass(stmt, subclassName, dismd, discMapping, discrimSqlTbl, clr);
if (discExpr == null) {
discExpr = discExprCandidate;
} else {
discExpr = discExpr.ior(discExprCandidate);
}
}
}
if (discExpr == null) {
// No possible candidates, so set expression as "1=0"
SQLExpressionFactory exprFactory = stmt.getSQLExpressionFactory();
JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
discExpr = exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, false));
}
}
if (discExpr != null) {
if (hasOption(OPTION_ALLOW_NULLS)) {
// Allow for null value of discriminator
SQLExpression expr = stmt.getSQLExpressionFactory().newExpression(stmt, discrimSqlTbl, discMapping);
SQLExpression val = new NullLiteral(stmt, null, null, null);
BooleanExpression nullDiscExpr = expr.eq(val);
discExpr = discExpr.ior(nullDiscExpr);
if (!multipleCandidates) {
multipleCandidates = true;
}
}
// Apply the discriminator to the query statement
if (multipleCandidates) {
discExpr.encloseInParentheses();
}
stmt.whereAnd(discExpr, true);
}
}
JavaTypeMapping multitenancyMapping = candidateTable.getSurrogateMapping(SurrogateColumnType.MULTITENANCY, false);
if (multitenancyMapping != null) {
// Multi-tenancy restriction
AbstractClassMetaData cmd = candidateTable.getClassMetaData();
SQLTable tenantSqlTbl = stmt.getTable(multitenancyMapping.getTable(), discrimSqlTbl.getGroupName());
SQLExpression tenantExpr = stmt.getSQLExpressionFactory().newExpression(stmt, tenantSqlTbl, multitenancyMapping);
SQLExpression tenantVal = stmt.getSQLExpressionFactory().newLiteral(stmt, multitenancyMapping, ec.getNucleusContext().getMultiTenancyId(ec, cmd));
stmt.whereAnd(tenantExpr.eq(tenantVal), true);
}
JavaTypeMapping softDeleteMapping = candidateTable.getSurrogateMapping(SurrogateColumnType.SOFTDELETE, false);
if (softDeleteMapping != null && !hasOption(OPTION_INCLUDE_SOFT_DELETES)) {
// Soft-delete restriction
SQLTable softDeleteSqlTbl = stmt.getTable(softDeleteMapping.getTable(), discrimSqlTbl.getGroupName());
SQLExpression softDeleteExpr = stmt.getSQLExpressionFactory().newExpression(stmt, softDeleteSqlTbl, softDeleteMapping);
SQLExpression softDeleteVal = stmt.getSQLExpressionFactory().newLiteral(stmt, softDeleteMapping, Boolean.FALSE);
stmt.whereAnd(softDeleteExpr.eq(softDeleteVal), true);
}
return stmt;
}
use of org.datanucleus.metadata.DiscriminatorMetaData 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());
}
}
use of org.datanucleus.metadata.DiscriminatorMetaData in project datanucleus-rdbms by datanucleus.
the class ClassTable method initialize.
/**
* Method to initialise the table.
* This adds the columns based on the MetaData representation for the class being represented by this table.
* @param clr The ClassLoaderResolver
*/
public void initialize(ClassLoaderResolver clr) {
// if already initialized, we have nothing further to do here
if (isInitialized()) {
return;
}
// we may inherit from that table are initialized at the point at which we may need them
if (supertable != null) {
supertable.initialize(clr);
}
// Add the fields for this class (and any other superclasses that we need to manage the
// fields for (inheritance-strategy="subclass-table" in the superclass)
initializeForClass(cmd, clr);
MappingManager mapMgr = storeMgr.getMappingManager();
// Add Version where specified in MetaData
// TODO If there is a superclass table that has a version we should omit from here even if in MetaData
// See "getTableWithDiscriminator()" for the logic
versionMetaData = cmd.getVersionMetaDataForTable();
if (versionMetaData != null && versionMetaData.getFieldName() == null) {
if (versionMetaData.getVersionStrategy() == VersionStrategy.NONE || versionMetaData.getVersionStrategy() == VersionStrategy.VERSION_NUMBER) {
// No optimistic locking but the idiot wants a column for that :-)
versionMapping = new VersionMapping.VersionLongMapping(this, mapMgr.getMapping(Long.class));
} else if (versionMetaData.getVersionStrategy() == VersionStrategy.DATE_TIME) {
if (!dba.supportsOption(DatastoreAdapter.DATETIME_STORES_MILLISECS)) {
// TODO Localise this
throw new NucleusException("Class " + cmd.getFullClassName() + " is defined " + "to use date-time versioning, yet this datastore doesnt support storing " + "milliseconds in DATETIME/TIMESTAMP columns. Use version-number");
}
versionMapping = new VersionMapping.VersionTimestampMapping(this, mapMgr.getMapping(Timestamp.class));
}
if (versionMapping != null) {
logMapping("VERSION", versionMapping);
}
}
// Add Discriminator where specified in MetaData
DiscriminatorMetaData dismd = cmd.getDiscriminatorMetaDataForTable();
if (dismd != null) {
discriminatorMetaData = dismd;
if (storeMgr.getBooleanProperty(RDBMSPropertyNames.PROPERTY_RDBMS_DISCRIM_PER_SUBCLASS_TABLE)) {
// Backwards compatibility only. Creates discriminator in all subclass tables even though not needed
// TODO Remove this in the future
discriminatorMapping = DiscriminatorMapping.createDiscriminatorMapping(this, dismd);
} else {
// Create discriminator column only in top most table that needs it
ClassTable tableWithDiscrim = getTableWithDiscriminator();
if (tableWithDiscrim == this) {
// No superclass with a discriminator so add it in this table
discriminatorMapping = DiscriminatorMapping.createDiscriminatorMapping(this, dismd);
}
}
if (discriminatorMapping != null) {
logMapping("DISCRIMINATOR", discriminatorMapping);
}
}
// TODO Only put on root table (i.e "if (supertable != null)" then omit)
if (storeMgr.getNucleusContext().isClassMultiTenant(cmd)) {
ColumnMetaData colmd = new ColumnMetaData();
if (cmd.hasExtension(MetaData.EXTENSION_CLASS_MULTITENANCY_COLUMN_NAME)) {
colmd.setName(cmd.getValueForExtension(MetaData.EXTENSION_CLASS_MULTITENANCY_COLUMN_NAME));
}
if (cmd.hasExtension(MetaData.EXTENSION_CLASS_MULTITENANCY_JDBC_TYPE)) {
colmd.setJdbcType(cmd.getValueForExtension(MetaData.EXTENSION_CLASS_MULTITENANCY_JDBC_TYPE));
}
if (cmd.hasExtension(MetaData.EXTENSION_CLASS_MULTITENANCY_COLUMN_LENGTH)) {
colmd.setLength(cmd.getValueForExtension(MetaData.EXTENSION_CLASS_MULTITENANCY_COLUMN_LENGTH));
}
String colName = (colmd.getName() != null) ? colmd.getName() : "TENANT_ID";
String typeName = (colmd.getJdbcType() == JdbcType.INTEGER) ? Integer.class.getName() : String.class.getName();
multitenancyMapping = (typeName.equals(Integer.class.getName())) ? new IntegerMapping() : new StringMapping();
multitenancyMapping.setTable(this);
multitenancyMapping.initialize(storeMgr, typeName);
Column tenantColumn = addColumn(typeName, storeMgr.getIdentifierFactory().newIdentifier(IdentifierType.COLUMN, colName), multitenancyMapping, colmd);
storeMgr.getMappingManager().createDatastoreMapping(multitenancyMapping, tenantColumn, typeName);
logMapping("MULTITENANCY", multitenancyMapping);
}
if (cmd.hasExtension(MetaData.EXTENSION_CLASS_SOFTDELETE)) {
// SoftDelete flag column
ColumnMetaData colmd = new ColumnMetaData();
if (cmd.hasExtension(MetaData.EXTENSION_CLASS_SOFTDELETE_COLUMN_NAME)) {
colmd.setName(cmd.getValueForExtension(MetaData.EXTENSION_CLASS_SOFTDELETE_COLUMN_NAME));
}
String colName = (colmd.getName() != null) ? colmd.getName() : "DELETED";
// TODO Allow integer?
String typeName = Boolean.class.getName();
softDeleteMapping = new BooleanMapping();
softDeleteMapping.setTable(this);
softDeleteMapping.initialize(storeMgr, typeName);
Column tenantColumn = addColumn(typeName, storeMgr.getIdentifierFactory().newIdentifier(IdentifierType.COLUMN, colName), softDeleteMapping, colmd);
storeMgr.getMappingManager().createDatastoreMapping(softDeleteMapping, tenantColumn, typeName);
logMapping("SOFTDELETE", softDeleteMapping);
}
// Initialise any SecondaryTables
if (secondaryTables != null) {
Iterator<Map.Entry<String, SecondaryTable>> secondaryTableEntryIter = secondaryTables.entrySet().iterator();
while (secondaryTableEntryIter.hasNext()) {
Map.Entry<String, SecondaryTable> secondaryTableEntry = secondaryTableEntryIter.next();
SecondaryTable second = secondaryTableEntry.getValue();
if (!second.isInitialized()) {
second.initialize(clr);
}
}
}
if (NucleusLogger.DATASTORE_SCHEMA.isDebugEnabled()) {
NucleusLogger.DATASTORE_SCHEMA.debug(Localiser.msg("057023", this));
}
storeMgr.registerTableInitialized(this);
state = TABLE_STATE_INITIALIZED;
}
use of org.datanucleus.metadata.DiscriminatorMetaData in project datanucleus-rdbms by datanucleus.
the class ClassTable method getExpectedIndices.
/**
* Accessor for the indices for this table. This includes both the
* user-defined indices (via MetaData), and the ones required by foreign
* keys (required by relationships).
* @param clr The ClassLoaderResolver
* @return The indices
*/
protected Set<Index> getExpectedIndices(ClassLoaderResolver clr) {
// Auto mode allows us to decide which indices are needed as well as using what is in the users MetaData
boolean autoMode = false;
if (storeMgr.getStringProperty(RDBMSPropertyNames.PROPERTY_RDBMS_CONSTRAINT_CREATE_MODE).equals("DataNucleus")) {
autoMode = true;
}
Set<Index> indices = new HashSet();
// Add on any user-required indices for the fields/properties
Set memberNumbersSet = memberMappingsMap.keySet();
Iterator iter = memberNumbersSet.iterator();
while (iter.hasNext()) {
AbstractMemberMetaData fmd = (AbstractMemberMetaData) iter.next();
JavaTypeMapping fieldMapping = memberMappingsMap.get(fmd);
if (fieldMapping instanceof EmbeddedPCMapping) {
// Add indexes for fields of this embedded PC object
EmbeddedPCMapping embMapping = (EmbeddedPCMapping) fieldMapping;
for (int i = 0; i < embMapping.getNumberOfJavaTypeMappings(); i++) {
JavaTypeMapping embFieldMapping = embMapping.getJavaTypeMapping(i);
IndexMetaData imd = embFieldMapping.getMemberMetaData().getIndexMetaData();
if (imd != null) {
Index index = TableUtils.getIndexForField(this, imd, embFieldMapping);
if (index != null) {
indices.add(index);
}
}
}
} else if (fieldMapping instanceof SerialisedMapping) {
// Don't index these
} else {
// Add any required index for this field
IndexMetaData imd = fmd.getIndexMetaData();
if (imd != null) {
// Index defined so add it
Index index = TableUtils.getIndexForField(this, imd, fieldMapping);
if (index != null) {
indices.add(index);
}
} else if (autoMode) {
if (fmd.getIndexed() == null) {
// Indexing not set, so add where we think it is appropriate
if (// Ignore PKs since they will be indexed anyway
!fmd.isPrimaryKey()) {
// TODO Some RDBMS create index automatically for all FK cols so we don't need to really
RelationType relationType = fmd.getRelationType(clr);
if (relationType == RelationType.ONE_TO_ONE_UNI) {
// 1-1 with FK at this side so index the FK
if (fieldMapping instanceof ReferenceMapping) {
ReferenceMapping refMapping = (ReferenceMapping) fieldMapping;
if (refMapping.getMappingStrategy() == ReferenceMapping.PER_IMPLEMENTATION_MAPPING) {
// Cols per implementation : index each of implementations
if (refMapping.getJavaTypeMapping() != null) {
int colNum = 0;
JavaTypeMapping[] implMappings = refMapping.getJavaTypeMapping();
for (int i = 0; i < implMappings.length; i++) {
int numColsInImpl = implMappings[i].getNumberOfDatastoreMappings();
Index index = new Index(this, false, null);
for (int j = 0; j < numColsInImpl; j++) {
index.setColumn(j, fieldMapping.getDatastoreMapping(colNum++).getColumn());
}
indices.add(index);
}
}
}
} else {
Index index = new Index(this, false, null);
for (int i = 0; i < fieldMapping.getNumberOfDatastoreMappings(); i++) {
index.setColumn(i, fieldMapping.getDatastoreMapping(i).getColumn());
}
indices.add(index);
}
} else if (relationType == RelationType.ONE_TO_ONE_BI && fmd.getMappedBy() == null) {
// 1-1 with FK at this side so index the FK
Index index = new Index(this, false, null);
for (int i = 0; i < fieldMapping.getNumberOfDatastoreMappings(); i++) {
index.setColumn(i, fieldMapping.getDatastoreMapping(i).getColumn());
}
indices.add(index);
} else if (relationType == RelationType.MANY_TO_ONE_BI) {
// N-1 with FK at this side so index the FK
AbstractMemberMetaData relMmd = fmd.getRelatedMemberMetaData(clr)[0];
if (relMmd.getJoinMetaData() == null && fmd.getJoinMetaData() == null) {
if (fieldMapping.getNumberOfDatastoreMappings() > 0) {
Index index = new Index(this, false, null);
for (int i = 0; i < fieldMapping.getNumberOfDatastoreMappings(); i++) {
index.setColumn(i, fieldMapping.getDatastoreMapping(i).getColumn());
}
indices.add(index);
} else {
// TODO How do we get this?
NucleusLogger.DATASTORE_SCHEMA.warn("Table " + this + " manages member " + fmd.getFullFieldName() + " which is a N-1 but there is no column for this mapping so not adding index!");
}
}
}
}
}
}
}
}
// Check if any version column needs indexing
if (versionMapping != null) {
IndexMetaData idxmd = getVersionMetaData().getIndexMetaData();
if (idxmd != null) {
Index index = new Index(this, idxmd.isUnique(), idxmd.getExtensions());
if (idxmd.getName() != null) {
index.setName(idxmd.getName());
}
int countVersionFields = versionMapping.getNumberOfDatastoreMappings();
for (int i = 0; i < countVersionFields; i++) {
index.addColumn(versionMapping.getDatastoreMapping(i).getColumn());
}
indices.add(index);
}
}
// Check if any discriminator column needs indexing
if (discriminatorMapping != null) {
DiscriminatorMetaData dismd = getDiscriminatorMetaData();
IndexMetaData idxmd = dismd.getIndexMetaData();
if (idxmd != null) {
Index index = new Index(this, idxmd.isUnique(), idxmd.getExtensions());
if (idxmd.getName() != null) {
index.setName(idxmd.getName());
}
int countDiscrimFields = discriminatorMapping.getNumberOfDatastoreMappings();
for (int i = 0; i < countDiscrimFields; i++) {
index.addColumn(discriminatorMapping.getDatastoreMapping(i).getColumn());
}
indices.add(index);
}
}
// Add on any order fields (for lists, arrays, collections) that need indexing
Set orderMappingsEntries = getExternalOrderMappings().entrySet();
Iterator orderMappingsEntriesIter = orderMappingsEntries.iterator();
while (orderMappingsEntriesIter.hasNext()) {
Map.Entry entry = (Map.Entry) orderMappingsEntriesIter.next();
AbstractMemberMetaData fmd = (AbstractMemberMetaData) entry.getKey();
JavaTypeMapping mapping = (JavaTypeMapping) entry.getValue();
OrderMetaData omd = fmd.getOrderMetaData();
if (omd != null && omd.getIndexMetaData() != null) {
Index index = getIndexForIndexMetaDataAndMapping(omd.getIndexMetaData(), mapping);
if (index != null) {
indices.add(index);
}
}
}
// Add on any user-required indices for the class(es) as a whole (subelement of <class>)
Iterator<AbstractClassMetaData> cmdIter = managedClassMetaData.iterator();
while (cmdIter.hasNext()) {
AbstractClassMetaData thisCmd = cmdIter.next();
List<IndexMetaData> classIndices = thisCmd.getIndexMetaData();
if (classIndices != null) {
for (IndexMetaData idxmd : classIndices) {
Index index = getIndexForIndexMetaData(idxmd);
if (index != null) {
indices.add(index);
}
}
}
}
if (cmd.getIdentityType() == IdentityType.APPLICATION) {
// Make sure there is no reuse of PK fields that cause a duplicate index for the PK. Remove it if required
PrimaryKey pk = getPrimaryKey();
Iterator<Index> indicesIter = indices.iterator();
while (indicesIter.hasNext()) {
Index idx = indicesIter.next();
if (idx.getColumnList().equals(pk.getColumnList())) {
NucleusLogger.DATASTORE_SCHEMA.debug("Index " + idx + " is for the same columns as the PrimaryKey so being removed from expected set of indices. PK is always indexed");
indicesIter.remove();
}
}
}
return indices;
}
Aggregations