// Create an index listing for ALL (fetchable) fields in the result class.
final AbstractClassMetaData candidateCmd = ec.getMetaDataManager().getMetaDataForClass(candidateClass, clr);
int fieldCount = candidateCmd.getNoOfManagedMembers() + candidateCmd.getNoOfInheritedManagedMembers();
Map columnFieldNumberMap = new HashMap(); // Map of field numbers keyed by the column name
stmtMappings = new StatementMappingIndex[fieldCount];
DatastoreClass tbl = storeMgr.getDatastoreClass(candidateClass.getName(), clr);
for (int fieldNumber = 0; fieldNumber < fieldCount; ++fieldNumber)
{
AbstractMemberMetaData fmd = candidateCmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
String fieldName = fmd.getName();
Class fieldType = fmd.getType();
JavaTypeMapping m = null;
if (fmd.getPersistenceModifier() != FieldPersistenceModifier.NONE)
{
if (tbl != null)
{
// Get the field mapping from the candidate table
m = tbl.getMemberMapping(fmd);
}
else
{
// Fall back to generating a mapping for this type - does this ever happen?
m = storeMgr.getMappingManager().getMappingWithDatastoreMapping(
fieldType, false, false, clr);
}
if (m.includeInFetchStatement())
{
// Set mapping for this field since it can potentially be returned from a fetch
String columnName = null;
if (fmd.getColumnMetaData() != null && fmd.getColumnMetaData().length > 0)
{
for (int colNum = 0;colNum<fmd.getColumnMetaData().length;colNum++)
{
columnName = fmd.getColumnMetaData()[colNum].getName();
columnFieldNumberMap.put(columnName, Integer.valueOf(fieldNumber));
}
}
else
{
columnName = storeMgr.getIdentifierFactory().newDatastoreFieldIdentifier(
fieldName, ec.getNucleusContext().getTypeManager().isDefaultEmbeddedType(fieldType),
FieldRole.ROLE_NONE).getIdentifierName();
columnFieldNumberMap.put(columnName, Integer.valueOf(fieldNumber));
}
}
else
{
// Don't put anything in this position (field has no column in the result set)
}
}
else
{
// Don't put anything in this position (field has no column in the result set)
}
stmtMappings[fieldNumber] = new StatementMappingIndex(m);
}
if (columnFieldNumberMap.size() == 0)
{
// None of the fields in the class have columns in the datastore table!
throw new NucleusUserException(LOCALISER.msg("059030", candidateClass.getName())).setFatal();
}
// Generate id column field information for later checking the id is present
DatastoreClass table = storeMgr.getDatastoreClass(candidateClass.getName(), clr);
PersistableMapping idMapping = (PersistableMapping)table.getIdMapping();
String[] idColNames = new String[idMapping.getNumberOfDatastoreMappings()];
boolean[] idColMissing = new boolean[idMapping.getNumberOfDatastoreMappings()];
for (int i=0;i<idMapping.getNumberOfDatastoreMappings();i++)
{
DatastoreMapping m = idMapping.getDatastoreMapping(i);
idColNames[i] = m.getDatastoreField().getIdentifier().toString();
idColMissing[i] = true;
}
// Generate discriminator/version information for later checking they are present
String discriminatorColName = table.getDiscriminatorMapping(false) != null ?
table.getDiscriminatorMapping(false).getDatastoreMapping(0).getDatastoreField().getIdentifier().toString() : null;
String versionColName = table.getVersionMapping(false) != null ?
table.getVersionMapping(false).getDatastoreMapping(0).getDatastoreField().getIdentifier().toString() : null;
boolean discrimMissing = (discriminatorColName != null);
boolean versionMissing = true;
if (versionColName == null)
{
versionMissing = false;
}
// Go through the fields of the ResultSet and map to the required fields in the candidate
// Note that we check the existence of the columns again here even though they were checked at compilation
// TODO This could be removed from here since its now done at compile time
ResultSetMetaData rsmd = rs.getMetaData();
HashSet remainingColumnNames = new HashSet(columnFieldNumberMap.size());
int colCount = rsmd.getColumnCount();
int[] datastoreIndex = null;
int[] versionIndex = null;
int[] matchedFieldNumbers = new int[colCount];
int fieldNumberPosition = 0;
for (int colNum=1; colNum<=colCount; ++colNum)
{
String colName = rsmd.getColumnName(colNum);
// Find the field for this column
int fieldNumber = -1;
Integer fieldNum = (Integer)columnFieldNumberMap.get(colName);
if (fieldNum == null)
{
// Try column name in lowercase
fieldNum = (Integer)columnFieldNumberMap.get(colName.toLowerCase());
if (fieldNum == null)
{
// Try column name in UPPERCASE
fieldNum = (Integer)columnFieldNumberMap.get(colName.toUpperCase());
}
}
if (fieldNum != null)
{
fieldNumber = fieldNum.intValue();
}
if (fieldNumber >= 0)
{
int[] exprIndices = null;
if (stmtMappings[fieldNumber].getColumnPositions() != null)
{
exprIndices = new int[stmtMappings[fieldNumber].getColumnPositions().length+1];
for (int i=0;i<stmtMappings[fieldNumber].getColumnPositions().length;i++)
{
exprIndices[i] = stmtMappings[fieldNumber].getColumnPositions()[i];
}
exprIndices[exprIndices.length-1] = colNum;
}
else
{
exprIndices = new int[] {colNum};
}
stmtMappings[fieldNumber].setColumnPositions(exprIndices);
remainingColumnNames.remove(colName);
matchedFieldNumbers[fieldNumberPosition++] = fieldNumber;
}
if (versionColName != null && colName.equals(versionColName))
{
// Identify the location of the version column
versionIndex = new int[1];
versionIndex[0] = colNum;
versionMissing = false;
}
if (candidateCmd.getIdentityType() == IdentityType.DATASTORE)
{
// Check for existence of id column, allowing for any RDBMS using quoted identifiers
if (columnNamesAreTheSame(dba, idColNames[0], colName))
{
datastoreIndex = new int[1];
datastoreIndex[0] = colNum;
idColMissing[0] = false;
}
}
else if (candidateCmd.getIdentityType() == IdentityType.APPLICATION)
{
for (int j=0;j<idColNames.length;j++)
{
// Check for existence of id column, allowing for any RDBMS using quoted identifiers
if (columnNamesAreTheSame(dba, idColNames[j], colName))
{
idColMissing[j] = false;
}
}
}
if (discrimMissing && columnNamesAreTheSame(dba, discriminatorColName, colName))
{
discrimMissing = false;
}
else if (versionMissing && columnNamesAreTheSame(dba, versionColName, colName))
{
versionMissing = false;
}
}
// Set the field numbers found to match what we really have
int[] fieldNumbers = new int[fieldNumberPosition];
for (int i=0;i<fieldNumberPosition;i++)
{
fieldNumbers[i] = matchedFieldNumbers[i];
}
if (discrimMissing)
{
throw new NucleusUserException(LOCALISER_RDBMS.msg("059014",
inputSQL, candidateClass.getName(), discriminatorColName));
}
if (versionMissing)
{
throw new NucleusUserException(LOCALISER_RDBMS.msg("059015",
inputSQL, candidateClass.getName(), versionColName));
}
for (int i=0;i<idColMissing.length;i++)
{
if (idColMissing[i])
{
throw new NucleusUserException(LOCALISER_RDBMS.msg("059013",
inputSQL, candidateClass.getName(), idColNames[i]));
}
}
StatementClassMapping mappingDefinition = new StatementClassMapping();
for (int i=0;i<fieldNumbers.length;i++)
{
mappingDefinition.addMappingForMember(fieldNumbers[i], stmtMappings[fieldNumbers[i]]);
}
if (datastoreIndex != null)
{
StatementMappingIndex datastoreMappingIdx = new StatementMappingIndex(table.getDatastoreObjectIdMapping());
datastoreMappingIdx.setColumnPositions(datastoreIndex);
mappingDefinition.addMappingForMember(StatementClassMapping.MEMBER_DATASTORE_ID, datastoreMappingIdx);
}
if (versionIndex != null)
{
StatementMappingIndex versionMappingIdx = new StatementMappingIndex(table.getVersionMapping(true));
versionMappingIdx.setColumnPositions(versionIndex);
mappingDefinition.addMappingForMember(StatementClassMapping.MEMBER_VERSION, versionMappingIdx);
}
return storeMgr.newResultObjectFactory(candidateCmd, mappingDefinition,