use of org.datanucleus.store.rdbms.sql.expression.CollectionLiteral in project datanucleus-rdbms by datanucleus.
the class ListGetMethod 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", "get", "CollectionExpression", 1));
}
CollectionExpression listSqlExpr = (CollectionExpression) expr;
AbstractMemberMetaData mmd = listSqlExpr.getJavaTypeMapping().getMemberMetaData();
if (mmd == null) {
// TODO Cater for the List being an input parameter
throw new NucleusException(Localiser.msg("060020", "indexOf", listSqlExpr.getClass().getName()));
}
if (!List.class.isAssignableFrom(mmd.getType())) {
throw new UnsupportedOperationException("Query contains " + expr + ".get(int) yet the field is not a List!");
} else if (mmd.getOrderMetaData() != null && !mmd.getOrderMetaData().isIndexedList()) {
throw new UnsupportedOperationException("Query contains " + expr + ".get(int) yet the field is not an 'indexed' List!");
}
SQLExpression idxExpr = args.get(0);
if (idxExpr instanceof SQLLiteral) {
if (!(((SQLLiteral) idxExpr).getValue() instanceof Number)) {
throw new UnsupportedOperationException("Query contains " + expr + ".get(int) yet the index is not a numeric literal so not yet supported");
}
} else {
throw new UnsupportedOperationException("Query contains " + expr + ".get(int) yet the index is not a numeric literal so not yet supported");
}
if (listSqlExpr instanceof CollectionLiteral && idxExpr instanceof SQLLiteral) {
CollectionLiteral lit = (CollectionLiteral) expr;
if (lit.getValue() == null) {
return new NullLiteral(stmt, null, null, null);
}
return lit.invoke("get", args);
}
if (stmt.getQueryGenerator().getCompilationComponent() == CompilationComponent.FILTER) {
return getAsInnerJoin(stmt, listSqlExpr, idxExpr);
} else if (stmt.getQueryGenerator().getCompilationComponent() == CompilationComponent.ORDERING || stmt.getQueryGenerator().getCompilationComponent() == CompilationComponent.RESULT || stmt.getQueryGenerator().getCompilationComponent() == CompilationComponent.HAVING) {
return getAsSubquery(stmt, listSqlExpr, idxExpr);
}
throw new NucleusException("List.get() is not supported for " + listSqlExpr + " with argument " + idxExpr + " for query component " + stmt.getQueryGenerator().getCompilationComponent());
}
use of org.datanucleus.store.rdbms.sql.expression.CollectionLiteral in project datanucleus-rdbms by datanucleus.
the class CollectionContainsMethod 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", "contains", "CollectionExpression", 1));
}
CollectionExpression collExpr = (CollectionExpression) expr;
AbstractMemberMetaData mmd = collExpr.getJavaTypeMapping().getMemberMetaData();
SQLExpression elemExpr = args.get(0);
SQLExpressionFactory exprFactory = stmt.getSQLExpressionFactory();
if (elemExpr.isParameter()) {
// Element is a parameter so make sure its type is set
if (mmd != null && mmd.getCollection() != null) {
Class elementCls = stmt.getQueryGenerator().getClassLoaderResolver().classForName(mmd.getCollection().getElementType());
stmt.getQueryGenerator().bindParameter(elemExpr.getParameterName(), elementCls);
}
}
ClassLoaderResolver clr = stmt.getQueryGenerator().getClassLoaderResolver();
if (collExpr instanceof CollectionLiteral) {
// Literal collection
CollectionLiteral lit = (CollectionLiteral) collExpr;
Collection coll = (Collection) lit.getValue();
JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
if (coll == null || coll.isEmpty()) {
return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, false));
}
if (collExpr.isParameter()) {
stmt.getQueryGenerator().useParameterExpressionAsLiteral((CollectionLiteral) collExpr);
}
boolean useInExpression = false;
List<SQLExpression> collElementExprs = lit.getElementExpressions();
if (collElementExprs != null && !collElementExprs.isEmpty()) {
// Make sure the the collection element(s) are compatible with the elemExpr
boolean incompatible = true;
Class elemtype = clr.classForName(elemExpr.getJavaTypeMapping().getType());
Iterator<SQLExpression> collElementExprIter = collElementExprs.iterator();
while (collElementExprIter.hasNext()) {
SQLExpression collElementExpr = collElementExprIter.next();
Class collElemType = clr.classForName(collElementExpr.getJavaTypeMapping().getType());
if (elementTypeCompatible(elemtype, collElemType)) {
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 collElementExpr = collElementExprs.get(0);
if (collElementExpr instanceof StringExpression || collElementExpr instanceof NumericExpression || collElementExpr instanceof TemporalExpression || collElementExpr instanceof CharacterExpression || collElementExpr instanceof EnumExpression) {
useInExpression = true;
}
}
if (useInExpression) {
// Return "elem IN (val1, val2, ...)"
SQLExpression[] exprs = (collElementExprs != null ? collElementExprs.toArray(new SQLExpression[collElementExprs.size()]) : null);
return new InExpression(elemExpr, exprs);
}
// Return "elem == val1 || elem == val2 || elem == val3 ..."
BooleanExpression bExpr = null;
if (collElementExprs != null) {
for (int i = 0; i < collElementExprs.size(); i++) {
if (bExpr == null) {
bExpr = (collElementExprs.get(i)).eq(elemExpr);
} else {
bExpr = bExpr.ior((collElementExprs.get(i)).eq(elemExpr));
}
}
}
if (bExpr != null) {
bExpr.encloseInParentheses();
}
return bExpr;
}
if (mmd == null) {
throw new NucleusUserException("Cannot perform Collection.contains when the field metadata is not provided");
}
if (mmd.isSerialized()) {
throw new NucleusUserException("Cannot perform Collection.contains when the collection is being serialised");
}
ApiAdapter api = stmt.getRDBMSManager().getApiAdapter();
Class elementType = clr.classForName(mmd.getCollection().getElementType());
if (!api.isPersistable(elementType) && mmd.getJoinMetaData() == null) {
throw new NucleusUserException("Cannot perform Collection.contains when the collection<Non-Persistable> is not in a join table");
}
if (stmt.getQueryGenerator().getCompilationComponent() == CompilationComponent.FILTER) {
boolean useSubquery = getNeedsSubquery(stmt, collExpr, elemExpr);
JoinType joinType = JoinType.INNER_JOIN;
if (elemExpr instanceof UnboundExpression) {
// See if the user has defined what should be used
String varName = ((UnboundExpression) elemExpr).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;
}
}
}
if (useSubquery) {
return containsAsSubquery(stmt, collExpr, elemExpr);
}
return containsAsJoin(stmt, collExpr, elemExpr, joinType);
}
return containsAsSubquery(stmt, collExpr, elemExpr);
}
use of org.datanucleus.store.rdbms.sql.expression.CollectionLiteral in project datanucleus-rdbms by datanucleus.
the class CollectionSizeMethod 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) {
throw new NucleusException(Localiser.msg("060015", "size", "CollectionExpression"));
}
SQLExpressionFactory exprFactory = stmt.getSQLExpressionFactory();
if (expr instanceof CollectionLiteral) {
// Just return the collection size since we have the value
Collection coll = (Collection) ((CollectionLiteral) expr).getValue();
return exprFactory.newLiteral(stmt, exprFactory.getMappingForType(int.class, false), Integer.valueOf(coll.size()));
}
AbstractMemberMetaData mmd = expr.getJavaTypeMapping().getMemberMetaData();
if (mmd.isSerialized()) {
throw new NucleusUserException("Cannot perform Collection.size when the collection is being serialised");
}
ApiAdapter api = stmt.getRDBMSManager().getApiAdapter();
ClassLoaderResolver clr = stmt.getQueryGenerator().getClassLoaderResolver();
Class elementCls = clr.classForName(mmd.getCollection().getElementType());
if (!api.isPersistable(elementCls) && mmd.getJoinMetaData() == null) {
throw new NucleusUserException("Cannot perform Collection.size when the collection<Non-Persistable> is not in a join table");
}
String elementType = mmd.getCollection().getElementType();
RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
// TODO Allow for interface elements, etc
JavaTypeMapping ownerMapping = null;
Table collectionTbl = null;
if (mmd.getMappedBy() != null) {
// Bidirectional
AbstractMemberMetaData elementMmd = mmd.getRelatedMemberMetaData(clr)[0];
if (mmd.getJoinMetaData() != null || elementMmd.getJoinMetaData() != null) {
// JoinTable
collectionTbl = storeMgr.getTable(mmd);
ownerMapping = ((JoinTable) collectionTbl).getOwnerMapping();
} else {
// ForeignKey
collectionTbl = storeMgr.getDatastoreClass(elementType, clr);
ownerMapping = collectionTbl.getMemberMapping(elementMmd);
}
} else {
// Unidirectional
if (mmd.getJoinMetaData() != null) {
// JoinTable
collectionTbl = storeMgr.getTable(mmd);
ownerMapping = ((JoinTable) collectionTbl).getOwnerMapping();
} else {
// ForeignKey
collectionTbl = storeMgr.getDatastoreClass(elementType, clr);
ownerMapping = ((DatastoreClass) collectionTbl).getExternalMapping(mmd, MappingType.EXTERNAL_FK);
}
}
SelectStatement subStmt = new SelectStatement(stmt, storeMgr, collectionTbl, null, null);
subStmt.setClassLoaderResolver(clr);
JavaTypeMapping mapping = storeMgr.getMappingManager().getMappingWithColumnMapping(String.class, false, false, clr);
SQLExpression countExpr = exprFactory.newLiteral(subStmt, mapping, "COUNT(*)");
((StringLiteral) countExpr).generateStatementWithoutQuotes();
subStmt.select(countExpr, null);
SQLExpression elementOwnerExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), ownerMapping);
SQLExpression ownerIdExpr = exprFactory.newExpression(stmt, expr.getSQLTable(), expr.getSQLTable().getTable().getIdMapping());
subStmt.whereAnd(elementOwnerExpr.eq(ownerIdExpr), true);
JavaTypeMapping subqMapping = exprFactory.getMappingForType(Integer.class, false);
SQLExpression subqExpr = new NumericSubqueryExpression(stmt, subStmt);
subqExpr.setJavaTypeMapping(subqMapping);
return subqExpr;
}
use of org.datanucleus.store.rdbms.sql.expression.CollectionLiteral in project datanucleus-rdbms by datanucleus.
the class CollectionIsEmptyMethod 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) {
throw new NucleusException(Localiser.msg("060015", "isEmpty", "CollectionExpression"));
}
SQLExpressionFactory exprFactory = stmt.getSQLExpressionFactory();
if (expr instanceof CollectionLiteral) {
Collection coll = (Collection) ((CollectionLiteral) expr).getValue();
boolean isEmpty = (coll == null || coll.size() == 0);
JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, false);
return new BooleanLiteral(stmt, m, isEmpty ? Boolean.TRUE : Boolean.FALSE);
}
AbstractMemberMetaData mmd = ((CollectionExpression) expr).getJavaTypeMapping().getMemberMetaData();
if (mmd.isSerialized()) {
throw new NucleusUserException("Cannot perform Collection.isEmpty when the collection is being serialised");
}
ClassLoaderResolver clr = stmt.getQueryGenerator().getClassLoaderResolver();
ApiAdapter api = stmt.getRDBMSManager().getApiAdapter();
Class elementType = clr.classForName(mmd.getCollection().getElementType());
if (!api.isPersistable(elementType) && mmd.getJoinMetaData() == null) {
throw new NucleusUserException("Cannot perform Collection.isEmpty when the collection<Non-Persistable> is not in a join table");
}
SQLExpression sizeExpr = exprFactory.invokeMethod(stmt, Collection.class.getName(), "size", expr, args);
JavaTypeMapping mapping = exprFactory.getMappingForType(Integer.class, true);
SQLExpression zeroExpr = exprFactory.newLiteral(stmt, mapping, 0);
return sizeExpr.eq(zeroExpr);
}
use of org.datanucleus.store.rdbms.sql.expression.CollectionLiteral in project datanucleus-rdbms by datanucleus.
the class QueryToSQLMapper method processInExpression.
/* (non-Javadoc)
* @see org.datanucleus.query.evaluator.AbstractExpressionEvaluator#processInExpression(org.datanucleus.query.expression.Expression)
*/
@Override
protected Object processInExpression(Expression expr) {
SQLExpression right = stack.pop();
SQLExpression left = stack.pop();
if (right instanceof CollectionExpression || right instanceof org.datanucleus.store.rdbms.sql.expression.ArrayExpression) {
// myElement IN myCollection
if (right.getParameterName() != null) {
setNotPrecompilable();
}
if (left instanceof TypeConverterExpression && right.getParameterName() != null && right instanceof CollectionLiteral) {
NucleusLogger.GENERAL.debug(">> processInExpression : left=" + left + " right=" + right + " rightParamName=" + right.getParameterName());
// TODO Support this somehow, but would need to split up user collection parameter into multiple single params
throw new NucleusUserException("Query has 'elem IN collectionParam'. We don't currently support this when the element value uses a TypeConverter." + " Suggest that you rewrite it using individual parameters for the elements.");
}
// Use Collection.contains(element)/Array.contains(element)
List<SQLExpression> sqlExprArgs = new ArrayList();
sqlExprArgs.add(left);
SQLExpression sqlExpr = right.invoke("contains", sqlExprArgs);
stack.push(sqlExpr);
return sqlExpr;
} else if (right.getParameterName() != null || left.getParameterName() != null) {
// "expr IN (:param)" or ":param IN (expr)" or ":param1 IN (:param2)"
setNotPrecompilable();
// Replace parameter(s) with equivalent literal of correct type
if (right instanceof ParameterLiteral) {
right = exprFactory.replaceParameterLiteral((ParameterLiteral) right, left);
}
if (left instanceof ParameterLiteral && !Collection.class.isAssignableFrom(right.getJavaTypeMapping().getJavaType())) {
left = exprFactory.replaceParameterLiteral((ParameterLiteral) left, right);
}
// Single valued parameter, so use equality
SQLExpression inExpr = new BooleanExpression(left, Expression.OP_EQ, right);
stack.push(inExpr);
return inExpr;
}
SQLExpression inExpr = left.in(right, false);
stack.push(inExpr);
return inExpr;
}
Aggregations