use of org.datanucleus.store.rdbms.table.DatastoreClass in project datanucleus-rdbms by datanucleus.
the class RDBMSQueryUtils method getStatementForCandidates.
/**
* Method to return a statement selecting the candidate table(s) required to cover all possible types for this candidates inheritance strategy.
* @param storeMgr RDBMS StoreManager
* @param parentStmt Parent statement (if there is one)
* @param cmd Metadata for the class
* @param clsMapping Mapping for the results of the statement
* @param ec ExecutionContext
* @param candidateCls Candidate class
* @param subclasses Whether to create a statement for subclasses of the candidate too
* @param result The result clause
* @param candidateAlias alias for the candidate (if any)
* @param candidateTableGroupName TableGroup name for the candidate (if any)
* @param options Any options for the statement for getting candidates. See SelectStatementGenerator for some options.
* @return The SQLStatement
* @throws NucleusException if there are no tables for concrete classes in this query (hence would return null)
*/
public static SelectStatement getStatementForCandidates(RDBMSStoreManager storeMgr, SQLStatement parentStmt, AbstractClassMetaData cmd, StatementClassMapping clsMapping, ExecutionContext ec, Class candidateCls, boolean subclasses, String result, String candidateAlias, String candidateTableGroupName, Set<String> options) {
SelectStatement stmt = null;
DatastoreIdentifier candidateAliasId = null;
if (candidateAlias != null) {
candidateAliasId = storeMgr.getIdentifierFactory().newTableIdentifier(candidateAlias);
}
ClassLoaderResolver clr = ec.getClassLoaderResolver();
List<DatastoreClass> candidateTables = new ArrayList<>();
if (cmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.COMPLETE_TABLE) {
DatastoreClass candidateTable = storeMgr.getDatastoreClass(cmd.getFullClassName(), clr);
if (candidateTable != null) {
candidateTables.add(candidateTable);
}
if (subclasses) {
Collection<String> subclassNames = storeMgr.getSubClassesForClass(cmd.getFullClassName(), subclasses, clr);
if (subclassNames != null) {
Iterator<String> subclassIter = subclassNames.iterator();
while (subclassIter.hasNext()) {
String subclassName = subclassIter.next();
DatastoreClass tbl = storeMgr.getDatastoreClass(subclassName, clr);
if (tbl != null) {
candidateTables.add(tbl);
}
}
}
}
Iterator<DatastoreClass> iter = candidateTables.iterator();
int maxClassNameLength = cmd.getFullClassName().length();
while (iter.hasNext()) {
DatastoreClass cls = iter.next();
String className = cls.getType();
if (className.length() > maxClassNameLength) {
maxClassNameLength = className.length();
}
}
iter = candidateTables.iterator();
while (iter.hasNext()) {
DatastoreClass cls = iter.next();
SelectStatement tblStmt = new SelectStatement(parentStmt, storeMgr, cls, candidateAliasId, candidateTableGroupName);
tblStmt.setClassLoaderResolver(clr);
tblStmt.setCandidateClassName(cls.getType());
// Add SELECT of dummy column accessible as "DN_TYPE" containing the classname
JavaTypeMapping m = storeMgr.getMappingManager().getMapping(String.class);
String nuctypeName = cls.getType();
if (maxClassNameLength > nuctypeName.length()) {
nuctypeName = StringUtils.leftAlignedPaddedString(nuctypeName, maxClassNameLength);
}
StringLiteral lit = new StringLiteral(tblStmt, m, nuctypeName, null);
tblStmt.select(lit, UnionStatementGenerator.DN_TYPE_COLUMN);
if (stmt == null) {
stmt = tblStmt;
} else {
stmt.union(tblStmt);
}
}
if (clsMapping != null) {
clsMapping.setNucleusTypeColumnName(UnionStatementGenerator.DN_TYPE_COLUMN);
}
} else {
// "new-table", "superclass-table", "subclass-table"
List<Class> candidateClasses = new ArrayList<>();
if (ClassUtils.isReferenceType(candidateCls)) {
// Persistent interface, so find all persistent implementations
String[] clsNames = storeMgr.getNucleusContext().getMetaDataManager().getClassesImplementingInterface(candidateCls.getName(), clr);
for (int i = 0; i < clsNames.length; i++) {
Class cls = clr.classForName(clsNames[i]);
DatastoreClass table = storeMgr.getDatastoreClass(clsNames[i], clr);
candidateClasses.add(cls);
candidateTables.add(table);
AbstractClassMetaData implCmd = storeMgr.getNucleusContext().getMetaDataManager().getMetaDataForClass(cls, clr);
if (implCmd.getIdentityType() != cmd.getIdentityType()) {
throw new NucleusUserException("You are querying an interface (" + cmd.getFullClassName() + ") " + "yet one of its implementations (" + implCmd.getFullClassName() + ") uses a different identity type!");
} else if (cmd.getIdentityType() == IdentityType.APPLICATION) {
if (cmd.getPKMemberPositions().length != implCmd.getPKMemberPositions().length) {
throw new NucleusUserException("You are querying an interface (" + cmd.getFullClassName() + ") " + "yet one of its implementations (" + implCmd.getFullClassName() + ") has a different number of PK members!");
}
}
}
} else {
DatastoreClass candidateTable = storeMgr.getDatastoreClass(cmd.getFullClassName(), clr);
if (candidateTable != null) {
// Candidate has own table
candidateClasses.add(candidateCls);
candidateTables.add(candidateTable);
} else {
// Candidate stored in subclass tables
AbstractClassMetaData[] cmds = storeMgr.getClassesManagingTableForClass(cmd, clr);
if (cmds != null && cmds.length > 0) {
for (int i = 0; i < cmds.length; i++) {
DatastoreClass table = storeMgr.getDatastoreClass(cmds[i].getFullClassName(), clr);
Class cls = clr.classForName(cmds[i].getFullClassName());
candidateClasses.add(cls);
candidateTables.add(table);
}
} else {
throw new UnsupportedOperationException("No tables for query of " + cmd.getFullClassName());
}
}
}
for (int i = 0; i < candidateTables.size(); i++) {
DatastoreClass tbl = candidateTables.get(i);
Class cls = candidateClasses.get(i);
SelectStatementGenerator stmtGen = null;
if (tbl.getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, true) != null || QueryUtils.resultHasOnlyAggregates(result)) {
// Either has a discriminator, or only selecting aggregates so need single select
// TODO Add option to omit discriminator restriction
stmtGen = new DiscriminatorStatementGenerator(storeMgr, clr, cls, subclasses, candidateAliasId, candidateTableGroupName);
stmtGen.setOption(SelectStatementGenerator.OPTION_RESTRICT_DISCRIM);
if (options != null) {
for (String option : options) {
stmtGen.setOption(option);
}
}
} else {
// No discriminator, so try to identify using UNIONs (hopefully one per class)
stmtGen = new UnionStatementGenerator(storeMgr, clr, cls, subclasses, candidateAliasId, candidateTableGroupName);
if (options != null) {
for (String option : options) {
stmtGen.setOption(option);
}
}
if (result == null) {
// Returning one row per candidate so include distinguisher column
stmtGen.setOption(SelectStatementGenerator.OPTION_SELECT_DN_TYPE);
if (clsMapping != null) {
clsMapping.setNucleusTypeColumnName(UnionStatementGenerator.DN_TYPE_COLUMN);
}
}
}
stmtGen.setParentStatement(parentStmt);
SelectStatement tblStmt = stmtGen.getStatement(ec);
if (stmt == null) {
stmt = tblStmt;
} else {
stmt.union(tblStmt);
}
}
}
return stmt;
}
use of org.datanucleus.store.rdbms.table.DatastoreClass in project datanucleus-rdbms by datanucleus.
the class ResultMetaDataROF method getObject.
/**
* Accessor for the object(s) from the current row of the ResultSet.
* @return The object(s) for this row of the ResultSet.
*/
public Object getObject() {
List returnObjects = new ArrayList();
// A). Process persistent types
PersistentTypeMapping[] persistentTypes = queryResultMetaData.getPersistentTypeMappings();
if (persistentTypes != null) {
if (persistentTypeResultSetGetters == null) {
persistentTypeResultSetGetters = new ResultSetGetter[persistentTypes.length];
}
int startColumnIndex = 0;
for (int i = 0; i < persistentTypes.length; i++) {
Set<String> columnsInThisType = new HashSet<>();
AbstractMemberMetaData[] mmds = new AbstractMemberMetaData[columnNames.length];
Map<String, AbstractMemberMetaData> fieldColumns = new HashMap<>();
DatastoreClass dc = ((RDBMSStoreManager) ec.getStoreManager()).getDatastoreClass(persistentTypes[i].getClassName(), ec.getClassLoaderResolver());
AbstractClassMetaData acmd = ec.getMetaDataManager().getMetaDataForClass(persistentTypes[i].getClassName(), ec.getClassLoaderResolver());
Object id = null;
// and two columns with similar names e.g "Col1" and "col1". Until that situation comes up we ignore it :-)
for (int j = startColumnIndex; j < columnNames.length; j++) {
if (columnsInThisType.contains(columnNames[j])) {
// already added this column, so must be another persistent type
startColumnIndex = j;
break;
}
boolean found = false;
if (acmd.getIdentityType() == IdentityType.DATASTORE) {
JavaTypeMapping datastoreIdMapping = dc.getSurrogateMapping(SurrogateColumnType.DATASTORE_ID, false);
Column df = datastoreIdMapping.getDatastoreMapping(0).getColumn();
if (df.getIdentifier().getName().equalsIgnoreCase(columnNames[j])) {
// add +1 because result sets in jdbc starts with 1
int datastoreIdentityExpressionIndex = j + 1;
id = datastoreIdMapping.getObject(ec, rs, new int[] { datastoreIdentityExpressionIndex });
found = true;
}
}
for (int k = 0; k < acmd.getNoOfManagedMembers() + acmd.getNoOfInheritedManagedMembers() && !found; k++) {
AbstractMemberMetaData apmd = acmd.getMetaDataForManagedMemberAtAbsolutePosition(k);
if (persistentTypes[i].getColumnForField(apmd.getName()) != null) {
if (persistentTypes[i].getColumnForField(apmd.getName()).equalsIgnoreCase(columnNames[j])) {
fieldColumns.put(columnNames[j], apmd);
columnsInThisType.add(columnNames[j]);
mmds[j] = apmd;
found = true;
}
} else {
JavaTypeMapping mapping = dc.getMemberMapping(apmd);
for (int l = 0; l < mapping.getDatastoreMappings().length && !found; l++) {
Column df = mapping.getDatastoreMapping(l).getColumn();
if (df.getIdentifier().getName().equalsIgnoreCase(columnNames[j])) {
fieldColumns.put(columnNames[j], apmd);
columnsInThisType.add(columnNames[j]);
mmds[j] = apmd;
found = true;
}
}
}
}
if (!columnsInThisType.contains(columnNames[j])) {
// column not found in this type, so must be another persistent type
startColumnIndex = j;
break;
}
}
// Build fields and mappings in the results
StatementMappingIndex[] stmtMappings = new StatementMappingIndex[acmd.getNoOfManagedMembers() + acmd.getNoOfInheritedManagedMembers()];
Set<AbstractMemberMetaData> resultMmds = new HashSet<>();
resultMmds.addAll(fieldColumns.values());
int[] resultFieldNumbers = new int[resultMmds.size()];
int j = 0;
for (AbstractMemberMetaData apmd : resultMmds) {
StatementMappingIndex stmtMapping = new StatementMappingIndex(dc.getMemberMapping(apmd));
resultFieldNumbers[j] = apmd.getAbsoluteFieldNumber();
List indexes = new ArrayList();
for (int k = 0; k < mmds.length; k++) {
if (mmds[k] == apmd) {
indexes.add(Integer.valueOf(k));
}
}
int[] indxs = new int[indexes.size()];
for (int k = 0; k < indxs.length; k++) {
// add +1 because result sets in JDBC starts with 1
indxs[k] = ((Integer) indexes.get(k)).intValue() + 1;
}
stmtMapping.setColumnPositions(indxs);
stmtMappings[resultFieldNumbers[j]] = stmtMapping;
j++;
}
Object obj = null;
Class type = ec.getClassLoaderResolver().classForName(persistentTypes[i].getClassName());
if (acmd.getIdentityType() == IdentityType.APPLICATION) {
if (persistentTypeResultSetGetters[i] == null) {
final StatementClassMapping resultMappings = new StatementClassMapping();
for (int k = 0; k < resultFieldNumbers.length; k++) {
resultMappings.addMappingForMember(resultFieldNumbers[k], stmtMappings[resultFieldNumbers[k]]);
}
persistentTypeResultSetGetters[i] = new ResultSetGetter(ec, rs, resultMappings, acmd);
}
ResultSetGetter rsGetter = persistentTypeResultSetGetters[i];
// TODO Make use of discriminator like in PersistentClassROF and set the pcClass in this?
id = IdentityUtils.getApplicationIdentityForResultSetRow(ec, acmd, type, false, rsGetter);
obj = ec.findObject(id, new FieldValues() {
public void fetchFields(ObjectProvider op) {
rsGetter.setObjectProvider(op);
op.replaceFields(resultFieldNumbers, rsGetter, false);
}
public void fetchNonLoadedFields(ObjectProvider op) {
rsGetter.setObjectProvider(op);
op.replaceNonLoadedFields(resultFieldNumbers, rsGetter);
}
public FetchPlan getFetchPlanForLoading() {
return null;
}
}, type, ignoreCache, false);
} else if (acmd.getIdentityType() == IdentityType.DATASTORE) {
if (persistentTypeResultSetGetters[i] == null) {
final StatementClassMapping resultMappings = new StatementClassMapping();
for (int k = 0; k < resultFieldNumbers.length; k++) {
resultMappings.addMappingForMember(resultFieldNumbers[k], stmtMappings[resultFieldNumbers[k]]);
}
persistentTypeResultSetGetters[i] = new ResultSetGetter(ec, rs, resultMappings, acmd);
}
ResultSetGetter rsGetter = persistentTypeResultSetGetters[i];
obj = ec.findObject(id, new FieldValues() {
public void fetchFields(ObjectProvider op) {
rsGetter.setObjectProvider(op);
op.replaceFields(resultFieldNumbers, rsGetter, false);
}
public void fetchNonLoadedFields(ObjectProvider op) {
rsGetter.setObjectProvider(op);
op.replaceNonLoadedFields(resultFieldNumbers, rsGetter);
}
public FetchPlan getFetchPlanForLoading() {
return null;
}
}, type, ignoreCache, false);
} else {
// TODO Handle non-durable
NucleusLogger.QUERY.warn("We do not currently support non-durable objects in the results of this type of query.");
}
returnObjects.add(obj);
}
}
// B). Process simple columns
String[] columns = queryResultMetaData.getScalarColumns();
if (columns != null) {
for (int i = 0; i < columns.length; i++) {
try {
Object obj = rs.getObject(columns[i]);
returnObjects.add(obj);
} catch (SQLException sqe) {
String msg = Localiser.msg("059027", sqe.getMessage());
NucleusLogger.QUERY.error(msg);
throw new NucleusUserException(msg, sqe);
}
}
}
// C). Process constructor type mappings
ConstructorTypeMapping[] ctrTypeMappings = queryResultMetaData.getConstructorTypeMappings();
if (ctrTypeMappings != null) {
for (int i = 0; i < ctrTypeMappings.length; i++) {
String ctrClassName = ctrTypeMappings[i].getClassName();
Class ctrCls = ec.getClassLoaderResolver().classForName(ctrClassName);
List<ConstructorTypeColumn> ctrColumns = ctrTypeMappings[i].getColumnsForConstructor();
Class[] ctrArgTypes = null;
Object[] ctrArgVals = null;
if (ctrColumns != null && ctrColumns.size() > 0) {
int j = 0;
ctrArgTypes = new Class[ctrColumns.size()];
ctrArgVals = new Object[ctrColumns.size()];
Iterator<ConstructorTypeColumn> colIter = ctrColumns.iterator();
while (colIter.hasNext()) {
ConstructorTypeColumn ctrCol = colIter.next();
try {
Object colVal = rs.getObject(ctrCol.getColumnName());
ctrArgTypes[j] = colVal.getClass();
if (ctrCol.getJavaType() != null) {
// Attempt to convert to the type requested
ctrArgTypes[j] = ctrCol.getJavaType();
ctrArgVals[j] = TypeConversionHelper.convertTo(colVal, ctrArgTypes[j]);
} else {
ctrArgTypes[j] = colVal.getClass();
ctrArgVals[j] = colVal;
}
} catch (SQLException sqle) {
// TODO Handle this
}
j++;
}
}
returnObjects.add(ClassUtils.newInstance(ctrCls, ctrArgTypes, ctrArgVals));
}
}
if (returnObjects.size() == 0) {
// No objects so user must have supplied incorrect MetaData
return null;
} else if (returnObjects.size() == 1) {
// Return Object
return returnObjects.get(0);
} else {
// Return Object[]
return returnObjects.toArray(new Object[returnObjects.size()]);
}
}
use of org.datanucleus.store.rdbms.table.DatastoreClass in project datanucleus-rdbms by datanucleus.
the class FKArrayStore method updateElementFk.
/**
* Update a FK and element position in the element.
* @param ownerOP ObjectProvider for the owner
* @param element The element to update
* @param owner The owner object to set in the FK
* @param index The index position (or -1 if not known)
* @return Whether it was performed successfully
*/
private boolean updateElementFk(ObjectProvider ownerOP, E element, Object owner, int index) {
if (element == null) {
return false;
}
boolean retval;
String updateFkStmt = getUpdateFkStmt();
ExecutionContext ec = ownerOP.getExecutionContext();
try {
ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec);
SQLController sqlControl = storeMgr.getSQLController();
try {
PreparedStatement ps = sqlControl.getStatementForUpdate(mconn, updateFkStmt, false);
try {
int jdbcPosition = 1;
if (elementInfo.length > 1) {
DatastoreClass table = storeMgr.getDatastoreClass(element.getClass().getName(), clr);
if (table != null) {
ps.setString(jdbcPosition++, table.toString());
} else {
NucleusLogger.PERSISTENCE.info(">> FKArrayStore.updateElementFK : need to set table in statement but dont know table where to store " + element);
}
}
if (owner == null) {
ownerMapping.setObject(ec, ps, MappingHelper.getMappingIndices(jdbcPosition, ownerMapping), null);
jdbcPosition += ownerMapping.getNumberOfDatastoreMappings();
} else {
jdbcPosition = BackingStoreHelper.populateOwnerInStatement(ownerOP, ec, ps, jdbcPosition, this);
}
jdbcPosition = BackingStoreHelper.populateOrderInStatement(ec, ps, index, jdbcPosition, orderMapping);
if (relationDiscriminatorMapping != null) {
jdbcPosition = BackingStoreHelper.populateRelationDiscriminatorInStatement(ec, ps, jdbcPosition, this);
}
jdbcPosition = BackingStoreHelper.populateElementInStatement(ec, ps, element, jdbcPosition, elementMapping);
sqlControl.executeStatementUpdate(ec, mconn, updateFkStmt, ps, true);
retval = true;
} finally {
sqlControl.closeStatement(mconn, ps);
}
} finally {
mconn.release();
}
} catch (SQLException e) {
throw new NucleusDataStoreException(Localiser.msg("056027", updateFkStmt), e);
}
return retval;
}
use of org.datanucleus.store.rdbms.table.DatastoreClass in project datanucleus-rdbms by datanucleus.
the class FKSetStore method add.
/**
* Method to add an object to the relationship at the collection end.
* @param ownerOP ObjectProvider for the owner.
* @param element Element to be added
* @return Success indicator
*/
public boolean add(final ObjectProvider ownerOP, E element, int size) {
if (element == null) {
// Sets allow no duplicates
throw new NucleusUserException(Localiser.msg("056039"));
}
// Make sure that the element is persisted in the datastore (reachability)
final Object newOwner = ownerOP.getObject();
final ExecutionContext ec = ownerOP.getExecutionContext();
// Find the (element) table storing the FK back to the owner
boolean isPersistentInterface = storeMgr.getNucleusContext().getMetaDataManager().isPersistentInterface(elementType);
DatastoreClass elementTable = null;
if (isPersistentInterface) {
elementTable = storeMgr.getDatastoreClass(storeMgr.getNucleusContext().getMetaDataManager().getImplementationNameForPersistentInterface(elementType), clr);
} else {
Class elementTypeCls = clr.classForName(elementType);
if (elementTypeCls.isInterface()) {
// Set<interface> so use type of element passed in and get its table
elementTable = storeMgr.getDatastoreClass(element.getClass().getName(), clr);
} else {
// Use table for element type
elementTable = storeMgr.getDatastoreClass(elementType, clr);
}
}
if (elementTable == null) {
// "subclass-table", persisted into table of other class
AbstractClassMetaData[] managingCmds = storeMgr.getClassesManagingTableForClass(elementCmd, clr);
if (managingCmds != null && managingCmds.length > 0) {
// Find which of these subclasses is appropriate for this element
for (int i = 0; i < managingCmds.length; i++) {
Class tblCls = clr.classForName(managingCmds[i].getFullClassName());
if (tblCls.isAssignableFrom(element.getClass())) {
elementTable = storeMgr.getDatastoreClass(managingCmds[i].getFullClassName(), clr);
break;
}
}
}
}
final DatastoreClass elementTbl = elementTable;
boolean inserted = validateElementForWriting(ec, element, new FieldValues() {
public void fetchFields(ObjectProvider elementOP) {
if (elementTbl != null) {
JavaTypeMapping externalFKMapping = elementTbl.getExternalMapping(ownerMemberMetaData, MappingType.EXTERNAL_FK);
if (externalFKMapping != null) {
// The element has an external FK mapping so set the value it needs to use in the INSERT
elementOP.setAssociatedValue(externalFKMapping, ownerOP.getObject());
}
if (relationDiscriminatorMapping != null) {
// Element type has a shared FK so set the discriminator value for this relation
elementOP.setAssociatedValue(relationDiscriminatorMapping, relationDiscriminatorValue);
}
}
int fieldNumInElement = getFieldNumberInElementForBidirectional(elementOP);
if (fieldNumInElement >= 0) {
// TODO Move this into RelationshipManager
// Managed Relations : 1-N bidir, so make sure owner is correct at persist
Object currentOwner = elementOP.provideField(fieldNumInElement);
if (currentOwner == null) {
// No owner, so correct it
NucleusLogger.PERSISTENCE.info(Localiser.msg("056037", ownerOP.getObjectAsPrintable(), ownerMemberMetaData.getFullFieldName(), StringUtils.toJVMIDString(elementOP.getObject())));
elementOP.replaceFieldMakeDirty(fieldNumInElement, newOwner);
} else if (currentOwner != newOwner) {
// Check for owner change
Object ownerId1 = ec.getApiAdapter().getIdForObject(currentOwner);
Object ownerId2 = ec.getApiAdapter().getIdForObject(newOwner);
if (ownerId1 != null && ownerId2 != null && ownerId1.equals(ownerId2)) {
// Must be attaching
if (!ec.getApiAdapter().isDetached(newOwner)) {
// Attaching, so make sure we set to the attached owner
elementOP.replaceField(fieldNumInElement, newOwner);
}
} else if (ownerOP.getReferencedPC() == null) {
// Not being attached so must be inconsistent owner, so throw exception
throw new NucleusUserException(Localiser.msg("056038", ownerOP.getObjectAsPrintable(), ownerMemberMetaData.getFullFieldName(), StringUtils.toJVMIDString(elementOP.getObject()), StringUtils.toJVMIDString(currentOwner)));
}
}
}
}
public void fetchNonLoadedFields(ObjectProvider op) {
}
public FetchPlan getFetchPlanForLoading() {
return null;
}
});
if (inserted) {
// Element has just been persisted so the FK will be set
return true;
}
// Element was already persistent so make sure the FK is in place
// TODO This is really "ManagedRelationships" so needs to go in RelationshipManager
ObjectProvider elementOP = ec.findObjectProvider(element);
if (elementOP == null) {
// Element is likely being attached and this is the detached element; lookup the attached element via the id
Object elementId = ec.getApiAdapter().getIdForObject(element);
if (elementId != null) {
element = (E) ec.findObject(elementId, false, false, element.getClass().getName());
if (element != null) {
elementOP = ec.findObjectProvider(element);
}
}
}
int fieldNumInElement = getFieldNumberInElementForBidirectional(elementOP);
if (fieldNumInElement >= 0 && elementOP != null) {
// Managed Relations : 1-N bidir, so update the owner of the element
// Ensure is loaded
elementOP.isLoaded(fieldNumInElement);
Object oldOwner = elementOP.provideField(fieldNumInElement);
if (oldOwner != newOwner) {
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.PERSISTENCE.debug(Localiser.msg("055009", ownerOP.getObjectAsPrintable(), ownerMemberMetaData.getFullFieldName(), StringUtils.toJVMIDString(element)));
}
elementOP.replaceFieldMakeDirty(fieldNumInElement, newOwner);
if (ec.getManageRelations()) {
// Managed Relationships - add the change we've made here to be analysed at flush
RelationshipManager relationshipManager = ec.getRelationshipManager(elementOP);
relationshipManager.relationChange(fieldNumInElement, oldOwner, newOwner);
if (ec.isFlushing()) {
// When already flushing process the changes right away to make them effective during the current flush
relationshipManager.process();
}
}
if (ec.isFlushing()) {
elementOP.flush();
}
}
return oldOwner != newOwner;
}
// 1-N unidir so update the FK if not set to be contained in the set
boolean contained = contains(ownerOP, element);
return (contained ? false : updateElementFk(ownerOP, element, newOwner));
}
use of org.datanucleus.store.rdbms.table.DatastoreClass 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