use of org.datanucleus.store.rdbms.table.DatastoreClass in project datanucleus-rdbms by datanucleus.
the class OracleClobRDBMSMapping method updateClobColumn.
/**
* Convenience method to update the contents of a CLOB column.
* Oracle requires that a CLOB is initialised with EMPTY_CLOB() and then you retrieve
* the column and update its CLOB value. Performs a statement
* <pre>
* SELECT {clobColumn} FROM TABLE WHERE ID=? FOR UPDATE
* </pre>
* and then updates the Clob value returned.
* @param op ObjectProvider of the object
* @param table Table storing the CLOB column
* @param mapping Datastore mapping for the CLOB column
* @param value The value to store in the CLOB
* @throws NucleusObjectNotFoundException Thrown if an object is not found
* @throws NucleusDataStoreException Thrown if an error occurs in datastore communication
*/
@SuppressWarnings("deprecation")
public static void updateClobColumn(ObjectProvider op, Table table, DatastoreMapping mapping, String value) {
ExecutionContext ec = op.getExecutionContext();
RDBMSStoreManager storeMgr = table.getStoreManager();
// Don't support join tables yet
DatastoreClass classTable = (DatastoreClass) table;
SQLExpressionFactory exprFactory = storeMgr.getSQLExpressionFactory();
// Generate "SELECT {clobColumn} FROM TABLE WHERE ID=? FOR UPDATE" statement
SelectStatement sqlStmt = new SelectStatement(storeMgr, table, null, null);
sqlStmt.setClassLoaderResolver(ec.getClassLoaderResolver());
sqlStmt.addExtension(SQLStatement.EXTENSION_LOCK_FOR_UPDATE, true);
SQLTable blobSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(sqlStmt, sqlStmt.getPrimaryTable(), mapping.getJavaTypeMapping());
sqlStmt.select(blobSqlTbl, mapping.getColumn(), null);
StatementClassMapping mappingDefinition = new StatementClassMapping();
AbstractClassMetaData cmd = op.getClassMetaData();
int inputParamNum = 1;
if (cmd.getIdentityType() == IdentityType.DATASTORE) {
// Datastore identity value for input
JavaTypeMapping datastoreIdMapping = classTable.getSurrogateMapping(SurrogateColumnType.DATASTORE_ID, false);
SQLExpression expr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), datastoreIdMapping);
SQLExpression val = exprFactory.newLiteralParameter(sqlStmt, datastoreIdMapping, null, "ID");
sqlStmt.whereAnd(expr.eq(val), true);
StatementMappingIndex datastoreIdx = mappingDefinition.getMappingForMemberPosition(SurrogateColumnType.DATASTORE_ID.getFieldNumber());
if (datastoreIdx == null) {
datastoreIdx = new StatementMappingIndex(datastoreIdMapping);
mappingDefinition.addMappingForMember(SurrogateColumnType.DATASTORE_ID.getFieldNumber(), datastoreIdx);
}
datastoreIdx.addParameterOccurrence(new int[] { inputParamNum });
} else if (cmd.getIdentityType() == IdentityType.APPLICATION) {
// Application identity value(s) for input
int[] pkNums = cmd.getPKMemberPositions();
for (int i = 0; i < pkNums.length; i++) {
AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(pkNums[i]);
JavaTypeMapping pkMapping = classTable.getMemberMapping(mmd);
SQLExpression expr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), pkMapping);
SQLExpression val = exprFactory.newLiteralParameter(sqlStmt, pkMapping, null, "PK" + i);
sqlStmt.whereAnd(expr.eq(val), true);
StatementMappingIndex pkIdx = mappingDefinition.getMappingForMemberPosition(pkNums[i]);
if (pkIdx == null) {
pkIdx = new StatementMappingIndex(pkMapping);
mappingDefinition.addMappingForMember(pkNums[i], pkIdx);
}
int[] inputParams = new int[pkMapping.getNumberOfDatastoreMappings()];
for (int j = 0; j < pkMapping.getNumberOfDatastoreMappings(); j++) {
inputParams[j] = inputParamNum++;
}
pkIdx.addParameterOccurrence(inputParams);
}
}
String textStmt = sqlStmt.getSQLText().toSQL();
if (op.isEmbedded()) {
// This mapping is embedded, so navigate back to the real owner since that is the "id" in the table
ObjectProvider[] embeddedOwners = ec.getOwnersForEmbeddedObjectProvider(op);
if (embeddedOwners != null) {
// Just use the first owner
// TODO Should check if the owner is stored in this table
op = embeddedOwners[0];
}
}
try {
ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec);
SQLController sqlControl = storeMgr.getSQLController();
try {
PreparedStatement ps = sqlControl.getStatementForQuery(mconn, textStmt);
try {
// Provide the primary key field(s) to the JDBC statement
if (cmd.getIdentityType() == IdentityType.DATASTORE) {
StatementMappingIndex datastoreIdx = mappingDefinition.getMappingForMemberPosition(SurrogateColumnType.DATASTORE_ID.getFieldNumber());
for (int i = 0; i < datastoreIdx.getNumberOfParameterOccurrences(); i++) {
classTable.getSurrogateMapping(SurrogateColumnType.DATASTORE_ID, false).setObject(ec, ps, datastoreIdx.getParameterPositionsForOccurrence(i), op.getInternalObjectId());
}
} else if (cmd.getIdentityType() == IdentityType.APPLICATION) {
op.provideFields(cmd.getPKMemberPositions(), new ParameterSetter(op, ps, mappingDefinition));
}
ResultSet rs = sqlControl.executeStatementQuery(ec, mconn, textStmt, ps);
try {
if (!rs.next()) {
throw new NucleusObjectNotFoundException("No such database row", op.getInternalObjectId());
}
DatastoreAdapter dba = storeMgr.getDatastoreAdapter();
int jdbcMajorVersion = dba.getDriverMajorVersion();
if (dba.getDatastoreDriverName().equalsIgnoreCase(OracleAdapter.OJDBC_DRIVER_NAME) && jdbcMajorVersion < 10) {
// Oracle JDBC drivers version 9 and below use some sh*tty Oracle-specific CLOB type
// we have to cast to that, face west, pray whilst saying ommmmmmmmmmm
oracle.sql.CLOB clob = (oracle.sql.CLOB) rs.getClob(1);
if (clob != null) {
// Deprecated but what can you do
clob.putString(1, value);
}
} else {
// Oracle JDBC drivers 10 and above supposedly use the JDBC standard class for Clobs
java.sql.Clob clob = rs.getClob(1);
if (clob != null) {
clob.setString(1, value);
}
}
} finally {
rs.close();
}
} finally {
sqlControl.closeStatement(mconn, ps);
}
} finally {
mconn.release();
}
} catch (SQLException e) {
throw new NucleusDataStoreException("Update of CLOB value failed: " + textStmt, e);
}
}
use of org.datanucleus.store.rdbms.table.DatastoreClass in project datanucleus-rdbms by datanucleus.
the class MappingHelper method getObjectForApplicationIdentity.
/**
* Get the object instance for a class using application identity
* @param ec ExecutionContext
* @param mapping The mapping in which this is returned
* @param rs the ResultSet
* @param resultIndexes indexes in the result set to retrieve
* @param cmd the AbstractClassMetaData
* @return the id
*/
public static Object getObjectForApplicationIdentity(final ExecutionContext ec, JavaTypeMapping mapping, final ResultSet rs, int[] resultIndexes, AbstractClassMetaData cmd) {
ClassLoaderResolver clr = ec.getClassLoaderResolver();
// Abstract class
if (((ClassMetaData) cmd).isAbstract() && cmd.getObjectidClass() != null) {
return getObjectForAbstractClass(ec, mapping, rs, resultIndexes, cmd);
}
int totalFieldCount = cmd.getNoOfManagedMembers() + cmd.getNoOfInheritedManagedMembers();
final StatementMappingIndex[] statementExpressionIndex = new StatementMappingIndex[totalFieldCount];
int paramIndex = 0;
DatastoreClass datastoreClass = mapping.getStoreManager().getDatastoreClass(cmd.getFullClassName(), clr);
final int[] pkFieldNumbers = cmd.getPKMemberPositions();
for (int i = 0; i < pkFieldNumbers.length; ++i) {
AbstractMemberMetaData fmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(pkFieldNumbers[i]);
JavaTypeMapping m = datastoreClass.getMemberMapping(fmd);
statementExpressionIndex[fmd.getAbsoluteFieldNumber()] = new StatementMappingIndex(m);
int[] expressionsIndex = new int[m.getNumberOfDatastoreMappings()];
for (int j = 0; j < expressionsIndex.length; j++) {
expressionsIndex[j] = resultIndexes[paramIndex++];
}
statementExpressionIndex[fmd.getAbsoluteFieldNumber()].setColumnPositions(expressionsIndex);
}
final StatementClassMapping resultMappings = new StatementClassMapping();
for (int i = 0; i < pkFieldNumbers.length; i++) {
resultMappings.addMappingForMember(pkFieldNumbers[i], statementExpressionIndex[pkFieldNumbers[i]]);
}
// TODO Use any other (non-PK) param values
final FieldManager resultsFM = new ResultSetGetter(ec, rs, resultMappings, cmd);
Object id = IdentityUtils.getApplicationIdentityForResultSetRow(ec, cmd, null, false, resultsFM);
Class type = ec.getClassLoaderResolver().classForName(cmd.getFullClassName());
return ec.findObject(id, new FieldValues() {
public void fetchFields(ObjectProvider sm) {
sm.replaceFields(pkFieldNumbers, resultsFM);
}
public void fetchNonLoadedFields(ObjectProvider sm) {
sm.replaceNonLoadedFields(pkFieldNumbers, resultsFM);
}
public FetchPlan getFetchPlanForLoading() {
return ec.getFetchPlan();
}
}, type, false, true);
}
use of org.datanucleus.store.rdbms.table.DatastoreClass in project datanucleus-rdbms by datanucleus.
the class QueryToSQLMapper method bindVariable.
/**
* Method to bind the specified unbound variable (as cross join) on the assumption that the type is a persistable class.
* @param expr Unbound expression
* @param type The type to bind as
*/
public SQLExpression bindVariable(UnboundExpression expr, Class type) {
String varName = expr.getVariableName();
Symbol varSym = compilation.getSymbolTable().getSymbol(varName);
if (varSym.getValueType() == null) {
varSym.setValueType(type);
}
AbstractClassMetaData cmd = ec.getMetaDataManager().getMetaDataForClass(type, clr);
if (cmd != null) {
// Variable is persistent type, so add cross join (may need changing later on in compilation)
DatastoreClass varTable = storeMgr.getDatastoreClass(varSym.getValueType().getName(), clr);
SQLTable varSqlTbl = stmt.join(JoinType.CROSS_JOIN, null, null, null, varTable, "VAR_" + varName, null, null, null, null, true, null);
SQLTableMapping varSqlTblMapping = new SQLTableMapping(varSqlTbl, cmd, varTable.getIdMapping());
setSQLTableMappingForAlias(varName, varSqlTblMapping);
return exprFactory.newExpression(stmt, varSqlTbl, varTable.getIdMapping());
}
return null;
}
use of org.datanucleus.store.rdbms.table.DatastoreClass in project datanucleus-rdbms by datanucleus.
the class QueryToSQLMapper method processPrimaryExpression.
/* (non-Javadoc)
* @see org.datanucleus.query.evaluator.AbstractExpressionEvaluator#processPrimaryExpression(org.datanucleus.query.expression.PrimaryExpression)
*/
protected Object processPrimaryExpression(PrimaryExpression expr) {
SQLExpression sqlExpr = null;
if (expr.getLeft() != null) {
if (expr.getLeft() instanceof DyadicExpression && expr.getLeft().getOperator() == Expression.OP_CAST) {
String exprCastName = null;
if (expr.getLeft().getLeft() instanceof PrimaryExpression) {
exprCastName = "CAST_" + ((PrimaryExpression) expr.getLeft().getLeft()).getId();
} else if (expr.getLeft().getLeft() instanceof VariableExpression) {
exprCastName = "CAST_" + ((VariableExpression) expr.getLeft().getLeft()).getId();
} else if (expr.getLeft().getLeft() instanceof InvokeExpression) {
exprCastName = "CAST_" + expr.getLeft().getLeft();
} else {
throw new NucleusException("Don't currently support cast of " + expr.getLeft().getLeft());
}
expr.getLeft().getLeft().evaluate(this);
sqlExpr = stack.pop();
JavaTypeMapping mapping = sqlExpr.getJavaTypeMapping();
if (mapping instanceof EmbeddedMapping) {
// Cast of an embedded field, so use same table
// Extract what we are casting it to
Literal castLitExpr = (Literal) expr.getLeft().getRight();
Class castType = resolveClass((String) castLitExpr.getLiteral());
AbstractClassMetaData castCmd = ec.getMetaDataManager().getMetaDataForClass(castType, clr);
JavaTypeMapping discMapping = ((EmbeddedMapping) mapping).getDiscriminatorMapping();
if (discMapping != null) {
// Should have a discriminator always when casting this
SQLExpression discExpr = exprFactory.newExpression(stmt, sqlExpr.getSQLTable(), discMapping);
Object discVal = castCmd.getDiscriminatorValue();
SQLExpression discValExpr = exprFactory.newLiteral(stmt, discMapping, discVal);
BooleanExpression discRestrictExpr = discExpr.eq(discValExpr);
Iterator<String> subclassIter = storeMgr.getSubClassesForClass(castType.getName(), true, clr).iterator();
while (subclassIter.hasNext()) {
String subclassName = subclassIter.next();
AbstractClassMetaData subtypeCmd = storeMgr.getMetaDataManager().getMetaDataForClass(subclassName, clr);
discVal = subtypeCmd.getDiscriminatorValue();
discValExpr = exprFactory.newLiteral(stmt, discMapping, discVal);
BooleanExpression subtypeExpr = discExpr.eq(discValExpr);
discRestrictExpr = discRestrictExpr.ior(subtypeExpr);
}
stmt.whereAnd(discRestrictExpr, true);
}
SQLTableMapping tblMapping = new SQLTableMapping(sqlExpr.getSQLTable(), castCmd, sqlExpr.getJavaTypeMapping());
setSQLTableMappingForAlias(exprCastName, tblMapping);
SQLTableMapping sqlMapping = getSQLTableMappingForPrimaryExpression(stmt, exprCastName, expr, Boolean.FALSE);
if (sqlMapping == null) {
throw new NucleusException("PrimaryExpression " + expr + " is not yet supported");
}
sqlExpr = exprFactory.newExpression(stmt, sqlMapping.table, sqlMapping.mapping);
stack.push(sqlExpr);
return sqlExpr;
}
// Evaluate the cast
expr.getLeft().evaluate(this);
sqlExpr = stack.pop();
// Extract what we are casting it to
Literal castLitExpr = (Literal) expr.getLeft().getRight();
AbstractClassMetaData castCmd = ec.getMetaDataManager().getMetaDataForClass(resolveClass((String) castLitExpr.getLiteral()), clr);
SQLTableMapping tblMapping = new SQLTableMapping(sqlExpr.getSQLTable(), castCmd, sqlExpr.getJavaTypeMapping());
setSQLTableMappingForAlias(exprCastName, tblMapping);
SQLTableMapping sqlMapping = getSQLTableMappingForPrimaryExpression(stmt, exprCastName, expr, Boolean.FALSE);
if (sqlMapping == null) {
throw new NucleusException("PrimaryExpression " + expr + " is not yet supported");
}
sqlExpr = exprFactory.newExpression(stmt, sqlMapping.table, sqlMapping.mapping);
stack.push(sqlExpr);
return sqlExpr;
} else if (expr.getLeft() instanceof ParameterExpression) {
// "{paramExpr}.field[.field[.field]]"
// Need parameter values to process this
setNotPrecompilable();
ParameterExpression paramExpr = (ParameterExpression) expr.getLeft();
Symbol paramSym = compilation.getSymbolTable().getSymbol(paramExpr.getId());
if (paramSym.getValueType() != null && paramSym.getValueType().isArray()) {
// Special case : array "methods" (particularly "length")
String first = expr.getTuples().get(0);
processParameterExpression(paramExpr, true);
SQLExpression paramSqlExpr = stack.pop();
sqlExpr = exprFactory.invokeMethod(stmt, "ARRAY", first, paramSqlExpr, null);
stack.push(sqlExpr);
return sqlExpr;
}
// Create Literal for the parameter (since we need to perform operations on it)
processParameterExpression(paramExpr, true);
SQLExpression paramSqlExpr = stack.pop();
SQLLiteral lit = (SQLLiteral) paramSqlExpr;
Object paramValue = lit.getValue();
List<String> tuples = expr.getTuples();
Iterator<String> tuplesIter = tuples.iterator();
Object objValue = paramValue;
while (tuplesIter.hasNext()) {
String fieldName = tuplesIter.next();
if (objValue == null) {
NucleusLogger.QUERY.warn(">> Compilation of " + expr + " : need to direct through field \"" + fieldName + "\" on null value, hence not compilable!");
// Null value, and we have further path to navigate TODO Handle this "NPE"
break;
}
objValue = getValueForObjectField(objValue, fieldName);
// Using literal value of parameter, so cannot precompile it
setNotPrecompilable();
}
if (objValue == null) {
sqlExpr = exprFactory.newLiteral(stmt, null, null);
stack.push(sqlExpr);
return sqlExpr;
}
JavaTypeMapping m = exprFactory.getMappingForType(objValue.getClass(), false);
sqlExpr = exprFactory.newLiteral(stmt, m, objValue);
stack.push(sqlExpr);
return sqlExpr;
} else if (expr.getLeft() instanceof VariableExpression) {
// "{varExpr}.field[.field[.field]]"
VariableExpression varExpr = (VariableExpression) expr.getLeft();
processVariableExpression(varExpr);
SQLExpression varSqlExpr = stack.pop();
if (varSqlExpr instanceof UnboundExpression) {
// Bind as CROSS JOIN for now
processUnboundExpression((UnboundExpression) varSqlExpr);
varSqlExpr = stack.pop();
}
Class varType = clr.classForName(varSqlExpr.getJavaTypeMapping().getType());
if (varSqlExpr.getSQLStatement() == stmt.getParentStatement()) {
// Use parent mapper to get the mapping for this field since it has the table
SQLTableMapping sqlMapping = parentMapper.getSQLTableMappingForPrimaryExpression(stmt, null, expr, Boolean.FALSE);
if (sqlMapping == null) {
throw new NucleusException("PrimaryExpression " + expr.getId() + " is not yet supported");
}
// TODO Cater for the table required to join to not being the primary table of the outer query
// This should check on
// getDatastoreAdapter().supportsOption(RDBMSAdapter.ACCESS_PARENTQUERY_IN_SUBQUERY))
sqlExpr = exprFactory.newExpression(varSqlExpr.getSQLStatement(), sqlMapping.table, sqlMapping.mapping);
stack.push(sqlExpr);
return sqlExpr;
}
SQLTableMapping varTblMapping = getSQLTableMappingForAlias(varExpr.getId());
if (varTblMapping == null) {
throw new NucleusUserException("Variable " + varExpr.getId() + " is not yet bound, so cannot get field " + expr.getId());
}
if (varTblMapping.cmd == null) {
throw new NucleusUserException("Variable " + varExpr.getId() + " of type " + varType.getName() + " cannot evaluate " + expr.getId());
}
SQLTableMapping sqlMapping = getSQLTableMappingForPrimaryExpression(varSqlExpr.getSQLStatement(), varExpr.getId(), expr, Boolean.FALSE);
sqlExpr = exprFactory.newExpression(sqlMapping.table.getSQLStatement(), sqlMapping.table, sqlMapping.mapping);
stack.push(sqlExpr);
return sqlExpr;
} else if (expr.getLeft() instanceof InvokeExpression) {
InvokeExpression invokeExpr = (InvokeExpression) expr.getLeft();
SQLExpression invokedSqlExpr = getInvokedSqlExpressionForInvokeExpression(invokeExpr);
processInvokeExpression(invokeExpr, invokedSqlExpr);
SQLExpression invokeSqlExpr = stack.pop();
Table tbl = invokeSqlExpr.getSQLTable().getTable();
if (expr.getTuples().size() > 1) {
throw new NucleusUserException("Dont currently support evaluating " + expr.getId() + " on " + invokeSqlExpr);
}
SQLTable invokeSqlTbl = invokeSqlExpr.getSQLTable();
if (invokedSqlExpr.getJavaTypeMapping() instanceof OptionalMapping && invokeExpr.getOperation().equals("get") && expr.getTuples().size() == 1) {
OptionalMapping opMapping = (OptionalMapping) invokedSqlExpr.getJavaTypeMapping();
if (opMapping.getWrappedMapping() instanceof PersistableMapping) {
// Special case of Optional.get().{field}, so we need to join to the related table
AbstractMemberMetaData mmd = invokedSqlExpr.getJavaTypeMapping().getMemberMetaData();
AbstractClassMetaData otherCmd = ec.getMetaDataManager().getMetaDataForClass(mmd.getCollection().getElementType(), clr);
Table otherTbl = storeMgr.getDatastoreClass(otherCmd.getFullClassName(), clr);
// Optional type so do LEFT OUTER JOIN since if it is null then we would eliminate all other results
invokeSqlTbl = stmt.join(JoinType.LEFT_OUTER_JOIN, invokeSqlExpr.getSQLTable(), opMapping.getWrappedMapping(), otherTbl, null, otherTbl.getIdMapping(), null, null, true);
tbl = invokeSqlTbl.getTable();
}
}
if (tbl instanceof DatastoreClass) {
// Table of a class, so assume to have field in the table of the class
// TODO Allow joins to superclasses if required
JavaTypeMapping mapping = ((DatastoreClass) tbl).getMemberMapping(expr.getId());
if (mapping == null) {
throw new NucleusUserException("Dont currently support evaluating " + expr.getId() + " on " + invokeSqlExpr + ". The field " + expr.getId() + " doesnt exist in table " + tbl);
}
sqlExpr = exprFactory.newExpression(stmt, invokeSqlTbl, mapping);
stack.push(sqlExpr);
return sqlExpr;
} else if (tbl instanceof JoinTable) {
if (invokeSqlExpr.getJavaTypeMapping() instanceof EmbeddedMapping) {
// Table containing an embedded element/key/value so assume we have a column in the join table
EmbeddedMapping embMapping = (EmbeddedMapping) invokeSqlExpr.getJavaTypeMapping();
JavaTypeMapping mapping = embMapping.getJavaTypeMapping(expr.getId());
if (mapping == null) {
throw new NucleusUserException("Dont currently support evaluating " + expr.getId() + " on " + invokeSqlExpr + ". The field " + expr.getId() + " doesnt exist in table " + tbl);
}
sqlExpr = exprFactory.newExpression(stmt, invokeSqlTbl, mapping);
stack.push(sqlExpr);
return sqlExpr;
}
}
throw new NucleusUserException("Dont currently support evaluating " + expr.getId() + " on " + invokeSqlExpr + " with invoke having table of " + tbl);
} else {
throw new NucleusUserException("Dont currently support PrimaryExpression with 'left' of " + expr.getLeft());
}
}
// Real primary expression ("field.field", "alias.field.field" etc)
SQLTableMapping sqlMapping = getSQLTableMappingForPrimaryExpression(stmt, null, expr, null);
if (sqlMapping == null) {
throw new NucleusException("PrimaryExpression " + expr.getId() + " is not yet supported");
}
sqlExpr = exprFactory.newExpression(stmt, sqlMapping.table, sqlMapping.mapping);
if (sqlMapping.mmd != null && sqlExpr instanceof MapExpression) {
// This sqlMapping is for something joined in a FROM clause, so set the alias on the returned MapExpression to avoid doing the same joins
String alias = getAliasForSQLTableMapping(sqlMapping);
if (alias == null && parentMapper != null) {
alias = parentMapper.getAliasForSQLTableMapping(sqlMapping);
}
((MapExpression) sqlExpr).setAliasForMapTable(alias);
}
stack.push(sqlExpr);
return sqlExpr;
}
use of org.datanucleus.store.rdbms.table.DatastoreClass in project datanucleus-rdbms by datanucleus.
the class SQLQuery method getResultObjectFactoryForCandidateClass.
/**
* Method to generate a ResultObjectFactory for converting rows of the provided ResultSet into instances of the candidate class.
* Populates "stmtMappings".
* @param rs The ResultSet
* @return The ResultObjectFactory
* @throws SQLException Thrown if an error occurs processing the ResultSet
*/
protected ResultObjectFactory getResultObjectFactoryForCandidateClass(ResultSet rs) throws SQLException {
ClassLoaderResolver clr = ec.getClassLoaderResolver();
RDBMSStoreManager storeMgr = (RDBMSStoreManager) getStoreManager();
DatastoreAdapter dba = storeMgr.getDatastoreAdapter();
// 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 of field numbers keyed by the column name
Map columnFieldNumberMap = new HashMap();
stmtMappings = new StatementMappingIndex[fieldCount];
DatastoreClass tbl = storeMgr.getDatastoreClass(candidateClass.getName(), clr);
for (int fieldNumber = 0; fieldNumber < fieldCount; ++fieldNumber) {
AbstractMemberMetaData mmd = candidateCmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
String fieldName = mmd.getName();
Class fieldType = mmd.getType();
JavaTypeMapping m = null;
if (mmd.getPersistenceModifier() != FieldPersistenceModifier.NONE) {
if (tbl != null) {
// Get the field mapping from the candidate table
m = tbl.getMemberMapping(mmd);
} 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 (mmd.getColumnMetaData() != null && mmd.getColumnMetaData().length > 0) {
for (int colNum = 0; colNum < mmd.getColumnMetaData().length; colNum++) {
columnName = mmd.getColumnMetaData()[colNum].getName();
columnFieldNumberMap.put(columnName, Integer.valueOf(fieldNumber));
}
} else {
columnName = storeMgr.getIdentifierFactory().newColumnIdentifier(fieldName, ec.getNucleusContext().getTypeManager().isDefaultEmbeddedType(fieldType), FieldRole.ROLE_NONE, false).getName();
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);
if (table == null) {
AbstractClassMetaData[] cmds = storeMgr.getClassesManagingTableForClass(candidateCmd, clr);
if (cmds != null && cmds.length == 1) {
table = storeMgr.getDatastoreClass(cmds[0].getFullClassName(), clr);
} else {
throw new NucleusUserException("SQL query specified with class " + candidateClass.getName() + " but this doesn't have its own table, or is mapped to multiple tables. Unsupported");
}
}
PersistableMapping idMapping = (PersistableMapping) table.getIdMapping();
String[] idColNames = new String[idMapping.getNumberOfDatastoreMappings()];
for (int i = 0; i < idMapping.getNumberOfDatastoreMappings(); i++) {
idColNames[i] = idMapping.getDatastoreMapping(i).getColumn().getIdentifier().toString();
}
// Generate discriminator information for later checking it is present
JavaTypeMapping discrimMapping = table.getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, false);
String discrimColName = discrimMapping != null ? discrimMapping.getDatastoreMapping(0).getColumn().getIdentifier().toString() : null;
// Generate version information for later checking it is present
JavaTypeMapping versionMapping = table.getSurrogateMapping(SurrogateColumnType.VERSION, false);
String versionColName = versionMapping != null ? versionMapping.getDatastoreMapping(0).getColumn().getIdentifier().toString() : null;
// Go through the fields of the ResultSet and map to the required fields in the candidate
ResultSetMetaData rsmd = rs.getMetaData();
// TODO We put nothing in this, so what is it for?!
HashSet remainingColumnNames = new HashSet(columnFieldNumberMap.size());
int colCount = rsmd.getColumnCount();
int[] datastoreIndex = null;
int[] versionIndex = null;
int[] discrimIndex = 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 (discrimColName != null && colName.equals(discrimColName)) {
// Identify the location of the discriminator column
discrimIndex = new int[1];
discrimIndex[0] = colNum;
}
if (versionColName != null && colName.equals(versionColName)) {
// Identify the location of the version column
versionIndex = new int[1];
versionIndex[0] = colNum;
}
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;
}
}
}
// 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];
}
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.getSurrogateMapping(SurrogateColumnType.DATASTORE_ID, false));
datastoreMappingIdx.setColumnPositions(datastoreIndex);
mappingDefinition.addMappingForMember(SurrogateColumnType.DATASTORE_ID.getFieldNumber(), datastoreMappingIdx);
}
if (discrimIndex != null) {
StatementMappingIndex discrimMappingIdx = new StatementMappingIndex(table.getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, true));
discrimMappingIdx.setColumnPositions(discrimIndex);
mappingDefinition.addMappingForMember(SurrogateColumnType.DISCRIMINATOR.getFieldNumber(), discrimMappingIdx);
}
if (versionIndex != null) {
StatementMappingIndex versionMappingIdx = new StatementMappingIndex(table.getSurrogateMapping(SurrogateColumnType.VERSION, true));
versionMappingIdx.setColumnPositions(versionIndex);
mappingDefinition.addMappingForMember(SurrogateColumnType.VERSION.getFieldNumber(), versionMappingIdx);
}
return new PersistentClassROF(ec, rs, ignoreCache, mappingDefinition, candidateCmd, getCandidateClass());
}
Aggregations