use of org.datanucleus.store.rdbms.sql.expression.UnboundExpression in project datanucleus-rdbms by datanucleus.
the class QueryToSQLMapper method processEqExpression.
/* (non-Javadoc)
* @see org.datanucleus.query.evaluator.AbstractExpressionEvaluator#processEqExpression(org.datanucleus.query.expression.Expression)
*/
protected Object processEqExpression(Expression expr) {
SQLExpression right = stack.pop();
SQLExpression left = stack.pop();
if (left instanceof ParameterLiteral && !(right instanceof ParameterLiteral)) {
left = replaceParameterLiteral((ParameterLiteral) left, right.getJavaTypeMapping());
} else if (right instanceof ParameterLiteral && !(left instanceof ParameterLiteral)) {
right = replaceParameterLiteral((ParameterLiteral) right, left.getJavaTypeMapping());
}
if (left.isParameter() && right.isParameter()) {
if (left.isParameter() && left instanceof SQLLiteral && ((SQLLiteral) left).getValue() != null) {
// Change this parameter to a plain literal
useParameterExpressionAsLiteral((SQLLiteral) left);
}
if (right.isParameter() && right instanceof SQLLiteral && ((SQLLiteral) right).getValue() != null) {
// Change this parameter to a plain literal
useParameterExpressionAsLiteral((SQLLiteral) right);
}
}
ExpressionUtils.checkAndCorrectExpressionMappingsForBooleanComparison(left, right);
if (left instanceof UnboundExpression) {
processUnboundExpression((UnboundExpression) left);
left = stack.pop();
}
if (right instanceof UnboundExpression) {
processUnboundExpression((UnboundExpression) right);
right = stack.pop();
}
// Logic for when one side is cross-joined (variable) and other side not, so transfer to a left outer join
if (!options.contains(OPTION_EXPLICIT_JOINS)) {
boolean leftIsCrossJoin = (stmt.getJoinTypeForTable(left.getSQLTable()) == JoinType.CROSS_JOIN);
boolean rightIsCrossJoin = (stmt.getJoinTypeForTable(right.getSQLTable()) == JoinType.CROSS_JOIN);
if (leftIsCrossJoin && !rightIsCrossJoin && !(right instanceof SQLLiteral)) {
// "a == b" and a is cross-joined currently (includes variable) so change to left outer join
String varName = getAliasForSQLTable(left.getSQLTable());
JoinType joinType = getRequiredJoinTypeForAlias(varName);
if (joinType != null) {
NucleusLogger.QUERY.debug("QueryToSQL.eq variable " + varName + " is mapped to table " + left.getSQLTable() + " was previously bound as CROSS JOIN but changing to " + joinType);
String leftTblAlias = stmt.removeCrossJoin(left.getSQLTable());
if (joinType == JoinType.LEFT_OUTER_JOIN) {
stmt.join(JoinType.LEFT_OUTER_JOIN, right.getSQLTable(), right.getJavaTypeMapping(), left.getSQLTable().getTable(), leftTblAlias, left.getJavaTypeMapping(), null, left.getSQLTable().getGroupName(), true);
} else {
stmt.join(JoinType.INNER_JOIN, right.getSQLTable(), right.getJavaTypeMapping(), left.getSQLTable().getTable(), leftTblAlias, left.getJavaTypeMapping(), null, left.getSQLTable().getGroupName(), true);
}
JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
SQLExpression opExpr = exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, true));
stack.push(opExpr);
return opExpr;
}
} else if (!leftIsCrossJoin && rightIsCrossJoin && !(left instanceof SQLLiteral)) {
// "a == b" and b is cross-joined currently (includes variable) so change to left outer join
String varName = getAliasForSQLTable(right.getSQLTable());
JoinType joinType = getRequiredJoinTypeForAlias(varName);
if (joinType != null) {
NucleusLogger.QUERY.debug("QueryToSQL.eq variable " + varName + " is mapped to table " + right.getSQLTable() + " was previously bound as CROSS JOIN but changing to " + joinType);
String rightTblAlias = stmt.removeCrossJoin(right.getSQLTable());
if (joinType == JoinType.LEFT_OUTER_JOIN) {
stmt.join(JoinType.LEFT_OUTER_JOIN, left.getSQLTable(), left.getJavaTypeMapping(), right.getSQLTable().getTable(), rightTblAlias, right.getJavaTypeMapping(), null, right.getSQLTable().getGroupName(), true);
} else {
stmt.join(JoinType.INNER_JOIN, left.getSQLTable(), left.getJavaTypeMapping(), right.getSQLTable().getTable(), rightTblAlias, right.getJavaTypeMapping(), null, right.getSQLTable().getGroupName(), true);
}
JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
SQLExpression opExpr = exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, true));
stack.push(opExpr);
return opExpr;
}
}
}
BooleanExpression opExpr = left.eq(right);
stack.push(opExpr);
return opExpr;
}
use of org.datanucleus.store.rdbms.sql.expression.UnboundExpression in project datanucleus-rdbms by datanucleus.
the class QueryToSQLMapper method compileResult.
/**
* Method to compile the result clause of the query into the SQLStatement.
* Note that this also compiles queries of the candidate (no specified result), selecting the candidate field(s).
* @param stmt SELECT statement
*/
protected void compileResult(SelectStatement stmt) {
compileComponent = CompilationComponent.RESULT;
boolean unionsPresent = stmt.getNumberOfUnions() > 0;
// TODO Cater for more expression types where we have UNIONs and select each UNION separately
if (compilation.getExprResult() != null) {
// Select any result expressions
Expression[] resultExprs = compilation.getExprResult();
for (int i = 0; i < resultExprs.length; i++) {
String alias = resultExprs[i].getAlias();
if (alias != null && resultAliases == null) {
resultAliases = new HashSet<>();
}
if (resultExprs[i] instanceof InvokeExpression || resultExprs[i] instanceof ParameterExpression || resultExprs[i] instanceof Literal) {
// Process expressions that need no special treatment
if (resultExprs[i] instanceof InvokeExpression) {
processInvokeExpression((InvokeExpression) resultExprs[i]);
} else if (resultExprs[i] instanceof ParameterExpression) {
// Second argument : parameters are literals in result
processParameterExpression((ParameterExpression) resultExprs[i], true);
} else {
processLiteral((Literal) resultExprs[i]);
}
SQLExpression sqlExpr = stack.pop();
validateExpressionForResult(sqlExpr);
int[] cols = stmt.select(sqlExpr, alias);
StatementMappingIndex idx = new StatementMappingIndex(sqlExpr.getJavaTypeMapping());
idx.setColumnPositions(cols);
if (alias != null) {
resultAliases.add(alias);
idx.setColumnAlias(alias);
}
resultDefinition.addMappingForResultExpression(i, idx);
} else if (resultExprs[i] instanceof PrimaryExpression) {
PrimaryExpression primExpr = (PrimaryExpression) resultExprs[i];
if (primExpr.getId().equals(candidateAlias)) {
// "this", so select fetch plan fields
if (unionsPresent) {
// Process the first union separately (in case they have TYPE/instanceof) and then handle remaining UNIONs below
stmt.setAllowUnions(false);
}
StatementClassMapping map = new StatementClassMapping(candidateCmd.getFullClassName(), null);
SQLStatementHelper.selectFetchPlanOfCandidateInStatement(stmt, map, candidateCmd, fetchPlan, 1);
resultDefinition.addMappingForResultExpression(i, map);
if (unionsPresent) {
// Process remaining UNIONs. Assumed that we have the same result mapping as the first UNION otherwise SQL wouldn't work anyway
stmt.setAllowUnions(true);
List<SelectStatement> unionStmts = stmt.getUnions();
SelectStatement originalStmt = stmt;
for (SelectStatement unionStmt : unionStmts) {
this.stmt = unionStmt;
unionStmt.setQueryGenerator(this);
unionStmt.setAllowUnions(false);
StatementClassMapping dummyClsMapping = new StatementClassMapping(candidateCmd.getFullClassName(), null);
SQLStatementHelper.selectFetchPlanOfCandidateInStatement(unionStmt, dummyClsMapping, candidateCmd, fetchPlan, 1);
unionStmt.setQueryGenerator(null);
unionStmt.setAllowUnions(true);
}
this.stmt = originalStmt;
}
} else {
processPrimaryExpression(primExpr);
SQLExpression sqlExpr = stack.pop();
validateExpressionForResult(sqlExpr);
if (primExpr.getId().endsWith("#KEY") || primExpr.getId().endsWith("#VALUE")) {
// JPQL KEY(map) or VALUE(map), so select FetchPlan fields where persistable
if (sqlExpr.getJavaTypeMapping() instanceof PersistableMapping) {
// Method returns persistable object, so select the FetchPlan
String selectedType = ((PersistableMapping) sqlExpr.getJavaTypeMapping()).getType();
AbstractClassMetaData selectedCmd = ec.getMetaDataManager().getMetaDataForClass(selectedType, clr);
FetchPlanForClass fpForCmd = fetchPlan.getFetchPlanForClass(selectedCmd);
int[] membersToSelect = fpForCmd.getMemberNumbers();
ClassTable selectedTable = (ClassTable) sqlExpr.getSQLTable().getTable();
StatementClassMapping map = new StatementClassMapping(selectedCmd.getFullClassName(), null);
if (selectedCmd.getIdentityType() == IdentityType.DATASTORE) {
int[] cols = stmt.select(sqlExpr.getSQLTable(), selectedTable.getSurrogateMapping(SurrogateColumnType.DATASTORE_ID, false), alias);
StatementMappingIndex idx = new StatementMappingIndex(selectedTable.getSurrogateMapping(SurrogateColumnType.DATASTORE_ID, false));
idx.setColumnPositions(cols);
map.addMappingForMember(SurrogateColumnType.DATASTORE_ID.getFieldNumber(), idx);
}
// Select the FetchPlan members
for (int memberToSelect : membersToSelect) {
AbstractMemberMetaData selMmd = selectedCmd.getMetaDataForManagedMemberAtAbsolutePosition(memberToSelect);
// TODO Arbitrary penultimate argument
SQLStatementHelper.selectMemberOfSourceInStatement(stmt, map, fetchPlan, sqlExpr.getSQLTable(), selMmd, clr, 1, null);
}
resultDefinition.addMappingForResultExpression(i, map);
continue;
} else if (sqlExpr.getJavaTypeMapping() instanceof EmbeddedMapping) {
// Method returns embedded object, so select the FetchPlan
EmbeddedMapping embMapping = (EmbeddedMapping) sqlExpr.getJavaTypeMapping();
AbstractClassMetaData selectedCmd = ec.getMetaDataManager().getMetaDataForClass(embMapping.getType(), clr);
// Select the FetchPlan members
StatementClassMapping map = new StatementClassMapping(selectedCmd.getFullClassName(), null);
int[] membersToSelect = fetchPlan.getFetchPlanForClass(selectedCmd).getMemberNumbers();
for (int memberToSelect : membersToSelect) {
AbstractMemberMetaData selMmd = selectedCmd.getMetaDataForManagedMemberAtAbsolutePosition(memberToSelect);
JavaTypeMapping selMapping = embMapping.getJavaTypeMapping(selMmd.getName());
if (selMapping.includeInFetchStatement()) {
int[] cols = stmt.select(sqlExpr.getSQLTable(), selMapping, alias);
StatementMappingIndex idx = new StatementMappingIndex(selMapping);
idx.setColumnPositions(cols);
map.addMappingForMember(memberToSelect, idx);
}
}
resultDefinition.addMappingForResultExpression(i, map);
continue;
}
}
// TODO If the user selects an alias here that is joined, should maybe respect FetchPlan for that (like above for candidate)
// TODO Cater for use of UNIONs (e.g "complete-table" inheritance) where mapping is different in other UNION
// The difficulty here is that processPrimaryExpression makes use of the sqlTableByPrimary lookup, which is based on the primary statement, so
// it still doesn't find the right table/mapping for the UNIONed statements.
int[] cols = null;
if (sqlExpr instanceof SQLLiteral) {
cols = stmt.select(sqlExpr, alias);
} else {
cols = stmt.select(sqlExpr.getSQLTable(), sqlExpr.getJavaTypeMapping(), alias);
}
StatementMappingIndex idx = new StatementMappingIndex(sqlExpr.getJavaTypeMapping());
idx.setColumnPositions(cols);
if (alias != null) {
resultAliases.add(alias);
idx.setColumnAlias(alias);
}
resultDefinition.addMappingForResultExpression(i, idx);
}
} else if (resultExprs[i] instanceof VariableExpression) {
// Subquery?
processVariableExpression((VariableExpression) resultExprs[i]);
SQLExpression sqlExpr = stack.pop();
validateExpressionForResult(sqlExpr);
if (sqlExpr instanceof UnboundExpression) {
// Variable wasn't bound in the compilation so far, so handle as cross-join
processUnboundExpression((UnboundExpression) sqlExpr);
sqlExpr = stack.pop();
NucleusLogger.QUERY.debug("QueryToSQL.exprResult variable was still unbound, so binding via cross-join");
}
int[] cols = stmt.select(sqlExpr, alias);
StatementMappingIndex idx = new StatementMappingIndex(sqlExpr.getJavaTypeMapping());
idx.setColumnPositions(cols);
if (alias != null) {
resultAliases.add(alias);
idx.setColumnAlias(alias);
}
resultDefinition.addMappingForResultExpression(i, idx);
} else if (resultExprs[i] instanceof TypeExpression) {
// TYPE(identification_variable | single_valued_path_expr | input_parameter)
TypeExpression typeExpr = (TypeExpression) resultExprs[i];
Expression containedExpr = typeExpr.getContainedExpression();
if (containedExpr instanceof PrimaryExpression) {
processPrimaryExpression((PrimaryExpression) containedExpr);
SQLExpression sqlExpr = stack.pop();
JavaTypeMapping discrimMapping = sqlExpr.getSQLTable().getTable().getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, true);
if (discrimMapping == null) {
// TODO If we have a UNIONED primary expression then it would be possible to just select the DN_TYPE from the particular union
throw new NucleusException("Result has call to " + typeExpr + " but contained expression has no discriminator. Not supported");
}
int[] cols = stmt.select(sqlExpr.getSQLTable(), discrimMapping, null, true);
StatementMappingIndex idx = new StatementMappingIndex(discrimMapping);
idx.setColumnPositions(cols);
resultDefinition.addMappingForResultExpression(i, idx);
} else {
throw new NucleusException("Result has call to " + typeExpr + " but contained expression not supported");
}
} else if (resultExprs[i] instanceof CreatorExpression) {
processCreatorExpression((CreatorExpression) resultExprs[i]);
NewObjectExpression sqlExpr = (NewObjectExpression) stack.pop();
StatementNewObjectMapping stmtMap = getStatementMappingForNewObjectExpression(sqlExpr, stmt);
resultDefinition.addMappingForResultExpression(i, stmtMap);
} else if (resultExprs[i] instanceof DyadicExpression || resultExprs[i] instanceof CaseExpression) {
if (unionsPresent) {
// Process the first union separately (in case they have TYPE/instanceof) and then handle remaining UNIONs below
stmt.setAllowUnions(false);
}
resultExprs[i].evaluate(this);
SQLExpression sqlExpr = stack.pop();
int[] cols = stmt.select(sqlExpr, alias);
StatementMappingIndex idx = new StatementMappingIndex(sqlExpr.getJavaTypeMapping());
idx.setColumnPositions(cols);
if (alias != null) {
resultAliases.add(alias);
idx.setColumnAlias(alias);
}
resultDefinition.addMappingForResultExpression(i, idx);
if (unionsPresent) {
// Process remaining UNIONs. Assumed that we have the same result mapping as the first UNION otherwise SQL wouldn't work anyway
stmt.setAllowUnions(true);
List<SelectStatement> unionStmts = stmt.getUnions();
SelectStatement originalStmt = stmt;
for (SelectStatement unionStmt : unionStmts) {
this.stmt = unionStmt;
unionStmt.setQueryGenerator(this);
unionStmt.setAllowUnions(false);
resultExprs[i].evaluate(this);
sqlExpr = stack.pop();
unionStmt.select(sqlExpr, alias);
unionStmt.setQueryGenerator(null);
unionStmt.setAllowUnions(true);
}
this.stmt = originalStmt;
}
} else {
throw new NucleusException("Dont currently support result clause containing expression of type " + resultExprs[i]);
}
}
if (stmt.getNumberOfSelects() == 0) {
// Nothing selected so likely the user had some "new MyClass()" expression, so select "1"
stmt.select(exprFactory.newLiteral(stmt, storeMgr.getMappingManager().getMapping(Integer.class), 1), null);
}
} else {
// Select of the candidate (no result)
if (candidateCmd.getIdentityType() == IdentityType.NONDURABLE) {
// Nondurable identity cases have no "id" for later fetching so get all fields now
if (NucleusLogger.QUERY.isDebugEnabled()) {
NucleusLogger.QUERY.debug(Localiser.msg("052520", candidateCmd.getFullClassName()));
}
fetchPlan.setGroup("all");
}
if (subclasses) {
// TODO Check for special case of candidate+subclasses stores in same table with discriminator, so select FetchGroup of subclasses also
}
int maxFetchDepth = fetchPlan.getMaxFetchDepth();
if (maxFetchDepth < 0) {
NucleusLogger.QUERY.debug("No limit specified on query fetch so limiting to 3 levels from candidate. " + "Specify the '" + PropertyNames.PROPERTY_MAX_FETCH_DEPTH + "' to override this");
// TODO Arbitrary
maxFetchDepth = 3;
}
// This means that we then cater for a UNION using a different column name than the primary statement
if (unionsPresent) {
// Process the first union separately (in case they have TYPE/instanceof) and then handle remaining UNIONs below
stmt.setAllowUnions(false);
}
selectFetchPlanForCandidate(stmt, resultDefinitionForClass, maxFetchDepth);
if (unionsPresent) {
// Process remaining UNIONs. Assumed that we have the same result mapping as the first UNION otherwise SQL wouldn't work anyway
stmt.setAllowUnions(true);
List<SelectStatement> unionStmts = stmt.getUnions();
SelectStatement originalStmt = stmt;
for (SelectStatement unionStmt : unionStmts) {
this.stmt = unionStmt;
unionStmt.setQueryGenerator(this);
unionStmt.setAllowUnions(false);
// We don't want to overwrite anything in the root StatementClassMapping
StatementClassMapping dummyResClsMapping = new StatementClassMapping();
selectFetchPlanForCandidate(unionStmt, dummyResClsMapping, maxFetchDepth);
unionStmt.setQueryGenerator(null);
unionStmt.setAllowUnions(true);
}
this.stmt = originalStmt;
}
}
compileComponent = null;
}
use of org.datanucleus.store.rdbms.sql.expression.UnboundExpression in project datanucleus-rdbms by datanucleus.
the class MapContainsEntryMethod method containsAsSubquery.
/**
* Method to return an expression for Map.containsEntry 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_VAL_ID = {valExpr}
* AND Ao_SUB.JOIN_KEY_ID = {keyExpr}
* </pre>
* </li>
* <li><b>Map with key stored in value</b>
* <pre>
* SELECT 1 FROM VAL_TABLE A0_SUB
* WHERE B0.JOIN_OWN_ID = A0.ID
* AND A0_SUB.ID = {valExpr}
* AND A0_SUB.KEY_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.VAL_ID = {valExpr}
* 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
* @param valExpr Expression for the value
* @return Contains expression
*/
protected SQLExpression containsAsSubquery(SQLStatement stmt, MapExpression mapExpr, SQLExpression keyExpr, SQLExpression valExpr) {
boolean keyIsUnbound = (keyExpr instanceof UnboundExpression);
String keyVarName = null;
if (keyIsUnbound) {
keyVarName = ((UnboundExpression) keyExpr).getVariableName();
NucleusLogger.QUERY.debug(">> Map.containsEntry binding unbound variable " + keyVarName + " using SUBQUERY");
// TODO What if the variable is declared as a subtype, handle this see CollectionContainsMethod
}
boolean valIsUnbound = (valExpr instanceof UnboundExpression);
String valVarName = null;
if (valIsUnbound) {
valVarName = ((UnboundExpression) valExpr).getVariableName();
NucleusLogger.QUERY.debug(">> Map.containsEntry binding unbound variable " + valVarName + " 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);
AbstractClassMetaData valCmd = mmd.getMap().getValueClassMetaData(clr);
MapTable joinTbl = (MapTable) storeMgr.getTable(mmd);
SelectStatement subStmt = null;
if (mmd.getMap().getMapType() == MapType.MAP_TYPE_JOIN) {
// JoinTable Map
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, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping());
subStmt.whereAnd(ownerExpr.eq(ownerIdExpr), true);
SQLExpression valIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), joinTbl.getValueMapping());
if (valIsUnbound) {
// Bind the variable in the QueryGenerator
stmt.getQueryGenerator().bindVariable(valVarName, valCmd, valIdExpr.getSQLTable(), valIdExpr.getJavaTypeMapping());
} else {
// Add restrict to value TODO Add join to valueTbl if present
subStmt.whereAnd(valIdExpr.eq(valExpr), true);
}
SQLExpression keyIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), joinTbl.getKeyMapping());
if (keyIsUnbound) {
// Bind the variable in the QueryGenerator
stmt.getQueryGenerator().bindVariable(keyVarName, keyCmd, keyIdExpr.getSQLTable(), keyIdExpr.getJavaTypeMapping());
} else {
// Add restrict to key TODO Add join to keyTbl if present
subStmt.whereAnd(keyIdExpr.eq(keyExpr), true);
}
} else if (mmd.getMap().getMapType() == MapType.MAP_TYPE_KEY_IN_VALUE) {
// Key stored in value table
DatastoreClass valTbl = storeMgr.getDatastoreClass(mmd.getMap().getValueType(), clr);
AbstractMemberMetaData valKeyMmd = valCmd.getMetaDataForMember(mmd.getKeyMetaData().getMappedBy());
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)
JavaTypeMapping ownerMapping = null;
if (mmd.getMappedBy() != null) {
ownerMapping = valTbl.getMemberMapping(valCmd.getMetaDataForMember(mmd.getMappedBy()));
} else {
ownerMapping = valTbl.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
}
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);
SQLExpression valIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), valTbl.getIdMapping());
if (valIsUnbound) {
// Bind the variable in the QueryGenerator
stmt.getQueryGenerator().bindVariable(valVarName, valCmd, valIdExpr.getSQLTable(), valIdExpr.getJavaTypeMapping());
} else {
// Add restrict to value
subStmt.whereAnd(valIdExpr.eq(valExpr), true);
}
SQLExpression keyIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), valTbl.getMemberMapping(valKeyMmd));
if (keyIsUnbound) {
// Bind the variable in the QueryGenerator
stmt.getQueryGenerator().bindVariable(keyVarName, keyCmd, keyIdExpr.getSQLTable(), keyIdExpr.getJavaTypeMapping());
} else {
// Add restrict to key TODO Add join to keyTbl if present
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);
}
AbstractMemberMetaData keyValMmd = keyCmd.getMetaDataForMember(mmd.getValueMetaData().getMappedBy());
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);
SQLExpression valIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), keyTbl.getMemberMapping(keyValMmd));
if (valIsUnbound) {
// Bind the variable in the QueryGenerator
stmt.getQueryGenerator().bindVariable(valVarName, valCmd, valIdExpr.getSQLTable(), valIdExpr.getJavaTypeMapping());
} else {
// Add restrict to value TODO Add join to valTbl if present
subStmt.whereAnd(valIdExpr.eq(valExpr), true);
}
JavaTypeMapping keyMapping = keyTbl.getIdMapping();
SQLExpression keyIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), keyMapping);
if (keyIsUnbound) {
// Bind the variable in the QueryGenerator
stmt.getQueryGenerator().bindVariable(keyVarName, keyCmd, keyIdExpr.getSQLTable(), keyIdExpr.getJavaTypeMapping());
} else {
// Add restrict to key
subStmt.whereAnd(keyIdExpr.eq(keyExpr), true);
}
}
return new BooleanSubqueryExpression(stmt, "EXISTS", subStmt);
}
use of org.datanucleus.store.rdbms.sql.expression.UnboundExpression in project datanucleus-rdbms by datanucleus.
the class MapContainsEntryMethod method containsAsInnerJoin.
/**
* Method to return an expression for Map.containsEntry using INNER JOIN to the element.
* This is only for use when there are no "!containsEntry" and no "OR" operations.
* Creates SQL by adding INNER JOIN to the join table (where it exists), and also to the value table
* adding an AND condition on the value (with value of the valueExpr).
* Returns a BooleanExpression "TRUE" (since the INNER JOIN will guarantee if the entry is
* contained of not).
* @param stmt SQLStatement
* @param mapExpr Map expression
* @param keyExpr Expression for the key
* @param valExpr Expression for the value
* @return Contains expression
*/
protected SQLExpression containsAsInnerJoin(SQLStatement stmt, MapExpression mapExpr, SQLExpression keyExpr, SQLExpression valExpr) {
boolean keyIsUnbound = (keyExpr instanceof UnboundExpression);
String keyVarName = null;
if (keyIsUnbound) {
keyVarName = ((UnboundExpression) keyExpr).getVariableName();
NucleusLogger.QUERY.debug(">> Map.containsEntry binding unbound variable " + keyVarName + " using INNER JOIN");
// TODO What if the variable is declared as a subtype, handle this see CollectionContainsMethod
}
boolean valIsUnbound = (valExpr instanceof UnboundExpression);
String valVarName = null;
if (valIsUnbound) {
valVarName = ((UnboundExpression) valExpr).getVariableName();
NucleusLogger.QUERY.debug(">> Map.containsEntry binding unbound variable " + valVarName + " using INNER JOIN");
// 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);
AbstractClassMetaData valCmd = mmd.getMap().getValueClassMetaData(clr);
if (mmd.getMap().getMapType() == MapType.MAP_TYPE_JOIN) {
// Map formed in join table - add join to join table, then to key/value tables (if present)
MapTable mapTbl = (MapTable) storeMgr.getTable(mmd);
SQLTable joinSqlTbl = stmt.join(JoinType.INNER_JOIN, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping(), mapTbl, null, mapTbl.getOwnerMapping(), null, null);
if (valCmd != null) {
DatastoreClass valTbl = storeMgr.getDatastoreClass(valCmd.getFullClassName(), clr);
SQLTable valSqlTbl = stmt.join(JoinType.INNER_JOIN, joinSqlTbl, mapTbl.getValueMapping(), valTbl, null, valTbl.getIdMapping(), null, null);
SQLExpression valIdExpr = exprFactory.newExpression(stmt, valSqlTbl, valTbl.getIdMapping());
if (valIsUnbound) {
// Bind the variable in the QueryGenerator
stmt.getQueryGenerator().bindVariable(valVarName, valCmd, valIdExpr.getSQLTable(), valIdExpr.getJavaTypeMapping());
} else {
// Add restrict to value
stmt.whereAnd(valIdExpr.eq(valExpr), true);
}
} else {
SQLExpression valIdExpr = exprFactory.newExpression(stmt, joinSqlTbl, mapTbl.getValueMapping());
if (valIsUnbound) {
// Bind the variable in the QueryGenerator
stmt.getQueryGenerator().bindVariable(valVarName, null, valIdExpr.getSQLTable(), valIdExpr.getJavaTypeMapping());
} else {
// Add restrict to value
stmt.whereAnd(valIdExpr.eq(valExpr), true);
}
}
if (keyCmd != null) {
DatastoreClass keyTbl = storeMgr.getDatastoreClass(keyCmd.getFullClassName(), clr);
SQLTable keySqlTbl = stmt.join(JoinType.INNER_JOIN, joinSqlTbl, mapTbl.getKeyMapping(), keyTbl, null, keyTbl.getIdMapping(), null, null);
SQLExpression keyIdExpr = exprFactory.newExpression(stmt, keySqlTbl, keyTbl.getIdMapping());
if (keyIsUnbound) {
// Bind the variable in the QueryGenerator
stmt.getQueryGenerator().bindVariable(keyVarName, keyCmd, keyIdExpr.getSQLTable(), keyIdExpr.getJavaTypeMapping());
} else {
// Add restrict to key
stmt.whereAnd(keyIdExpr.eq(keyExpr), true);
}
} else {
SQLExpression keyIdExpr = exprFactory.newExpression(stmt, joinSqlTbl, mapTbl.getKeyMapping());
if (keyIsUnbound) {
// Bind the variable in the QueryGenerator
stmt.getQueryGenerator().bindVariable(keyVarName, null, keyIdExpr.getSQLTable(), keyIdExpr.getJavaTypeMapping());
} else {
// Add restrict to key
stmt.whereAnd(keyIdExpr.eq(keyExpr), true);
}
}
} else if (mmd.getMap().getMapType() == MapType.MAP_TYPE_KEY_IN_VALUE) {
// Map formed in value table - add join to value table, then to key table (if present)
DatastoreClass valTbl = storeMgr.getDatastoreClass(valCmd.getFullClassName(), clr);
JavaTypeMapping ownerMapping = null;
if (mmd.getMappedBy() != null) {
ownerMapping = valTbl.getMemberMapping(valCmd.getMetaDataForMember(mmd.getMappedBy()));
} else {
ownerMapping = valTbl.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
}
SQLTable valSqlTbl = stmt.join(JoinType.INNER_JOIN, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping(), valTbl, null, ownerMapping, null, null);
SQLExpression valIdExpr = exprFactory.newExpression(stmt, valSqlTbl, valTbl.getIdMapping());
if (valIsUnbound) {
// Bind the variable in the QueryGenerator
stmt.getQueryGenerator().bindVariable(valVarName, valCmd, valIdExpr.getSQLTable(), valIdExpr.getJavaTypeMapping());
} else {
// Add restrict to value
stmt.whereAnd(valIdExpr.eq(valExpr), true);
}
if (keyCmd != null) {
// Add inner join to key table
AbstractMemberMetaData valKeyMmd = valCmd.getMetaDataForMember(mmd.getKeyMetaData().getMappedBy());
DatastoreClass keyTbl = storeMgr.getDatastoreClass(keyCmd.getFullClassName(), clr);
SQLTable keySqlTbl = stmt.join(JoinType.INNER_JOIN, valSqlTbl, valTbl.getMemberMapping(valKeyMmd), keyTbl, null, keyTbl.getIdMapping(), null, null);
SQLExpression keyIdExpr = exprFactory.newExpression(stmt, keySqlTbl, keyTbl.getIdMapping());
if (keyIsUnbound) {
// Bind the variable in the QueryGenerator
stmt.getQueryGenerator().bindVariable(keyVarName, keyCmd, keyIdExpr.getSQLTable(), keyIdExpr.getJavaTypeMapping());
} else {
// Add restriction to key
stmt.whereAnd(keyIdExpr.eq(keyExpr), true);
}
} else {
AbstractMemberMetaData valKeyMmd = valCmd.getMetaDataForMember(mmd.getKeyMetaData().getMappedBy());
SQLExpression keyIdExpr = exprFactory.newExpression(stmt, valSqlTbl, valTbl.getMemberMapping(valKeyMmd));
if (keyIsUnbound) {
// Bind the variable in the QueryGenerator
stmt.getQueryGenerator().bindVariable(keyVarName, keyCmd, keyIdExpr.getSQLTable(), keyIdExpr.getJavaTypeMapping());
} else {
// Add restriction to key
stmt.whereAnd(keyIdExpr.eq(keyExpr), true);
}
}
} else if (mmd.getMap().getMapType() == MapType.MAP_TYPE_VALUE_IN_KEY) {
// Map formed in key table - add join to key table then to value table (if present)
DatastoreClass keyTbl = storeMgr.getDatastoreClass(keyCmd.getFullClassName(), clr);
AbstractMemberMetaData keyValMmd = keyCmd.getMetaDataForMember(mmd.getValueMetaData().getMappedBy());
JavaTypeMapping ownerMapping = null;
if (mmd.getMappedBy() != null) {
ownerMapping = keyTbl.getMemberMapping(keyCmd.getMetaDataForMember(mmd.getMappedBy()));
} else {
ownerMapping = keyTbl.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
}
SQLTable keySqlTbl = stmt.join(JoinType.INNER_JOIN, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping(), keyTbl, null, ownerMapping, null, null);
SQLExpression keyIdExpr = exprFactory.newExpression(stmt, keySqlTbl, keyTbl.getIdMapping());
if (keyIsUnbound) {
// Bind the variable in the QueryGenerator
stmt.getQueryGenerator().bindVariable(keyVarName, keyCmd, keyIdExpr.getSQLTable(), keyIdExpr.getJavaTypeMapping());
} else {
// Add restrict to key
stmt.whereAnd(keyIdExpr.eq(keyExpr), true);
}
if (valCmd != null) {
// Add inner join to value table
DatastoreClass valTbl = storeMgr.getDatastoreClass(valCmd.getFullClassName(), clr);
SQLTable valSqlTbl = stmt.join(JoinType.INNER_JOIN, keySqlTbl, keyTbl.getMemberMapping(keyValMmd), valTbl, null, valTbl.getIdMapping(), null, null);
SQLExpression valIdExpr = exprFactory.newExpression(stmt, valSqlTbl, valTbl.getIdMapping());
if (valIsUnbound) {
// Bind the variable in the QueryGenerator
stmt.getQueryGenerator().bindVariable(valVarName, valCmd, valIdExpr.getSQLTable(), valIdExpr.getJavaTypeMapping());
} else {
// Add restrict to value
stmt.whereAnd(valIdExpr.eq(valExpr), true);
}
} else {
SQLExpression valIdExpr = exprFactory.newExpression(stmt, keySqlTbl, keyTbl.getMemberMapping(keyValMmd));
if (valIsUnbound) {
// Bind the variable in the QueryGenerator
stmt.getQueryGenerator().bindVariable(valVarName, null, valIdExpr.getSQLTable(), valIdExpr.getJavaTypeMapping());
} else {
// Add restrict to value
stmt.whereAnd(valIdExpr.eq(valExpr), true);
}
}
}
JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, true));
}
use of org.datanucleus.store.rdbms.sql.expression.UnboundExpression in project datanucleus-rdbms by datanucleus.
the class MapContainsKeyMethod method containsAsJoin.
/**
* Method to return an expression for Map.containsKey using INNER JOIN to the element.
* This is only for use when there are no "!containsKey" and no "OR" operations.
* Creates SQL by adding INNER JOIN to the join table (where it exists), and also to the key table
* adding an AND condition on the element (with value of the keyExpr).
* Returns a BooleanExpression "TRUE" (since the INNER JOIN will guarantee if the key is contained of not).
* @param stmt SQLStatement
* @param mapExpr Map expression
* @param keyExpr Expression for the key
* @param joinType Type of join
* @return Contains expression
*/
protected SQLExpression containsAsJoin(SQLStatement stmt, MapExpression mapExpr, SQLExpression keyExpr, JoinType joinType) {
boolean keyIsUnbound = (keyExpr instanceof UnboundExpression);
String varName = null;
String keyAlias = null;
if (keyIsUnbound) {
varName = ((UnboundExpression) keyExpr).getVariableName();
NucleusLogger.QUERY.debug("map.containsKey(" + keyExpr + ") binding unbound variable " + varName + " using INNER JOIN");
// TODO What if the variable is declared as a subtype, handle this see CollectionContainsMethod
} else if (!stmt.getQueryGenerator().hasExplicitJoins()) {
if (stmt.getJoinTypeForTable(keyExpr.getSQLTable()) == JoinType.CROSS_JOIN) {
keyAlias = stmt.removeCrossJoin(keyExpr.getSQLTable());
keyIsUnbound = true;
NucleusLogger.QUERY.debug("map.containsKey(" + keyExpr + ") was previously bound as CROSS JOIN but changing to INNER JOIN");
}
}
RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
SQLExpressionFactory exprFactory = stmt.getSQLExpressionFactory();
ClassLoaderResolver clr = stmt.getQueryGenerator().getClassLoaderResolver();
AbstractMemberMetaData mmd = mapExpr.getJavaTypeMapping().getMemberMetaData();
AbstractClassMetaData keyCmd = mmd.getMap().getKeyClassMetaData(clr);
if (mmd.getMap().getMapType() == MapType.MAP_TYPE_JOIN) {
// Map formed in join table - add join to join table, then to key table (if present)
MapTable mapTbl = (MapTable) storeMgr.getTable(mmd);
SQLTable joinSqlTbl = stmt.join(joinType, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping(), mapTbl, null, mapTbl.getOwnerMapping(), null, null);
if (keyCmd != null) {
if (keyIsUnbound) {
DatastoreClass keyTbl = storeMgr.getDatastoreClass(keyCmd.getFullClassName(), clr);
SQLTable keySqlTbl = stmt.join(joinType, joinSqlTbl, mapTbl.getKeyMapping(), keyTbl, keyAlias, keyTbl.getIdMapping(), null, null);
// Bind the variable in the QueryGenerator
keyExpr = exprFactory.newExpression(stmt, keySqlTbl, keyTbl.getIdMapping());
stmt.getQueryGenerator().bindVariable(varName, keyCmd, keyExpr.getSQLTable(), keyExpr.getJavaTypeMapping());
} else {
// Add restrict to key
SQLExpression keyIdExpr = exprFactory.newExpression(stmt, joinSqlTbl, mapTbl.getKeyMapping());
stmt.whereAnd(keyIdExpr.eq(keyExpr), true);
}
} else {
if (keyIsUnbound) {
// Bind the variable in the QueryGenerator
keyExpr = exprFactory.newExpression(stmt, joinSqlTbl, mapTbl.getKeyMapping());
stmt.getQueryGenerator().bindVariable(varName, null, keyExpr.getSQLTable(), keyExpr.getJavaTypeMapping());
} else {
// Add restrict to key
SQLExpression keyIdExpr = exprFactory.newExpression(stmt, joinSqlTbl, mapTbl.getKeyMapping());
stmt.whereAnd(keyIdExpr.eq(keyExpr), true);
}
}
} else if (mmd.getMap().getMapType() == MapType.MAP_TYPE_KEY_IN_VALUE) {
// Map formed in value table - add join to value table, then to key table
AbstractClassMetaData valCmd = mmd.getMap().getValueClassMetaData(clr);
DatastoreClass valTbl = storeMgr.getDatastoreClass(valCmd.getFullClassName(), clr);
AbstractMemberMetaData valKeyMmd = valCmd.getMetaDataForMember(mmd.getKeyMetaData().getMappedBy());
JavaTypeMapping ownerMapping = null;
if (mmd.getMappedBy() != null) {
ownerMapping = valTbl.getMemberMapping(valCmd.getMetaDataForMember(mmd.getMappedBy()));
} else {
ownerMapping = valTbl.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
}
SQLTable valSqlTbl = stmt.join(joinType, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping(), valTbl, null, ownerMapping, null, null);
if (keyCmd != null) {
DatastoreClass keyTbl = storeMgr.getDatastoreClass(keyCmd.getFullClassName(), clr);
SQLTable keySqlTbl = stmt.join(joinType, valSqlTbl, valTbl.getMemberMapping(valKeyMmd), keyTbl, keyAlias, keyTbl.getIdMapping(), null, null);
if (keyIsUnbound) {
// Bind the variable in the QueryGenerator
keyExpr = exprFactory.newExpression(stmt, keySqlTbl, keyTbl.getIdMapping());
stmt.getQueryGenerator().bindVariable(varName, keyCmd, keyExpr.getSQLTable(), keyExpr.getJavaTypeMapping());
} else {
// Add restrict to key
SQLExpression keyIdExpr = exprFactory.newExpression(stmt, keySqlTbl, keyTbl.getIdMapping());
stmt.whereAnd(keyIdExpr.eq(keyExpr), true);
}
} else {
if (keyIsUnbound) {
// Bind the variable in the QueryGenerator
keyExpr = exprFactory.newExpression(stmt, valSqlTbl, valTbl.getMemberMapping(valKeyMmd));
stmt.getQueryGenerator().bindVariable(varName, null, keyExpr.getSQLTable(), keyExpr.getJavaTypeMapping());
} else {
// Add restrict to key
SQLExpression keyIdExpr = exprFactory.newExpression(stmt, valSqlTbl, valTbl.getMemberMapping(valKeyMmd));
stmt.whereAnd(keyIdExpr.eq(keyExpr), true);
}
}
} else if (mmd.getMap().getMapType() == MapType.MAP_TYPE_VALUE_IN_KEY) {
// Map formed in key table - add join to key table
DatastoreClass keyTbl = storeMgr.getDatastoreClass(keyCmd.getFullClassName(), clr);
JavaTypeMapping ownerMapping = null;
if (mmd.getMappedBy() != null) {
ownerMapping = keyTbl.getMemberMapping(keyCmd.getMetaDataForMember(mmd.getMappedBy()));
} else {
ownerMapping = keyTbl.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
}
SQLTable keySqlTbl = stmt.join(joinType, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping(), keyTbl, keyAlias, ownerMapping, null, null);
if (keyIsUnbound) {
// Bind the variable in the QueryGenerator
keyExpr = exprFactory.newExpression(stmt, keySqlTbl, keyTbl.getIdMapping());
stmt.getQueryGenerator().bindVariable(varName, keyCmd, keyExpr.getSQLTable(), keyExpr.getJavaTypeMapping());
} else {
// Add restrict to key
SQLExpression keyIdExpr = exprFactory.newExpression(stmt, keySqlTbl, keyTbl.getIdMapping());
stmt.whereAnd(keyIdExpr.eq(keyExpr), true);
}
}
JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, true));
}
Aggregations