use of org.datanucleus.store.rdbms.scostore.FKSetStore 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.store.rdbms.scostore.FKSetStore 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.store.rdbms.scostore.FKSetStore in project datanucleus-rdbms by datanucleus.
the class RDBMSStoreManager method getBackingStoreForField.
/**
* Accessor for the backing store for the specified member.
* Note : if we have an embedded object that is embedded into some other type and the object has a member that requires a join table (backing store), this method
* will not cater for the different places that can be embedded.
* @param clr The ClassLoaderResolver
* @param mmd metadata for the member to be persisted by this Store
* @param type instantiated type or prefered type
* @return The backing store
*/
public Store getBackingStoreForField(ClassLoaderResolver clr, AbstractMemberMetaData mmd, Class type) {
if (mmd == null || mmd.isSerialized()) {
return null;
}
Store store = backingStoreByMemberName.get(mmd.getFullFieldName());
if (store != null) {
return store;
}
synchronized (backingStoreByMemberName) {
// Just in case we synced just after someone added since our previous lookup above
store = backingStoreByMemberName.get(mmd.getFullFieldName());
if (store != null) {
return store;
}
Class expectedMappingType = null;
if (mmd.getMap() != null) {
expectedMappingType = MapMapping.class;
} else if (mmd.getArray() != null) {
expectedMappingType = ArrayMapping.class;
} else if (mmd.getCollection() != null) {
expectedMappingType = CollectionMapping.class;
} else {
expectedMappingType = PersistableMapping.class;
}
// Validate the mapping type matches the table
try {
DatastoreClass ownerTable = getDatastoreClass(mmd.getClassName(), clr);
if (ownerTable == null) {
// Class doesn't manage its own table (uses subclass-table, or superclass-table?)
AbstractClassMetaData fieldTypeCmd = getMetaDataManager().getMetaDataForClass(mmd.getClassName(), clr);
AbstractClassMetaData[] tableOwnerCmds = getClassesManagingTableForClass(fieldTypeCmd, clr);
if (tableOwnerCmds != null && tableOwnerCmds.length == 1) {
ownerTable = getDatastoreClass(tableOwnerCmds[0].getFullClassName(), clr);
}
}
if (ownerTable != null) {
JavaTypeMapping m = ownerTable.getMemberMapping(mmd);
if (!expectedMappingType.isAssignableFrom(m.getClass())) {
String requiredType = type != null ? type.getName() : mmd.getTypeName();
NucleusLogger.PERSISTENCE.warn("Member " + mmd.getFullFieldName() + " in table=" + ownerTable + " has mapping=" + m + " but expected mapping type=" + expectedMappingType);
throw new IncompatibleFieldTypeException(mmd.getFullFieldName(), requiredType, m.getType());
}
}
} catch (NoTableManagedException ntme) {
// Embedded, so just pass through
}
if (mmd.getMap() != null) {
Table datastoreTable = getTable(mmd);
if (datastoreTable == null) {
store = new FKMapStore(mmd, this, clr);
} else {
store = new JoinMapStore((MapTable) datastoreTable, clr);
}
} else if (mmd.getArray() != null) {
Table datastoreTable = getTable(mmd);
if (datastoreTable != null) {
store = new JoinArrayStore(mmd, (ArrayTable) datastoreTable, clr);
} else {
store = new FKArrayStore(mmd, this, clr);
}
} else if (mmd.getCollection() != null) {
Table datastoreTable = getTable(mmd);
if (type == null) {
// No type to base it on so create it based on the field declared type
if (datastoreTable == null) {
// We need a "FK" relation
if (Set.class.isAssignableFrom(mmd.getType())) {
store = new FKSetStore(mmd, this, clr);
} else if (List.class.isAssignableFrom(mmd.getType()) || Queue.class.isAssignableFrom(mmd.getType())) {
store = new FKListStore(mmd, this, clr);
} else if (mmd.getOrderMetaData() != null) {
// User has requested ordering
store = new FKListStore(mmd, this, clr);
} else {
store = new FKSetStore(mmd, this, clr);
}
} else {
// We need a "JoinTable" relation.
if (Set.class.isAssignableFrom(mmd.getType())) {
store = new JoinSetStore(mmd, (CollectionTable) datastoreTable, clr);
} else if (List.class.isAssignableFrom(mmd.getType()) || Queue.class.isAssignableFrom(mmd.getType())) {
store = new JoinListStore(mmd, (CollectionTable) datastoreTable, clr);
} else if (mmd.getOrderMetaData() != null) {
// User has requested ordering
store = new JoinListStore(mmd, (CollectionTable) datastoreTable, clr);
} else {
store = new JoinSetStore(mmd, (CollectionTable) datastoreTable, clr);
}
}
} else {
// Instantiated type specified, so use it to pick the associated backing store
if (datastoreTable == null) {
if (SCOUtils.isListBased(type)) {
// List required
store = new FKListStore(mmd, this, clr);
} else {
// Set required
store = new FKSetStore(mmd, this, clr);
}
} else {
if (SCOUtils.isListBased(type)) {
// List required
store = new JoinListStore(mmd, (CollectionTable) datastoreTable, clr);
} else {
// Set required
store = new JoinSetStore(mmd, (CollectionTable) datastoreTable, clr);
}
}
}
} else {
store = new JoinPersistableRelationStore(mmd, (PersistableJoinTable) getTable(mmd), clr);
}
backingStoreByMemberName.put(mmd.getFullFieldName(), store);
return store;
}
}
Aggregations