use of org.datanucleus.store.rdbms.table.DatastoreClass in project datanucleus-rdbms by datanucleus.
the class SQLStatementHelper method selectFetchPlanFieldsOfFKRelatedObject.
/**
* Convenience method to join to and select all required FP fields of a related object where linked via an FK at this side.
* @return Whether the caller should select the FK themselves (i.e we haven't selected anything)
*/
private static boolean selectFetchPlanFieldsOfFKRelatedObject(SelectStatement stmt, StatementClassMapping mappingDefinition, FetchPlan fetchPlan, SQLTable sourceSqlTbl, AbstractMemberMetaData mmd, ClassLoaderResolver clr, int maxFetchPlanLimit, JavaTypeMapping m, String tableGroupName, StatementMappingIndex stmtMapping, SQLTable sqlTbl, JoinType inputJoinType) {
boolean selectFK = true;
if (mmd.fetchFKOnly()) {
// Only want FK fetching, and not the fields of the object (so avoid the join)
} else {
RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
Class type = mmd.isSingleCollection() ? clr.classForName(mmd.getCollection().getElementType()) : mmd.getType();
if (m instanceof ReferenceMapping) {
ReferenceMapping refMapping = (ReferenceMapping) m;
if (refMapping.getMappingStrategy() == ReferenceMapping.PER_IMPLEMENTATION_MAPPING && refMapping.getJavaTypeMapping().length == 1) {
JavaTypeMapping[] subMappings = refMapping.getJavaTypeMapping();
if (subMappings != null && subMappings.length == 1) {
// Special case of reference mapping with single FK implementation
type = clr.classForName(refMapping.getJavaTypeMapping()[0].getType());
}
}
}
// select fetch plan fields of this object
AbstractClassMetaData relatedCmd = storeMgr.getMetaDataManager().getMetaDataForClass(type, clr);
if (relatedCmd != null) {
if (relatedCmd.isEmbeddedOnly()) {
return true;
}
if (relatedCmd.getBaseAbstractClassMetaData().getInheritanceMetaData().getStrategy() == InheritanceStrategy.COMPLETE_TABLE) {
// Related object uses complete-table
Collection<String> relSubclassNames = storeMgr.getSubClassesForClass(relatedCmd.getFullClassName(), true, clr);
if (relatedCmd.isMappedSuperclass() && relSubclassNames.size() > 1) {
// Multiple possible related types and we don't have the FK so omit
return true;
} else if (!relatedCmd.isMappedSuperclass() && relSubclassNames.size() > 0) {
// Multiple possible related types and we don't have the FK so omit
return true;
}
// TODO Maybe do a LEFT OUTER JOIN to each possible?
}
// Find the table of the related class
DatastoreClass relatedTbl = storeMgr.getDatastoreClass(relatedCmd.getFullClassName(), clr);
if (relatedTbl == null) {
// Class doesn't have its own table (subclass-table) so find where it persists
AbstractClassMetaData[] ownerParentCmds = storeMgr.getClassesManagingTableForClass(relatedCmd, clr);
if (ownerParentCmds.length > 1) {
NucleusLogger.QUERY.info("Relation (" + mmd.getFullFieldName() + ") with multiple related tables (using subclass-table). Not supported so selecting FK of related object only");
return true;
}
relatedTbl = storeMgr.getDatastoreClass(ownerParentCmds[0].getFullClassName(), clr);
}
String requiredGroupName = null;
if (sourceSqlTbl.getGroupName() != null) {
// JPQL will have table groups defined already, named as per "alias.fieldName"
requiredGroupName = sourceSqlTbl.getGroupName() + "." + mmd.getName();
}
SQLTable relatedSqlTbl = stmt.getTable(relatedTbl, requiredGroupName);
if (relatedSqlTbl == null) {
// Join the 1-1 relation
JoinType joinType = getJoinTypeForOneToOneRelationJoin(m, sqlTbl, inputJoinType);
if (joinType == JoinType.LEFT_OUTER_JOIN || joinType == JoinType.RIGHT_OUTER_JOIN) {
inputJoinType = joinType;
}
relatedSqlTbl = addJoinForOneToOneRelation(stmt, m, sqlTbl, relatedTbl.getIdMapping(), relatedTbl, null, null, tableGroupName, joinType);
}
StatementClassMapping subMappingDefinition = new StatementClassMapping(mmd.getClassName(), mmd.getName());
selectFetchPlanOfSourceClassInStatement(stmt, subMappingDefinition, fetchPlan, relatedSqlTbl, relatedCmd, maxFetchPlanLimit - 1, inputJoinType);
if (mappingDefinition != null) {
if (relatedCmd.getIdentityType() == IdentityType.APPLICATION) {
int[] pkFields = relatedCmd.getPKMemberPositions();
int[] pkCols = new int[m.getNumberOfDatastoreMappings()];
int pkColNo = 0;
for (int pkField : pkFields) {
StatementMappingIndex pkIdx = subMappingDefinition.getMappingForMemberPosition(pkField);
int[] pkColNumbers = pkIdx.getColumnPositions();
for (int pkColNumber : pkColNumbers) {
pkCols[pkColNo] = pkColNumber;
pkColNo++;
}
}
selectFK = false;
stmtMapping.setColumnPositions(pkCols);
} else if (relatedCmd.getIdentityType() == IdentityType.DATASTORE) {
StatementMappingIndex pkIdx = subMappingDefinition.getMappingForMemberPosition(SurrogateColumnType.DATASTORE_ID.getFieldNumber());
selectFK = false;
stmtMapping.setColumnPositions(pkIdx.getColumnPositions());
}
mappingDefinition.addMappingDefinitionForMember(mmd.getAbsoluteFieldNumber(), subMappingDefinition);
}
} else {
// TODO 1-1 interface relation
}
}
return selectFK;
}
use of org.datanucleus.store.rdbms.table.DatastoreClass in project datanucleus-rdbms by datanucleus.
the class SQLStatementHelper method selectIdentityOfCandidateInStatement.
/**
* Method to select the identity for the candidate class.
* The supplied statement and mapping definition are updated during this method.
* Selects the datastore id (if using datastore id) as "DN_DATASTOREID",
* the version (if present) as "DN_VERSION", the discriminator (if present) as "DN_DISCRIM",
* and the application id (if using application id) as "DN_APPID_{i}"
* @param stmt The statement
* @param mappingDefinition Mapping definition for result columns
* @param candidateCmd The candidate class meta-data
*/
public static void selectIdentityOfCandidateInStatement(SelectStatement stmt, StatementClassMapping mappingDefinition, AbstractClassMetaData candidateCmd) {
DatastoreClass candidateTbl = (DatastoreClass) stmt.getPrimaryTable().getTable();
if (candidateCmd.getIdentityType() == IdentityType.DATASTORE) {
// Datastore-identity surrogate column
JavaTypeMapping idMapping = candidateTbl.getSurrogateMapping(SurrogateColumnType.DATASTORE_ID, false);
int[] colNumbers = stmt.select(stmt.getPrimaryTable(), idMapping, "DN_DATASTOREID", false);
if (mappingDefinition != null) {
StatementMappingIndex datastoreIdIdx = new StatementMappingIndex(idMapping);
datastoreIdIdx.setColumnPositions(colNumbers);
mappingDefinition.addMappingForMember(SurrogateColumnType.DATASTORE_ID.getFieldNumber(), datastoreIdIdx);
}
} else if (candidateCmd.getIdentityType() == IdentityType.APPLICATION) {
// Application-identity column(s)
int[] pkPositions = candidateCmd.getPKMemberPositions();
String alias = "DN_APPID";
for (int i = 0; i < pkPositions.length; i++) {
AbstractMemberMetaData pkMmd = candidateCmd.getMetaDataForManagedMemberAtAbsolutePosition(pkPositions[i]);
JavaTypeMapping pkMapping = candidateTbl.getMemberMapping(pkMmd);
SQLTable sqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(stmt, stmt.getPrimaryTable(), pkMapping);
if (pkPositions.length > 1) {
alias = "DN_APPID" + i;
}
int[] colNumbers = stmt.select(sqlTbl, pkMapping, alias, false);
if (mappingDefinition != null) {
StatementMappingIndex appIdIdx = new StatementMappingIndex(pkMapping);
appIdIdx.setColumnPositions(colNumbers);
mappingDefinition.addMappingForMember(pkPositions[i], appIdIdx);
}
}
}
JavaTypeMapping verMapping = candidateTbl.getSurrogateMapping(SurrogateColumnType.VERSION, true);
if (verMapping != null) {
// Version surrogate column (adds inner join to any required superclass table)
SQLTable versionSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(stmt, stmt.getPrimaryTable(), verMapping);
int[] colNumbers = stmt.select(versionSqlTbl, verMapping, "DN_VERSION", false);
if (mappingDefinition != null) {
StatementMappingIndex versionIdx = new StatementMappingIndex(verMapping);
versionIdx.setColumnPositions(colNumbers);
mappingDefinition.addMappingForMember(SurrogateColumnType.VERSION.getFieldNumber(), versionIdx);
}
}
JavaTypeMapping discrimMapping = candidateTbl.getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, true);
if (discrimMapping != null) {
// Discriminator surrogate column (adds inner join to any required superclass table)
SQLTable discrimSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(stmt, stmt.getPrimaryTable(), discrimMapping);
int[] colNumbers = stmt.select(discrimSqlTbl, discrimMapping, "DN_DISCRIM", false);
if (mappingDefinition != null) {
StatementMappingIndex discrimIdx = new StatementMappingIndex(discrimMapping);
discrimIdx.setColumnPositions(colNumbers);
mappingDefinition.addMappingForMember(SurrogateColumnType.DISCRIMINATOR.getFieldNumber(), discrimIdx);
}
}
List<SelectStatement> unionStmts = stmt.getUnions();
if (unionStmts != null) {
Iterator<SelectStatement> iter = unionStmts.iterator();
while (iter.hasNext()) {
SelectStatement unionStmt = iter.next();
selectIdentityOfCandidateInStatement(unionStmt, null, candidateCmd);
}
}
}
use of org.datanucleus.store.rdbms.table.DatastoreClass in project datanucleus-rdbms by datanucleus.
the class SQLStatementHelper method getSQLTableForMappingOfTable.
/**
* Method to return the SQLTable where the specified mapping (in the same table group as the provided
* SQLTable) is defined. If the statement doesn't currently join to the required table then a join will
* be added. If the required table is a superclass table then the join will be INNER. If the required
* table is a secondary table then the join will be defined by the meta-data for the secondary table.
* If this table group is NOT the candidate table group then LEFT OUTER JOIN will be used.
* @param stmt The statement
* @param sqlTbl SQLTable to start from for the supplied mapping (may be in super-table, or secondary-table of this)
* @param mapping The mapping
* @return The SQLTable for this mapping (may have been added to the statement during this method)
*/
public static SQLTable getSQLTableForMappingOfTable(SQLStatement stmt, SQLTable sqlTbl, JavaTypeMapping mapping) {
Table table = sqlTbl.getTable();
if (table instanceof SecondaryDatastoreClass || table instanceof JoinTable) {
// Secondary/join tables have no inheritance so ought to be correct
if (mapping.getTable() != null) {
// Check there is no better table already present in the TableGroup for this mapping
// This can happen when we do a select of a join table and the element table is in the
// same table group, so hence already is present
SQLTable mappingSqlTbl = stmt.getTable(mapping.getTable(), sqlTbl.getGroupName());
if (mappingSqlTbl != null) {
return mappingSqlTbl;
}
}
return sqlTbl;
}
DatastoreClass sourceTbl = (DatastoreClass) sqlTbl.getTable();
DatastoreClass mappingTbl = null;
if (mapping.getTable() != null) {
mappingTbl = (DatastoreClass) mapping.getTable();
} else {
mappingTbl = sourceTbl.getBaseDatastoreClassWithMember(mapping.getMemberMetaData());
}
if (mappingTbl == sourceTbl) {
return sqlTbl;
}
// Try to find this datastore table in the same table group
SQLTable mappingSqlTbl = stmt.getTable(mappingTbl, sqlTbl.getGroupName());
if (mappingSqlTbl == null) {
boolean forceLeftOuter = false;
SQLTableGroup tableGrp = stmt.getTableGroup(sqlTbl.getGroupName());
if (tableGrp.getJoinType() == JoinType.LEFT_OUTER_JOIN) {
// This group isn't the candidate group, and we joined to the candidate group using
// a left outer join originally, so use the same type for this table
forceLeftOuter = true;
}
if (mappingTbl instanceof SecondaryDatastoreClass) {
// Secondary table, so add inner/outer based on metadata
boolean innerJoin = true;
JoinMetaData joinmd = ((SecondaryDatastoreClass) mappingTbl).getJoinMetaData();
if (joinmd != null && joinmd.isOuter() && !forceLeftOuter) {
innerJoin = false;
}
if (innerJoin && !forceLeftOuter) {
// Add join from {sourceTbl}.ID to {secondaryTbl}.ID
mappingSqlTbl = stmt.join(JoinType.INNER_JOIN, sqlTbl, sqlTbl.getTable().getIdMapping(), mappingTbl, null, mappingTbl.getIdMapping(), null, sqlTbl.getGroupName());
} else {
// Add join from {sourceTbl}.ID to {secondaryTbl}.ID
mappingSqlTbl = stmt.join(JoinType.LEFT_OUTER_JOIN, sqlTbl, sqlTbl.getTable().getIdMapping(), mappingTbl, null, mappingTbl.getIdMapping(), null, sqlTbl.getGroupName());
}
} else {
if (forceLeftOuter) {
// Add join from {sourceTbl}.ID to {superclassTbl}.ID
mappingSqlTbl = stmt.join(JoinType.LEFT_OUTER_JOIN, sqlTbl, sqlTbl.getTable().getIdMapping(), mappingTbl, null, mappingTbl.getIdMapping(), null, sqlTbl.getGroupName());
} else {
// Add join from {sourceTbl}.ID to {superclassTbl}.ID
mappingSqlTbl = stmt.join(JoinType.INNER_JOIN, sqlTbl, sqlTbl.getTable().getIdMapping(), mappingTbl, null, mappingTbl.getIdMapping(), null, sqlTbl.getGroupName());
}
}
}
return mappingSqlTbl;
}
use of org.datanucleus.store.rdbms.table.DatastoreClass in project datanucleus-rdbms by datanucleus.
the class SQLStatementHelper method selectFetchPlanOfSourceClassInStatement.
/**
* Method to select all fetch plan members for the "source" class.
* If the passed FetchPlan is null then the default fetch group fields will be selected.
* The source class is defined by the supplied meta-data, and the SQLTable that we are selecting from.
* The supplied statement and mapping definition are updated during this method.
* @param stmt The statement
* @param mappingDefinition Mapping definition for result columns (populated with column positions
* of any selected mappings if provided as input)
* @param fetchPlan FetchPlan in use
* @param sourceSqlTbl SQLTable for the source class that we select from
* @param sourceCmd Meta-data for the source class
* @param maxFetchDepth 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 selectFetchPlanOfSourceClassInStatement(SelectStatement stmt, StatementClassMapping mappingDefinition, FetchPlan fetchPlan, SQLTable sourceSqlTbl, AbstractClassMetaData sourceCmd, int maxFetchDepth, JoinType inputJoinType) {
DatastoreClass sourceTbl = (DatastoreClass) sourceSqlTbl.getTable();
int[] fieldNumbers;
if (fetchPlan != null) {
// Use FetchPlan fields
fieldNumbers = fetchPlan.getFetchPlanForClass(sourceCmd).getMemberNumbers();
} else {
// Use DFG fields
fieldNumbers = sourceCmd.getDFGMemberPositions();
}
ClassLoaderResolver clr = stmt.getRDBMSManager().getNucleusContext().getClassLoaderResolver(null);
for (int fieldNumber : fieldNumbers) {
AbstractMemberMetaData mmd = sourceCmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
selectMemberOfSourceInStatement(stmt, mappingDefinition, fetchPlan, sourceSqlTbl, mmd, clr, maxFetchDepth, inputJoinType);
}
if (sourceCmd.getIdentityType() == IdentityType.DATASTORE) {
// Datastore-identity surrogate column
JavaTypeMapping idMapping = sourceTbl.getSurrogateMapping(SurrogateColumnType.DATASTORE_ID, false);
int[] colNumbers = stmt.select(sourceSqlTbl, idMapping, null);
if (mappingDefinition != null) {
StatementMappingIndex datastoreIdIdx = new StatementMappingIndex(idMapping);
datastoreIdIdx.setColumnPositions(colNumbers);
mappingDefinition.addMappingForMember(SurrogateColumnType.DATASTORE_ID.getFieldNumber(), datastoreIdIdx);
}
}
JavaTypeMapping verMapping = sourceTbl.getSurrogateMapping(SurrogateColumnType.VERSION, true);
if (verMapping != null) {
// Version surrogate column (adds inner join to any required superclass table)
SQLTable versionSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(stmt, sourceSqlTbl, verMapping);
int[] colNumbers = stmt.select(versionSqlTbl, verMapping, null);
if (mappingDefinition != null) {
StatementMappingIndex versionIdx = new StatementMappingIndex(verMapping);
versionIdx.setColumnPositions(colNumbers);
mappingDefinition.addMappingForMember(SurrogateColumnType.VERSION.getFieldNumber(), versionIdx);
}
}
JavaTypeMapping discrimMapping = sourceTbl.getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, true);
if (discrimMapping != null) {
// Discriminator surrogate column (adds inner join to any required superclass table)
SQLTable discrimSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(stmt, sourceSqlTbl, discrimMapping);
int[] colNumbers = stmt.select(discrimSqlTbl, discrimMapping, null);
if (mappingDefinition != null) {
StatementMappingIndex discrimIdx = new StatementMappingIndex(discrimMapping);
discrimIdx.setColumnPositions(colNumbers);
mappingDefinition.addMappingForMember(SurrogateColumnType.DISCRIMINATOR.getFieldNumber(), discrimIdx);
}
}
}
use of org.datanucleus.store.rdbms.table.DatastoreClass in project datanucleus-rdbms by datanucleus.
the class DeleteRequest method updateOneToOneBidirectionalOwnerObjectForField.
/**
* Method to update any 1-1 bidir non-owner fields where the foreign-key is stored in the other object.
* @param op ObjectProvider of this object
* @param mmd MetaData for field that has related (owner) objects
*/
private void updateOneToOneBidirectionalOwnerObjectForField(ObjectProvider op, AbstractMemberMetaData fmd) {
if (softDeleteStmt != null) {
// If we are soft deleting the owner then no need to null the linkage BUT we need to check the soft delete status on retrieval of the owner from related
return;
}
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.PERSISTENCE.debug(Localiser.msg("052217", op.getObjectAsPrintable(), fmd.getFullFieldName()));
}
RDBMSStoreManager storeMgr = table.getStoreManager();
ExecutionContext ec = op.getExecutionContext();
ClassLoaderResolver clr = ec.getClassLoaderResolver();
AbstractMemberMetaData[] relatedMmds = fmd.getRelatedMemberMetaData(clr);
// Check if we should null here, or leave to the datastore FK handler
boolean checkFK = true;
if (ec.getStringProperty(PropertyNames.PROPERTY_DELETION_POLICY).equals("JDO2")) {
// JDO2 doesn't currently (2.0 spec) take note of foreign-key
checkFK = false;
}
if (checkFK) {
for (int i = 0; i < relatedMmds.length; i++) {
ForeignKeyMetaData relFkmd = relatedMmds[i].getForeignKeyMetaData();
if (relFkmd != null && relFkmd.getDeleteAction() != null) {
// Field has a FK with a delete-action so leave to the datastore to process the delete
return;
}
}
}
// TODO Cater for more than 1 related field
String fullClassName = ((AbstractClassMetaData) relatedMmds[0].getParent()).getFullClassName();
// TODO I'm not sure that we need to loop all implementations. will we have the fk set to all tables, if many?
String[] classes;
if (((AbstractClassMetaData) relatedMmds[0].getParent()) instanceof InterfaceMetaData) {
classes = storeMgr.getNucleusContext().getMetaDataManager().getClassesImplementingInterface(fullClassName, clr);
} else {
classes = new String[] { fullClassName };
}
Set<DatastoreClass> datastoreClasses = new HashSet();
for (int i = 0; i < classes.length; i++) {
// just remove duplicates
datastoreClasses.add(storeMgr.getDatastoreClass(classes[i], clr));
}
Iterator<DatastoreClass> it = datastoreClasses.iterator();
while (it.hasNext()) {
DatastoreClass refTable = it.next();
JavaTypeMapping refMapping = refTable.getMemberMapping(fmd.getMappedBy());
if (// Only clear the references that can be cleared
refMapping.isNullable()) {
// Create a statement to clear the link from the previous related object
StringBuilder clearLinkStmt = new StringBuilder("UPDATE " + refTable.toString() + " SET ");
for (int j = 0; j < refMapping.getNumberOfDatastoreMappings(); j++) {
if (j > 0) {
clearLinkStmt.append(",");
}
clearLinkStmt.append(refMapping.getDatastoreMapping(j).getColumn().getIdentifier());
clearLinkStmt.append("=NULL");
}
clearLinkStmt.append(" WHERE ");
for (int j = 0; j < refMapping.getNumberOfDatastoreMappings(); j++) {
if (j > 0) {
clearLinkStmt.append(" AND ");
}
clearLinkStmt.append(refMapping.getDatastoreMapping(j).getColumn().getIdentifier());
clearLinkStmt.append("=?");
}
try {
ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec);
SQLController sqlControl = storeMgr.getSQLController();
try {
// Null out the relationship to the object being deleted.
PreparedStatement ps = null;
try {
ps = sqlControl.getStatementForUpdate(mconn, clearLinkStmt.toString(), false);
refMapping.setObject(ec, ps, MappingHelper.getMappingIndices(1, refMapping), op.getObject());
sqlControl.executeStatementUpdate(ec, mconn, clearLinkStmt.toString(), ps, true);
} finally {
if (ps != null) {
sqlControl.closeStatement(mconn, ps);
}
}
} finally {
mconn.release();
}
} catch (Exception e) {
throw new NucleusDataStoreException("Update request failed", e);
}
}
}
}
Aggregations