use of org.datanucleus.exceptions.NucleusUserException in project datanucleus-rdbms by datanucleus.
the class QueryToSQLMapper method processFromClauseSubquery.
/**
* Method to process a ClassExpression where it represents a subquery.
* User defined the candidate of the subquery as an implied join to the outer query, for example "SELECT c FROM Customer c WHERE EXISTS (SELECT o FROM c.orders o ...)"
* so this method will add the join(s) to the outer query.
* @param clsExpr The ClassExpression
* @param candSqlTbl Candidate SQL Table
* @param mmgr MetaData Manager
*/
protected void processFromClauseSubquery(ClassExpression clsExpr, SQLTable candSqlTbl, MetaDataManager mmgr) {
String[] tokens = StringUtils.split(clsExpr.getCandidateExpression(), ".");
String leftAlias = tokens[0];
SQLTableMapping outerSqlTblMapping = parentMapper.getSQLTableMappingForAlias(leftAlias);
AbstractClassMetaData leftCmd = outerSqlTblMapping.cmd;
// Get array of the left-right sides of this expression so we can work back from the subquery candidate
AbstractMemberMetaData[] leftMmds = new AbstractMemberMetaData[tokens.length - 1];
AbstractMemberMetaData[] rightMmds = new AbstractMemberMetaData[tokens.length - 1];
for (int i = 0; i < tokens.length - 1; i++) {
String joinedField = tokens[i + 1];
AbstractMemberMetaData leftMmd = leftCmd.getMetaDataForMember(joinedField);
AbstractMemberMetaData rightMmd = null;
AbstractClassMetaData rightCmd = null;
RelationType relationType = leftMmd.getRelationType(clr);
if (RelationType.isBidirectional(relationType)) {
// Take first possible
rightMmd = leftMmd.getRelatedMemberMetaData(clr)[0];
rightCmd = rightMmd.getAbstractClassMetaData();
} else if (relationType == RelationType.ONE_TO_ONE_UNI) {
rightCmd = mmgr.getMetaDataForClass(leftMmd.getType(), clr);
} else if (relationType == RelationType.ONE_TO_MANY_UNI) {
if (leftMmd.hasCollection()) {
rightCmd = mmgr.getMetaDataForClass(leftMmd.getCollection().getElementType(), clr);
} else if (leftMmd.hasMap()) {
rightCmd = mmgr.getMetaDataForClass(leftMmd.getMap().getValueType(), clr);
}
} else {
throw new NucleusUserException("Subquery has been specified with a candidate-expression that includes \"" + tokens[i] + "\" that isnt a relation field!!");
}
leftMmds[i] = leftMmd;
rightMmds[i] = rightMmd;
leftCmd = rightCmd;
}
// Work from subquery candidate back to outer query table, adding joins and where clause as appropriate
SQLTable rSqlTbl = candSqlTbl;
SQLTable outerSqlTbl = outerSqlTblMapping.table;
JoinType joinType = JoinType.INNER_JOIN;
for (int i = leftMmds.length - 1; i >= 0; i--) {
AbstractMemberMetaData leftMmd = leftMmds[i];
AbstractMemberMetaData rightMmd = rightMmds[i];
DatastoreClass leftTbl = storeMgr.getDatastoreClass(leftMmd.getClassName(true), clr);
SQLTable lSqlTbl = null;
RelationType relationType = leftMmd.getRelationType(clr);
if (relationType == RelationType.ONE_TO_ONE_UNI) {
// 1-1 with FK in left table
if (i == 0) {
// Add where clause right table to outer table
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(), outerSqlTbl, outerSqlTbl.getTable().getMemberMapping(leftMmd));
SQLExpression rightExpr = exprFactory.newExpression(stmt, rSqlTbl, rSqlTbl.getTable().getIdMapping());
stmt.whereAnd(outerExpr.eq(rightExpr), false);
} else {
// Join to left table
JavaTypeMapping leftMapping = leftTbl.getMemberMapping(leftMmd);
lSqlTbl = stmt.join(joinType, rSqlTbl, rSqlTbl.getTable().getIdMapping(), leftTbl, null, leftMapping, null, null, true);
}
} else if (relationType == RelationType.ONE_TO_ONE_BI) {
if (leftMmd.getMappedBy() != null) {
// 1-1 with FK in right table
JavaTypeMapping rightMapping = rSqlTbl.getTable().getMemberMapping(rightMmd);
if (i == 0) {
// Add where clause right table to outer table
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(), outerSqlTbl, outerSqlTbl.getTable().getIdMapping());
SQLExpression rightExpr = exprFactory.newExpression(stmt, rSqlTbl, rightMapping);
stmt.whereAnd(outerExpr.eq(rightExpr), false);
} else {
// Join to left table
lSqlTbl = stmt.join(joinType, rSqlTbl, rightMapping, leftTbl, null, leftTbl.getIdMapping(), null, null, true);
}
} else {
// 1-1 with FK in left table
if (i == 0) {
// Add where clause right table to outer table
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(), outerSqlTbl, outerSqlTbl.getTable().getMemberMapping(leftMmd));
SQLExpression rightExpr = exprFactory.newExpression(stmt, rSqlTbl, rSqlTbl.getTable().getIdMapping());
stmt.whereAnd(outerExpr.eq(rightExpr), false);
} else {
// Join to left table
lSqlTbl = stmt.join(joinType, rSqlTbl, rSqlTbl.getTable().getIdMapping(), leftTbl, null, leftTbl.getMemberMapping(leftMmd), null, null, true);
}
}
} else if (relationType == RelationType.ONE_TO_MANY_UNI) {
if (leftMmd.getJoinMetaData() != null || rightMmd.getJoinMetaData() != null) {
// 1-N with join table to right table, so join from right to join table
JoinTable joinTbl = (JoinTable) storeMgr.getTable(leftMmd);
SQLTable joinSqlTbl = null;
if (leftMmd.hasCollection()) {
joinSqlTbl = stmt.join(joinType, rSqlTbl, rSqlTbl.getTable().getIdMapping(), joinTbl, null, ((ElementContainerTable) joinTbl).getElementMapping(), null, null, true);
} else if (leftMmd.hasMap()) {
joinSqlTbl = stmt.join(joinType, rSqlTbl, rSqlTbl.getTable().getIdMapping(), joinTbl, null, ((MapTable) joinTbl).getValueMapping(), null, null, true);
}
if (i == 0) {
// Add where clause join table (owner) to outer table (id)
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(), outerSqlTbl, outerSqlTbl.getTable().getIdMapping());
SQLExpression joinExpr = exprFactory.newExpression(stmt, joinSqlTbl, joinTbl.getOwnerMapping());
stmt.whereAnd(outerExpr.eq(joinExpr), false);
} else {
// Join to left table
lSqlTbl = stmt.join(joinType, joinSqlTbl, joinTbl.getOwnerMapping(), leftTbl, null, leftTbl.getIdMapping(), null, null, true);
}
} else {
// 1-N with FK in right table
if (i == 0) {
// Add where clause right table to outer table
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(), outerSqlTbl, outerSqlTbl.getTable().getMemberMapping(leftMmd));
SQLExpression rightExpr = exprFactory.newExpression(stmt, rSqlTbl, rSqlTbl.getTable().getMemberMapping(rightMmd));
stmt.whereAnd(outerExpr.eq(rightExpr), false);
} else {
// Join to left table
lSqlTbl = stmt.join(joinType, rSqlTbl, rSqlTbl.getTable().getMemberMapping(rightMmd), leftTbl, null, leftTbl.getIdMapping(), null, null, true);
}
}
} else if (relationType == RelationType.ONE_TO_MANY_BI) {
if (leftMmd.getJoinMetaData() != null || rightMmd.getJoinMetaData() != null) {
// 1-N with join table to right table, so join from right to join table
JoinTable joinTbl = (JoinTable) storeMgr.getTable(leftMmd);
SQLTable joinSqlTbl = null;
if (leftMmd.hasCollection()) {
joinSqlTbl = stmt.join(joinType, rSqlTbl, rSqlTbl.getTable().getIdMapping(), joinTbl, null, ((ElementContainerTable) joinTbl).getElementMapping(), null, null, true);
} else if (leftMmd.hasMap()) {
joinSqlTbl = stmt.join(joinType, rSqlTbl, rSqlTbl.getTable().getIdMapping(), joinTbl, null, ((MapTable) joinTbl).getValueMapping(), null, null, true);
}
if (i == 0) {
// Add where clause join table (owner) to outer table (id)
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(), outerSqlTbl, outerSqlTbl.getTable().getIdMapping());
SQLExpression joinExpr = exprFactory.newExpression(stmt, joinSqlTbl, joinTbl.getOwnerMapping());
stmt.whereAnd(outerExpr.eq(joinExpr), false);
} else {
// Join to left table
lSqlTbl = stmt.join(joinType, joinSqlTbl, joinTbl.getOwnerMapping(), leftTbl, null, leftTbl.getIdMapping(), null, null, true);
}
} else {
// 1-N with FK in right table
if (i == 0) {
// Add where clause right table to outer table
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(), outerSqlTbl, outerSqlTbl.getTable().getIdMapping());
SQLExpression rightExpr = exprFactory.newExpression(stmt, rSqlTbl, rSqlTbl.getTable().getMemberMapping(rightMmd));
stmt.whereAnd(outerExpr.eq(rightExpr), false);
} else {
// Join to left table
lSqlTbl = stmt.join(joinType, rSqlTbl, rSqlTbl.getTable().getMemberMapping(rightMmd), leftTbl, null, leftTbl.getIdMapping(), null, null, true);
}
}
} else if (relationType == RelationType.MANY_TO_ONE_BI) {
if (leftMmd.getJoinMetaData() != null || rightMmd.getJoinMetaData() != null) {
// 1-N with join table to right table, so join from right to join table
JoinTable joinTbl = (JoinTable) storeMgr.getTable(leftMmd);
SQLTable joinSqlTbl = stmt.join(joinType, rSqlTbl, rSqlTbl.getTable().getIdMapping(), joinTbl, null, joinTbl.getOwnerMapping(), null, null, true);
if (leftMmd.hasCollection()) {
if (i == 0) {
// Add where clause join table (element) to outer table (id)
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(), outerSqlTbl, outerSqlTbl.getTable().getIdMapping());
SQLExpression joinExpr = exprFactory.newExpression(stmt, joinSqlTbl, ((ElementContainerTable) joinTbl).getElementMapping());
stmt.whereAnd(outerExpr.eq(joinExpr), false);
} else {
// Join to left table
lSqlTbl = stmt.join(joinType, joinSqlTbl, ((ElementContainerTable) joinTbl).getElementMapping(), leftTbl, null, leftTbl.getIdMapping(), null, null, true);
}
} else if (leftMmd.hasMap()) {
if (i == 0) {
// Add where clause join table (value) to outer table (id)
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(), outerSqlTbl, outerSqlTbl.getTable().getIdMapping());
SQLExpression joinExpr = exprFactory.newExpression(stmt, joinSqlTbl, ((MapTable) joinTbl).getValueMapping());
stmt.whereAnd(outerExpr.eq(joinExpr), false);
} else {
// Join to left table
lSqlTbl = stmt.join(joinType, joinSqlTbl, ((MapTable) joinTbl).getValueMapping(), leftTbl, null, leftTbl.getIdMapping(), null, null, true);
}
}
} else {
if (i == 0) {
// Add where clause right table to outer table
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(), outerSqlTbl, outerSqlTbl.getTable().getMemberMapping(leftMmd));
SQLExpression rightExpr = exprFactory.newExpression(stmt, rSqlTbl, rSqlTbl.getTable().getIdMapping());
stmt.whereAnd(outerExpr.eq(rightExpr), false);
} else {
// Join to left table
lSqlTbl = stmt.join(joinType, rSqlTbl, rSqlTbl.getTable().getIdMapping(), leftTbl, null, leftTbl.getMemberMapping(leftMmd), null, null, true);
}
}
}
rSqlTbl = lSqlTbl;
}
}
use of org.datanucleus.exceptions.NucleusUserException in project datanucleus-rdbms by datanucleus.
the class QueryToSQLMapper method getSQLTableMappingForPrimaryExpression.
/**
* Method to take in a PrimaryExpression and return the SQLTable mapping info that it signifies.
* If the primary expression implies joining to other objects then adds the joins to the statement.
* Only adds joins if necessary; so if there is a further component after the required join, or if
* the "forceJoin" flag is set.
* @param theStmt SQLStatement to use when looking for tables etc
* @param exprName Name for an expression that this primary is relative to (optional)
* If not specified then the tuples are relative to the candidate.
* If specified then should have an entry in sqlTableByPrimary under this name.
* @param primExpr The primary expression
* @param forceJoin Whether to force a join if a relation member (or null if leaving to this method to decide)
* @return The SQL table mapping information for the specified primary
*/
private SQLTableMapping getSQLTableMappingForPrimaryExpression(SQLStatement theStmt, String exprName, PrimaryExpression primExpr, Boolean forceJoin) {
if (forceJoin == null && primExpr.getParent() != null) {
if (primExpr.getParent().getOperator() == Expression.OP_IS || primExpr.getParent().getOperator() == Expression.OP_ISNOT) {
// "instanceOf" needs to be in the table of the primary expression
forceJoin = Boolean.TRUE;
}
}
SQLTableMapping sqlMapping = null;
List<String> tuples = primExpr.getTuples();
// Find source object
ListIterator<String> iter = tuples.listIterator();
String first = tuples.get(0);
boolean mapKey = false;
boolean mapValue = false;
if (first.endsWith("#KEY")) {
first = first.substring(0, first.length() - 4);
mapKey = true;
} else if (first.endsWith("#VALUE")) {
first = first.substring(0, first.length() - 6);
mapValue = true;
}
String primaryName = null;
if (exprName != null) {
// Primary relative to some object etc
sqlMapping = getSQLTableMappingForAlias(exprName);
primaryName = exprName;
} else {
if (hasSQLTableMappingForAlias(first)) {
// Start from a candidate (e.g JPQL alias)
sqlMapping = getSQLTableMappingForAlias(first);
primaryName = first;
// Skip first tuple
iter.next();
}
if (sqlMapping != null && first.equals(candidateAlias) && candidateCmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.COMPLETE_TABLE) {
// Special case of using COMPLETE_TABLE for candidate and picked wrong table
// TODO Use OPTION_CASE_INSENSITIVE
SQLTable firstSqlTbl = stmt.getTable(first.toUpperCase());
if (firstSqlTbl != null && firstSqlTbl.getTable() != sqlMapping.table.getTable()) {
// Cached the SQLTableMapping for one of the other inherited classes, so create our own
sqlMapping = new SQLTableMapping(firstSqlTbl, sqlMapping.cmd, firstSqlTbl.getTable().getIdMapping());
}
}
if (sqlMapping == null) {
if (parentMapper != null) {
QueryToSQLMapper theParentMapper = parentMapper;
while (theParentMapper != null) {
if (theParentMapper.hasSQLTableMappingForAlias(first)) {
// Try parent query
sqlMapping = theParentMapper.getSQLTableMappingForAlias(first);
primaryName = first;
// Skip first tuple
iter.next();
// This expression is for the parent statement so any joins need to go on that statement
theStmt = sqlMapping.table.getSQLStatement();
break;
}
theParentMapper = theParentMapper.parentMapper;
}
}
}
if (sqlMapping == null) {
// Field of candidate, so use candidate
sqlMapping = getSQLTableMappingForAlias(candidateAlias);
primaryName = candidateAlias;
}
}
AbstractClassMetaData cmd = sqlMapping.cmd;
JavaTypeMapping mapping = sqlMapping.mapping;
if (sqlMapping.mmd != null && (mapKey || mapValue)) {
// Special case of MAP#KEY or MAP#VALUE, so navigate from the Map "table" to the key or value
SQLTable sqlTbl = sqlMapping.table;
AbstractMemberMetaData mmd = sqlMapping.mmd;
MapMetaData mapmd = mmd.getMap();
// Find the table forming the Map. This may be a join table, or the key or value depending on the type
if (mapKey) {
// Cater for all case possibilities of table name/alias
// TODO Use OPTION_CASE_INSENSITIVE
SQLTable mapSqlTbl = stmt.getTable(first + "_MAP");
if (mapSqlTbl == null) {
mapSqlTbl = stmt.getTable((first + "_MAP").toUpperCase());
if (mapSqlTbl == null) {
mapSqlTbl = stmt.getTable((first + "_MAP").toLowerCase());
}
}
if (mapSqlTbl != null) {
sqlTbl = mapSqlTbl;
}
}
if (mapmd.getMapType() == MapType.MAP_TYPE_JOIN) {
if (sqlTbl.getTable() instanceof MapTable) {
MapTable mapTable = (MapTable) sqlTbl.getTable();
if (mapKey) {
cmd = mapmd.getKeyClassMetaData(clr);
if (!mapmd.isEmbeddedKey() && !mapmd.isSerializedKey()) {
// Join to key table
DatastoreClass keyTable = storeMgr.getDatastoreClass(mapmd.getKeyType(), clr);
sqlTbl = stmt.join(getDefaultJoinTypeForNavigation(), sqlMapping.table, mapTable.getKeyMapping(), keyTable, null, keyTable.getIdMapping(), null, null, true);
mapping = keyTable.getIdMapping();
} else {
mapping = mapTable.getKeyMapping();
}
} else {
cmd = mapmd.getValueClassMetaData(clr);
if (!mapmd.isEmbeddedValue() && !mapmd.isSerializedValue()) {
// Join to value table
DatastoreClass valueTable = storeMgr.getDatastoreClass(mapmd.getValueType(), clr);
sqlTbl = stmt.join(getDefaultJoinTypeForNavigation(), sqlMapping.table, mapTable.getValueMapping(), valueTable, null, valueTable.getIdMapping(), null, null, true);
mapping = valueTable.getIdMapping();
} else {
mapping = mapTable.getValueMapping();
}
}
} else {
// TODO Document exactly which situation this is
if (!mapmd.isEmbeddedValue() && !mapmd.isSerializedValue()) {
mapping = sqlTbl.getTable().getIdMapping();
}
}
} else if (mapmd.getMapType() == MapType.MAP_TYPE_KEY_IN_VALUE) {
if (mapKey) {
AbstractClassMetaData keyCmd = mapmd.getKeyClassMetaData(clr);
String keyMappedBy = mmd.getKeyMetaData().getMappedBy();
mapping = ((DatastoreClass) sqlTbl.getTable()).getMemberMapping(keyMappedBy);
if (keyCmd != null) {
// Join to key table
DatastoreClass keyTable = storeMgr.getDatastoreClass(mapmd.getKeyType(), clr);
sqlTbl = stmt.join(getDefaultJoinTypeForNavigation(), sqlMapping.table, mapping, keyTable, null, keyTable.getIdMapping(), null, null, true);
mapping = keyTable.getIdMapping();
}
} else {
}
} else if (mapmd.getMapType() == MapType.MAP_TYPE_VALUE_IN_KEY) {
// TODO We maybe already have the VALUE TABLE from the original join
if (!mapKey) {
AbstractClassMetaData valCmd = mapmd.getValueClassMetaData(clr);
String valMappedBy = mmd.getValueMetaData().getMappedBy();
mapping = ((DatastoreClass) sqlTbl.getTable()).getMemberMapping(valMappedBy);
if (valCmd != null) {
// Join to value table
DatastoreClass valueTable = storeMgr.getDatastoreClass(mapmd.getValueType(), clr);
sqlTbl = stmt.join(getDefaultJoinTypeForNavigation(), sqlMapping.table, mapping, valueTable, null, valueTable.getIdMapping(), null, null, true);
mapping = valueTable.getIdMapping();
}
}
}
sqlMapping = new SQLTableMapping(sqlTbl, cmd, mapping);
}
while (iter.hasNext()) {
String component = iter.next();
// fully-qualified primary name
primaryName += "." + component;
// Derive SQLTableMapping for this component
SQLTableMapping sqlMappingNew = getSQLTableMappingForAlias(primaryName);
if (sqlMappingNew == null) {
// Table not present for this primary
AbstractMemberMetaData mmd = cmd.getMetaDataForMember(component);
if (mmd == null) {
// Not valid member name
throw new NucleusUserException(Localiser.msg("021062", component, cmd.getFullClassName()));
} else if (mmd.getPersistenceModifier() != FieldPersistenceModifier.PERSISTENT) {
throw new NucleusUserException("Field " + mmd.getFullFieldName() + " is not marked as persistent so cannot be queried");
}
RelationType relationType = mmd.getRelationType(clr);
// Find the table and the mapping for this field in the table
SQLTable sqlTbl = null;
if (mapping instanceof EmbeddedMapping) {
// Embedded into the current table
sqlTbl = sqlMapping.table;
mapping = ((EmbeddedMapping) mapping).getJavaTypeMapping(component);
} else if (mapping instanceof PersistableMapping && cmd.isEmbeddedOnly()) {
// JPA EmbeddedId into current table
sqlTbl = sqlMapping.table;
JavaTypeMapping[] subMappings = ((PersistableMapping) mapping).getJavaTypeMapping();
if (subMappings.length == 1 && subMappings[0] instanceof EmbeddedPCMapping) {
mapping = ((EmbeddedPCMapping) subMappings[0]).getJavaTypeMapping(component);
} else {
// TODO What situation is this?
}
} else {
DatastoreClass table = storeMgr.getDatastoreClass(cmd.getFullClassName(), clr);
if (table == null) {
if (cmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.COMPLETE_TABLE && candidateCmd.getFullClassName().equals(cmd.getFullClassName())) {
// Special case of a candidate having no table of its own and using COMPLETE_TABLE, so we use the candidate class for this statement (or UNION)
table = storeMgr.getDatastoreClass(stmt.getCandidateClassName(), clr);
}
}
if (table == null) {
AbstractClassMetaData[] subCmds = storeMgr.getClassesManagingTableForClass(cmd, clr);
if (subCmds.length == 1) {
table = storeMgr.getDatastoreClass(subCmds[0].getFullClassName(), clr);
} else {
// all of UNIONs, and this primary expression refers to a mapping in each of subclass tables
throw new NucleusUserException("Unable to find table for primary " + primaryName + " since the class " + cmd.getFullClassName() + " is managed in multiple tables");
}
}
if (table == null) {
throw new NucleusUserException("Unable to find table for primary " + primaryName + ". Table for class=" + cmd.getFullClassName() + " is null : is the field correct? or using some inheritance pattern?");
}
mapping = table.getMemberMapping(mmd);
sqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(theStmt, sqlMapping.table, mapping);
}
if (relationType == RelationType.NONE) {
sqlMappingNew = new SQLTableMapping(sqlTbl, cmd, mapping);
cmd = sqlMappingNew.cmd;
setSQLTableMappingForAlias(primaryName, sqlMappingNew);
} else if (relationType == RelationType.ONE_TO_ONE_UNI || relationType == RelationType.ONE_TO_ONE_BI) {
if (mmd.getMappedBy() != null) {
// FK in other table so join to that first
AbstractMemberMetaData relMmd = mmd.getRelatedMemberMetaData(clr)[0];
if (relMmd.getAbstractClassMetaData().isEmbeddedOnly()) {
// Member is embedded, so keep same SQL table mapping
sqlMappingNew = sqlMapping;
cmd = relMmd.getAbstractClassMetaData();
} else {
// Member is in own table, so move to that SQL table mapping
DatastoreClass relTable = storeMgr.getDatastoreClass(mmd.getTypeName(), clr);
JavaTypeMapping relMapping = relTable.getMemberMapping(relMmd);
// Join to related table unless we already have the join in place
sqlTbl = theStmt.getTable(relTable, primaryName);
if (sqlTbl == null) {
sqlTbl = SQLStatementHelper.addJoinForOneToOneRelation(theStmt, sqlMapping.table.getTable().getIdMapping(), sqlMapping.table, relMapping, relTable, null, null, primaryName, getDefaultJoinTypeForNavigation());
}
if (iter.hasNext()) {
sqlMappingNew = new SQLTableMapping(sqlTbl, relMmd.getAbstractClassMetaData(), relTable.getIdMapping());
cmd = sqlMappingNew.cmd;
} else {
sqlMappingNew = new SQLTableMapping(sqlTbl, cmd, relTable.getIdMapping());
cmd = sqlMappingNew.cmd;
}
}
} else {
// FK is at this side
if (forceJoin == null) {
if (!iter.hasNext()) {
// Further component provided, so check if we should force a join to the other side
if (primExpr.getParent() != null && primExpr.getParent().getOperator() == Expression.OP_CAST) {
// Cast and not an interface field, so do a join to the table of the persistable object
if (mapping instanceof ReferenceMapping) {
// Don't join with interface field since represents multiple implementations
// and the cast will be a restrict on which implementation to join to
} else {
AbstractClassMetaData relCmd = ec.getMetaDataManager().getMetaDataForClass(mmd.getType(), clr);
if (relCmd != null && !relCmd.isEmbeddedOnly()) {
DatastoreClass relTable = storeMgr.getDatastoreClass(relCmd.getFullClassName(), clr);
if (relTable == null) {
} else {
forceJoin = Boolean.TRUE;
}
} else {
forceJoin = Boolean.TRUE;
}
}
}
} else {
// TODO Add optimisation to omit join if the FK is at this side and only selecting PK of the related object
if (iter.hasNext()) {
// Peek ahead to see if just selecting "id" of the related (i.e candidate.related.id with related FK in candidate table, so don't join)
String next = iter.next();
if (!iter.hasNext()) {
AbstractClassMetaData relCmd = storeMgr.getMetaDataManager().getMetaDataForClass(mmd.getType(), clr);
if (relCmd != null) {
AbstractMemberMetaData mmdOfRelCmd = relCmd.getMetaDataForMember(next);
if (mmdOfRelCmd != null && mmdOfRelCmd.isPrimaryKey() && relCmd.getNoOfPrimaryKeyMembers() == 1 && !storeMgr.getMetaDataManager().isClassPersistable(mmdOfRelCmd.getTypeName())) {
// We have something like "a.b.id" and have the FK to the "B" table in the "A" table, so just refer to A.FK rather than joining and using B.ID
NucleusLogger.QUERY.debug("Found implicit join to member=" + mmdOfRelCmd.getFullFieldName() + " which is PK of the other type but FK is in this table so avoiding the join");
JavaTypeMapping subMapping = ((PersistableMapping) mapping).getJavaTypeMapping()[0];
// Component mappings of a PersistableMapping sometimes don't have table set, so fix it
subMapping.setTable(mapping.getTable());
return new SQLTableMapping(sqlMapping.table, relCmd, subMapping);
}
}
}
iter.previous();
}
}
}
if (iter.hasNext() || Boolean.TRUE.equals(forceJoin)) {
AbstractClassMetaData relCmd = null;
JavaTypeMapping relMapping = null;
DatastoreClass relTable = null;
if (relationType == RelationType.ONE_TO_ONE_BI) {
AbstractMemberMetaData relMmd = mmd.getRelatedMemberMetaData(clr)[0];
relCmd = relMmd.getAbstractClassMetaData();
} else {
String typeName = mmd.isSingleCollection() ? mmd.getCollection().getElementType() : mmd.getTypeName();
relCmd = ec.getMetaDataManager().getMetaDataForClass(typeName, clr);
}
if (relCmd != null && relCmd.isEmbeddedOnly()) {
// Member is embedded so use same table but embedded mapping
sqlMappingNew = new SQLTableMapping(sqlTbl, relCmd, mapping);
cmd = relCmd;
} else {
// Member is in own table, so move to that SQL table mapping
relTable = storeMgr.getDatastoreClass(relCmd.getFullClassName(), clr);
if (relTable == null) {
// No table for the related type (subclass-table), so see if this class has a single subclass with its own table
Collection<String> relSubclassNames = storeMgr.getSubClassesForClass(relCmd.getFullClassName(), false, clr);
if (relSubclassNames != null && relSubclassNames.size() == 1) {
String relSubclassName = relSubclassNames.iterator().next();
relTable = storeMgr.getDatastoreClass(relSubclassName, clr);
// TODO Cater for this having no table and next level yes etc
if (relTable != null) {
relCmd = ec.getMetaDataManager().getMetaDataForClass(relSubclassName, clr);
}
}
if (relTable == null) {
// No table as such, so likely using subclass-table at other side and we don't know where to join to
throw new NucleusUserException("Reference to PrimaryExpression " + primExpr + " yet this needs to join relation " + mmd.getFullFieldName() + " and the other type has no table (subclass-table?). Maybe use a CAST to the appropriate subclass?");
}
}
relMapping = relTable.getIdMapping();
// Join to other table unless we already have the join in place
sqlTbl = theStmt.getTable(relTable, primaryName);
if (sqlTbl == null) {
sqlTbl = SQLStatementHelper.addJoinForOneToOneRelation(theStmt, mapping, sqlMapping.table, relMapping, relTable, null, null, primaryName, getDefaultJoinTypeForNavigation());
}
sqlMappingNew = new SQLTableMapping(sqlTbl, relCmd, relMapping);
cmd = sqlMappingNew.cmd;
setSQLTableMappingForAlias(primaryName, sqlMappingNew);
}
} else {
sqlMappingNew = new SQLTableMapping(sqlTbl, cmd, mapping);
cmd = sqlMappingNew.cmd;
// Don't register the SQLTableMapping for this alias since only using FK
}
}
} else if (relationType == RelationType.MANY_TO_ONE_BI) {
AbstractMemberMetaData relMmd = mmd.getRelatedMemberMetaData(clr)[0];
DatastoreClass relTable = storeMgr.getDatastoreClass(mmd.getTypeName(), clr);
if (mmd.getJoinMetaData() != null || relMmd.getJoinMetaData() != null) {
// Has join table so use that
sqlTbl = theStmt.getTable(relTable, primaryName);
if (sqlTbl == null) {
// Join to the join table
CollectionTable joinTbl = (CollectionTable) storeMgr.getTable(relMmd);
JoinType defJoinType = getDefaultJoinTypeForNavigation();
if (defJoinType == JoinType.INNER_JOIN) {
SQLTable joinSqlTbl = theStmt.join(JoinType.INNER_JOIN, sqlMapping.table, sqlMapping.table.getTable().getIdMapping(), joinTbl, null, joinTbl.getElementMapping(), null, null, true);
sqlTbl = theStmt.join(JoinType.INNER_JOIN, joinSqlTbl, joinTbl.getOwnerMapping(), relTable, null, relTable.getIdMapping(), null, primaryName, true);
} else if (defJoinType == JoinType.LEFT_OUTER_JOIN || defJoinType == null) {
SQLTable joinSqlTbl = theStmt.join(JoinType.LEFT_OUTER_JOIN, sqlMapping.table, sqlMapping.table.getTable().getIdMapping(), joinTbl, null, joinTbl.getElementMapping(), null, null, true);
sqlTbl = theStmt.join(JoinType.LEFT_OUTER_JOIN, joinSqlTbl, joinTbl.getOwnerMapping(), relTable, null, relTable.getIdMapping(), null, primaryName, true);
}
}
sqlMappingNew = new SQLTableMapping(sqlTbl, relMmd.getAbstractClassMetaData(), relTable.getIdMapping());
cmd = sqlMappingNew.cmd;
setSQLTableMappingForAlias(primaryName, sqlMappingNew);
} else {
// FK in this table
sqlTbl = theStmt.getTable(relTable, primaryName);
if (sqlTbl == null) {
if (mmd.getMappedBy() == null) {
// FK at this side so check for optimisations
if (iter.hasNext()) {
// Peek ahead to see if just selecting "id" of the related (i.e candidate.related.id with related FK in candidate table, so don't join)
String next = iter.next();
if (!iter.hasNext()) {
AbstractClassMetaData relCmd = relMmd.getAbstractClassMetaData();
AbstractMemberMetaData mmdOfRelCmd = relCmd.getMetaDataForMember(next);
if (mmdOfRelCmd != null && mmdOfRelCmd.isPrimaryKey() && relCmd.getNoOfPrimaryKeyMembers() == 1 && !storeMgr.getMetaDataManager().isClassPersistable(mmdOfRelCmd.getTypeName())) {
// We have something like "a.b.id" and have the FK to the "B" table in the "A" table, so just refer to A.FK rather than joining and using B.ID
NucleusLogger.QUERY.debug("Found implicit join to member=" + mmdOfRelCmd.getFullFieldName() + " which is PK of the other type but FK is in this table so avoiding the join");
JavaTypeMapping subMapping = ((PersistableMapping) mapping).getJavaTypeMapping()[0];
// Component mappings of a PersistableMapping sometimes don't have table set, so fix it
subMapping.setTable(mapping.getTable());
return new SQLTableMapping(sqlMapping.table, relCmd, subMapping);
}
}
iter.previous();
}
}
Operator op = (primExpr.getParent() != null ? primExpr.getParent().getOperator() : null);
if (!iter.hasNext() && (op == Expression.OP_EQ || op == Expression.OP_GT || op == Expression.OP_LT || op == Expression.OP_GTEQ || op == Expression.OP_LTEQ || op == Expression.OP_NOTEQ)) {
// Just return the FK mapping since in a "a.b == c.d" type expression and not needing to go further than the FK
sqlMappingNew = new SQLTableMapping(sqlMapping.table, relMmd.getAbstractClassMetaData(), mapping);
} else {
// Join to the related table
JoinType defJoinType = getDefaultJoinTypeForNavigation();
if (defJoinType == JoinType.INNER_JOIN) {
sqlTbl = theStmt.join(JoinType.INNER_JOIN, sqlMapping.table, mapping, relTable, null, relTable.getIdMapping(), null, primaryName, true);
} else if (defJoinType == JoinType.LEFT_OUTER_JOIN || defJoinType == null) {
sqlTbl = theStmt.join(JoinType.LEFT_OUTER_JOIN, sqlMapping.table, mapping, relTable, null, relTable.getIdMapping(), null, primaryName, true);
}
sqlMappingNew = new SQLTableMapping(sqlTbl, relMmd.getAbstractClassMetaData(), relTable.getIdMapping());
cmd = sqlMappingNew.cmd;
setSQLTableMappingForAlias(primaryName, sqlMappingNew);
}
} else {
sqlMappingNew = new SQLTableMapping(sqlTbl, relMmd.getAbstractClassMetaData(), relTable.getIdMapping());
cmd = sqlMappingNew.cmd;
setSQLTableMappingForAlias(primaryName, sqlMappingNew);
}
}
} else if (RelationType.isRelationMultiValued(relationType)) {
// Can't reference further than a collection/map so just return its mapping here
sqlMappingNew = new SQLTableMapping(sqlTbl, cmd, mapping);
cmd = sqlMappingNew.cmd;
setSQLTableMappingForAlias(primaryName, sqlMappingNew);
}
} else {
cmd = sqlMappingNew.cmd;
}
sqlMapping = sqlMappingNew;
}
return sqlMapping;
}
use of org.datanucleus.exceptions.NucleusUserException in project datanucleus-rdbms by datanucleus.
the class PersistableMapping method postInsert.
/**
* Method executed just after the insert of the owning object, allowing any necessary action
* to this field and the object stored in it.
* @param op ObjectProvider for the owner
*/
public void postInsert(ObjectProvider op) {
Object pc = op.provideField(mmd.getAbsoluteFieldNumber());
TypeManager typeManager = op.getExecutionContext().getTypeManager();
pc = mmd.isSingleCollection() ? singleCollectionValue(typeManager, pc) : pc;
if (pc == null) {
// Has been set to null so nothing to do
return;
}
ClassLoaderResolver clr = op.getExecutionContext().getClassLoaderResolver();
AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
RelationType relationType = mmd.getRelationType(clr);
if (relationType == RelationType.ONE_TO_ONE_BI) {
ObjectProvider otherOP = op.getExecutionContext().findObjectProvider(pc);
if (otherOP == null) {
return;
}
AbstractMemberMetaData relatedMmd = mmd.getRelatedMemberMetaDataForObject(clr, op.getObject(), pc);
if (relatedMmd == null) {
// Fsck knows why
throw new NucleusUserException("You have a field " + mmd.getFullFieldName() + " that is 1-1 bidir yet cannot find the equivalent field at the other side. Why is that?");
}
Object relatedValue = otherOP.provideField(relatedMmd.getAbsoluteFieldNumber());
relatedValue = relatedMmd.isSingleCollection() ? singleCollectionValue(typeManager, relatedValue) : relatedValue;
if (relatedValue == null) {
// Managed Relations : Other side not set so update it in memory
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.PERSISTENCE.debug(Localiser.msg("041018", op.getObjectAsPrintable(), mmd.getFullFieldName(), StringUtils.toJVMIDString(pc), relatedMmd.getFullFieldName()));
}
Object replaceValue = op.getObject();
if (relatedMmd.isSingleCollection()) {
ElementContainerHandler containerHandler = typeManager.getContainerHandler(relatedMmd.getType());
replaceValue = containerHandler.newContainer(relatedMmd, op.getObject());
}
otherOP.replaceField(relatedMmd.getAbsoluteFieldNumber(), replaceValue);
} else if (relatedValue != op.getObject()) {
// Managed Relations : Other side is inconsistent so throw exception
throw new NucleusUserException(Localiser.msg("041020", op.getObjectAsPrintable(), mmd.getFullFieldName(), StringUtils.toJVMIDString(pc), StringUtils.toJVMIDString(relatedValue)));
}
} else if (relationType == RelationType.MANY_TO_ONE_BI && relatedMmds[0].hasCollection()) {
// TODO Make sure we have this PC in the collection at the other side
ObjectProvider otherOP = op.getExecutionContext().findObjectProvider(pc);
if (otherOP != null) {
// Managed Relations : add to the collection on the other side
Collection relatedColl = (Collection) otherOP.provideField(relatedMmds[0].getAbsoluteFieldNumber());
if (relatedColl != null && !(relatedColl instanceof SCOCollection)) {
// TODO Make sure the collection is a wrapper
boolean contained = relatedColl.contains(op.getObject());
if (!contained) {
NucleusLogger.PERSISTENCE.info(Localiser.msg("041022", op.getObjectAsPrintable(), mmd.getFullFieldName(), StringUtils.toJVMIDString(pc), relatedMmds[0].getFullFieldName()));
// TODO Enable this. Currently causes issues with PMImplTest, InheritanceStrategyTest, TCK "inheritance1.conf"
/*relatedColl.add(op.getObject());*/
}
}
}
} else if (relationType == RelationType.MANY_TO_ONE_UNI) {
ObjectProvider otherOP = op.getExecutionContext().findObjectProvider(pc);
if (otherOP == null) {
// Related object is not yet persisted so persist it
Object other = op.getExecutionContext().persistObjectInternal(pc, null, -1, ObjectProvider.PC);
otherOP = op.getExecutionContext().findObjectProvider(other);
}
// Add join table entry
PersistableRelationStore store = (PersistableRelationStore) storeMgr.getBackingStoreForField(clr, mmd, mmd.getType());
store.add(op, otherOP);
}
}
use of org.datanucleus.exceptions.NucleusUserException in project datanucleus-rdbms by datanucleus.
the class PersistableMapping method setObjectAsValue.
/**
* Method to set an object reference (FK) in the datastore.
* @param ec The ExecutionContext
* @param ps The Prepared Statement
* @param param The parameter ids in the statement
* @param value The value to put in the statement at these ids
* @param ownerOP ObjectProvider for the owner object
* @param ownerFieldNumber Field number of this PC object in the owner
* @throws NotYetFlushedException Just put "null" in and throw "NotYetFlushedException", to be caught by ParameterSetter and will signal to the
* PC object being inserted that it needs to inform this object when it is inserted.
*/
private void setObjectAsValue(ExecutionContext ec, PreparedStatement ps, int[] param, Object value, ObjectProvider ownerOP, int ownerFieldNumber) {
Object id;
ApiAdapter api = ec.getApiAdapter();
if (!api.isPersistable(value)) {
throw new NucleusException(Localiser.msg("041016", value.getClass(), value)).setFatal();
}
ObjectProvider valueOP = ec.findObjectProvider(value);
try {
ClassLoaderResolver clr = ec.getClassLoaderResolver();
// Check if the field is attributed in the datastore
boolean hasDatastoreAttributedPrimaryKeyValues = hasDatastoreAttributedPrimaryKeyValues(ec.getMetaDataManager(), storeMgr, clr);
boolean inserted = false;
if (ownerFieldNumber >= 0) {
// Field mapping : is this field of the related object present in the datastore?
inserted = storeMgr.isObjectInserted(valueOP, ownerFieldNumber);
} else if (mmd == null) {
// Identity mapping : is the object inserted far enough to be considered of this mapping type?
inserted = storeMgr.isObjectInserted(valueOP, type);
}
if (valueOP != null) {
if (ec.getApiAdapter().isDetached(value) && valueOP.getReferencedPC() != null && ownerOP != null && mmd != null) {
// Still detached but started attaching so replace the field with what will be the attached
// Note that we have "fmd != null" here hence omitting any M-N relations where this is a join table
// mapping
ownerOP.replaceFieldMakeDirty(ownerFieldNumber, valueOP.getReferencedPC());
}
if (valueOP.isWaitingToBeFlushedToDatastore()) {
try {
// Related object is not yet flushed to the datastore so flush it so we can set the FK
valueOP.flush();
} catch (NotYetFlushedException nfe) {
// Could not flush it, maybe it has a relation to this object! so set as null TODO check nullability
if (ownerOP != null) {
ownerOP.updateFieldAfterInsert(value, ownerFieldNumber);
}
setObjectAsNull(ec, ps, param);
return;
}
}
} else {
if (ec.getApiAdapter().isDetached(value)) {
// Field value is detached and not yet started attaching, so attach
Object attachedValue = ec.persistObjectInternal(value, null, -1, ObjectProvider.PC);
if (attachedValue != value && ownerOP != null) {
// Replace the field value if using copy-on-attach
ownerOP.replaceFieldMakeDirty(ownerFieldNumber, attachedValue);
// Work from attached value now that it is attached
value = attachedValue;
}
valueOP = ec.findObjectProvider(value);
}
}
// 5) the value is the same object as we are inserting anyway and has its identity set
if (inserted || !ec.isInserting(value) || (!hasDatastoreAttributedPrimaryKeyValues && (this.mmd != null && this.mmd.isPrimaryKey())) || (!hasDatastoreAttributedPrimaryKeyValues && ownerOP == valueOP && api.getIdForObject(value) != null)) {
// The PC is either already inserted, or inserted down to the level we need, or not inserted at all,
// or the field is a PK and identity not attributed by the datastore
// Object either already exists, or is not yet being inserted.
id = api.getIdForObject(value);
// Check if the persistable object exists in this datastore
boolean requiresPersisting = false;
if (ec.getApiAdapter().isDetached(value) && ownerOP != null) {
// Detached object so needs attaching
if (ownerOP.isInserting()) {
// we can just return the value now and attach later (in InsertRequest)
if (!ec.getBooleanProperty(PropertyNames.PROPERTY_ATTACH_SAME_DATASTORE)) {
if (ec.getObjectFromCache(api.getIdForObject(value)) != null) {
// Object is in cache so exists for this datastore, so no point checking
} else {
try {
Object obj = ec.findObject(api.getIdForObject(value), true, false, value.getClass().getName());
if (obj != null) {
// Make sure this object is not retained in cache etc
ObjectProvider objOP = ec.findObjectProvider(obj);
if (objOP != null) {
ec.evictFromTransaction(objOP);
}
ec.removeObjectFromLevel1Cache(api.getIdForObject(value));
}
} catch (NucleusObjectNotFoundException onfe) {
// Object doesn't yet exist
requiresPersisting = true;
}
}
}
} else {
requiresPersisting = true;
}
} else if (id == null) {
// Transient object, so we need to persist it
requiresPersisting = true;
} else {
ExecutionContext pcEC = ec.getApiAdapter().getExecutionContext(value);
if (pcEC != null && ec != pcEC) {
throw new NucleusUserException(Localiser.msg("041015"), id);
}
}
if (requiresPersisting) {
// This PC object needs persisting (new or detached) to do the "set"
if (mmd != null && !mmd.isCascadePersist() && !ec.getApiAdapter().isDetached(value)) {
// Related PC object not persistent, but cant do cascade-persist so throw exception
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.PERSISTENCE.debug(Localiser.msg("007006", mmd.getFullFieldName()));
}
throw new ReachableObjectNotCascadedException(mmd.getFullFieldName(), value);
}
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.PERSISTENCE.debug(Localiser.msg("007007", mmd != null ? mmd.getFullFieldName() : null));
}
try {
Object pcNew = ec.persistObjectInternal(value, null, -1, ObjectProvider.PC);
if (hasDatastoreAttributedPrimaryKeyValues) {
ec.flushInternal(false);
}
id = api.getIdForObject(pcNew);
if (ec.getApiAdapter().isDetached(value) && ownerOP != null && mmd != null) {
// Update any detached reference to refer to the attached variant
ownerOP.replaceFieldMakeDirty(ownerFieldNumber, pcNew);
RelationType relationType = mmd.getRelationType(clr);
if (relationType == RelationType.MANY_TO_ONE_BI) {
// TODO Update the container to refer to the attached object
if (NucleusLogger.PERSISTENCE.isInfoEnabled()) {
NucleusLogger.PERSISTENCE.info("PCMapping.setObject : object " + ownerOP.getInternalObjectId() + " has field " + ownerFieldNumber + " that is 1-N bidirectional." + " Have just attached the N side so should really update the reference in the 1 side collection" + " to refer to this attached object. Not yet implemented");
}
} else if (relationType == RelationType.ONE_TO_ONE_BI) {
AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
// TODO Cater for more than 1 related field
ObjectProvider relatedOP = ec.findObjectProvider(pcNew);
relatedOP.replaceFieldMakeDirty(relatedMmds[0].getAbsoluteFieldNumber(), ownerOP.getObject());
}
}
} catch (NotYetFlushedException e) {
setObjectAsNull(ec, ps, param);
throw new NotYetFlushedException(value);
}
}
if (valueOP != null) {
valueOP.setStoringPC();
}
// If the field doesn't map to any datastore fields (e.g remote FK), omit the set process
if (getNumberOfDatastoreMappings() > 0) {
if (IdentityUtils.isDatastoreIdentity(id)) {
Object idKey = IdentityUtils.getTargetKeyForDatastoreIdentity(id);
try {
// Try as a Long
getDatastoreMapping(0).setObject(ps, param[0], idKey);
} catch (Exception e) {
// Must be a String
getDatastoreMapping(0).setObject(ps, param[0], idKey.toString());
}
} else {
boolean fieldsSet = false;
if (IdentityUtils.isSingleFieldIdentity(id) && javaTypeMappings.length > 1) {
Object key = IdentityUtils.getTargetKeyForSingleFieldIdentity(id);
AbstractClassMetaData keyCmd = ec.getMetaDataManager().getMetaDataForClass(key.getClass(), clr);
if (keyCmd != null && keyCmd.getIdentityType() == IdentityType.NONDURABLE) {
// Embedded ID - Make sure these are called starting at lowest first, in order
// We cannot just call OP.provideFields with all fields since that does last first
ObjectProvider keyOP = ec.findObjectProvider(key);
int[] fieldNums = keyCmd.getAllMemberPositions();
FieldManager fm = new AppIDObjectIdFieldManager(param, ec, ps, javaTypeMappings);
for (int i = 0; i < fieldNums.length; i++) {
keyOP.provideFields(new int[] { fieldNums[i] }, fm);
}
fieldsSet = true;
}
}
if (!fieldsSet) {
// Copy PK fields from identity to the object
FieldManager fm = new AppIDObjectIdFieldManager(param, ec, ps, javaTypeMappings);
api.copyKeyFieldsFromIdToObject(value, new AppIdObjectIdFieldConsumer(api, fm), id);
}
}
}
} else {
if (valueOP != null) {
valueOP.setStoringPC();
}
if (getNumberOfDatastoreMappings() > 0) {
// Object is in the process of being inserted so we cant use its id currently and we need to store
// a foreign key to it (which we cant yet do). Just put "null" in and throw "NotYetFlushedException",
// to be caught by ParameterSetter and will signal to the PC object being inserted that it needs
// to inform this object when it is inserted.
setObjectAsNull(ec, ps, param);
throw new NotYetFlushedException(value);
}
}
} finally {
if (valueOP != null) {
valueOP.unsetStoringPC();
}
}
}
use of org.datanucleus.exceptions.NucleusUserException in project datanucleus-rdbms by datanucleus.
the class ReferenceMapping method createPerImplementationColumnsForReferenceField.
/**
* Create columns for reference (Interface/Object) fields on a per-implementation basis.
* This call ColumnCreator.createColumnsForField for each implementation class of the reference.
*/
void createPerImplementationColumnsForReferenceField(boolean pk, boolean nullable, boolean serialised, boolean embedded, FieldRole fieldRole, ColumnMetaData[] columnMetaData, ClassLoaderResolver clr) {
if (this instanceof InterfaceMapping && mmd.hasExtension(MetaData.EXTENSION_MEMBER_IMPLEMENTATION_CLASSES)) {
// Store the implementation-classes with the mapping (persistent interfaces?)
((InterfaceMapping) this).setImplementationClasses(mmd.getValueForExtension(MetaData.EXTENSION_MEMBER_IMPLEMENTATION_CLASSES));
}
// Find the available implementations that we are creating columns for
String[] implTypes = null;
try {
implTypes = MetaDataUtils.getInstance().getImplementationNamesForReferenceField(mmd, fieldRole, clr, storeMgr.getMetaDataManager());
} catch (NucleusUserException nue) {
// No implementation classes found, so log warning and return
if (storeMgr.getBooleanProperty(PropertyNames.PROPERTY_STORE_ALLOW_REFS_WITHOUT_IMPLS, false)) {
NucleusLogger.DATASTORE_SCHEMA.warn("Possible problem encountered while adding columns for field " + mmd.getFullFieldName() + " : " + nue.getMessage());
return;
}
throw nue;
}
// Set the PK and nullability of column(s) for the implementations (based on the number of impls etc)
if (implTypes.length > 1) {
// Cannot be part of PK if more than 1 implementation
pk = false;
}
if (implTypes.length > 1 && !pk) {
// Must be nullable if more than 1 impl (since only 1 impl can have value at a time)
nullable = true;
}
// Create list of classes that require columns.
// We only add columns for the implementation that is the root of a particular inheritance tree
// e.g if we have A implements I1, and B extends A then they both are valid implementations
// but we only want to create column(s) for A.
Collection implClasses = new ArrayList();
for (int i = 0; i < implTypes.length; i++) {
Class type = clr.classForName(implTypes[i]);
if (type == null) {
throw new NucleusUserException(Localiser.msg("020189", mmd.getTypeName(), implTypes[i]));
} else if (type.isInterface()) {
throw new NucleusUserException(Localiser.msg("020190", mmd.getFullFieldName(), mmd.getTypeName(), implTypes[i]));
}
Iterator iter = implClasses.iterator();
boolean toBeAdded = true;
Class clsToSwap = null;
while (iter.hasNext()) {
Class cls = (Class) iter.next();
if (cls == type) {
// Implementation already present
toBeAdded = false;
break;
}
if (type.isAssignableFrom(cls)) {
// "type" is superclass of "cls" so swap subclass for this class
clsToSwap = cls;
toBeAdded = false;
break;
} else if (cls.isAssignableFrom(type)) {
toBeAdded = false;
break;
}
}
if (toBeAdded) {
implClasses.add(type);
} else if (clsToSwap != null) {
implClasses.remove(clsToSwap);
implClasses.add(type);
}
}
// Add columns for each of these implementations
int colPos = 0;
Iterator implClsIter = implClasses.iterator();
while (implClsIter.hasNext()) {
Class implClass = (Class) implClsIter.next();
boolean present = false;
int numJavaTypeMappings = getJavaTypeMapping().length;
for (int i = 0; i < numJavaTypeMappings; i++) {
JavaTypeMapping implMapping = getJavaTypeMapping()[i];
if (implClass.getName().equals(implMapping.getType())) {
present = true;
}
}
if (present) {
// Implementation already present in mapping (e.g reinitialising) so skip this
continue;
}
String fieldTypeName = getReferenceFieldType(fieldRole);
boolean isPersistentInterfaceField = storeMgr.getNucleusContext().getMetaDataManager().isPersistentInterface(fieldTypeName);
boolean columnsNeeded = true;
if (isPersistentInterfaceField && !storeMgr.getNucleusContext().getMetaDataManager().isPersistentInterfaceImplementation(fieldTypeName, implClass.getName())) {
// We have a "persistent-interface" field yet this is not a generated implementation so ignore it
// It is arguable if we should allow the real implementations of this interface here, but the JDO2 TCK doesn't
// make that assumption so we don't either
columnsNeeded = false;
}
if (columnsNeeded) {
// Get the mapping for this implementation
JavaTypeMapping m;
if (storeMgr.getMappingManager().isSupportedMappedType(implClass.getName())) {
m = storeMgr.getMappingManager().getMapping(implClass, serialised, embedded, mmd.getFullFieldName());
} else {
try {
DatastoreClass dc = storeMgr.getDatastoreClass(implClass.getName(), clr);
m = dc.getIdMapping();
} catch (NoTableManagedException ex) {
// TODO Localise this message
throw new NucleusUserException("Cannot define columns for " + mmd.getFullFieldName() + " due to " + ex.getMessage(), ex);
}
}
ColumnMetaData[] columnMetaDataForType = null;
if (columnMetaData != null && columnMetaData.length > 0) {
if (columnMetaData.length < colPos + m.getNumberOfDatastoreMappings()) {
throw new NucleusUserException(Localiser.msg("020186", mmd.getFullFieldName(), "" + columnMetaData.length, "" + (colPos + m.getNumberOfDatastoreMappings())));
}
columnMetaDataForType = new ColumnMetaData[m.getNumberOfDatastoreMappings()];
System.arraycopy(columnMetaData, colPos, columnMetaDataForType, 0, columnMetaDataForType.length);
colPos += columnMetaDataForType.length;
}
// Create the FK column(s) for this implementation
ColumnCreator.createColumnsForField(implClass, this, table, storeMgr, mmd, pk, nullable, serialised, embedded, fieldRole, columnMetaDataForType, clr, true, null);
if (NucleusLogger.DATASTORE.isInfoEnabled()) {
NucleusLogger.DATASTORE.info(Localiser.msg("020188", implClass, mmd.getName()));
}
}
}
}
Aggregations