use of org.datanucleus.store.rdbms.sql.SelectStatement in project datanucleus-rdbms by datanucleus.
the class FKListStore method listIterator.
/**
* Accessor for an iterator through the list elements.
* @param ownerOP ObjectProvider for the owner.
* @param startIdx The start index in the list (only for indexed lists)
* @param endIdx The end index in the list (only for indexed lists)
* @return The List Iterator
*/
protected ListIterator<E> listIterator(ObjectProvider ownerOP, int startIdx, int endIdx) {
ExecutionContext ec = ownerOP.getExecutionContext();
Transaction tx = ec.getTransaction();
if (elementInfo == null || elementInfo.length == 0) {
return null;
}
// Generate the statement. Note that this is not cached since depends on the current FetchPlan and other things
IteratorStatement iterStmt = getIteratorStatement(ownerOP.getExecutionContext(), ec.getFetchPlan(), true, startIdx, endIdx);
SelectStatement sqlStmt = iterStmt.getSelectStatement();
StatementClassMapping resultMapping = iterStmt.getStatementClassMapping();
// Input parameter(s) - the owner
int inputParamNum = 1;
StatementMappingIndex ownerIdx = new StatementMappingIndex(ownerMapping);
if (sqlStmt.getNumberOfUnions() > 0) {
// Add parameter occurrence for each union of statement
for (int j = 0; j < sqlStmt.getNumberOfUnions() + 1; j++) {
int[] paramPositions = new int[ownerMapping.getNumberOfDatastoreMappings()];
for (int k = 0; k < ownerMapping.getNumberOfDatastoreMappings(); k++) {
paramPositions[k] = inputParamNum++;
}
ownerIdx.addParameterOccurrence(paramPositions);
}
} else {
int[] paramPositions = new int[ownerMapping.getNumberOfDatastoreMappings()];
for (int k = 0; k < ownerMapping.getNumberOfDatastoreMappings(); k++) {
paramPositions[k] = inputParamNum++;
}
ownerIdx.addParameterOccurrence(paramPositions);
}
if (tx.getSerializeRead() != null && tx.getSerializeRead()) {
sqlStmt.addExtension(SQLStatement.EXTENSION_LOCK_FOR_UPDATE, true);
}
String stmt = sqlStmt.getSQLText().toSQL();
try {
ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec);
SQLController sqlControl = storeMgr.getSQLController();
try {
// Create the statement
PreparedStatement ps = sqlControl.getStatementForQuery(mconn, stmt);
// Set the owner
ObjectProvider stmtOwnerOP = BackingStoreHelper.getOwnerObjectProviderForBackingStore(ownerOP);
int numParams = ownerIdx.getNumberOfParameterOccurrences();
for (int paramInstance = 0; paramInstance < numParams; paramInstance++) {
ownerIdx.getMapping().setObject(ec, ps, ownerIdx.getParameterPositionsForOccurrence(paramInstance), stmtOwnerOP.getObject());
}
try {
ResultSet rs = sqlControl.executeStatementQuery(ec, mconn, stmt, ps);
try {
ResultObjectFactory rof = null;
if (elementsAreEmbedded || elementsAreSerialised) {
throw new NucleusException("Cannot have FK set with non-persistent objects");
}
rof = new PersistentClassROF(ec, rs, false, resultMapping, elementCmd, clr.classForName(elementType));
return new ListStoreIterator(ownerOP, rs, rof, this);
} finally {
rs.close();
}
} finally {
sqlControl.closeStatement(mconn, ps);
}
} finally {
mconn.release();
}
} catch (SQLException | MappedDatastoreException e) {
throw new NucleusDataStoreException(Localiser.msg("056006", stmt), e);
}
}
use of org.datanucleus.store.rdbms.sql.SelectStatement in project datanucleus-rdbms by datanucleus.
the class FKMapStore method getSQLStatementForGet.
/**
* Method to return an SQLStatement for retrieving the value for a key.
* Selects the join table and optionally joins to the value table if it has its own table.
* @param ownerOP ObjectProvider for the owning object
* @return The SQLStatement
*/
protected SelectStatement getSQLStatementForGet(ObjectProvider ownerOP) {
SelectStatement sqlStmt = null;
ExecutionContext ec = ownerOP.getExecutionContext();
final ClassLoaderResolver clr = ownerOP.getExecutionContext().getClassLoaderResolver();
final Class valueCls = clr.classForName(this.valueType);
if (ownerMemberMetaData.getMap().getMapType() == MapType.MAP_TYPE_KEY_IN_VALUE) {
getMappingDef = new StatementClassMapping();
if (valueTable.getDiscriminatorMetaData() != null && valueTable.getDiscriminatorMetaData().getStrategy() != DiscriminatorStrategy.NONE) {
// Value class has discriminator
if (ClassUtils.isReferenceType(valueCls)) {
String[] clsNames = storeMgr.getNucleusContext().getMetaDataManager().getClassesImplementingInterface(valueType, clr);
Class[] cls = new Class[clsNames.length];
for (int i = 0; i < clsNames.length; i++) {
cls[i] = clr.classForName(clsNames[i]);
}
sqlStmt = new DiscriminatorStatementGenerator(storeMgr, clr, cls, true, null, null).getStatement(ec);
} else {
sqlStmt = new DiscriminatorStatementGenerator(storeMgr, clr, valueCls, true, null, null).getStatement(ec);
}
iterateUsingDiscriminator = true;
} else {
// Use union to resolve any subclasses of value
UnionStatementGenerator stmtGen = new UnionStatementGenerator(storeMgr, clr, valueCls, true, null, null);
stmtGen.setOption(SelectStatementGenerator.OPTION_SELECT_DN_TYPE);
getMappingDef.setNucleusTypeColumnName(UnionStatementGenerator.DN_TYPE_COLUMN);
sqlStmt = stmtGen.getStatement(ec);
}
// Select the value field(s)
SQLStatementHelper.selectFetchPlanOfSourceClassInStatement(sqlStmt, getMappingDef, ec.getFetchPlan(), sqlStmt.getPrimaryTable(), valueCmd, ec.getFetchPlan().getMaxFetchDepth());
} else {
// Value is in key table
sqlStmt = new SelectStatement(storeMgr, mapTable, null, null);
sqlStmt.setClassLoaderResolver(clr);
if (valueCmd != null) {
// Left outer join to value table (so we allow for null values)
SQLTable valueSqlTbl = sqlStmt.join(JoinType.LEFT_OUTER_JOIN, sqlStmt.getPrimaryTable(), valueMapping, valueTable, null, valueTable.getIdMapping(), null, null, true);
// Select the value field(s)
SQLStatementHelper.selectFetchPlanOfSourceClassInStatement(sqlStmt, getMappingDef, ec.getFetchPlan(), valueSqlTbl, valueCmd, ec.getFetchPlan().getMaxFetchDepth());
} else {
sqlStmt.select(sqlStmt.getPrimaryTable(), valueMapping, null);
}
}
// Apply condition on owner field to filter by owner
SQLExpressionFactory exprFactory = storeMgr.getSQLExpressionFactory();
SQLTable ownerSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(sqlStmt, sqlStmt.getPrimaryTable(), ownerMapping);
SQLExpression ownerExpr = exprFactory.newExpression(sqlStmt, ownerSqlTbl, ownerMapping);
SQLExpression ownerVal = exprFactory.newLiteralParameter(sqlStmt, ownerMapping, null, "OWNER");
sqlStmt.whereAnd(ownerExpr.eq(ownerVal), true);
// Apply condition on key
if (keyMapping instanceof SerialisedMapping) {
// if the keyMapping contains a BLOB column (or any other column not supported by the database
// as primary key), uses like instead of the operator OP_EQ (=)
// in future do not check if the keyMapping is of ObjectMapping, but use the database
// adapter to check the data types not supported as primary key
// if object mapping (BLOB) use like
SQLExpression keyExpr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), keyMapping);
SQLExpression keyVal = exprFactory.newLiteralParameter(sqlStmt, keyMapping, null, "KEY");
sqlStmt.whereAnd(new org.datanucleus.store.rdbms.sql.expression.BooleanExpression(keyExpr, Expression.OP_LIKE, keyVal), true);
} else {
SQLExpression keyExpr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), keyMapping);
SQLExpression keyVal = exprFactory.newLiteralParameter(sqlStmt, keyMapping, null, "KEY");
sqlStmt.whereAnd(keyExpr.eq(keyVal), true);
}
// Input parameter(s) - owner, key
int inputParamNum = 1;
StatementMappingIndex ownerIdx = new StatementMappingIndex(ownerMapping);
StatementMappingIndex keyIdx = new StatementMappingIndex(keyMapping);
if (sqlStmt.getNumberOfUnions() > 0) {
// Add parameter occurrence for each union of statement
for (int j = 0; j < sqlStmt.getNumberOfUnions() + 1; j++) {
int[] ownerPositions = new int[ownerMapping.getNumberOfDatastoreMappings()];
for (int k = 0; k < ownerPositions.length; k++) {
ownerPositions[k] = inputParamNum++;
}
ownerIdx.addParameterOccurrence(ownerPositions);
int[] keyPositions = new int[keyMapping.getNumberOfDatastoreMappings()];
for (int k = 0; k < keyPositions.length; k++) {
keyPositions[k] = inputParamNum++;
}
keyIdx.addParameterOccurrence(keyPositions);
}
} else {
int[] ownerPositions = new int[ownerMapping.getNumberOfDatastoreMappings()];
for (int k = 0; k < ownerPositions.length; k++) {
ownerPositions[k] = inputParamNum++;
}
ownerIdx.addParameterOccurrence(ownerPositions);
int[] keyPositions = new int[keyMapping.getNumberOfDatastoreMappings()];
for (int k = 0; k < keyPositions.length; k++) {
keyPositions[k] = inputParamNum++;
}
keyIdx.addParameterOccurrence(keyPositions);
}
getMappingParams = new StatementParameterMapping();
getMappingParams.addMappingForParameter("owner", ownerIdx);
getMappingParams.addMappingForParameter("key", keyIdx);
return sqlStmt;
}
use of org.datanucleus.store.rdbms.sql.SelectStatement in project datanucleus-rdbms by datanucleus.
the class JoinListStore method listIterator.
/**
* Accessor for an iterator through the list elements.
* @param ownerOP ObjectProvider for the owner
* @param startIdx The start point in the list (only for indexed lists).
* @param endIdx End index in the list (only for indexed lists).
* @return The List Iterator
*/
protected ListIterator<E> listIterator(ObjectProvider ownerOP, int startIdx, int endIdx) {
ExecutionContext ec = ownerOP.getExecutionContext();
Transaction tx = ec.getTransaction();
// Generate the statement. Note that this is not cached since depends on the current FetchPlan and other things
IteratorStatement iterStmt = getIteratorStatement(ownerOP.getExecutionContext(), ec.getFetchPlan(), true, startIdx, endIdx);
SelectStatement sqlStmt = iterStmt.getSelectStatement();
StatementClassMapping resultMapping = iterStmt.getStatementClassMapping();
// Input parameter(s) - the owner
int inputParamNum = 1;
StatementMappingIndex ownerIdx = new StatementMappingIndex(ownerMapping);
if (sqlStmt.getNumberOfUnions() > 0) {
// Add parameter occurrence for each union of statement
for (int j = 0; j < sqlStmt.getNumberOfUnions() + 1; j++) {
int[] paramPositions = new int[ownerMapping.getNumberOfDatastoreMappings()];
for (int k = 0; k < paramPositions.length; k++) {
paramPositions[k] = inputParamNum++;
}
ownerIdx.addParameterOccurrence(paramPositions);
}
} else {
int[] paramPositions = new int[ownerMapping.getNumberOfDatastoreMappings()];
for (int k = 0; k < paramPositions.length; k++) {
paramPositions[k] = inputParamNum++;
}
ownerIdx.addParameterOccurrence(paramPositions);
}
if (tx.getSerializeRead() != null && tx.getSerializeRead()) {
sqlStmt.addExtension(SQLStatement.EXTENSION_LOCK_FOR_UPDATE, true);
}
String stmt = sqlStmt.getSQLText().toSQL();
try {
ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec);
SQLController sqlControl = storeMgr.getSQLController();
try {
// Create the statement
PreparedStatement ps = sqlControl.getStatementForQuery(mconn, stmt);
// Set the owner
ObjectProvider stmtOwnerOP = BackingStoreHelper.getOwnerObjectProviderForBackingStore(ownerOP);
int numParams = ownerIdx.getNumberOfParameterOccurrences();
for (int paramInstance = 0; paramInstance < numParams; paramInstance++) {
ownerIdx.getMapping().setObject(ec, ps, ownerIdx.getParameterPositionsForOccurrence(paramInstance), stmtOwnerOP.getObject());
}
try {
ResultSet rs = sqlControl.executeStatementQuery(ec, mconn, stmt, ps);
try {
if (elementsAreEmbedded || elementsAreSerialised) {
// No ResultObjectFactory needed - handled by SetStoreIterator
return new ListStoreIterator(ownerOP, rs, null, this);
} else if (elementMapping instanceof ReferenceMapping) {
// No ResultObjectFactory needed - handled by SetStoreIterator
return new ListStoreIterator(ownerOP, rs, null, this);
} else {
ResultObjectFactory rof = new PersistentClassROF(ec, rs, false, resultMapping, elementCmd, clr.classForName(elementType));
return new ListStoreIterator(ownerOP, rs, rof, this);
}
} finally {
rs.close();
}
} finally {
sqlControl.closeStatement(mconn, ps);
}
} finally {
mconn.release();
}
} catch (SQLException | MappedDatastoreException e) {
throw new NucleusDataStoreException(Localiser.msg("056006", stmt), e);
}
}
use of org.datanucleus.store.rdbms.sql.SelectStatement in project datanucleus-rdbms by datanucleus.
the class JoinListStore method getIteratorStatement.
/**
* Method to return the SQLStatement and mapping for an iterator for this backing store.
* Create a statement of the form
* <pre>
* SELECT ELEM_COLS
* FROM JOIN_TBL
* [JOIN ELEM_TBL ON ELEM_TBL.ID = JOIN_TBL.ELEM_ID]
* [WHERE]
* [JOIN_TBL.OWNER_ID = {value}] [AND]
* [JOIN_TBL.DISCRIM = {discrimValue}]
* [ORDER BY {orderClause}]
* </pre>
* @param ec ExecutionContext
* @param fp FetchPlan to use in determing which fields of element to select
* @param addRestrictionOnOwner Whether to restrict to a particular owner (otherwise functions as bulk fetch for many owners).
* @param startIdx Start index for the iterator (or -1)
* @param endIdx End index for the iterator (or -1)
* @return The SQLStatement and its associated StatementClassMapping
*/
public IteratorStatement getIteratorStatement(ExecutionContext ec, FetchPlan fp, boolean addRestrictionOnOwner, int startIdx, int endIdx) {
SelectStatement sqlStmt = null;
StatementClassMapping stmtClassMapping = new StatementClassMapping();
SQLExpressionFactory exprFactory = storeMgr.getSQLExpressionFactory();
if (elementsAreEmbedded || elementsAreSerialised) {
// Element = embedded, serialised (maybe Non-PC)
// Just select the join table since we're going to return the embedded/serialised columns from it
sqlStmt = new SelectStatement(storeMgr, containerTable, null, null);
sqlStmt.setClassLoaderResolver(clr);
// Select the element column - first select is assumed by ListStoreIterator
sqlStmt.select(sqlStmt.getPrimaryTable(), elementMapping, null);
// TODO If embedded element and it includes 1-1/N-1 in FetchPlan then select its fields also
} else if (elementMapping instanceof ReferenceMapping) {
// Element = Reference type (interface/Object)
// Just select the join table since we're going to return the implementation id columns only
sqlStmt = new SelectStatement(storeMgr, containerTable, null, null);
sqlStmt.setClassLoaderResolver(clr);
// Select the reference column(s) - first select is assumed by ListStoreIterator
sqlStmt.select(sqlStmt.getPrimaryTable(), elementMapping, null);
} else {
// Join to the element table(s)
if (elementInfo != null) {
for (int i = 0; i < elementInfo.length; i++) {
// TODO This will only work if all element types have a discriminator
final int elementNo = i;
final Class elementCls = clr.classForName(elementInfo[elementNo].getClassName());
SelectStatement elementStmt = null;
if (elementInfo[elementNo].getDiscriminatorStrategy() != null && elementInfo[elementNo].getDiscriminatorStrategy() != DiscriminatorStrategy.NONE) {
// The element uses a discriminator so just use that in the SELECT
String elementType = ownerMemberMetaData.getCollection().getElementType();
if (ClassUtils.isReferenceType(clr.classForName(elementType))) {
String[] clsNames = storeMgr.getNucleusContext().getMetaDataManager().getClassesImplementingInterface(elementType, clr);
Class[] cls = new Class[clsNames.length];
for (int j = 0; j < clsNames.length; j++) {
cls[j] = clr.classForName(clsNames[j]);
}
SelectStatementGenerator stmtGen = new DiscriminatorStatementGenerator(storeMgr, clr, cls, true, null, null, containerTable, null, elementMapping);
if (allowNulls) {
stmtGen.setOption(SelectStatementGenerator.OPTION_ALLOW_NULLS);
}
elementStmt = stmtGen.getStatement(ec);
} else {
SelectStatementGenerator stmtGen = new DiscriminatorStatementGenerator(storeMgr, clr, elementCls, true, null, null, containerTable, null, elementMapping);
if (allowNulls) {
stmtGen.setOption(SelectStatementGenerator.OPTION_ALLOW_NULLS);
}
elementStmt = stmtGen.getStatement(ec);
}
iterateUsingDiscriminator = true;
} else {
// No discriminator, but subclasses so use UNIONs
SelectStatementGenerator stmtGen = new UnionStatementGenerator(storeMgr, clr, elementCls, true, null, null, containerTable, null, elementMapping);
stmtGen.setOption(SelectStatementGenerator.OPTION_SELECT_DN_TYPE);
stmtClassMapping.setNucleusTypeColumnName(UnionStatementGenerator.DN_TYPE_COLUMN);
elementStmt = stmtGen.getStatement(ec);
}
if (sqlStmt == null) {
sqlStmt = elementStmt;
} else {
sqlStmt.union(elementStmt);
}
}
if (sqlStmt == null) {
throw new NucleusException("Error in generation of SQL statement for iterator over (Join) list. Statement is null");
}
// Select the required fields
SQLTable elementSqlTbl = sqlStmt.getTable(elementInfo[0].getDatastoreClass(), sqlStmt.getPrimaryTable().getGroupName());
SQLStatementHelper.selectFetchPlanOfSourceClassInStatement(sqlStmt, stmtClassMapping, fp, elementSqlTbl, elementCmd, fp.getMaxFetchDepth());
} else {
throw new NucleusException("Unable to create SQL statement to retrieve elements of List");
}
}
if (addRestrictionOnOwner) {
// Apply condition on join-table owner field to filter by owner
SQLTable ownerSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(sqlStmt, sqlStmt.getPrimaryTable(), ownerMapping);
SQLExpression ownerExpr = exprFactory.newExpression(sqlStmt, ownerSqlTbl, ownerMapping);
SQLExpression ownerVal = exprFactory.newLiteralParameter(sqlStmt, ownerMapping, null, "OWNER");
sqlStmt.whereAnd(ownerExpr.eq(ownerVal), true);
}
if (relationDiscriminatorMapping != null) {
// Apply condition on distinguisher field to filter by distinguisher (when present)
SQLTable distSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(sqlStmt, sqlStmt.getPrimaryTable(), relationDiscriminatorMapping);
SQLExpression distExpr = exprFactory.newExpression(sqlStmt, distSqlTbl, relationDiscriminatorMapping);
SQLExpression distVal = exprFactory.newLiteral(sqlStmt, relationDiscriminatorMapping, relationDiscriminatorValue);
sqlStmt.whereAnd(distExpr.eq(distVal), true);
}
if (indexedList) {
// "Indexed List" so allow restriction on returned indexes
boolean needsOrdering = true;
if (startIdx == -1 && endIdx == -1) {
// Just restrict to >= 0 so we don't get any disassociated elements
SQLExpression indexExpr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), orderMapping);
SQLExpression indexVal = exprFactory.newLiteral(sqlStmt, orderMapping, 0);
sqlStmt.whereAnd(indexExpr.ge(indexVal), true);
} else if (startIdx >= 0 && endIdx == startIdx) {
// Particular index required so add restriction
needsOrdering = false;
SQLExpression indexExpr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), orderMapping);
SQLExpression indexVal = exprFactory.newLiteral(sqlStmt, orderMapping, startIdx);
sqlStmt.whereAnd(indexExpr.eq(indexVal), true);
} else {
// Add restrictions on start/end indices as required
if (startIdx >= 0) {
SQLExpression indexExpr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), orderMapping);
SQLExpression indexVal = exprFactory.newLiteral(sqlStmt, orderMapping, startIdx);
sqlStmt.whereAnd(indexExpr.ge(indexVal), true);
} else {
// Just restrict to >= 0 so we don't get any disassociated elements
SQLExpression indexExpr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), orderMapping);
SQLExpression indexVal = exprFactory.newLiteral(sqlStmt, orderMapping, 0);
sqlStmt.whereAnd(indexExpr.ge(indexVal), true);
}
if (endIdx >= 0) {
SQLExpression indexExpr2 = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), orderMapping);
SQLExpression indexVal2 = exprFactory.newLiteral(sqlStmt, orderMapping, endIdx);
sqlStmt.whereAnd(indexExpr2.lt(indexVal2), true);
}
}
if (needsOrdering) {
// Order by the ordering column, when present
SQLTable orderSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(sqlStmt, sqlStmt.getPrimaryTable(), orderMapping);
SQLExpression[] orderExprs = new SQLExpression[orderMapping.getNumberOfDatastoreMappings()];
boolean[] descendingOrder = new boolean[orderMapping.getNumberOfDatastoreMappings()];
orderExprs[0] = exprFactory.newExpression(sqlStmt, orderSqlTbl, orderMapping);
sqlStmt.setOrdering(orderExprs, descendingOrder);
}
} else {
if (elementInfo != null) {
// Apply ordering defined by <order-by>
DatastoreClass elementTbl = elementInfo[0].getDatastoreClass();
FieldOrder[] orderComponents = ownerMemberMetaData.getOrderMetaData().getFieldOrders();
SQLExpression[] orderExprs = new SQLExpression[orderComponents.length];
boolean[] orderDirs = new boolean[orderComponents.length];
for (int i = 0; i < orderComponents.length; i++) {
String fieldName = orderComponents[i].getFieldName();
JavaTypeMapping fieldMapping = elementTbl.getMemberMapping(elementInfo[0].getAbstractClassMetaData().getMetaDataForMember(fieldName));
orderDirs[i] = !orderComponents[i].isForward();
SQLTable fieldSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(sqlStmt, sqlStmt.getPrimaryTable(), fieldMapping);
orderExprs[i] = exprFactory.newExpression(sqlStmt, fieldSqlTbl, fieldMapping);
}
sqlStmt.setOrdering(orderExprs, orderDirs);
}
}
return new IteratorStatement(this, sqlStmt, stmtClassMapping);
}
use of org.datanucleus.store.rdbms.sql.SelectStatement in project datanucleus-rdbms by datanucleus.
the class MapContainsKeyMethod method containsAsSubquery.
/**
* Method to return an expression for Map.containsKey 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>Map using join table</b>
* <pre>
* SELECT 1 FROM JOIN_TBL A0_SUB
* WHERE A0_SUB.JOIN_OWN_ID = A0.ID AND A0_SUB.JOIN_KEY_ID = {keyExpr}
* </pre>
* </li>
* <li><b>Map with key stored in value</b>
* <pre>
* SELECT 1 FROM KEY_TABLE A0_SUB INNER JOIN VALUE_TBL B0 ON ...
* WHERE B0.JOIN_OWN_ID = A0.ID AND A0_SUB.ID = {keyExpr}
* </pre>
* </li>
* <li><b>Map of value stored in key</b>
* <pre>
* SELECT 1 FROM KEY_TABLE A0_SUB
* WHERE A0_SUB.OWN_ID = A0.ID AND A0_SUB.ID = {keyExpr}
* </pre>
* </li>
* </ul>
* and returns a BooleanSubqueryExpression ("EXISTS (subquery)")
* @param stmt SQLStatement
* @param mapExpr Map expression
* @param keyExpr Expression for the key
* @return Contains expression
*/
protected SQLExpression containsAsSubquery(SQLStatement stmt, MapExpression mapExpr, SQLExpression keyExpr) {
boolean keyIsUnbound = (keyExpr instanceof UnboundExpression);
String varName = null;
if (keyIsUnbound) {
varName = ((UnboundExpression) keyExpr).getVariableName();
NucleusLogger.QUERY.debug("map.containsKey binding unbound variable " + varName + " using SUBQUERY");
// TODO What if the variable is declared as a subtype, handle this see CollectionContainsMethod
}
RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
SQLExpressionFactory exprFactory = stmt.getSQLExpressionFactory();
ClassLoaderResolver clr = stmt.getQueryGenerator().getClassLoaderResolver();
AbstractMemberMetaData mmd = mapExpr.getJavaTypeMapping().getMemberMetaData();
AbstractClassMetaData keyCmd = mmd.getMap().getKeyClassMetaData(clr);
MapTable joinTbl = (MapTable) storeMgr.getTable(mmd);
SelectStatement subStmt = null;
if (mmd.getMap().getMapType() == MapType.MAP_TYPE_JOIN) {
// JoinTable Map
if (keyCmd == null) {
// Map<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 map owner
JavaTypeMapping ownerMapping = ((JoinTable) joinTbl).getOwnerMapping();
SQLExpression ownerExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), ownerMapping);
SQLExpression ownerIdExpr = exprFactory.newExpression(stmt, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping());
subStmt.whereAnd(ownerExpr.eq(ownerIdExpr), true);
if (keyIsUnbound) {
// Bind the variable in the QueryGenerator
keyExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), joinTbl.getKeyMapping());
stmt.getQueryGenerator().bindVariable(varName, null, keyExpr.getSQLTable(), keyExpr.getJavaTypeMapping());
} else {
// Add restrict to key
SQLExpression elemIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), joinTbl.getKeyMapping());
subStmt.whereAnd(elemIdExpr.eq(keyExpr), true);
}
} else {
// Map<PC, ?>
DatastoreClass keyTbl = storeMgr.getDatastoreClass(mmd.getMap().getKeyType(), clr);
subStmt = new SelectStatement(stmt, storeMgr, keyTbl, 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(), keyTbl.getIdMapping(), joinTbl, null, joinTbl.getKeyMapping(), null, null, true);
// Restrict to map owner
JavaTypeMapping ownerMapping = joinTbl.getOwnerMapping();
SQLExpression ownerExpr = exprFactory.newExpression(subStmt, joinSqlTbl, ownerMapping);
SQLExpression ownerIdExpr = exprFactory.newExpression(stmt, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping());
subStmt.whereAnd(ownerExpr.eq(ownerIdExpr), true);
if (keyIsUnbound) {
// Bind the variable in the QueryGenerator
keyExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), keyTbl.getIdMapping());
stmt.getQueryGenerator().bindVariable(varName, keyCmd, keyExpr.getSQLTable(), keyExpr.getJavaTypeMapping());
} else {
// Add restrict to key
SQLExpression keyIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), keyTbl.getIdMapping());
subStmt.whereAnd(keyIdExpr.eq(keyExpr), true);
}
}
} else if (mmd.getMap().getMapType() == MapType.MAP_TYPE_KEY_IN_VALUE) {
// Key stored in value table
AbstractClassMetaData valCmd = mmd.getMap().getValueClassMetaData(clr);
DatastoreClass valTbl = storeMgr.getDatastoreClass(mmd.getMap().getValueType(), clr);
JavaTypeMapping ownerMapping = null;
if (mmd.getMappedBy() != null) {
ownerMapping = valTbl.getMemberMapping(valCmd.getMetaDataForMember(mmd.getMappedBy()));
} else {
ownerMapping = valTbl.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
}
AbstractMemberMetaData valKeyMmd = valCmd.getMetaDataForMember(mmd.getKeyMetaData().getMappedBy());
if (keyCmd == null) {
subStmt = new SelectStatement(stmt, storeMgr, valTbl, null, null);
subStmt.setClassLoaderResolver(clr);
JavaTypeMapping oneMapping = storeMgr.getMappingManager().getMapping(Integer.class);
subStmt.select(exprFactory.newLiteral(subStmt, oneMapping, 1), null);
// Restrict to map owner (on value table)
SQLExpression ownerExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), ownerMapping);
SQLExpression ownerIdExpr = exprFactory.newExpression(stmt, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping());
subStmt.whereAnd(ownerExpr.eq(ownerIdExpr), true);
if (keyIsUnbound) {
// Bind the variable in the QueryGenerator
keyExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), valTbl.getMemberMapping(valKeyMmd));
stmt.getQueryGenerator().bindVariable(varName, null, keyExpr.getSQLTable(), keyExpr.getJavaTypeMapping());
} else {
// Add restrict to key
JavaTypeMapping keyMapping = valTbl.getMemberMapping(valKeyMmd);
SQLExpression elemIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), keyMapping);
subStmt.whereAnd(elemIdExpr.eq(keyExpr), true);
}
} else {
DatastoreClass keyTbl = storeMgr.getDatastoreClass(mmd.getMap().getKeyType(), clr);
subStmt = new SelectStatement(stmt, storeMgr, keyTbl, null, null);
subStmt.setClassLoaderResolver(clr);
JavaTypeMapping oneMapping = storeMgr.getMappingManager().getMapping(Integer.class);
subStmt.select(exprFactory.newLiteral(subStmt, oneMapping, 1), null);
// Join to value table
SQLTable valSqlTbl = subStmt.join(JoinType.INNER_JOIN, subStmt.getPrimaryTable(), keyTbl.getIdMapping(), valTbl, null, valTbl.getMemberMapping(valKeyMmd), null, null, true);
// Restrict to map owner (on value table)
SQLExpression ownerExpr = exprFactory.newExpression(subStmt, valSqlTbl, ownerMapping);
SQLExpression ownerIdExpr = exprFactory.newExpression(stmt, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping());
subStmt.whereAnd(ownerExpr.eq(ownerIdExpr), true);
if (keyIsUnbound) {
// Bind the variable in the QueryGenerator
keyExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), keyTbl.getIdMapping());
stmt.getQueryGenerator().bindVariable(varName, keyCmd, keyExpr.getSQLTable(), keyExpr.getJavaTypeMapping());
} else {
// Add restrict to key
SQLExpression keyIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), keyTbl.getIdMapping());
subStmt.whereAnd(keyIdExpr.eq(keyExpr), true);
}
}
} else if (mmd.getMap().getMapType() == MapType.MAP_TYPE_VALUE_IN_KEY) {
DatastoreClass keyTbl = storeMgr.getDatastoreClass(mmd.getMap().getKeyType(), clr);
JavaTypeMapping ownerMapping = null;
if (mmd.getMappedBy() != null) {
ownerMapping = keyTbl.getMemberMapping(keyCmd.getMetaDataForMember(mmd.getMappedBy()));
} else {
ownerMapping = keyTbl.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
}
subStmt = new SelectStatement(stmt, storeMgr, keyTbl, null, null);
subStmt.setClassLoaderResolver(clr);
JavaTypeMapping oneMapping = storeMgr.getMappingManager().getMapping(Integer.class);
subStmt.select(exprFactory.newLiteral(subStmt, oneMapping, 1), null);
// Restrict to map owner (on key table)
SQLExpression ownerExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), ownerMapping);
SQLExpression ownerIdExpr = exprFactory.newExpression(stmt, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping());
subStmt.whereAnd(ownerExpr.eq(ownerIdExpr), true);
if (keyIsUnbound) {
// Bind the variable in the QueryGenerator
keyExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), keyTbl.getIdMapping());
stmt.getQueryGenerator().bindVariable(varName, keyCmd, keyExpr.getSQLTable(), keyExpr.getJavaTypeMapping());
} else {
// Add restrict to key
JavaTypeMapping keyMapping = keyTbl.getIdMapping();
SQLExpression keyIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), keyMapping);
subStmt.whereAnd(keyIdExpr.eq(keyExpr), true);
}
}
return new BooleanSubqueryExpression(stmt, "EXISTS", subStmt);
}
Aggregations