use of org.datanucleus.ClassLoaderResolver in project datanucleus-rdbms by datanucleus.
the class PersistableMapping method preDelete.
/**
* Method executed just before the owning object is deleted, allowing tidying up of any relation information.
* @param sm StateManager for the owner
*/
public void preDelete(DNStateManager sm) {
int fieldNumber = mmd.getAbsoluteFieldNumber();
ExecutionContext ec = sm.getExecutionContext();
ClassLoaderResolver clr = ec.getClassLoaderResolver();
RelationType relationType = mmd.getRelationType(clr);
AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
// Check if we should delete the related object when this object is deleted
boolean dependent = mmd.isDependent();
if (mmd.isCascadeRemoveOrphans()) {
// JPA allows "orphan removal" to define deletion of the other side
dependent = true;
}
if (!dependent) {
if (relationType == RelationType.ONE_TO_ONE_UNI) {
// Special case of FK this side and unidirectional, just return
return;
}
// TODO If we have the FK and not dependent then should avoid the load on the related object
}
if (!sm.isFieldLoaded(fieldNumber)) {
// Load the field if we need its value
try {
// First try from stored FK value, otherwise load from database
if (!sm.loadStoredField(fieldNumber)) {
sm.loadField(fieldNumber);
}
} catch (NucleusObjectNotFoundException onfe) {
// Already deleted so just return
return;
}
}
Object pc = sm.provideField(fieldNumber);
pc = mmd.isSingleCollection() ? SCOUtils.singleCollectionValue(getStoreManager().getNucleusContext().getTypeManager(), pc) : pc;
if (pc == null) {
// Null value so nothing to do
return;
}
// N-1 Uni, so delete join table entry
if (relationType == RelationType.MANY_TO_ONE_UNI) {
// Update join table entry
PersistableRelationStore store = (PersistableRelationStore) storeMgr.getBackingStoreForField(clr, mmd, mmd.getType());
store.remove(sm);
}
// Check if the field has a FK defined TODO Cater for more than 1 related field
boolean hasFK = false;
if (!dependent) {
// Not dependent, so check if the datastore has a FK and will take care of it for us
if (mmd.getForeignKeyMetaData() != null) {
hasFK = true;
}
if (RelationType.isBidirectional(relationType) && relatedMmds[0].getForeignKeyMetaData() != null) {
hasFK = true;
}
if (ec.getStringProperty(PropertyNames.PROPERTY_DELETION_POLICY).equals("JDO2")) {
// JDO doesn't currently take note of foreign-key
hasFK = false;
}
}
// There may be some corner cases that this code doesn't yet cater for
if (relationType == RelationType.ONE_TO_ONE_UNI || (relationType == RelationType.ONE_TO_ONE_BI && mmd.getMappedBy() == null)) {
// 1-1 with FK at this side (owner of the relation)
if (dependent) {
boolean relatedObjectDeleted = ec.getApiAdapter().isDeleted(pc);
if (isNullable() && !relatedObjectDeleted) {
// Other object not yet deleted, but the field is nullable so just null out the FK
// TODO Not doing this would cause errors in 1-1 uni relations (e.g AttachDetachTest)
// TODO Log this since it affects the resultant objects
sm.replaceFieldMakeDirty(fieldNumber, null);
storeMgr.getPersistenceHandler().updateObject(sm, new int[] { fieldNumber });
if (!relatedObjectDeleted) {
// Mark the other object for deletion since not yet tagged
ec.deleteObjectInternal(pc);
}
} else {
// Can't just delete the other object since that would cause a FK constraint violation. Do nothing - handled by DeleteRequest on other object
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.DATASTORE_PERSIST.debug(Localiser.msg("041017", StringUtils.toJVMIDString(sm.getObject()), mmd.getFullFieldName()));
}
}
} else {
// We're deleting the FK at this side so shouldn't be an issue
AbstractMemberMetaData relatedMmd = mmd.getRelatedMemberMetaDataForObject(clr, sm.getObject(), pc);
if (relatedMmd != null) {
DNStateManager otherSM = ec.findStateManager(pc);
if (otherSM != null) {
// Managed Relations : 1-1 bidir, so null out the object at the other
Object currentValue = otherSM.provideField(relatedMmd.getAbsoluteFieldNumber());
if (currentValue != null) {
if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
NucleusLogger.PERSISTENCE.debug(Localiser.msg("041019", StringUtils.toJVMIDString(pc), relatedMmd.getFullFieldName(), sm.getObjectAsPrintable()));
}
otherSM.replaceFieldMakeDirty(relatedMmd.getAbsoluteFieldNumber(), null);
if (ec.getManageRelations()) {
otherSM.getExecutionContext().getRelationshipManager(otherSM).relationChange(relatedMmd.getAbsoluteFieldNumber(), sm.getObject(), null);
}
}
}
}
}
} else if (relationType == RelationType.ONE_TO_ONE_BI && mmd.getMappedBy() != null) {
// 1-1 with FK at other side
DatastoreClass relatedTable = storeMgr.getDatastoreClass(relatedMmds[0].getClassName(), clr);
JavaTypeMapping relatedMapping = relatedTable.getMemberMapping(relatedMmds[0]);
boolean isNullable = relatedMapping.isNullable();
DNStateManager otherSM = ec.findStateManager(pc);
if (dependent) {
if (isNullable) {
// Null out the FK in the datastore using a direct update (since we are deleting)
otherSM.replaceFieldMakeDirty(relatedMmds[0].getAbsoluteFieldNumber(), null);
storeMgr.getPersistenceHandler().updateObject(otherSM, new int[] { relatedMmds[0].getAbsoluteFieldNumber() });
}
// Mark the other object for deletion
ec.deleteObjectInternal(pc);
} else if (!hasFK) {
if (isNullable()) {
Object currentRelatedValue = otherSM.provideField(relatedMmds[0].getAbsoluteFieldNumber());
if (currentRelatedValue != null) {
// Null out the FK in the datastore using a direct update (since we are deleting)
otherSM.replaceFieldMakeDirty(relatedMmds[0].getAbsoluteFieldNumber(), null);
storeMgr.getPersistenceHandler().updateObject(otherSM, new int[] { relatedMmds[0].getAbsoluteFieldNumber() });
// Managed Relations : 1-1 bidir, so null out the object at the other
if (ec.getManageRelations()) {
otherSM.getExecutionContext().getRelationshipManager(otherSM).relationChange(relatedMmds[0].getAbsoluteFieldNumber(), sm.getObject(), null);
}
}
} else {
// TODO Remove it
}
} else {
// User has a FK defined (in MetaData) so let the datastore take care of it
}
} else if (relationType == RelationType.MANY_TO_ONE_BI) {
DNStateManager otherSM = ec.findStateManager(pc);
if (relatedMmds[0].getJoinMetaData() == null) {
// N-1 with FK at this side
if (otherSM.isDeleting()) {
// Other object is being deleted too but this side has the FK so just delete this object
} else {
// Other object is not being deleted so delete it if necessary
if (dependent) {
if (isNullable()) {
// TODO Datastore nullability info can be unreliable so try to avoid this call
// Null out the FK in the datastore using a direct update (since we are deleting)
sm.replaceFieldMakeDirty(fieldNumber, null);
storeMgr.getPersistenceHandler().updateObject(sm, new int[] { fieldNumber });
}
if (ec.getApiAdapter().isDeleted(pc)) {
// Object is already tagged for deletion but we're deleting the FK so leave til flush()
} else {
// Mark the other object for deletion
ec.deleteObjectInternal(pc);
}
} else {
// Managed Relations : remove element from collection/map
if (relatedMmds[0].hasCollection()) {
// Only update the other side if not already being deleted
if (!ec.getApiAdapter().isDeleted(otherSM.getObject()) && !otherSM.isDeleting()) {
// Make sure the other object is updated in any caches
ec.markDirty(otherSM, false);
// Make sure collection field is loaded
otherSM.isLoaded(relatedMmds[0].getAbsoluteFieldNumber());
Collection otherColl = (Collection) otherSM.provideField(relatedMmds[0].getAbsoluteFieldNumber());
if (otherColl != null) {
if (ec.getManageRelations()) {
otherSM.getExecutionContext().getRelationshipManager(otherSM).relationRemove(relatedMmds[0].getAbsoluteFieldNumber(), sm.getObject());
}
if (otherColl.contains(sm.getObject())) {
// TODO Localise this message
NucleusLogger.PERSISTENCE.debug("ManagedRelationships : delete of object causes removal from collection at " + relatedMmds[0].getFullFieldName());
otherColl.remove(sm.getObject());
}
}
}
} else if (relatedMmds[0].hasMap()) {
// TODO Cater for maps, but what is the key/value pair ?
}
}
}
} else {
// N-1 with join table so no FK here so need to remove from Collection/Map first? (managed relations)
if (dependent) {
// Mark the other object for deletion
ec.deleteObjectInternal(pc);
} else {
// Managed Relations : remove element from collection/map
if (relatedMmds[0].hasCollection()) {
// Only update the other side if not already being deleted
if (!ec.getApiAdapter().isDeleted(otherSM.getObject()) && !otherSM.isDeleting()) {
// Make sure the other object is updated in any caches
ec.markDirty(otherSM, false);
// Make sure the other object has the collection loaded so does this change
otherSM.isLoaded(relatedMmds[0].getAbsoluteFieldNumber());
Collection otherColl = (Collection) otherSM.provideField(relatedMmds[0].getAbsoluteFieldNumber());
if (otherColl != null && otherColl.contains(sm.getObject())) {
// TODO Localise this
NucleusLogger.PERSISTENCE.debug("ManagedRelationships : delete of object causes removal from collection at " + relatedMmds[0].getFullFieldName());
otherColl.remove(sm.getObject());
}
}
} else if (relatedMmds[0].hasMap()) {
// TODO Cater for maps, but what is the key/value pair ?
}
}
}
} else if (relationType == RelationType.MANY_TO_ONE_UNI) {
// N-1 uni with join table
if (dependent) {
// Mark the other object for deletion
ec.deleteObjectInternal(pc);
}
} else {
// No relation so what is this field ?
}
}
use of org.datanucleus.ClassLoaderResolver in project datanucleus-rdbms by datanucleus.
the class BulkFetchExistsHandler method getStatementToBulkFetchField.
/**
* Convenience method to generate a bulk-fetch statement for the specified multi-valued field of the owning query.
* @param candidateCmd Metadata for the candidate
* @param parameters Parameters for the query
* @param mmd Metadata for the multi-valued field
* @param datastoreCompilation The datastore compilation of the query
* @param mapperOptions Any options for the query to SQL mapper
* @return The bulk-fetch statement for retrieving this multi-valued field.
*/
public IteratorStatement getStatementToBulkFetchField(AbstractClassMetaData candidateCmd, AbstractMemberMetaData mmd, Query query, Map parameters, RDBMSQueryCompilation datastoreCompilation, Set<String> mapperOptions) {
IteratorStatement iterStmt = null;
ExecutionContext ec = query.getExecutionContext();
ClassLoaderResolver clr = ec.getClassLoaderResolver();
RDBMSStoreManager storeMgr = (RDBMSStoreManager) query.getStoreManager();
Store backingStore = storeMgr.getBackingStoreForField(clr, mmd, null);
if (backingStore instanceof JoinSetStore || backingStore instanceof JoinListStore || backingStore instanceof JoinArrayStore) {
// Set/List/array using join-table : Generate an iterator query of the form
if (backingStore instanceof JoinSetStore) {
iterStmt = ((JoinSetStore) backingStore).getIteratorStatement(ec, ec.getFetchPlan(), false);
} else if (backingStore instanceof JoinListStore) {
iterStmt = ((JoinListStore) backingStore).getIteratorStatement(ec, ec.getFetchPlan(), false, -1, -1);
} else if (backingStore instanceof JoinArrayStore) {
iterStmt = ((JoinArrayStore) backingStore).getIteratorStatement(ec, ec.getFetchPlan(), false);
} else {
throw new NucleusUserException("We do not support BulkFetch using EXISTS for backingStore = " + backingStore);
}
// SELECT ELEM_TBL.COL1, ELEM_TBL.COL2, ... FROM JOIN_TBL INNER_JOIN ELEM_TBL WHERE JOIN_TBL.ELEMENT_ID = ELEM_TBL.ID
// AND EXISTS (SELECT OWNER_TBL.ID FROM OWNER_TBL WHERE (queryWhereClause) AND JOIN_TBL.OWNER_ID = OWNER_TBL.ID)
SelectStatement sqlStmt = iterStmt.getSelectStatement();
JoinTable joinTbl = (JoinTable) sqlStmt.getPrimaryTable().getTable();
JavaTypeMapping joinOwnerMapping = joinTbl.getOwnerMapping();
// Generate the EXISTS subquery (based on the JDOQL/JPQL query)
SelectStatement existsStmt = RDBMSQueryUtils.getStatementForCandidates(storeMgr, sqlStmt, candidateCmd, datastoreCompilation.getResultDefinitionForClass(), ec, query.getCandidateClass(), query.isSubclasses(), query.getResult(), null, null, null);
Set<String> options = new HashSet<>();
if (mapperOptions != null) {
options.addAll(mapperOptions);
}
options.add(QueryToSQLMapper.OPTION_SELECT_CANDIDATE_ID_ONLY);
QueryToSQLMapper sqlMapper = new QueryToSQLMapper(existsStmt, query.getCompilation(), parameters, null, null, candidateCmd, query.isSubclasses(), query.getFetchPlan(), ec, query.getParsedImports(), options, query.getExtensions());
sqlMapper.compile();
// Add EXISTS clause on iterator statement so we can restrict to just the owners in this query
// ORDER BY in EXISTS is forbidden by some RDBMS
existsStmt.setOrdering(null, null);
BooleanExpression existsExpr = new BooleanSubqueryExpression(sqlStmt, "EXISTS", existsStmt);
sqlStmt.whereAnd(existsExpr, true);
// Join to outer statement so we restrict to collection elements for the query candidates
SQLExpression joinTblOwnerExpr = sqlStmt.getRDBMSManager().getSQLExpressionFactory().newExpression(sqlStmt, sqlStmt.getPrimaryTable(), joinOwnerMapping);
SQLExpression existsOwnerExpr = sqlStmt.getRDBMSManager().getSQLExpressionFactory().newExpression(existsStmt, existsStmt.getPrimaryTable(), existsStmt.getPrimaryTable().getTable().getIdMapping());
existsStmt.whereAnd(joinTblOwnerExpr.eq(existsOwnerExpr), true);
// Select the owner candidate so we can separate the collection elements out to their owner
int[] ownerColIndexes = sqlStmt.select(joinTblOwnerExpr, null);
StatementMappingIndex ownerMapIdx = new StatementMappingIndex(existsStmt.getPrimaryTable().getTable().getIdMapping());
ownerMapIdx.setColumnPositions(ownerColIndexes);
iterStmt.setOwnerMapIndex(ownerMapIdx);
} else if (backingStore instanceof FKSetStore || backingStore instanceof FKListStore || backingStore instanceof FKArrayStore) {
if (backingStore instanceof FKSetStore) {
iterStmt = ((FKSetStore) backingStore).getIteratorStatement(ec, ec.getFetchPlan(), false);
} else if (backingStore instanceof FKListStore) {
iterStmt = ((FKListStore) backingStore).getIteratorStatement(ec, ec.getFetchPlan(), false, -1, -1);
} else if (backingStore instanceof FKArrayStore) {
iterStmt = ((FKArrayStore) backingStore).getIteratorStatement(ec, ec.getFetchPlan(), false);
} else {
throw new NucleusUserException("We do not support BulkFetch using EXISTS for backingStore = " + backingStore);
}
// Set/List/array using foreign-key : Generate an iterator query of the form
// SELECT ELEM_TBL.COL1, ELEM_TBL.COL2, ... FROM ELEM_TBL
// WHERE EXISTS (SELECT OWNER_TBL.ID FROM OWNER_TBL WHERE (queryWhereClause) AND ELEM_TBL.OWNER_ID = OWNER_TBL.ID)
SelectStatement sqlStmt = iterStmt.getSelectStatement();
// Generate the EXISTS subquery (based on the JDOQL/JPQL query)
SelectStatement existsStmt = RDBMSQueryUtils.getStatementForCandidates(storeMgr, sqlStmt, candidateCmd, datastoreCompilation.getResultDefinitionForClass(), ec, query.getCandidateClass(), query.isSubclasses(), query.getResult(), null, null, null);
Set<String> options = new HashSet<>();
if (mapperOptions != null) {
options.addAll(mapperOptions);
}
options.add(QueryToSQLMapper.OPTION_SELECT_CANDIDATE_ID_ONLY);
QueryToSQLMapper sqlMapper = new QueryToSQLMapper(existsStmt, query.getCompilation(), parameters, null, null, candidateCmd, query.isSubclasses(), query.getFetchPlan(), ec, query.getParsedImports(), options, query.getExtensions());
sqlMapper.compile();
// Add EXISTS clause on iterator statement so we can restrict to just the owners in this query
// ORDER BY in EXISTS is forbidden by some RDBMS
existsStmt.setOrdering(null, null);
BooleanExpression existsExpr = new BooleanSubqueryExpression(sqlStmt, "EXISTS", existsStmt);
sqlStmt.whereAnd(existsExpr, true);
// Join to outer statement so we restrict to collection elements for the query candidates
SQLExpression elemTblOwnerExpr = sqlStmt.getRDBMSManager().getSQLExpressionFactory().newExpression(sqlStmt, sqlStmt.getPrimaryTable(), ((BaseContainerStore) backingStore).getOwnerMapping());
SQLExpression existsOwnerExpr = sqlStmt.getRDBMSManager().getSQLExpressionFactory().newExpression(existsStmt, existsStmt.getPrimaryTable(), existsStmt.getPrimaryTable().getTable().getIdMapping());
existsStmt.whereAnd(elemTblOwnerExpr.eq(existsOwnerExpr), true);
// Select the owner candidate so we can separate the collection elements out to their owner
int[] ownerColIndexes = sqlStmt.select(elemTblOwnerExpr, null);
StatementMappingIndex ownerMapIdx = new StatementMappingIndex(existsStmt.getPrimaryTable().getTable().getIdMapping());
ownerMapIdx.setColumnPositions(ownerColIndexes);
iterStmt.setOwnerMapIndex(ownerMapIdx);
}
return iterStmt;
}
use of org.datanucleus.ClassLoaderResolver in project datanucleus-rdbms by datanucleus.
the class BulkFetchJoinHandler method getStatementToBulkFetchField.
/**
* Convenience method to generate a bulk-fetch statement for the specified multi-valued field of the owning query.
* @param candidateCmd Metadata for the candidate
* @param mmd Metadata for the member we are bulk-fetching the value(s) for
* @param query The query
* @param parameters Parameters for the query
* @param datastoreCompilation The datastore compilation of the query
* @param mapperOptions Any mapper options for query generation
* @return The statement to use for bulk fetching, together with mappings for extracting the results of the elements
*/
public IteratorStatement getStatementToBulkFetchField(AbstractClassMetaData candidateCmd, AbstractMemberMetaData mmd, Query query, Map parameters, RDBMSQueryCompilation datastoreCompilation, Set<String> mapperOptions) {
ExecutionContext ec = query.getExecutionContext();
ClassLoaderResolver clr = ec.getClassLoaderResolver();
RDBMSStoreManager storeMgr = (RDBMSStoreManager) query.getStoreManager();
Store backingStore = storeMgr.getBackingStoreForField(clr, mmd, null);
if (backingStore instanceof JoinSetStore || backingStore instanceof JoinListStore || backingStore instanceof JoinArrayStore) {
// Set/List/array using join-table : Generate an iterator query of the form
// SELECT ELEM_TBL.COL1, ELEM_TBL.COL2, ... FROM CANDIDATE_TBL T1 INNER JOIN JOIN_TBL T2 ON T2.OWNER_ID = T1.ID INNER_JOIN ELEM_TBL T3 ON T3.ID = T2.ELEM_ID
// WHERE (queryWhereClause)
// TODO Start from the original query, and remove any grouping, having, ordering etc, and join to join table + element table.
} else if (backingStore instanceof FKSetStore || backingStore instanceof FKListStore || backingStore instanceof FKArrayStore) {
// Set/List/array using foreign-key : Generate an iterator query of the form
// SELECT ELEM_TBL.COL1, ELEM_TBL.COL2, ... FROM ELEM_TBL
// WHERE EXISTS (SELECT OWNER_TBL.ID FROM OWNER_TBL WHERE (queryWhereClause) AND ELEM_TBL.OWNER_ID = OWNER_TBL.ID)
// TODO Start from the original query, and remove any grouping, having, ordering etc, and join to element table.
}
throw new NucleusException("BulkFetch via JOIN is not yet implemented");
// return iterStmt;
}
use of org.datanucleus.ClassLoaderResolver in project datanucleus-rdbms by datanucleus.
the class ReferenceIdMapping method setObject.
/**
* Method to set the object based on an input identity.
* @param ec execution context
* @param ps PreparedStatement
* @param param Parameter positions to populate when setting the value
* @param value The identity
*/
public void setObject(ExecutionContext ec, PreparedStatement ps, int[] param, Object value) {
if (value == null) {
super.setObject(ec, ps, param, null);
return;
}
if (mappingStrategy == ID_MAPPING || mappingStrategy == XCALIA_MAPPING) {
String refString = getReferenceStringForObject(ec, value);
getJavaTypeMapping()[0].setString(ec, ps, param, refString);
return;
}
ClassLoaderResolver clr = ec.getClassLoaderResolver();
int colPos = 0;
for (int i = 0; i < javaTypeMappings.length; i++) {
int[] cols = new int[javaTypeMappings[i].getNumberOfColumnMappings()];
for (int j = 0; j < cols.length; j++) {
cols[j] = param[colPos++];
}
Class cls = clr.classForName(javaTypeMappings[i].getType());
AbstractClassMetaData implCmd = ec.getMetaDataManager().getMetaDataForClass(cls, clr);
if (implCmd.getObjectidClass().equals(value.getClass().getName())) {
if (IdentityUtils.isDatastoreIdentity(value)) {
Object key = IdentityUtils.getTargetKeyForDatastoreIdentity(value);
if (key instanceof String) {
javaTypeMappings[i].setString(ec, ps, cols, (String) key);
} else {
javaTypeMappings[i].setObject(ec, ps, cols, key);
}
} else if (IdentityUtils.isSingleFieldIdentity(value)) {
Object key = IdentityUtils.getTargetKeyForSingleFieldIdentity(value);
if (key instanceof String) {
javaTypeMappings[i].setString(ec, ps, cols, (String) key);
} else {
javaTypeMappings[i].setObject(ec, ps, cols, key);
}
} else {
// TODO Cater for compound identity
String[] pkMemberNames = implCmd.getPrimaryKeyMemberNames();
for (int j = 0; j < pkMemberNames.length; j++) {
Object pkMemberValue = ClassUtils.getValueForIdentityField(value, pkMemberNames[j]);
if (pkMemberValue instanceof Byte) {
getColumnMapping(j).setByte(ps, param[j], (Byte) pkMemberValue);
} else if (pkMemberValue instanceof Character) {
getColumnMapping(j).setChar(ps, param[j], (Character) pkMemberValue);
} else if (pkMemberValue instanceof Integer) {
getColumnMapping(j).setInt(ps, param[j], (Integer) pkMemberValue);
} else if (pkMemberValue instanceof Long) {
getColumnMapping(j).setLong(ps, param[j], (Long) pkMemberValue);
} else if (pkMemberValue instanceof Short) {
getColumnMapping(j).setShort(ps, param[j], (Short) pkMemberValue);
} else if (pkMemberValue instanceof String) {
getColumnMapping(j).setString(ps, param[j], (String) pkMemberValue);
} else {
getColumnMapping(j).setObject(ps, param[j], pkMemberValue);
}
}
}
} else {
// Set columns to null for this implementation
javaTypeMappings[i].setObject(ec, ps, cols, null);
}
}
}
use of org.datanucleus.ClassLoaderResolver in project datanucleus-rdbms by datanucleus.
the class SimpleNumericAggregateMethod method getExpression.
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.sql.method.SQLMethod#getExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression, java.util.List)
*/
public SQLExpression getExpression(SQLStatement stmt, SQLExpression expr, List<SQLExpression> args) {
if (expr != null) {
throw new NucleusException(Localiser.msg("060002", getFunctionName(), expr));
}
if (args == null || args.size() != 1) {
throw new NucleusException(getFunctionName() + " is only supported with a single argument");
}
if (stmt.getQueryGenerator().getCompilationComponent() == CompilationComponent.RESULT || stmt.getQueryGenerator().getCompilationComponent() == CompilationComponent.HAVING) {
// FUNC(argExpr)
// Use same java type as the argument
SQLExpression argExpr = args.get(0);
JavaTypeMapping m = argExpr.getJavaTypeMapping();
return new AggregateNumericExpression(stmt, m, getFunctionName(), args);
}
ClassLoaderResolver clr = stmt.getQueryGenerator().getClassLoaderResolver();
// Handle as Subquery "SELECT AVG(expr) FROM tbl"
SQLExpression argExpr = args.get(0);
SelectStatement subStmt = new SelectStatement(stmt, stmt.getRDBMSManager(), argExpr.getSQLTable().getTable(), argExpr.getSQLTable().getAlias(), null);
subStmt.setClassLoaderResolver(clr);
SQLExpressionFactory exprFactory = stmt.getSQLExpressionFactory();
JavaTypeMapping mapping = stmt.getRDBMSManager().getMappingManager().getMappingWithColumnMapping(String.class, false, false, clr);
String aggregateString = getFunctionName() + "(" + argExpr.toSQLText() + ")";
SQLExpression aggExpr = exprFactory.newLiteral(subStmt, mapping, aggregateString);
((StringLiteral) aggExpr).generateStatementWithoutQuotes();
subStmt.select(aggExpr, null);
JavaTypeMapping subqMapping = exprFactory.getMappingForType(Integer.class, false);
SQLExpression subqExpr = new NumericSubqueryExpression(stmt, subStmt);
subqExpr.setJavaTypeMapping(subqMapping);
return subqExpr;
}
Aggregations