use of org.datanucleus.store.rdbms.scostore.BaseContainerStore 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;
}
Aggregations