use of org.datanucleus.store.rdbms.sql.expression.MapExpression in project datanucleus-rdbms by datanucleus.
the class QueryToSQLMapper method processPrimaryExpression.
/* (non-Javadoc)
* @see org.datanucleus.query.evaluator.AbstractExpressionEvaluator#processPrimaryExpression(org.datanucleus.query.expression.PrimaryExpression)
*/
protected Object processPrimaryExpression(PrimaryExpression expr) {
SQLExpression sqlExpr = null;
if (expr.getLeft() != null) {
if (expr.getLeft() instanceof DyadicExpression && expr.getLeft().getOperator() == Expression.OP_CAST) {
String exprCastName = null;
if (expr.getLeft().getLeft() instanceof PrimaryExpression) {
exprCastName = "CAST_" + ((PrimaryExpression) expr.getLeft().getLeft()).getId();
} else if (expr.getLeft().getLeft() instanceof VariableExpression) {
exprCastName = "CAST_" + ((VariableExpression) expr.getLeft().getLeft()).getId();
} else if (expr.getLeft().getLeft() instanceof InvokeExpression) {
exprCastName = "CAST_" + expr.getLeft().getLeft();
} else {
throw new NucleusException("Don't currently support cast of " + expr.getLeft().getLeft());
}
expr.getLeft().getLeft().evaluate(this);
sqlExpr = stack.pop();
JavaTypeMapping mapping = sqlExpr.getJavaTypeMapping();
if (mapping instanceof EmbeddedMapping) {
// Cast of an embedded field, so use same table
// Extract what we are casting it to
Literal castLitExpr = (Literal) expr.getLeft().getRight();
Class castType = resolveClass((String) castLitExpr.getLiteral());
AbstractClassMetaData castCmd = ec.getMetaDataManager().getMetaDataForClass(castType, clr);
JavaTypeMapping discMapping = ((EmbeddedMapping) mapping).getDiscriminatorMapping();
if (discMapping != null) {
// Should have a discriminator always when casting this
SQLExpression discExpr = exprFactory.newExpression(stmt, sqlExpr.getSQLTable(), discMapping);
Object discVal = castCmd.getDiscriminatorValue();
SQLExpression discValExpr = exprFactory.newLiteral(stmt, discMapping, discVal);
BooleanExpression discRestrictExpr = discExpr.eq(discValExpr);
Iterator<String> subclassIter = storeMgr.getSubClassesForClass(castType.getName(), true, clr).iterator();
while (subclassIter.hasNext()) {
String subclassName = subclassIter.next();
AbstractClassMetaData subtypeCmd = storeMgr.getMetaDataManager().getMetaDataForClass(subclassName, clr);
discVal = subtypeCmd.getDiscriminatorValue();
discValExpr = exprFactory.newLiteral(stmt, discMapping, discVal);
BooleanExpression subtypeExpr = discExpr.eq(discValExpr);
discRestrictExpr = discRestrictExpr.ior(subtypeExpr);
}
stmt.whereAnd(discRestrictExpr, true);
}
SQLTableMapping tblMapping = new SQLTableMapping(sqlExpr.getSQLTable(), castCmd, sqlExpr.getJavaTypeMapping());
setSQLTableMappingForAlias(exprCastName, tblMapping);
SQLTableMapping sqlMapping = getSQLTableMappingForPrimaryExpression(stmt, exprCastName, expr, Boolean.FALSE);
if (sqlMapping == null) {
throw new NucleusException("PrimaryExpression " + expr + " is not yet supported");
}
sqlExpr = exprFactory.newExpression(stmt, sqlMapping.table, sqlMapping.mapping);
stack.push(sqlExpr);
return sqlExpr;
}
// Evaluate the cast
expr.getLeft().evaluate(this);
sqlExpr = stack.pop();
// Extract what we are casting it to
Literal castLitExpr = (Literal) expr.getLeft().getRight();
AbstractClassMetaData castCmd = ec.getMetaDataManager().getMetaDataForClass(resolveClass((String) castLitExpr.getLiteral()), clr);
SQLTableMapping tblMapping = new SQLTableMapping(sqlExpr.getSQLTable(), castCmd, sqlExpr.getJavaTypeMapping());
setSQLTableMappingForAlias(exprCastName, tblMapping);
SQLTableMapping sqlMapping = getSQLTableMappingForPrimaryExpression(stmt, exprCastName, expr, Boolean.FALSE);
if (sqlMapping == null) {
throw new NucleusException("PrimaryExpression " + expr + " is not yet supported");
}
sqlExpr = exprFactory.newExpression(stmt, sqlMapping.table, sqlMapping.mapping);
stack.push(sqlExpr);
return sqlExpr;
} else if (expr.getLeft() instanceof ParameterExpression) {
// "{paramExpr}.field[.field[.field]]"
// Need parameter values to process this
setNotPrecompilable();
ParameterExpression paramExpr = (ParameterExpression) expr.getLeft();
Symbol paramSym = compilation.getSymbolTable().getSymbol(paramExpr.getId());
if (paramSym.getValueType() != null && paramSym.getValueType().isArray()) {
// Special case : array "methods" (particularly "length")
String first = expr.getTuples().get(0);
processParameterExpression(paramExpr, true);
SQLExpression paramSqlExpr = stack.pop();
sqlExpr = exprFactory.invokeMethod(stmt, "ARRAY", first, paramSqlExpr, null);
stack.push(sqlExpr);
return sqlExpr;
}
// Create Literal for the parameter (since we need to perform operations on it)
processParameterExpression(paramExpr, true);
SQLExpression paramSqlExpr = stack.pop();
SQLLiteral lit = (SQLLiteral) paramSqlExpr;
Object paramValue = lit.getValue();
List<String> tuples = expr.getTuples();
Iterator<String> tuplesIter = tuples.iterator();
Object objValue = paramValue;
while (tuplesIter.hasNext()) {
String fieldName = tuplesIter.next();
if (objValue == null) {
NucleusLogger.QUERY.warn(">> Compilation of " + expr + " : need to direct through field \"" + fieldName + "\" on null value, hence not compilable!");
// Null value, and we have further path to navigate TODO Handle this "NPE"
break;
}
objValue = getValueForObjectField(objValue, fieldName);
// Using literal value of parameter, so cannot precompile it
setNotPrecompilable();
}
if (objValue == null) {
sqlExpr = exprFactory.newLiteral(stmt, null, null);
stack.push(sqlExpr);
return sqlExpr;
}
JavaTypeMapping m = exprFactory.getMappingForType(objValue.getClass(), false);
sqlExpr = exprFactory.newLiteral(stmt, m, objValue);
stack.push(sqlExpr);
return sqlExpr;
} else if (expr.getLeft() instanceof VariableExpression) {
// "{varExpr}.field[.field[.field]]"
VariableExpression varExpr = (VariableExpression) expr.getLeft();
processVariableExpression(varExpr);
SQLExpression varSqlExpr = stack.pop();
if (varSqlExpr instanceof UnboundExpression) {
// Bind as CROSS JOIN for now
processUnboundExpression((UnboundExpression) varSqlExpr);
varSqlExpr = stack.pop();
}
Class varType = clr.classForName(varSqlExpr.getJavaTypeMapping().getType());
if (varSqlExpr.getSQLStatement() == stmt.getParentStatement()) {
// Use parent mapper to get the mapping for this field since it has the table
SQLTableMapping sqlMapping = parentMapper.getSQLTableMappingForPrimaryExpression(stmt, null, expr, Boolean.FALSE);
if (sqlMapping == null) {
throw new NucleusException("PrimaryExpression " + expr.getId() + " is not yet supported");
}
// TODO Cater for the table required to join to not being the primary table of the outer query
// This should check on
// getDatastoreAdapter().supportsOption(RDBMSAdapter.ACCESS_PARENTQUERY_IN_SUBQUERY))
sqlExpr = exprFactory.newExpression(varSqlExpr.getSQLStatement(), sqlMapping.table, sqlMapping.mapping);
stack.push(sqlExpr);
return sqlExpr;
}
SQLTableMapping varTblMapping = getSQLTableMappingForAlias(varExpr.getId());
if (varTblMapping == null) {
throw new NucleusUserException("Variable " + varExpr.getId() + " is not yet bound, so cannot get field " + expr.getId());
}
if (varTblMapping.cmd == null) {
throw new NucleusUserException("Variable " + varExpr.getId() + " of type " + varType.getName() + " cannot evaluate " + expr.getId());
}
SQLTableMapping sqlMapping = getSQLTableMappingForPrimaryExpression(varSqlExpr.getSQLStatement(), varExpr.getId(), expr, Boolean.FALSE);
sqlExpr = exprFactory.newExpression(sqlMapping.table.getSQLStatement(), sqlMapping.table, sqlMapping.mapping);
stack.push(sqlExpr);
return sqlExpr;
} else if (expr.getLeft() instanceof InvokeExpression) {
InvokeExpression invokeExpr = (InvokeExpression) expr.getLeft();
SQLExpression invokedSqlExpr = getInvokedSqlExpressionForInvokeExpression(invokeExpr);
processInvokeExpression(invokeExpr, invokedSqlExpr);
SQLExpression invokeSqlExpr = stack.pop();
Table tbl = invokeSqlExpr.getSQLTable().getTable();
if (expr.getTuples().size() > 1) {
throw new NucleusUserException("Dont currently support evaluating " + expr.getId() + " on " + invokeSqlExpr);
}
SQLTable invokeSqlTbl = invokeSqlExpr.getSQLTable();
if (invokedSqlExpr.getJavaTypeMapping() instanceof OptionalMapping && invokeExpr.getOperation().equals("get") && expr.getTuples().size() == 1) {
OptionalMapping opMapping = (OptionalMapping) invokedSqlExpr.getJavaTypeMapping();
if (opMapping.getWrappedMapping() instanceof PersistableMapping) {
// Special case of Optional.get().{field}, so we need to join to the related table
AbstractMemberMetaData mmd = invokedSqlExpr.getJavaTypeMapping().getMemberMetaData();
AbstractClassMetaData otherCmd = ec.getMetaDataManager().getMetaDataForClass(mmd.getCollection().getElementType(), clr);
Table otherTbl = storeMgr.getDatastoreClass(otherCmd.getFullClassName(), clr);
// Optional type so do LEFT OUTER JOIN since if it is null then we would eliminate all other results
invokeSqlTbl = stmt.join(JoinType.LEFT_OUTER_JOIN, invokeSqlExpr.getSQLTable(), opMapping.getWrappedMapping(), otherTbl, null, otherTbl.getIdMapping(), null, null, true);
tbl = invokeSqlTbl.getTable();
}
}
if (tbl instanceof DatastoreClass) {
// Table of a class, so assume to have field in the table of the class
// TODO Allow joins to superclasses if required
JavaTypeMapping mapping = ((DatastoreClass) tbl).getMemberMapping(expr.getId());
if (mapping == null) {
throw new NucleusUserException("Dont currently support evaluating " + expr.getId() + " on " + invokeSqlExpr + ". The field " + expr.getId() + " doesnt exist in table " + tbl);
}
sqlExpr = exprFactory.newExpression(stmt, invokeSqlTbl, mapping);
stack.push(sqlExpr);
return sqlExpr;
} else if (tbl instanceof JoinTable) {
if (invokeSqlExpr.getJavaTypeMapping() instanceof EmbeddedMapping) {
// Table containing an embedded element/key/value so assume we have a column in the join table
EmbeddedMapping embMapping = (EmbeddedMapping) invokeSqlExpr.getJavaTypeMapping();
JavaTypeMapping mapping = embMapping.getJavaTypeMapping(expr.getId());
if (mapping == null) {
throw new NucleusUserException("Dont currently support evaluating " + expr.getId() + " on " + invokeSqlExpr + ". The field " + expr.getId() + " doesnt exist in table " + tbl);
}
sqlExpr = exprFactory.newExpression(stmt, invokeSqlTbl, mapping);
stack.push(sqlExpr);
return sqlExpr;
}
}
throw new NucleusUserException("Dont currently support evaluating " + expr.getId() + " on " + invokeSqlExpr + " with invoke having table of " + tbl);
} else {
throw new NucleusUserException("Dont currently support PrimaryExpression with 'left' of " + expr.getLeft());
}
}
// Real primary expression ("field.field", "alias.field.field" etc)
SQLTableMapping sqlMapping = getSQLTableMappingForPrimaryExpression(stmt, null, expr, null);
if (sqlMapping == null) {
throw new NucleusException("PrimaryExpression " + expr.getId() + " is not yet supported");
}
sqlExpr = exprFactory.newExpression(stmt, sqlMapping.table, sqlMapping.mapping);
if (sqlMapping.mmd != null && sqlExpr instanceof MapExpression) {
// This sqlMapping is for something joined in a FROM clause, so set the alias on the returned MapExpression to avoid doing the same joins
String alias = getAliasForSQLTableMapping(sqlMapping);
if (alias == null && parentMapper != null) {
alias = parentMapper.getAliasForSQLTableMapping(sqlMapping);
}
((MapExpression) sqlExpr).setAliasForMapTable(alias);
}
stack.push(sqlExpr);
return sqlExpr;
}
use of org.datanucleus.store.rdbms.sql.expression.MapExpression in project datanucleus-rdbms by datanucleus.
the class MapContainsKeyMethod method getExpression.
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.sql.method.SQLMethod#getExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression, java.util.List)
*/
public SQLExpression getExpression(SQLStatement stmt, SQLExpression expr, List<SQLExpression> args) {
if (args == null || args.size() == 0 || args.size() > 1) {
throw new NucleusException(Localiser.msg("060016", "containsKey", "MapExpression", 1));
}
MapExpression mapExpr = (MapExpression) expr;
SQLExpression keyExpr = args.get(0);
if (keyExpr.isParameter()) {
// Key is a parameter so make sure its type is set
AbstractMemberMetaData mmd = mapExpr.getJavaTypeMapping().getMemberMetaData();
if (mmd != null && mmd.getMap() != null) {
Class keyCls = stmt.getQueryGenerator().getClassLoaderResolver().classForName(mmd.getMap().getKeyType());
stmt.getQueryGenerator().bindParameter(keyExpr.getParameterName(), keyCls);
}
}
SQLExpressionFactory exprFactory = stmt.getSQLExpressionFactory();
ClassLoaderResolver clr = stmt.getQueryGenerator().getClassLoaderResolver();
if (expr instanceof MapLiteral) {
// Literal Map
MapLiteral lit = (MapLiteral) expr;
Map map = (Map) lit.getValue();
JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
if (map == null || map.size() == 0) {
return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, false));
}
boolean useInExpression = false;
List<SQLExpression> mapKeyExprs = lit.getKeyLiteral().getKeyExpressions();
if (mapKeyExprs != null && !mapKeyExprs.isEmpty()) {
// Make sure the the map key(s) are compatible with the keyExpr
boolean incompatible = true;
Class elemtype = clr.classForName(keyExpr.getJavaTypeMapping().getType());
Iterator<SQLExpression> mapKeyExprIter = mapKeyExprs.iterator();
while (mapKeyExprIter.hasNext()) {
SQLExpression mapKeyExpr = mapKeyExprIter.next();
Class mapKeyType = clr.classForName(mapKeyExpr.getJavaTypeMapping().getType());
if (keyTypeCompatible(elemtype, mapKeyType)) {
incompatible = false;
break;
}
}
if (incompatible) {
// The provided element type isn't assignable to any of the input collection elements!
return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, false));
}
// Check if we should compare using an "IN (...)" expression
SQLExpression mapKeyExpr = mapKeyExprs.get(0);
if (mapKeyExpr instanceof StringExpression || mapKeyExpr instanceof NumericExpression || mapKeyExpr instanceof TemporalExpression || mapKeyExpr instanceof CharacterExpression || mapKeyExpr instanceof EnumExpression) {
useInExpression = true;
}
}
if (useInExpression) {
// Return "key IN (val1, val2, ...)"
SQLExpression[] exprs = (mapKeyExprs != null ? mapKeyExprs.toArray(new SQLExpression[mapKeyExprs.size()]) : null);
return new InExpression(keyExpr, exprs);
}
// TODO If keyExpr is a parameter and mapExpr is derived from a parameter ?
MapKeyLiteral mapKeyLiteral = lit.getKeyLiteral();
BooleanExpression bExpr = null;
List<SQLExpression> elementExprs = mapKeyLiteral.getKeyExpressions();
for (int i = 0; i < elementExprs.size(); i++) {
if (bExpr == null) {
bExpr = (elementExprs.get(i)).eq(keyExpr);
} else {
bExpr = bExpr.ior((elementExprs.get(i)).eq(keyExpr));
}
}
if (bExpr != null) {
bExpr.encloseInParentheses();
}
return bExpr;
}
if (stmt.getQueryGenerator().getCompilationComponent() == CompilationComponent.FILTER) {
boolean useSubquery = getNeedsSubquery(stmt);
JoinType joinType = JoinType.INNER_JOIN;
if (keyExpr instanceof UnboundExpression) {
// See if the user has defined what should be used
String varName = ((UnboundExpression) keyExpr).getVariableName();
String extensionName = "datanucleus.query.jdoql." + varName + ".join";
String extensionValue = (String) stmt.getQueryGenerator().getValueForExtension(extensionName);
if (extensionValue != null) {
if (extensionValue.equalsIgnoreCase("SUBQUERY")) {
useSubquery = true;
} else if (extensionValue.equalsIgnoreCase("INNERJOIN")) {
useSubquery = false;
} else if (extensionValue.equalsIgnoreCase("LEFTOUTERJOIN")) {
joinType = JoinType.LEFT_OUTER_JOIN;
}
}
}
// TODO Check if *this* "containsKey" is negated, not any of them (and remove above check)
if (useSubquery) {
return containsAsSubquery(stmt, mapExpr, keyExpr);
}
return containsAsJoin(stmt, mapExpr, keyExpr, joinType);
}
return containsAsSubquery(stmt, mapExpr, keyExpr);
}
use of org.datanucleus.store.rdbms.sql.expression.MapExpression in project datanucleus-rdbms by datanucleus.
the class QueryToSQLMapper method processInvokeExpression.
/**
* Internal method to handle the processing of an InvokeExpression.
* @param expr The InvokeExpression
* @param invokedSqlExpr The SQLExpression that we are invoking the method on.
* @return The resultant SQLExpression
*/
protected SQLExpression processInvokeExpression(InvokeExpression expr, SQLExpression invokedSqlExpr) {
if (invokedSqlExpr instanceof NullLiteral) {
// We cannot invoke anything on a null TODO Handle this "NPE"
NucleusLogger.QUERY.warn("Compilation of InvokeExpression needs to invoke method \"" + expr.getOperation() + "\" on " + invokedSqlExpr + " but not possible");
}
String operation = expr.getOperation();
if (invokedSqlExpr instanceof MapExpression && operation.equals("contains") && compilation.getQueryLanguage().equalsIgnoreCase(Query.LANGUAGE_JPQL)) {
// JPQL "MEMBER OF" will be passed through from generic compilation as "contains" since we don't know types at that point
operation = "containsValue";
}
// Process the arguments for invoking
List args = expr.getArguments();
List sqlExprArgs = null;
if (args != null) {
sqlExprArgs = new ArrayList<SQLExpression>();
Iterator<Expression> iter = args.iterator();
while (iter.hasNext()) {
Expression argExpr = iter.next();
if (argExpr instanceof PrimaryExpression) {
processPrimaryExpression((PrimaryExpression) argExpr);
SQLExpression argSqlExpr = stack.pop();
if (compileComponent == CompilationComponent.RESULT && operation.equalsIgnoreCase("count") && stmt.getNumberOfTableGroups() > 1) {
if (argSqlExpr.getSQLTable() == stmt.getPrimaryTable() && argSqlExpr.getJavaTypeMapping() == stmt.getPrimaryTable().getTable().getIdMapping()) {
// Result with "count(this)" and joins to other groups, so enforce distinct
argSqlExpr.distinct();
}
}
sqlExprArgs.add(argSqlExpr);
} else if (argExpr instanceof ParameterExpression) {
processParameterExpression((ParameterExpression) argExpr);
sqlExprArgs.add(stack.pop());
} else if (argExpr instanceof InvokeExpression) {
processInvokeExpression((InvokeExpression) argExpr);
sqlExprArgs.add(stack.pop());
} else if (argExpr instanceof Literal) {
processLiteral((Literal) argExpr);
sqlExprArgs.add(stack.pop());
} else if (argExpr instanceof DyadicExpression) {
// Evaluate using this evaluator
argExpr.evaluate(this);
sqlExprArgs.add(stack.pop());
} else if (argExpr instanceof VariableExpression) {
processVariableExpression((VariableExpression) argExpr);
sqlExprArgs.add(stack.pop());
} else if (argExpr instanceof CaseExpression) {
processCaseExpression((CaseExpression) argExpr);
sqlExprArgs.add(stack.pop());
} else {
throw new NucleusException("Dont currently support invoke expression argument " + argExpr);
}
}
if (operation.equals("INDEX")) {
// Special case of index expression
List<Expression> indexArgs = expr.getArguments();
if (indexArgs == null || indexArgs.size() > 1) {
throw new NucleusException("Can only use INDEX with single argument");
}
PrimaryExpression indexExpr = (PrimaryExpression) indexArgs.get(0);
String joinAlias = indexExpr.getId();
String collExprName = joinAlias;
if (explicitJoinPrimaryByAlias != null) {
collExprName = explicitJoinPrimaryByAlias.get(joinAlias);
if (collExprName == null) {
throw new NucleusException("Unable to locate primary expression for alias " + joinAlias);
}
}
// Find an expression for the collection field
List<String> tuples = new ArrayList<>();
StringTokenizer primTokenizer = new StringTokenizer(collExprName, ".");
while (primTokenizer.hasMoreTokens()) {
String token = primTokenizer.nextToken();
tuples.add(token);
}
PrimaryExpression collPrimExpr = new PrimaryExpression(tuples);
processPrimaryExpression(collPrimExpr);
SQLExpression collSqlExpr = stack.pop();
sqlExprArgs.add(collSqlExpr);
}
}
// Invoke the method
SQLExpression sqlExpr = null;
if (invokedSqlExpr instanceof org.datanucleus.store.rdbms.sql.expression.SubqueryExpression) {
if (operation.equalsIgnoreCase("isEmpty")) {
// Special case of {subquery}.isEmpty(), equates to "NOT EXISTS (subquery)"
org.datanucleus.store.rdbms.sql.expression.SubqueryExpression subquerySqlExpr = (org.datanucleus.store.rdbms.sql.expression.SubqueryExpression) invokedSqlExpr;
SQLStatement subStmt = subquerySqlExpr.getSubqueryStatement();
SQLExpression subqueryNotExistsExpr = new BooleanSubqueryExpression(stmt, "EXISTS", subStmt).not();
stack.push(subqueryNotExistsExpr);
return subqueryNotExistsExpr;
} else if (operation.equalsIgnoreCase("size")) {
// {subquery}.size() should simply be changed to have a subquery of "SELECT COUNT(*) FROM ..."
throw new NucleusUserException("Attempt to invoke method `" + operation + "` on Subquery. This is not supported. Change the subquery to return COUNT() instead.");
}
throw new NucleusUserException("Attempt to invoke method `" + operation + "` on Subquery. This is not supported");
}
if (invokedSqlExpr != null) {
sqlExpr = invokedSqlExpr.invoke(operation, sqlExprArgs);
} else {
sqlExpr = exprFactory.invokeMethod(stmt, null, operation, null, sqlExprArgs);
}
stack.push(sqlExpr);
return sqlExpr;
}
use of org.datanucleus.store.rdbms.sql.expression.MapExpression in project datanucleus-rdbms by datanucleus.
the class MapContainsEntryMethod method getExpression.
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.sql.method.SQLMethod#getExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression, java.util.List)
*/
public SQLExpression getExpression(SQLStatement stmt, SQLExpression expr, List<SQLExpression> args) {
if (args == null || args.size() != 2) {
throw new NucleusException(Localiser.msg("060016", "containsValue", "MapExpression", 2));
}
MapExpression mapExpr = (MapExpression) expr;
SQLExpression keyExpr = args.get(0);
SQLExpression valExpr = args.get(1);
if (keyExpr.isParameter()) {
// Key is a parameter so make sure its type is set
AbstractMemberMetaData mmd = mapExpr.getJavaTypeMapping().getMemberMetaData();
if (mmd != null && mmd.getMap() != null) {
Class keyCls = stmt.getQueryGenerator().getClassLoaderResolver().classForName(mmd.getMap().getKeyType());
stmt.getQueryGenerator().bindParameter(keyExpr.getParameterName(), keyCls);
}
}
if (valExpr.isParameter()) {
// Value is a parameter so make sure its type is set
AbstractMemberMetaData mmd = mapExpr.getJavaTypeMapping().getMemberMetaData();
if (mmd != null && mmd.getMap() != null) {
Class valCls = stmt.getQueryGenerator().getClassLoaderResolver().classForName(mmd.getMap().getValueType());
stmt.getQueryGenerator().bindParameter(valExpr.getParameterName(), valCls);
}
}
if (mapExpr instanceof MapLiteral) {
MapLiteral lit = (MapLiteral) mapExpr;
Map map = (Map) lit.getValue();
if (map == null || map.size() == 0) {
return new BooleanLiteral(stmt, expr.getJavaTypeMapping(), Boolean.FALSE);
}
// TODO Handle this
return lit.getValueLiteral().invoke("contains", args);
}
if (stmt.getQueryGenerator().getCompilationComponent() == CompilationComponent.FILTER) {
boolean needsSubquery = getNeedsSubquery(stmt);
// TODO Check if *this* "containsEntry" is negated, not any of them (and remove above check)
if (needsSubquery) {
NucleusLogger.QUERY.debug("MapContainsEntry on " + mapExpr + "(" + keyExpr + "," + valExpr + ") using SUBQUERY");
return containsAsSubquery(stmt, mapExpr, keyExpr, valExpr);
}
NucleusLogger.QUERY.debug("MapContainsEntry on " + mapExpr + "(" + keyExpr + "," + valExpr + ") using INNERJOIN");
return containsAsInnerJoin(stmt, mapExpr, keyExpr, valExpr);
}
return containsAsSubquery(stmt, mapExpr, keyExpr, valExpr);
}
use of org.datanucleus.store.rdbms.sql.expression.MapExpression in project datanucleus-rdbms by datanucleus.
the class MapContainsValueMethod method getExpression.
/* (non-Javadoc)
* @see org.datanucleus.store.rdbms.sql.method.SQLMethod#getExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression, java.util.List)
*/
public SQLExpression getExpression(SQLStatement stmt, SQLExpression expr, List<SQLExpression> args) {
if (args == null || args.size() == 0 || args.size() > 1) {
throw new NucleusException(Localiser.msg("060016", "containsValue", "MapExpression", 1));
}
MapExpression mapExpr = (MapExpression) expr;
SQLExpression valExpr = args.get(0);
if (valExpr.isParameter()) {
// Value is a parameter so make sure its type is set
AbstractMemberMetaData mmd = mapExpr.getJavaTypeMapping().getMemberMetaData();
if (mmd != null && mmd.getMap() != null) {
Class valCls = stmt.getQueryGenerator().getClassLoaderResolver().classForName(mmd.getMap().getValueType());
stmt.getQueryGenerator().bindParameter(valExpr.getParameterName(), valCls);
}
}
ClassLoaderResolver clr = stmt.getQueryGenerator().getClassLoaderResolver();
SQLExpressionFactory exprFactory = stmt.getSQLExpressionFactory();
if (mapExpr instanceof MapLiteral) {
MapLiteral lit = (MapLiteral) mapExpr;
Map map = (Map) lit.getValue();
JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
if (map == null || map.size() == 0) {
return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, false));
}
boolean useInExpression = false;
List<SQLExpression> mapValExprs = lit.getValueLiteral().getValueExpressions();
if (mapValExprs != null && !mapValExprs.isEmpty()) {
// Make sure the the map key(s) are compatible with the keyExpr
boolean incompatible = true;
Class elemtype = clr.classForName(valExpr.getJavaTypeMapping().getType());
Iterator<SQLExpression> mapKeyExprIter = mapValExprs.iterator();
while (mapKeyExprIter.hasNext()) {
SQLExpression mapKeyExpr = mapKeyExprIter.next();
Class mapKeyType = clr.classForName(mapKeyExpr.getJavaTypeMapping().getType());
if (valueTypeCompatible(elemtype, mapKeyType)) {
incompatible = false;
break;
}
}
if (incompatible) {
// The provided element type isn't assignable to any of the input collection elements!
return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, false));
}
// Check if we should compare using an "IN (...)" expression
SQLExpression mapKeyExpr = mapValExprs.get(0);
if (mapKeyExpr instanceof StringExpression || mapKeyExpr instanceof NumericExpression || mapKeyExpr instanceof TemporalExpression || mapKeyExpr instanceof CharacterExpression || mapKeyExpr instanceof EnumExpression) {
useInExpression = true;
}
}
if (useInExpression) {
// Return "key IN (val1, val2, ...)"
SQLExpression[] exprs = (mapValExprs != null ? mapValExprs.toArray(new SQLExpression[mapValExprs.size()]) : null);
return new InExpression(valExpr, exprs);
}
// TODO If valExpr is a parameter and mapExpr is derived from a parameter ?
MapValueLiteral mapValueLiteral = lit.getValueLiteral();
BooleanExpression bExpr = null;
List<SQLExpression> elementExprs = mapValueLiteral.getValueExpressions();
for (int i = 0; i < elementExprs.size(); i++) {
if (bExpr == null) {
bExpr = (elementExprs.get(i)).eq(valExpr);
} else {
bExpr = bExpr.ior((elementExprs.get(i)).eq(valExpr));
}
}
if (bExpr != null) {
bExpr.encloseInParentheses();
}
return bExpr;
}
if (stmt.getQueryGenerator().getCompilationComponent() == CompilationComponent.FILTER) {
boolean useSubquery = getNeedsSubquery(stmt);
JoinType joinType = JoinType.INNER_JOIN;
if (valExpr instanceof UnboundExpression) {
// See if the user has defined what should be used
String varName = ((UnboundExpression) valExpr).getVariableName();
String extensionName = "datanucleus.query.jdoql." + varName + ".join";
String extensionValue = (String) stmt.getQueryGenerator().getValueForExtension(extensionName);
if (extensionValue != null) {
if (extensionValue.equalsIgnoreCase("SUBQUERY")) {
useSubquery = true;
} else if (extensionValue.equalsIgnoreCase("INNERJOIN")) {
useSubquery = false;
} else if (extensionValue.equalsIgnoreCase("LEFTOUTERJOIN")) {
joinType = JoinType.LEFT_OUTER_JOIN;
}
}
}
// TODO Check if *this* "containsValue" is negated, not any of them (and remove above check)
if (useSubquery) {
return containsAsSubquery(stmt, mapExpr, valExpr);
}
return containsAsJoin(stmt, mapExpr, valExpr, joinType);
}
return containsAsSubquery(stmt, mapExpr, valExpr);
}
Aggregations