use of org.datanucleus.store.rdbms.table.JoinTable in project datanucleus-rdbms by datanucleus.
the class CollectionContainsMethod method containsAsSubquery.
/**
* Method to return an expression for Collection.contains using a subquery "EXISTS".
* This is for use when there are "!contains" or "OR" operations in the filter.
* Creates the following SQL,
* <ul>
* <li><b>Collection of NonPC using join table</b>
* <pre>
* SELECT 1 FROM JOIN_TBL A0_SUB
* WHERE A0_SUB.JOIN_OWN_ID = A0.ID AND A0_SUB.JOIN_ELEM_ID = {elemExpr}
* </pre>
* </li>
* <li><b>Collection of PC using join table</b>
* <pre>
* SELECT 1 FROM ELEM_TABLE A0_SUB INNER JOIN JOIN_TBL B0 ON ...
* WHERE B0.JOIN_OWN_ID = A0.ID AND A0_SUB.ID = {elemExpr}
* </pre>
* </li>
* <li><b>Collection of PC using FK</b>
* <pre>
* SELECT 1 FROM ELEM_TABLE A0_SUB
* WHERE A0_SUB.OWN_ID = A0.ID AND A0_SUB.ID = {elemExpr}
* </pre>
* </li>
* </ul>
* and returns a BooleanSubqueryExpression ("EXISTS (subquery)")
* @param stmt SQLStatement
* @param collExpr Collection expression
* @param elemExpr Expression for the element
* @return Contains expression
*/
protected SQLExpression containsAsSubquery(SQLStatement stmt, CollectionExpression collExpr, SQLExpression elemExpr) {
boolean elemIsUnbound = (elemExpr instanceof UnboundExpression);
String varName = null;
if (elemIsUnbound) {
varName = ((UnboundExpression) elemExpr).getVariableName();
NucleusLogger.QUERY.debug("collection.contains(" + elemExpr + ") binding unbound variable " + varName + " using SUBQUERY");
}
RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
SQLExpressionFactory exprFactory = stmt.getSQLExpressionFactory();
ClassLoaderResolver clr = stmt.getQueryGenerator().getClassLoaderResolver();
AbstractMemberMetaData mmd = collExpr.getJavaTypeMapping().getMemberMetaData();
AbstractClassMetaData elemCmd = mmd.getCollection().getElementClassMetaData(clr);
CollectionTable joinTbl = (CollectionTable) storeMgr.getTable(mmd);
String elemType = mmd.getCollection().getElementType();
if (elemIsUnbound) {
Class varType = stmt.getQueryGenerator().getTypeOfVariable(varName);
if (varType != null) {
elemType = varType.getName();
elemCmd = storeMgr.getMetaDataManager().getMetaDataForClass(elemType, clr);
}
}
SelectStatement subStmt = null;
if (joinTbl != null) {
// JoinTable Collection
if (elemCmd == null) {
// Collection<Non-PC>
subStmt = new SelectStatement(stmt, storeMgr, joinTbl, null, null);
subStmt.setClassLoaderResolver(clr);
JavaTypeMapping oneMapping = storeMgr.getMappingManager().getMapping(Integer.class);
subStmt.select(exprFactory.newLiteral(subStmt, oneMapping, 1), null);
// Restrict to collection owner
JavaTypeMapping ownerMapping = ((JoinTable) joinTbl).getOwnerMapping();
SQLExpression ownerExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), ownerMapping);
SQLExpression ownerIdExpr = exprFactory.newExpression(stmt, collExpr.getSQLTable(), collExpr.getSQLTable().getTable().getIdMapping());
subStmt.whereAnd(ownerExpr.eq(ownerIdExpr), true);
SQLExpression elemIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), joinTbl.getElementMapping());
if (elemIsUnbound) {
// Bind the variable in the QueryGenerator
stmt.getQueryGenerator().bindVariable(varName, null, elemIdExpr.getSQLTable(), elemIdExpr.getJavaTypeMapping());
} else {
// Add restrict to element
addRestrictionOnElement(subStmt, elemIdExpr, elemExpr);
}
} else {
// Collection<PC>
DatastoreClass elemTbl = storeMgr.getDatastoreClass(elemType, clr);
subStmt = new SelectStatement(stmt, storeMgr, elemTbl, null, null);
subStmt.setClassLoaderResolver(clr);
JavaTypeMapping oneMapping = storeMgr.getMappingManager().getMapping(Integer.class);
subStmt.select(exprFactory.newLiteral(subStmt, oneMapping, 1), null);
// Join to join table
SQLTable joinSqlTbl = subStmt.join(JoinType.INNER_JOIN, subStmt.getPrimaryTable(), elemTbl.getIdMapping(), joinTbl, null, joinTbl.getElementMapping(), null, null, true, null);
// Restrict to collection owner
JavaTypeMapping ownerMapping = ((JoinTable) joinTbl).getOwnerMapping();
SQLExpression ownerExpr = exprFactory.newExpression(subStmt, joinSqlTbl, ownerMapping);
SQLExpression ownerIdExpr = exprFactory.newExpression(stmt, collExpr.getSQLTable(), collExpr.getSQLTable().getTable().getIdMapping());
subStmt.whereAnd(ownerExpr.eq(ownerIdExpr), true);
SQLExpression elemIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), elemTbl.getIdMapping());
if (elemIsUnbound) {
// Bind the variable in the QueryGenerator
stmt.getQueryGenerator().bindVariable(varName, elemCmd, elemIdExpr.getSQLTable(), elemIdExpr.getJavaTypeMapping());
} else {
// Add restrict to element
addRestrictionOnElement(subStmt, elemIdExpr, elemExpr);
}
}
} else {
// FK Collection
DatastoreClass elemTbl = storeMgr.getDatastoreClass(mmd.getCollection().getElementType(), clr);
subStmt = new SelectStatement(stmt, storeMgr, elemTbl, null, null);
subStmt.setClassLoaderResolver(clr);
JavaTypeMapping oneMapping = storeMgr.getMappingManager().getMapping(Integer.class);
subStmt.select(exprFactory.newLiteral(subStmt, oneMapping, 1), null);
// Restrict to collection owner
JavaTypeMapping ownerMapping = null;
if (mmd.getMappedBy() != null) {
ownerMapping = elemTbl.getMemberMapping(mmd.getRelatedMemberMetaData(clr)[0]);
} else {
ownerMapping = elemTbl.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
}
SQLExpression ownerExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), ownerMapping);
SQLExpression ownerIdExpr = exprFactory.newExpression(stmt, collExpr.getSQLTable(), collExpr.getSQLTable().getTable().getIdMapping());
subStmt.whereAnd(ownerExpr.eq(ownerIdExpr), true);
if (elemIsUnbound) {
SQLExpression elemIdExpr = null;
if (!elemType.equals(mmd.getCollection().getElementType())) {
// Variable is defined as a subclass of the declared type so add extra join to variable type
DatastoreClass varTbl = storeMgr.getDatastoreClass(elemType, clr);
SQLTable varSqlTbl = subStmt.join(JoinType.INNER_JOIN, subStmt.getPrimaryTable(), elemTbl.getIdMapping(), null, varTbl, null, varTbl.getIdMapping(), null, null, null, true, null);
elemIdExpr = exprFactory.newExpression(subStmt, varSqlTbl, varTbl.getIdMapping());
} else {
elemIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), elemTbl.getIdMapping());
}
// Bind the variable in the QueryGenerator
stmt.getQueryGenerator().bindVariable(varName, elemCmd, elemIdExpr.getSQLTable(), elemIdExpr.getJavaTypeMapping());
} else {
// Add restrict to element
SQLExpression elemIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), elemTbl.getIdMapping());
addRestrictionOnElement(subStmt, elemIdExpr, elemExpr);
}
}
return new BooleanSubqueryExpression(stmt, "EXISTS", subStmt);
}
use of org.datanucleus.store.rdbms.table.JoinTable 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;
}
}
use of org.datanucleus.store.rdbms.table.JoinTable in project datanucleus-rdbms by datanucleus.
the class DeleteTablesSchemaTransaction method run.
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.AbstractSchemaTransaction#run(org.datanucleus.ClassLoaderResolver)
*/
protected void run(ClassLoaderResolver clr) throws SQLException {
synchronized (rdbmsMgr) {
boolean success = true;
try {
NucleusLogger.DATASTORE_SCHEMA.debug(Localiser.msg("050045", rdbmsMgr.getCatalogName(), rdbmsMgr.getSchemaName()));
// Build up map of tables and views TODO Why use maps?
Map baseTablesByName = new HashMap();
Map viewsByName = new HashMap();
for (Iterator i = storeDataMgr.getManagedStoreData().iterator(); i.hasNext(); ) {
RDBMSStoreData data = (RDBMSStoreData) i.next();
if (NucleusLogger.DATASTORE_SCHEMA.isDebugEnabled()) {
NucleusLogger.DATASTORE_SCHEMA.debug(Localiser.msg("050046", data.getName()));
}
// If the class has a table/view to remove, add it to the list
if (data.hasTable()) {
if (data.mapsToView()) {
viewsByName.put(data.getDatastoreIdentifier(), data.getTable());
} else {
baseTablesByName.put(data.getDatastoreIdentifier(), data.getTable());
}
}
}
// Remove views
Iterator viewsIter = viewsByName.values().iterator();
while (viewsIter.hasNext()) {
ViewImpl view = (ViewImpl) viewsIter.next();
if (writer != null) {
try {
if (view instanceof ClassView) {
writer.write("-- ClassView " + view.toString() + " for classes " + StringUtils.objectArrayToString(((ClassView) view).getManagedClasses()) + "\n");
}
} catch (IOException ioe) {
NucleusLogger.DATASTORE_SCHEMA.error("error writing DDL into file", ioe);
}
((ViewImpl) viewsIter.next()).drop(getCurrentConnection());
} else {
// Drop view if exists in the datastore
StoreSchemaData info = rdbmsMgr.getSchemaHandler().getSchemaData(getCurrentConnection(), RDBMSSchemaHandler.TYPE_COLUMNS, new Object[] { view });
if (info != null) {
((ViewImpl) viewsIter.next()).drop(getCurrentConnection());
}
}
}
// Remove table constraints
Map<TableImpl, Boolean> schemaExistsForTableMap = new HashMap();
Iterator tablesIter = baseTablesByName.values().iterator();
while (tablesIter.hasNext()) {
TableImpl tbl = (TableImpl) tablesIter.next();
if (writer != null) {
try {
if (tbl instanceof ClassTable) {
writer.write("-- Constraints for ClassTable " + tbl.toString() + " for classes " + StringUtils.objectArrayToString(((ClassTable) tbl).getManagedClasses()) + "\n");
} else if (tbl instanceof JoinTable) {
writer.write("-- Constraints for JoinTable " + tbl.toString() + " for join relationship\n");
}
} catch (IOException ioe) {
NucleusLogger.DATASTORE_SCHEMA.error("error writing DDL into file", ioe);
}
tbl.dropConstraints(getCurrentConnection());
} else {
// Drop constraints if exists in the datastore
boolean exists = false;
try {
// Check table type as way of detecting existence
String tableType = ((RDBMSSchemaHandler) rdbmsMgr.getSchemaHandler()).getTableType(getCurrentConnection(), tbl);
if (tableType != null) {
exists = true;
}
} catch (Exception e) {
exists = false;
}
schemaExistsForTableMap.put(tbl, exists);
if (exists) {
tbl.dropConstraints(getCurrentConnection());
}
}
}
// Remove tables
tablesIter = baseTablesByName.values().iterator();
while (tablesIter.hasNext()) {
TableImpl tbl = (TableImpl) tablesIter.next();
if (writer != null) {
try {
if (tbl instanceof ClassTable) {
writer.write("-- ClassTable " + tbl.toString() + " for classes " + StringUtils.objectArrayToString(((ClassTable) tbl).getManagedClasses()) + "\n");
} else if (tbl instanceof JoinTable) {
writer.write("-- JoinTable " + tbl.toString() + " for join relationship\n");
}
} catch (IOException ioe) {
NucleusLogger.DATASTORE_SCHEMA.error("error writing DDL into file", ioe);
}
tbl.drop(getCurrentConnection());
} else {
// Drop table if exists in the datastore
Boolean schemaExists = schemaExistsForTableMap.get(tbl);
if (schemaExists != null && schemaExists == Boolean.TRUE) {
tbl.drop(getCurrentConnection());
}
}
}
} catch (Exception e) {
success = false;
String errorMsg = Localiser.msg("050047", e);
NucleusLogger.DATASTORE_SCHEMA.error(errorMsg);
throw new NucleusUserException(errorMsg, e);
}
if (!success) {
throw new NucleusException("DeleteTables operation failed");
}
}
}
use of org.datanucleus.store.rdbms.table.JoinTable in project datanucleus-rdbms by datanucleus.
the class JoinMapStore method internalPut.
/**
* Method to process a "put" statement (where the key has no value in the join table).
* @param ownerOP ObjectProvider for the owner
* @param conn The Connection
* @param batched Whether we are batching it
* @param key The key
* @param value The value
* @param executeNow Whether to execute the statement now or wait til batching
* @return The return codes from any executed statement
* @throws MappedDatastoreException Thrown if an error occurs
*/
protected int[] internalPut(ObjectProvider ownerOP, ManagedConnection conn, boolean batched, Object key, Object value, boolean executeNow) throws MappedDatastoreException {
ExecutionContext ec = ownerOP.getExecutionContext();
SQLController sqlControl = storeMgr.getSQLController();
try {
PreparedStatement ps = sqlControl.getStatementForUpdate(conn, putStmt, false);
try {
int jdbcPosition = 1;
if (valueMapping != null) {
jdbcPosition = BackingStoreHelper.populateValueInStatement(ec, ps, value, jdbcPosition, valueMapping);
} else {
jdbcPosition = BackingStoreHelper.populateEmbeddedValueFieldsInStatement(ownerOP, value, ps, jdbcPosition, (JoinTable) mapTable, this);
}
jdbcPosition = BackingStoreHelper.populateOwnerInStatement(ownerOP, ec, ps, jdbcPosition, this);
if (adapterMapping != null) {
// Only set the adapter mapping if we have a new object
long nextIDAdapter = getNextIDForAdapterColumn(ownerOP);
adapterMapping.setObject(ec, ps, MappingHelper.getMappingIndices(jdbcPosition, adapterMapping), Long.valueOf(nextIDAdapter));
jdbcPosition += adapterMapping.getNumberOfDatastoreMappings();
}
jdbcPosition = BackingStoreHelper.populateKeyInStatement(ec, ps, key, jdbcPosition, keyMapping);
// Execute the statement
return sqlControl.executeStatementUpdate(ec, conn, putStmt, ps, true);
} finally {
sqlControl.closeStatement(conn, ps);
}
} catch (SQLException e) {
throw new MappedDatastoreException(getPutStmt(), e);
}
}
use of org.datanucleus.store.rdbms.table.JoinTable in project datanucleus-rdbms by datanucleus.
the class AbstractMapStore method updateEmbeddedValue.
public boolean updateEmbeddedValue(ObjectProvider op, Object value, int fieldNumber, Object newValue, JavaTypeMapping fieldMapping) {
boolean modified;
String stmt = getUpdateEmbeddedValueStmt(fieldMapping, getOwnerMapping(), getValueMapping(), getMapTable());
try {
ExecutionContext ec = op.getExecutionContext();
ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec);
SQLController sqlControl = storeMgr.getSQLController();
try {
PreparedStatement ps = sqlControl.getStatementForUpdate(mconn, stmt, false);
try {
int jdbcPosition = 1;
fieldMapping.setObject(ec, ps, MappingHelper.getMappingIndices(jdbcPosition, fieldMapping), newValue);
jdbcPosition += fieldMapping.getNumberOfDatastoreMappings();
jdbcPosition = BackingStoreHelper.populateOwnerInStatement(op, ec, ps, jdbcPosition, this);
jdbcPosition = BackingStoreHelper.populateEmbeddedValueFieldsInStatement(op, value, ps, jdbcPosition, (JoinTable) getMapTable(), this);
sqlControl.executeStatementUpdate(ec, mconn, stmt, ps, true);
modified = true;
} finally {
sqlControl.closeStatement(mconn, ps);
}
} finally {
mconn.release();
}
} catch (SQLException e) {
NucleusLogger.DATASTORE_PERSIST.warn("Exception in backing store update", e);
throw new NucleusDataStoreException(Localiser.msg("056011", stmt), e);
}
return modified;
}
Aggregations