Revision: 8054
http://datanucleus.svn.sourceforge.net/datanucleus/?rev=8054&view=rev
Author: andy_jefferson
Date: 2009-11-11 12:07:13 +0000 (Wed, 11 Nov 2009)
Log Message:
-----------
[NUCRDBMS-265] Convert "! instanceof" into "OP_ISNOT" operator so we can detect things later on. Add simplified handling of a unioned statement where the candidate is used in the instanceof - will fail for ORed conditions but we can't have everything at once!
Modified Paths:
--------------
platform/core/trunk/src/java/org/datanucleus/query/evaluator/AbstractExpressionEvaluator.java
platform/core/trunk/src/java/org/datanucleus/query/expression/ExpressionCompiler.java
platform/store.rdbms/trunk/src/java/org/datanucleus/store/rdbms/query/QueryToSQLMapper.java
platform/store.rdbms/trunk/src/java/org/datanucleus/store/rdbms/sql/expression/ObjectExpression.java
platform/store.rdbms/trunk/src/java/org/datanucleus/store/rdbms/sql/expression/SQLExpression.java
Modified: platform/core/trunk/src/java/org/datanucleus/query/evaluator/AbstractExpressionEvaluator.java
===================================================================
--- platform/core/trunk/src/java/org/datanucleus/query/evaluator/AbstractExpressionEvaluator.java 2009-11-11 10:04:13 UTC (rev 8053)
+++ platform/core/trunk/src/java/org/datanucleus/query/evaluator/AbstractExpressionEvaluator.java 2009-11-11 12:07:13 UTC (rev 8054)
@@ -102,6 +102,10 @@
{
return processIsExpression(expr);
}
+ else if (expr.getOperator() == Expression.OP_ISNOT)
+ {
+ return processIsnotExpression(expr);
+ }
else if (expr.getOperator() == Expression.OP_IN)
{
return processInExpression(expr);
@@ -305,6 +309,17 @@
}
/**
+ * Method to process the supplied ISNOT (!instanceof) expression.
+ * To be implemented by subclasses.
+ * @param expr The expression
+ * @return The result
+ */
+ protected Object processIsnotExpression(Expression expr)
+ {
+ throw new NucleusException("Operation ISNOT (!instanceof) is not supported by this mapper");
+ }
+
+ /**
* Method to process the supplied IN expression.
* To be implemented by subclasses.
* @param expr The expression
Modified: platform/core/trunk/src/java/org/datanucleus/query/expression/ExpressionCompiler.java
===================================================================
--- platform/core/trunk/src/java/org/datanucleus/query/expression/ExpressionCompiler.java 2009-11-11 10:04:13 UTC (rev 8053)
+++ platform/core/trunk/src/java/org/datanucleus/query/expression/ExpressionCompiler.java 2009-11-11 12:07:13 UTC (rev 8054)
@@ -301,6 +301,12 @@
else if (isOperator(node, "!"))
{
Expression left = compileExpression(node.getFirstChild());
+ if (left instanceof DyadicExpression && left.getOperator() == Expression.OP_IS)
+ {
+ // Convert "NOT ({expr} IS {expr2})" into "{expr} ISNOT {expr2}"
+ DyadicExpression leftExpr = (DyadicExpression)left;
+ return new DyadicExpression(leftExpr.getLeft(), Expression.OP_ISNOT, leftExpr.getRight());
+ }
return new DyadicExpression(Expression.OP_NOT, left);
}
else if (isOperator(node, "DISTINCT"))
Modified: platform/store.rdbms/trunk/src/java/org/datanucleus/store/rdbms/query/QueryToSQLMapper.java
===================================================================
--- platform/store.rdbms/trunk/src/java/org/datanucleus/store/rdbms/query/QueryToSQLMapper.java 2009-11-11 10:04:13 UTC (rev 8053)
+++ platform/store.rdbms/trunk/src/java/org/datanucleus/store/rdbms/query/QueryToSQLMapper.java 2009-11-11 12:07:13 UTC (rev 8054)
@@ -2095,12 +2095,25 @@
{
SQLExpression right = stack.pop();
SQLExpression left = stack.pop();
- SQLExpression instanceofExpr = left.is(right);
+ SQLExpression instanceofExpr = left.is(right, false);
stack.push(instanceofExpr);
return instanceofExpr;
}
/* (non-Javadoc)
+ * @see org.datanucleus.query.evaluator.AbstractExpressionEvaluator#processIsnotExpression(org.datanucleus.query.expression.Expression)
+ */
+ @Override
+ protected Object processIsnotExpression(Expression expr)
+ {
+ SQLExpression right = stack.pop();
+ SQLExpression left = stack.pop();
+ SQLExpression instanceofExpr = left.is(right, true);
+ stack.push(instanceofExpr);
+ return instanceofExpr;
+ }
+
+ /* (non-Javadoc)
* @see org.datanucleus.query.evaluator.AbstractExpressionEvaluator#processInExpression(org.datanucleus.query.expression.Expression)
*/
@Override
Modified: platform/store.rdbms/trunk/src/java/org/datanucleus/store/rdbms/sql/expression/ObjectExpression.java
===================================================================
--- platform/store.rdbms/trunk/src/java/org/datanucleus/store/rdbms/sql/expression/ObjectExpression.java 2009-11-11 10:04:13 UTC (rev 8053)
+++ platform/store.rdbms/trunk/src/java/org/datanucleus/store/rdbms/sql/expression/ObjectExpression.java 2009-11-11 12:07:13 UTC (rev 8054)
@@ -421,9 +421,10 @@
* An "is" (instanceOf) expression, providing a BooleanExpression whether this expression
* is an instanceof the provided type.
* @param expr The expression representing the type
+ * @param not Whether the operator is "!instanceof"
* @return Whether this expression is an instance of the provided type
*/
- public BooleanExpression is(SQLExpression expr)
+ public BooleanExpression is(SQLExpression expr, boolean not)
{
RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
ClassLoaderResolver clr = storeMgr.getOMFContext().getClassLoaderResolver(null);
@@ -447,20 +448,20 @@
{
// Member type and instanceof type are totally incompatible, so just return false
JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
- return exprFactory.newLiteral(stmt, m, false).eq(exprFactory.newLiteral(stmt, m, true));
+ return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, not));
}
else if (memberType == type)
{
// instanceof type is the same as the member type therefore must comply (can't store supertypes)
JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
- return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, true));
+ return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, !not));
}
if (mapping instanceof EmbeddedMapping)
{
// Don't support embedded instanceof expressions
JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
- return exprFactory.newLiteral(stmt, m, false).eq(exprFactory.newLiteral(stmt, m, true));
+ return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, not));
}
else if (mapping instanceof PersistableMapping || mapping instanceof ReferenceMapping)
{
@@ -538,7 +539,7 @@
{
discExpr.encloseInParentheses();
}
- return discExpr;
+ return (not ? discExpr.not() : discExpr);
}
else
{
@@ -576,38 +577,78 @@
{
// This type is managed in this table so must be an instance
JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
- return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, true));
+ return exprFactory.newLiteral(stmt, m, true).eq(
+ exprFactory.newLiteral(stmt, m, !not));
}
else
{
- // TODO If the instanceof is on the candidate and we have a Union statement then
- // remove the other unions (only valid if the instanceof is *not* ORed)
- // If ORed (e.g instanceof SUB1 || instanceof SUB2) then need to just remove particular unions)
- /*if (table == stmt.getPrimaryTable().getTable())
+ if (table == stmt.getPrimaryTable().getTable())
{
- NucleusLogger.JDO.info(">> ObjectExpr.instanceof stmt for " + stmt.getCandidateClassName());
- List<SQLStatement> unionStmts = stmt.getUnions();
- Iterator<SQLStatement> iter = unionStmts.iterator();
- while (iter.hasNext())
+ // Candidate is used in instanceof, and union statement so restrict some unions
+ // Note that this is only really valid is wanting "a instanceof SUB1".
+ // It fails when we want to do "a instanceof SUB1 || a instanceof SUB2"
+ // TODO How do we handle those cases?
+ JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
+ if (stmt.getNumberOfUnions() > 0)
{
- SQLStatement unionStmt = iter.next();
- NucleusLogger.JDO.info(">> ObjectExpr.instanceof union for " + unionStmt.getCandidateClassName());
+ Class mainCandidateCls = clr.classForName(stmt.getCandidateClassName());
+ if (type.isAssignableFrom(mainCandidateCls) == not)
+ {
+ SQLExpression unionClauseExpr = exprFactory.newLiteral(stmt, m, true).eq(
+ exprFactory.newLiteral(stmt, m, false));
+ stmt.whereAnd((BooleanExpression)unionClauseExpr, false);
+ }
+
+ List<SQLStatement> unionStmts = stmt.getUnions();
+ Iterator<SQLStatement> iter = unionStmts.iterator();
+ while (iter.hasNext())
+ {
+ SQLStatement unionStmt = iter.next();
+ Class unionCandidateCls = clr.classForName(unionStmt.getCandidateClassName());
+ if (type.isAssignableFrom(unionCandidateCls) == not)
+ {
+ SQLExpression unionClauseExpr = exprFactory.newLiteral(unionStmt, m, true).eq(
+ exprFactory.newLiteral(unionStmt, m, false));
+ unionStmt.whereAnd((BooleanExpression)unionClauseExpr, false);
+ }
+ }
+
+ // Just return true since we applied the condition direct to the unions
+ SQLExpression returnExpr = exprFactory.newLiteral(stmt, m, true).eq(
+ exprFactory.newLiteral(stmt, m, true));
+ return (BooleanExpression)returnExpr;
}
- }*/
-
- // Do inner join to this table to impose the instanceOf
- DatastoreClass instanceofTable = storeMgr.getDatastoreClass(type.getName(), clr);
- if (stmt.getNumberOfUnions() > 0)
+ else
+ {
+ Class mainCandidateCls = clr.classForName(stmt.getCandidateClassName());
+ if (!type.isAssignableFrom(mainCandidateCls))
+ {
+ return exprFactory.newLiteral(stmt, m, true).eq(
+ exprFactory.newLiteral(stmt, m, not));
+ }
+ else
+ {
+ return exprFactory.newLiteral(stmt, m, true).eq(
+ exprFactory.newLiteral(stmt, m, !not));
+ }
+ }
+ }
+ else
{
- // Inner join will likely not give the right result
- NucleusLogger.QUERY.debug("InstanceOf for " + table +
- " but no discriminator so adding inner join to " + instanceofTable +
+ // Do inner join to this table to impose the instanceOf
+ DatastoreClass instanceofTable = storeMgr.getDatastoreClass(type.getName(), clr);
+ if (stmt.getNumberOfUnions() > 0)
+ {
+ // Inner join will likely not give the right result
+ NucleusLogger.QUERY.debug("InstanceOf for " + table +
+ " but no discriminator so adding inner join to " + instanceofTable +
" : in some cases with UNIONs this may fail");
+ }
+ stmt.innerJoin(this.table, this.table.getTable().getIDMapping(),
+ instanceofTable, null, instanceofTable.getIDMapping(), null, this.table.getGroupName());
+ JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
+ return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, !not));
}
- stmt.innerJoin(this.table, this.table.getTable().getIDMapping(),
- instanceofTable, null, instanceofTable.getIDMapping(), null, this.table.getGroupName());
- JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
- return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, true));
}
}
}
Modified: platform/store.rdbms/trunk/src/java/org/datanucleus/store/rdbms/sql/expression/SQLExpression.java
===================================================================
--- platform/store.rdbms/trunk/src/java/org/datanucleus/store/rdbms/sql/expression/SQLExpression.java 2009-11-11 10:04:13 UTC (rev 8053)
+++ platform/store.rdbms/trunk/src/java/org/datanucleus/store/rdbms/sql/expression/SQLExpression.java 2009-11-11 12:07:13 UTC (rev 8054)
@@ -536,9 +536,10 @@
* An "is" (instanceOf) expression, providing a BooleanExpression whether this expression
* is an instanceof the provided type.
* @param expr the expression representing the type
+ * @param not Whether we really want "!instanceof"
* @return Whether this expression is an instance of the provided type
*/
- public BooleanExpression is(SQLExpression expr)
+ public BooleanExpression is(SQLExpression expr, boolean not)
{
throw new IllegalExpressionOperationException("instanceof " + expr, this);
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|