Add visitor pattern to query expression trees, and redo a couple of our existing

tree interrogation methods to use it.  This will allow us to add more 
validations at query compilation time (we're missing some that are required for
JDO 2, for example) without having to expand the API of every query 
expression/value implementation, in addition to just being more flexible 
overall.



git-svn-id: https://svn.apache.org/repos/asf/incubator/openjpa/trunk@432778 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
A. Abram White 2006-08-19 01:03:35 +00:00
parent eb2b5e6551
commit 037a45d7e4
90 changed files with 589 additions and 514 deletions

View File

@ -19,17 +19,22 @@ import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
import org.apache.openjpa.jdbc.kernel.JDBCStore; import org.apache.openjpa.jdbc.kernel.JDBCStore;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
/** /**
* Aggregate listener that evaluates to a value. * Abstract value for easy extension.
* *
* @author Marc Prud'hommeaux * @author Marc Prud'hommeaux
*/ */
abstract class AbstractVal abstract class AbstractVal
implements Val { implements Val {
private static final String TRUE = "1 = 1"; protected static final String TRUE = "1 = 1";
private static final String FALSE = "1 <> 1"; protected static final String FALSE = "1 <> 1";
public boolean isVariable() {
return false;
}
public void appendIsEmpty(SQLBuffer sql, Select sel, JDBCStore store, public void appendIsEmpty(SQLBuffer sql, Select sel, JDBCStore store,
Object[] params, JDBCFetchConfiguration fetch) { Object[] params, JDBCFetchConfiguration fetch) {
@ -57,5 +62,10 @@ abstract class AbstractVal
Object[] params, JDBCFetchConfiguration fetch) { Object[] params, JDBCFetchConfiguration fetch) {
sql.append("1"); sql.append("1");
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
visitor.exit(this);
}
} }

View File

@ -26,6 +26,7 @@ import org.apache.openjpa.jdbc.sql.Result;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.Filters; import org.apache.openjpa.kernel.Filters;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
import org.apache.openjpa.meta.ClassMetaData; import org.apache.openjpa.meta.ClassMetaData;
/** /**
@ -34,8 +35,7 @@ import org.apache.openjpa.meta.ClassMetaData;
* @author Abe White * @author Abe White
*/ */
class Aggregate class Aggregate
extends AbstractVal extends AbstractVal {
implements Val {
private final JDBCAggregateListener _listener; private final JDBCAggregateListener _listener;
private final Val _arg; private final Val _arg;
@ -145,12 +145,6 @@ class Aggregate
JavaSQLTypes.JDBC_DEFAULT, null), getType()); JavaSQLTypes.JDBC_DEFAULT, null), getType());
} }
public boolean hasVariable(Variable var) {
if (_arg != null)
return _arg.hasVariable(var);
return false;
}
public void calculateValue(Select sel, JDBCStore store, public void calculateValue(Select sel, JDBCStore store,
Object[] params, Val other, JDBCFetchConfiguration fetch) { Object[] params, Val other, JDBCFetchConfiguration fetch) {
if (_arg != null) if (_arg != null)
@ -189,4 +183,11 @@ class Aggregate
new FilterValueImpl(_arg, sel, store, params, fetch) new FilterValueImpl(_arg, sel, store, params, fetch)
}; };
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
if (_arg != null)
_arg.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -22,6 +22,7 @@ import org.apache.openjpa.jdbc.kernel.JDBCStore;
import org.apache.openjpa.jdbc.sql.Joins; import org.apache.openjpa.jdbc.sql.Joins;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
/** /**
* Combines two expressions. * Combines two expressions.
@ -81,11 +82,10 @@ class AndExpression
return _joins; return _joins;
} }
public boolean hasContainsExpression() { public void acceptVisit(ExpressionVisitor visitor) {
return _exp1.hasContainsExpression() || _exp2.hasContainsExpression(); visitor.enter(this);
} _exp1.acceptVisit(visitor);
_exp2.acceptVisit(visitor);
public boolean hasVariable(Variable var) { visitor.exit(this);
return _exp1.hasVariable(var) || _exp2.hasVariable(var);
} }
} }

View File

@ -22,6 +22,7 @@ import org.apache.openjpa.jdbc.sql.Result;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.exps.Arguments; import org.apache.openjpa.kernel.exps.Arguments;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
import org.apache.openjpa.kernel.exps.Value; import org.apache.openjpa.kernel.exps.Value;
import org.apache.openjpa.meta.ClassMetaData; import org.apache.openjpa.meta.ClassMetaData;
@ -31,7 +32,8 @@ import org.apache.openjpa.meta.ClassMetaData;
* @author Abe White * @author Abe White
*/ */
public class Args public class Args
implements Val, Arguments { extends AbstractVal
implements Arguments {
private final Val[] _args; private final Val[] _args;
private Joins _joins = null; private Joins _joins = null;
@ -130,13 +132,6 @@ public class Args
return null; return null;
} }
public boolean hasVariable(Variable var) {
for (int i = 0; i < _args.length; i++)
if (_args[i].hasVariable(var))
return true;
return false;
}
public void calculateValue(Select sel, JDBCStore store, public void calculateValue(Select sel, JDBCStore store,
Object[] params, Val other, JDBCFetchConfiguration fetch) { Object[] params, Val other, JDBCFetchConfiguration fetch) {
for (int i = 0; i < _args.length; i++) for (int i = 0; i < _args.length; i++)
@ -175,4 +170,11 @@ public class Args
public void appendIsNotNull(SQLBuffer sql, Select sel, public void appendIsNotNull(SQLBuffer sql, Select sel,
JDBCStore store, Object[] params, JDBCFetchConfiguration fetch) { JDBCStore store, Object[] params, JDBCFetchConfiguration fetch) {
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
for (int i = 0; i < _args.length; i++)
_args[i].acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -22,6 +22,7 @@ import org.apache.openjpa.jdbc.kernel.JDBCStore;
import org.apache.openjpa.jdbc.sql.Joins; import org.apache.openjpa.jdbc.sql.Joins;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
/** /**
* Combines a bind variable expression with another. * Combines a bind variable expression with another.
@ -69,11 +70,10 @@ class BindVariableAndExpression
return _joins; return _joins;
} }
public boolean hasContainsExpression() { public void acceptVisit(ExpressionVisitor visitor) {
return true; visitor.enter(this);
} _bind.acceptVisit(visitor);
_exp.acceptVisit(visitor);
public boolean hasVariable(Variable var) { visitor.exit(this);
return _exp.hasVariable(var);
} }
} }

View File

@ -22,6 +22,7 @@ import org.apache.openjpa.jdbc.kernel.JDBCStore;
import org.apache.openjpa.jdbc.sql.Joins; import org.apache.openjpa.jdbc.sql.Joins;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
/** /**
* Binds a variable to a value. Typically, the {@link #initialize} and * Binds a variable to a value. Typically, the {@link #initialize} and
@ -71,11 +72,9 @@ class BindVariableExpression
return _var.getJoins(); return _var.getJoins();
} }
public boolean hasContainsExpression() { public void acceptVisit(ExpressionVisitor visitor) {
return false; visitor.enter(this);
} _var.acceptVisit(visitor);
visitor.exit(this);
public boolean hasVariable(Variable var) {
return _var == var;
} }
} }

View File

@ -23,6 +23,7 @@ import org.apache.openjpa.jdbc.sql.Joins;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.Filters; import org.apache.openjpa.kernel.Filters;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
import org.apache.openjpa.lib.util.Localizer; import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.util.UserException; import org.apache.openjpa.util.UserException;
@ -108,14 +109,6 @@ abstract class CompareEqualExpression
return _joins; return _joins;
} }
public boolean hasContainsExpression() {
return false;
}
public boolean hasVariable(Variable var) {
return _val1.hasVariable(var) || _val2.hasVariable(var);
}
/** /**
* Append the SQL for the comparison. * Append the SQL for the comparison.
*/ */
@ -131,4 +124,11 @@ abstract class CompareEqualExpression
protected boolean isDirectComparison() { protected boolean isDirectComparison() {
return true; return true;
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_val1.acceptVisit(visitor);
_val2.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -23,6 +23,7 @@ import org.apache.openjpa.jdbc.sql.Joins;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.Filters; import org.apache.openjpa.kernel.Filters;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
import org.apache.openjpa.lib.util.Localizer; import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.util.UserException; import org.apache.openjpa.util.UserException;
@ -91,11 +92,10 @@ class CompareExpression
return _joins; return _joins;
} }
public boolean hasContainsExpression() { public void acceptVisit(ExpressionVisitor visitor) {
return false; visitor.enter(this);
} _val1.acceptVisit(visitor);
_val2.acceptVisit(visitor);
public boolean hasVariable(Variable var) { visitor.exit(this);
return _val1.hasVariable(var) || _val2.hasVariable(var);
} }
} }

View File

@ -27,6 +27,7 @@ import org.apache.openjpa.jdbc.sql.Result;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.Filters; import org.apache.openjpa.kernel.Filters;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
import org.apache.openjpa.meta.ClassMetaData; import org.apache.openjpa.meta.ClassMetaData;
/** /**
@ -35,8 +36,7 @@ import org.apache.openjpa.meta.ClassMetaData;
* @author Marc Prud'hommeaux * @author Marc Prud'hommeaux
*/ */
class Concat class Concat
extends AbstractVal extends AbstractVal {
implements Val {
private final Val _val1; private final Val _val1;
private final Val _val2; private final Val _val2;
@ -137,10 +137,6 @@ class Concat
JavaSQLTypes.JDBC_DEFAULT, null), getType()); JavaSQLTypes.JDBC_DEFAULT, null), getType());
} }
public boolean hasVariable(Variable var) {
return _val1.hasVariable(var) || _val2.hasVariable(var);
}
public void calculateValue(Select sel, JDBCStore store, public void calculateValue(Select sel, JDBCStore store,
Object[] params, Val other, JDBCFetchConfiguration fetch) { Object[] params, Val other, JDBCFetchConfiguration fetch) {
_val1.calculateValue(sel, store, params, null, fetch); _val1.calculateValue(sel, store, params, null, fetch);
@ -167,5 +163,12 @@ class Concat
_val2.appendTo(sql, 0, sel, store, params, fetch); _val2.appendTo(sql, 0, sel, store, params, fetch);
sql.append(_part3); sql.append(_part3);
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_val1.acceptVisit(visitor);
_val2.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -38,7 +38,8 @@ import org.apache.openjpa.meta.JavaTypes;
* @author Abe White * @author Abe White
*/ */
abstract class Const abstract class Const
implements Val, Constant { extends AbstractVal
implements Constant {
private ClassMetaData _meta = null; private ClassMetaData _meta = null;
private Column[] _cols = null; private Column[] _cols = null;
@ -51,10 +52,6 @@ abstract class Const
_meta = meta; _meta = meta;
} }
public boolean isVariable() {
return false;
}
/** /**
* Return the column for the value at the specified index, or null. * Return the column for the value at the specified index, or null.
*/ */
@ -152,10 +149,6 @@ abstract class Const
return Filters.convert(res.getObject(this, code, null), getType()); return Filters.convert(res.getObject(this, code, null), getType());
} }
public boolean hasVariable(Variable var) {
return false;
}
public int length() { public int length() {
return 1; return 1;
} }
@ -164,22 +157,22 @@ abstract class Const
JDBCStore store, Object[] params, JDBCFetchConfiguration fetch) { JDBCStore store, Object[] params, JDBCFetchConfiguration fetch) {
Object obj = getValue(); Object obj = getValue();
if (obj instanceof Collection && ((Collection) obj).isEmpty()) if (obj instanceof Collection && ((Collection) obj).isEmpty())
sql.append("1 = 1"); sql.append(TRUE);
else if (obj instanceof Map && ((Map) obj).isEmpty()) else if (obj instanceof Map && ((Map) obj).isEmpty())
sql.append("1 = 1"); sql.append(TRUE);
else else
sql.append("1 <> 1"); sql.append(FALSE);
} }
public void appendIsNotEmpty(SQLBuffer sql, Select sel, public void appendIsNotEmpty(SQLBuffer sql, Select sel,
JDBCStore store, Object[] params, JDBCFetchConfiguration fetch) { JDBCStore store, Object[] params, JDBCFetchConfiguration fetch) {
Object obj = getValue(); Object obj = getValue();
if (obj instanceof Collection && ((Collection) obj).isEmpty()) if (obj instanceof Collection && ((Collection) obj).isEmpty())
sql.append("1 <> 1"); sql.append(FALSE);
else if (obj instanceof Map && ((Map) obj).isEmpty()) else if (obj instanceof Map && ((Map) obj).isEmpty())
sql.append("1 <> 1"); sql.append(FALSE);
else else
sql.append("1 = 1"); sql.append(TRUE);
} }
public void appendSize(SQLBuffer sql, Select sel, JDBCStore store, public void appendSize(SQLBuffer sql, Select sel, JDBCStore store,
@ -196,16 +189,16 @@ abstract class Const
public void appendIsNull(SQLBuffer sql, Select sel, public void appendIsNull(SQLBuffer sql, Select sel,
JDBCStore store, Object[] params, JDBCFetchConfiguration fetch) { JDBCStore store, Object[] params, JDBCFetchConfiguration fetch) {
if (getSQLValue() == null) if (getSQLValue() == null)
sql.append("1 = 1"); sql.append(TRUE);
else else
sql.append("1 <> 1"); sql.append(FALSE);
} }
public void appendIsNotNull(SQLBuffer sql, Select sel, public void appendIsNotNull(SQLBuffer sql, Select sel,
JDBCStore store, Object[] params, JDBCFetchConfiguration fetch) { JDBCStore store, Object[] params, JDBCFetchConfiguration fetch) {
if (getSQLValue() != null) if (getSQLValue() != null)
sql.append("1 = 1"); sql.append(TRUE);
else else
sql.append("1 <> 1"); sql.append(FALSE);
} }
} }

View File

@ -23,6 +23,7 @@ import org.apache.openjpa.jdbc.sql.Joins;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.Filters; import org.apache.openjpa.kernel.Filters;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
/** /**
* Tests whether a value is an instance of a class. * Tests whether a value is an instance of a class.
@ -67,11 +68,9 @@ class ConstInstanceofExpression
return _const.getJoins(); return _const.getJoins();
} }
public boolean hasContainsExpression() { public void acceptVisit(ExpressionVisitor visitor) {
return false; visitor.enter(this);
} _const.acceptVisit(visitor);
visitor.exit(this);
public boolean hasVariable(Variable var) {
return _const.hasVariable(var);
} }
} }

View File

@ -27,6 +27,7 @@ import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.Broker; import org.apache.openjpa.kernel.Broker;
import org.apache.openjpa.kernel.Filters; import org.apache.openjpa.kernel.Filters;
import org.apache.openjpa.kernel.OpenJPAStateManager; import org.apache.openjpa.kernel.OpenJPAStateManager;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
import org.apache.openjpa.meta.ClassMetaData; import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.meta.FieldMetaData; import org.apache.openjpa.meta.FieldMetaData;
@ -175,4 +176,10 @@ class ConstPath
_val = null; _val = null;
_sqlVal = null; _sqlVal = null;
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_constant.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -59,8 +59,4 @@ class ContainsExpression
protected boolean isDirectComparison() { protected boolean isDirectComparison() {
return false; return false;
} }
public boolean hasContainsExpression() {
return true;
}
} }

View File

@ -35,7 +35,6 @@ class Count
public void initialize(Select sel, JDBCStore store, boolean nullTest) { public void initialize(Select sel, JDBCStore store, boolean nullTest) {
super.initialize(sel, store, nullTest); super.initialize(sel, store, nullTest);
// join into related object if present // join into related object if present
if (getVal()instanceof PCPath) if (getVal()instanceof PCPath)
((PCPath) getVal()).joinRelation(); ((PCPath) getVal()).joinRelation();

View File

@ -22,6 +22,7 @@ import org.apache.openjpa.jdbc.kernel.JDBCStore;
import org.apache.openjpa.jdbc.sql.Joins; import org.apache.openjpa.jdbc.sql.Joins;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
/** /**
* An empty expression. * An empty expression.
@ -47,11 +48,8 @@ class EmptyExpression
return null; return null;
} }
public boolean hasContainsExpression() { public void acceptVisit(ExpressionVisitor visitor) {
return false; visitor.enter(this);
} visitor.exit(this);
public boolean hasVariable(Variable var) {
return false;
} }
} }

View File

@ -27,6 +27,7 @@ import org.apache.openjpa.jdbc.sql.DBDictionary;
import org.apache.openjpa.jdbc.sql.Joins; import org.apache.openjpa.jdbc.sql.Joins;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
/** /**
* Test if one string ends with another. * Test if one string ends with another.
@ -116,12 +117,11 @@ class EndsWithExpression
return _joins; return _joins;
} }
public boolean hasContainsExpression() { public void acceptVisit(ExpressionVisitor visitor) {
return false; visitor.enter(this);
} _val1.acceptVisit(visitor);
_val2.acceptVisit(visitor);
public boolean hasVariable(Variable var) { visitor.exit(this);
return _val1.hasVariable(var) || _val2.hasVariable(var);
} }
/** /**

View File

@ -69,15 +69,4 @@ interface Exp
* that common joins are moved up the expression tree. * that common joins are moved up the expression tree.
*/ */
public Joins getJoins(); public Joins getJoins();
/**
* Return true if this expression is or is made up of a contains expression.
*/
public boolean hasContainsExpression();
/**
* Return true if the expression or any subexpression uses the given
* variable.
*/
public boolean hasVariable(Variable var);
} }

View File

@ -27,6 +27,7 @@ import org.apache.openjpa.jdbc.sql.Result;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.Filters; import org.apache.openjpa.kernel.Filters;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
import org.apache.openjpa.meta.ClassMetaData; import org.apache.openjpa.meta.ClassMetaData;
/** /**
@ -159,11 +160,6 @@ class Extension
JavaSQLTypes.JDBC_DEFAULT, null), getType()); JavaSQLTypes.JDBC_DEFAULT, null), getType());
} }
public boolean hasVariable(Variable var) {
return (_target != null && _target.hasVariable(var))
|| (_arg != null && _arg.hasVariable(var));
}
public void calculateValue(Select sel, JDBCStore store, public void calculateValue(Select sel, JDBCStore store,
Object[] params, Val other, JDBCFetchConfiguration fetch) { Object[] params, Val other, JDBCFetchConfiguration fetch) {
if (_target != null) if (_target != null)
@ -209,6 +205,15 @@ class Extension
}; };
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter((Exp) this);
if (_target != null)
_target.acceptVisit(visitor);
if (_arg != null)
_arg.acceptVisit(visitor);
visitor.exit((Exp) this);
}
////////////////////// //////////////////////
// Exp implementation // Exp implementation
////////////////////// //////////////////////
@ -225,8 +230,4 @@ class Extension
sel.append(sql, getJoins()); sel.append(sql, getJoins());
clearParameters(); clearParameters();
} }
public boolean hasContainsExpression() {
return false;
}
} }

View File

@ -27,6 +27,7 @@ import org.apache.openjpa.jdbc.sql.Result;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.Filters; import org.apache.openjpa.kernel.Filters;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
import org.apache.openjpa.lib.util.Localizer; import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.meta.ClassMetaData; import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.util.ApplicationIds; import org.apache.openjpa.util.ApplicationIds;
@ -41,8 +42,7 @@ import serp.util.Numbers;
* @author Abe White * @author Abe White
*/ */
class GetObjectId class GetObjectId
extends AbstractVal extends AbstractVal {
implements Val {
private static final Localizer _loc = Localizer.forPackage private static final Localizer _loc = Localizer.forPackage
(GetObjectId.class); (GetObjectId.class);
@ -69,10 +69,6 @@ class GetObjectId
_meta = meta; _meta = meta;
} }
public boolean isVariable() {
return false;
}
public Class getType() { public Class getType() {
return Object.class; return Object.class;
} }
@ -159,10 +155,6 @@ class GetObjectId
return _path.load(res, store, true, fetch); return _path.load(res, store, true, fetch);
} }
public boolean hasVariable(Variable var) {
return _path.hasVariable(var);
}
public void calculateValue(Select sel, JDBCStore store, public void calculateValue(Select sel, JDBCStore store,
Object[] params, Val other, JDBCFetchConfiguration fetch) { Object[] params, Val other, JDBCFetchConfiguration fetch) {
_path.calculateValue(sel, store, params, null, fetch); _path.calculateValue(sel, store, params, null, fetch);
@ -180,5 +172,11 @@ class GetObjectId
JDBCStore store, Object[] params, JDBCFetchConfiguration fetch) { JDBCStore store, Object[] params, JDBCFetchConfiguration fetch) {
_path.appendTo(sql, index, sel, store, params, fetch); _path.appendTo(sql, index, sel, store, params, fetch);
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_path.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -0,0 +1,29 @@
package org.apache.openjpa.jdbc.kernel.exps;
import org.apache.openjpa.kernel.exps.AbstractExpressionVisitor;
import org.apache.openjpa.kernel.exps.Expression;
import org.apache.openjpa.kernel.exps.Value;
/**
* Determines whether the visited expressions include a "contains" expression.
*
* @author Abe White
*/
class HasContainsExpressionVisitor
extends AbstractExpressionVisitor {
private boolean _found = false;
/**
* Whether a contains expression has been found.
*/
public boolean foundContainsExpression() {
return _found;
}
public void enter(Expression exp) {
if (!_found)
_found = exp instanceof ContainsExpression
|| exp instanceof BindVariableAndExpression;
}
}

View File

@ -26,6 +26,7 @@ import org.apache.openjpa.jdbc.schema.Column;
import org.apache.openjpa.jdbc.sql.Joins; import org.apache.openjpa.jdbc.sql.Joins;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
/** /**
* Tests whether a value is IN a collection. * Tests whether a value is IN a collection.
@ -158,18 +159,17 @@ class InExpression
return _val.getJoins(); return _val.getJoins();
} }
public boolean hasContainsExpression() {
return false;
}
public boolean hasVariable(Variable var) {
return _const.hasVariable(var) || _val.hasVariable(var);
}
/** /**
* Return the collection to test for containment with. * Return the collection to test for containment with.
*/ */
protected Collection getCollection() { protected Collection getCollection() {
return (Collection) _const.getValue(); return (Collection) _const.getValue();
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_val.acceptVisit(visitor);
_const.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -22,6 +22,7 @@ import org.apache.openjpa.jdbc.kernel.JDBCStore;
import org.apache.openjpa.jdbc.sql.Joins; import org.apache.openjpa.jdbc.sql.Joins;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
/** /**
* Tests whether a value is IN a subquery. * Tests whether a value is IN a subquery.
@ -69,11 +70,10 @@ class InSubQExpression
return _val.getJoins(); return _val.getJoins();
} }
public boolean hasContainsExpression() { public void acceptVisit(ExpressionVisitor visitor) {
return false; visitor.enter(this);
} _val.acceptVisit(visitor);
_sub.acceptVisit(visitor);
public boolean hasVariable(Variable var) { visitor.exit(this);
return _val.hasVariable(var) || _sub.hasVariable(var);
} }
} }

View File

@ -25,6 +25,7 @@ import org.apache.openjpa.jdbc.sql.Result;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.Filters; import org.apache.openjpa.kernel.Filters;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
import org.apache.openjpa.meta.ClassMetaData; import org.apache.openjpa.meta.ClassMetaData;
/** /**
@ -33,8 +34,7 @@ import org.apache.openjpa.meta.ClassMetaData;
* @author Abe White * @author Abe White
*/ */
class IndexOf class IndexOf
extends AbstractVal extends AbstractVal {
implements Val {
private final Val _val1; private final Val _val1;
private final Val _val2; private final Val _val2;
@ -123,10 +123,6 @@ class IndexOf
JavaSQLTypes.JDBC_DEFAULT, null), getType()); JavaSQLTypes.JDBC_DEFAULT, null), getType());
} }
public boolean hasVariable(Variable var) {
return _val1.hasVariable(var) || _val2.hasVariable(var);
}
public void calculateValue(Select sel, JDBCStore store, public void calculateValue(Select sel, JDBCStore store,
Object[] params, Val other, JDBCFetchConfiguration fetch) { Object[] params, Val other, JDBCFetchConfiguration fetch) {
_val1.calculateValue(sel, store, params, null, fetch); _val1.calculateValue(sel, store, params, null, fetch);
@ -158,5 +154,12 @@ class IndexOf
store.getDBDictionary().indexOf(sql, str, search, start); store.getDBDictionary().indexOf(sql, str, search, start);
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_val1.acceptVisit(visitor);
_val2.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -26,6 +26,7 @@ import org.apache.openjpa.jdbc.meta.MappingRepository;
import org.apache.openjpa.jdbc.sql.Joins; import org.apache.openjpa.jdbc.sql.Joins;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
import org.apache.openjpa.meta.JavaTypes; import org.apache.openjpa.meta.JavaTypes;
/** /**
@ -143,12 +144,10 @@ class InstanceofExpression
return _joins; return _joins;
} }
public boolean hasContainsExpression() { public void acceptVisit(ExpressionVisitor visitor) {
return false; visitor.enter(this);
} _path.acceptVisit(visitor);
visitor.exit(this);
public boolean hasVariable(Variable var) {
return _path.hasVariable(var);
} }
} }

View File

@ -22,6 +22,7 @@ import org.apache.openjpa.jdbc.kernel.JDBCStore;
import org.apache.openjpa.jdbc.sql.Joins; import org.apache.openjpa.jdbc.sql.Joins;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
/** /**
* Tests whether the given value is empty. * Tests whether the given value is empty.
@ -62,11 +63,9 @@ class IsEmptyExpression
return _val.getJoins(); return _val.getJoins();
} }
public boolean hasContainsExpression() { public void acceptVisit(ExpressionVisitor visitor) {
return false; visitor.enter(this);
} _val.acceptVisit(visitor);
visitor.exit(this);
public boolean hasVariable(Variable var) {
return _val.hasVariable(var);
} }
} }

View File

@ -22,6 +22,7 @@ import org.apache.openjpa.jdbc.kernel.JDBCStore;
import org.apache.openjpa.jdbc.sql.Joins; import org.apache.openjpa.jdbc.sql.Joins;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
/** /**
* Tests whether the given value is not empty. * Tests whether the given value is not empty.
@ -62,11 +63,9 @@ class IsNotEmptyExpression
return _val.getJoins(); return _val.getJoins();
} }
public boolean hasContainsExpression() { public void acceptVisit(ExpressionVisitor visitor) {
return false; visitor.enter(this);
} _val.acceptVisit(visitor);
visitor.exit(this);
public boolean hasVariable(Variable var) {
return _val.hasVariable(var);
} }
} }

View File

@ -214,7 +214,10 @@ public class JDBCExpressionFactory
public Expression not(Expression exp) { public Expression not(Expression exp) {
Exp e = (Exp) exp; Exp e = (Exp) exp;
if (e.hasContainsExpression()) HasContainsExpressionVisitor visitor =
new HasContainsExpressionVisitor();
e.acceptVisit(visitor);
if (visitor.foundContainsExpression())
return new NotContainsExpression(e); return new NotContainsExpression(e);
return new NotExpression(e); return new NotExpression(e);
} }

View File

@ -26,8 +26,7 @@ import org.apache.openjpa.util.UserException;
* Tests if the target contains the given argument. The argument must be * Tests if the target contains the given argument. The argument must be
* a constant. * a constant.
* Examples:<br /> * Examples:<br />
* <code> "address.street.ext:stringContains (\"main\")" * <code>"address.street.ext:stringContains (\"main\")"</code>
* </code>
* *
* @nojavadoc * @nojavadoc
* @deprecated Use <code>matches()</code> instead. * @deprecated Use <code>matches()</code> instead.

View File

@ -27,8 +27,7 @@ import org.apache.openjpa.util.UserException;
* argument. The wildcard '?' is used to represent any single character, * argument. The wildcard '?' is used to represent any single character,
* while '*' is used to represent any series of 0 or more characters. * while '*' is used to represent any series of 0 or more characters.
* Examples:<br /> * Examples:<br />
* <code> "address.street.ext:wildcardMatch (\"?ain*reet\")" * <code>"address.street.ext:wildcardMatch (\"?ain*reet\")"</code>
* </code>
* *
* @nojavadoc * @nojavadoc
* @deprecated Use <code>matches()</code> instead. * @deprecated Use <code>matches()</code> instead.

View File

@ -23,6 +23,7 @@ import org.apache.openjpa.jdbc.schema.Column;
import org.apache.openjpa.jdbc.sql.Joins; import org.apache.openjpa.jdbc.sql.Joins;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
import serp.util.Strings; import serp.util.Strings;
/** /**
@ -123,11 +124,10 @@ class MatchesExpression
return _joins; return _joins;
} }
public boolean hasContainsExpression() { public void acceptVisit(ExpressionVisitor visitor) {
return false; visitor.enter(this);
} _val.acceptVisit(visitor);
_const.acceptVisit(visitor);
public boolean hasVariable(Variable var) { visitor.exit(this);
return _val.hasVariable(var) || _const.hasVariable(var);
} }
} }

View File

@ -25,6 +25,7 @@ import org.apache.openjpa.jdbc.sql.Result;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.Filters; import org.apache.openjpa.kernel.Filters;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
import org.apache.openjpa.meta.ClassMetaData; import org.apache.openjpa.meta.ClassMetaData;
/** /**
@ -33,8 +34,7 @@ import org.apache.openjpa.meta.ClassMetaData;
* @author Abe White * @author Abe White
*/ */
class Math class Math
extends AbstractVal extends AbstractVal {
implements Val {
public static final String ADD = "+"; public static final String ADD = "+";
public static final String SUBTRACT = "-"; public static final String SUBTRACT = "-";
@ -134,10 +134,6 @@ class Math
JavaSQLTypes.JDBC_DEFAULT, null), getType()); JavaSQLTypes.JDBC_DEFAULT, null), getType());
} }
public boolean hasVariable(Variable var) {
return _val1.hasVariable(var) || _val2.hasVariable(var);
}
public void calculateValue(Select sel, JDBCStore store, public void calculateValue(Select sel, JDBCStore store,
Object[] params, Val other, JDBCFetchConfiguration fetch) { Object[] params, Val other, JDBCFetchConfiguration fetch) {
_val1.calculateValue(sel, store, params, _val2, fetch); _val1.calculateValue(sel, store, params, _val2, fetch);
@ -159,5 +155,12 @@ class Math
new FilterValueImpl(_val1, sel, store, params, fetch), new FilterValueImpl(_val1, sel, store, params, fetch),
new FilterValueImpl(_val2, sel, store, params, fetch)); new FilterValueImpl(_val2, sel, store, params, fetch));
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_val1.acceptVisit(visitor);
_val2.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -23,6 +23,7 @@ import org.apache.openjpa.jdbc.sql.DBDictionary;
import org.apache.openjpa.jdbc.sql.Joins; import org.apache.openjpa.jdbc.sql.Joins;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
/** /**
* Negates a contains expression using a subselect to make sure no * Negates a contains expression using a subselect to make sure no
@ -76,11 +77,9 @@ class NotContainsExpression
return null; return null;
} }
public boolean hasContainsExpression() { public void acceptVisit(ExpressionVisitor visitor) {
return false; visitor.enter(this);
} _exp.acceptVisit(visitor);
visitor.exit(this);
public boolean hasVariable(Variable var) {
return _exp.hasVariable(var);
} }
} }

View File

@ -22,6 +22,7 @@ import org.apache.openjpa.jdbc.kernel.JDBCStore;
import org.apache.openjpa.jdbc.sql.Joins; import org.apache.openjpa.jdbc.sql.Joins;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
/** /**
* Negates an expression. * Negates an expression.
@ -63,11 +64,9 @@ class NotExpression
return _joins; return _joins;
} }
public boolean hasContainsExpression() { public void acceptVisit(ExpressionVisitor visitor) {
return _exp.hasContainsExpression(); visitor.enter(this);
} _exp.acceptVisit(visitor);
visitor.exit(this);
public boolean hasVariable(Variable var) {
return _exp.hasVariable(var);
} }
} }

View File

@ -24,6 +24,7 @@ import org.apache.openjpa.jdbc.kernel.JDBCStore;
import org.apache.openjpa.jdbc.sql.Joins; import org.apache.openjpa.jdbc.sql.Joins;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
/** /**
* Combines two expressions. * Combines two expressions.
@ -97,11 +98,10 @@ class OrExpression
return _joins; return _joins;
} }
public boolean hasContainsExpression() { public void acceptVisit(ExpressionVisitor visitor) {
return _exp1.hasContainsExpression() || _exp2.hasContainsExpression(); visitor.enter(this);
} _exp1.acceptVisit(visitor);
_exp2.acceptVisit(visitor);
public boolean hasVariable(Variable var) { visitor.exit(this);
return _exp1.hasVariable(var) || _exp2.hasVariable(var);
} }
} }

View File

@ -44,6 +44,7 @@ import org.apache.openjpa.util.UserException;
* @author Abe White * @author Abe White
*/ */
class PCPath class PCPath
extends AbstractVal
implements JDBCPath { implements JDBCPath {
private static final int PATH = 0; private static final int PATH = 0;
@ -543,6 +544,9 @@ class PCPath
return ret; return ret;
} }
/**
* Whether the given variable appears in this path.
*/
public boolean hasVariable(Variable var) { public boolean hasVariable(Variable var) {
if (_actions == null) if (_actions == null)
return false; return false;
@ -585,7 +589,7 @@ class PCPath
public void appendIsEmpty(SQLBuffer sql, Select sel, public void appendIsEmpty(SQLBuffer sql, Select sel,
JDBCStore store, Object[] params, JDBCFetchConfiguration fetch) { JDBCStore store, Object[] params, JDBCFetchConfiguration fetch) {
if (_field == null) if (_field == null)
sql.append("1 <> 1"); sql.append(FALSE);
else else
_field.appendIsEmpty(sql, sel, _joins); _field.appendIsEmpty(sql, sel, _joins);
} }
@ -593,7 +597,7 @@ class PCPath
public void appendIsNotEmpty(SQLBuffer sql, Select sel, public void appendIsNotEmpty(SQLBuffer sql, Select sel,
JDBCStore store, Object[] params, JDBCFetchConfiguration fetch) { JDBCStore store, Object[] params, JDBCFetchConfiguration fetch) {
if (_field == null) if (_field == null)
sql.append("1 <> 1"); sql.append(FALSE);
else else
_field.appendIsNotEmpty(sql, sel, _joins); _field.appendIsNotEmpty(sql, sel, _joins);
} }
@ -609,7 +613,7 @@ class PCPath
public void appendIsNull(SQLBuffer sql, Select sel, public void appendIsNull(SQLBuffer sql, Select sel,
JDBCStore store, Object[] params, JDBCFetchConfiguration fetch) { JDBCStore store, Object[] params, JDBCFetchConfiguration fetch) {
if (_field == null) if (_field == null)
sql.append("1 <> 1"); sql.append(FALSE);
else else
_field.appendIsNull(sql, sel, _joins); _field.appendIsNull(sql, sel, _joins);
} }
@ -617,7 +621,7 @@ class PCPath
public void appendIsNotNull(SQLBuffer sql, Select sel, public void appendIsNotNull(SQLBuffer sql, Select sel,
JDBCStore store, Object[] params, JDBCFetchConfiguration fetch) { JDBCStore store, Object[] params, JDBCFetchConfiguration fetch) {
if (_field == null) if (_field == null)
sql.append("1 = 1"); sql.append(TRUE);
else else
_field.appendIsNotNull(sql, sel, _joins); _field.appendIsNotNull(sql, sel, _joins);
} }

View File

@ -27,8 +27,7 @@ import org.apache.openjpa.util.UserException;
* Simple listener which embeds its SQL argument into the query. Listens * Simple listener which embeds its SQL argument into the query. Listens
* on <code>sql</code>. * on <code>sql</code>.
* Example:<br /> * Example:<br />
* <code> "price &lt; sql(\"(SELECT AVG (PRICE) FROM PRODUCT_TABLE)\")" * <code>"price &lt; sql(\"(SELECT AVG (PRICE) FROM PRODUCT_TABLE)\")"</code>
* </code>
* *
* @nojavadoc * @nojavadoc
*/ */

View File

@ -205,9 +205,12 @@ class SelectConstructor {
private void initializeJoins(Select sel, JDBCStore store, private void initializeJoins(Select sel, JDBCStore store,
QueryExpressions exps, Object[] params) { QueryExpressions exps, Object[] params) {
Map contains = null; Map contains = null;
if (((Exp) exps.filter).hasContainsExpression() HasContainsExpressionVisitor visitor =
|| (exps.having != null new HasContainsExpressionVisitor();
&& ((Exp) exps.having).hasContainsExpression())) exps.filter.acceptVisit(visitor);
if (!visitor.foundContainsExpression() && exps.having != null)
exps.having.acceptVisit(visitor);
if (visitor.foundContainsExpression())
contains = new HashMap(7); contains = new HashMap(7);
// initialize filter and having expressions // initialize filter and having expressions

View File

@ -27,8 +27,7 @@ import org.apache.openjpa.util.InternalException;
* @author Marc Prud'hommeaux * @author Marc Prud'hommeaux
*/ */
class Size class Size
extends UnaryOp extends UnaryOp {
implements Val {
public Size(Val val) { public Size(Val val) {
super(val); super(val);

View File

@ -27,6 +27,7 @@ import org.apache.openjpa.jdbc.sql.DBDictionary;
import org.apache.openjpa.jdbc.sql.Joins; import org.apache.openjpa.jdbc.sql.Joins;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
import serp.util.Numbers; import serp.util.Numbers;
/** /**
@ -117,12 +118,11 @@ class StartsWithExpression
return _joins; return _joins;
} }
public boolean hasContainsExpression() { public void acceptVisit(ExpressionVisitor visitor) {
return false; visitor.enter(this);
} _val1.acceptVisit(visitor);
_val2.acceptVisit(visitor);
public boolean hasVariable(Variable var) { visitor.exit(this);
return _val1.hasVariable(var) || _val2.hasVariable(var);
} }
/** /**

View File

@ -25,6 +25,7 @@ import org.apache.openjpa.jdbc.sql.Result;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.Filters; import org.apache.openjpa.kernel.Filters;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
import org.apache.openjpa.meta.ClassMetaData; import org.apache.openjpa.meta.ClassMetaData;
/** /**
@ -33,8 +34,7 @@ import org.apache.openjpa.meta.ClassMetaData;
* @author Marc Prud'hommeaux * @author Marc Prud'hommeaux
*/ */
abstract class StringFunction abstract class StringFunction
extends AbstractVal extends AbstractVal {
implements Val {
final Val _val; final Val _val;
ClassMetaData _meta = null; ClassMetaData _meta = null;
@ -111,10 +111,6 @@ abstract class StringFunction
JavaSQLTypes.JDBC_DEFAULT, null), getType()); JavaSQLTypes.JDBC_DEFAULT, null), getType());
} }
public boolean hasVariable(Variable var) {
return _val.hasVariable(var);
}
public void calculateValue(Select sel, JDBCStore store, public void calculateValue(Select sel, JDBCStore store,
Object[] params, Val other, JDBCFetchConfiguration fetch) { Object[] params, Val other, JDBCFetchConfiguration fetch) {
_val.calculateValue(sel, store, params, null, fetch); _val.calculateValue(sel, store, params, null, fetch);
@ -134,5 +130,11 @@ abstract class StringFunction
_val.appendTo(sql, 0, sel, store, params, fetch); _val.appendTo(sql, 0, sel, store, params, fetch);
sql.append(_post); sql.append(_post);
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_val.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -26,6 +26,7 @@ import org.apache.openjpa.jdbc.sql.Result;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.Filters; import org.apache.openjpa.kernel.Filters;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
import org.apache.openjpa.kernel.exps.QueryExpressions; import org.apache.openjpa.kernel.exps.QueryExpressions;
import org.apache.openjpa.kernel.exps.Subquery; import org.apache.openjpa.kernel.exps.Subquery;
import org.apache.openjpa.meta.ClassMetaData; import org.apache.openjpa.meta.ClassMetaData;
@ -36,7 +37,8 @@ import org.apache.openjpa.meta.ClassMetaData;
* @author Abe White * @author Abe White
*/ */
class SubQ class SubQ
implements Val, Subquery { extends AbstractVal
implements Subquery {
private final ClassMapping _candidate; private final ClassMapping _candidate;
private final boolean _subs; private final boolean _subs;
@ -155,25 +157,6 @@ class SubQ
JavaSQLTypes.JDBC_DEFAULT, null), getType()); JavaSQLTypes.JDBC_DEFAULT, null), getType());
} }
public boolean hasVariable(Variable var) {
for (int i = 0; i < _exps.projections.length; i++)
if (((Val) _exps.projections[i]).hasVariable(var))
return true;
if (_exps.filter != null)
if (((Exp) _exps.filter).hasVariable(var))
return true;
for (int i = 0; i < _exps.grouping.length; i++)
if (((Val) _exps.grouping[i]).hasVariable(var))
return true;
if (_exps.having != null)
if (((Exp) _exps.having).hasVariable(var))
return true;
for (int i = 0; i < _exps.ordering.length; i++)
if (((Val) _exps.ordering[i]).hasVariable(var))
return true;
return false;
}
public void calculateValue(Select sel, JDBCStore store, public void calculateValue(Select sel, JDBCStore store,
Object[] params, Val other, JDBCFetchConfiguration fetch) { Object[] params, Val other, JDBCFetchConfiguration fetch) {
} }
@ -222,15 +205,18 @@ class SubQ
appendTo(sql, 0, sel, store, params, fetch, true); appendTo(sql, 0, sel, store, params, fetch, true);
} }
public void appendIsNull(SQLBuffer sql, Select sel, public void acceptVisit(ExpressionVisitor visitor) {
JDBCStore store, Object[] params, JDBCFetchConfiguration fetch) { visitor.enter(this);
appendTo(sql, 0, sel, store, params, fetch); for (int i = 0; i < _exps.projections.length; i++)
sql.append(" IS NULL"); _exps.projections[i].acceptVisit(visitor);
} if (_exps.filter != null)
_exps.filter.acceptVisit(visitor);
public void appendIsNotNull(SQLBuffer sql, Select sel, for (int i = 0; i < _exps.grouping.length; i++)
JDBCStore store, Object[] params, JDBCFetchConfiguration fetch) { _exps.grouping[i].acceptVisit(visitor);
appendTo(sql, 0, sel, store, params, fetch); if (_exps.having != null)
sql.append(" IS NOT NULL"); _exps.having.acceptVisit(visitor);
for (int i = 0; i < _exps.ordering.length; i++)
_exps.ordering[i].acceptVisit(visitor);
visitor.exit(this);
} }
} }

View File

@ -25,6 +25,7 @@ import org.apache.openjpa.jdbc.sql.Result;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.Filters; import org.apache.openjpa.kernel.Filters;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
import org.apache.openjpa.meta.ClassMetaData; import org.apache.openjpa.meta.ClassMetaData;
/** /**
@ -33,8 +34,7 @@ import org.apache.openjpa.meta.ClassMetaData;
* @author Abe White * @author Abe White
*/ */
class Substring class Substring
extends AbstractVal extends AbstractVal {
implements Val {
private final Val _val1; private final Val _val1;
private final Val _val2; private final Val _val2;
@ -119,10 +119,6 @@ class Substring
JavaSQLTypes.JDBC_DEFAULT, null), getType()); JavaSQLTypes.JDBC_DEFAULT, null), getType());
} }
public boolean hasVariable(Variable var) {
return _val1.hasVariable(var) || _val2.hasVariable(var);
}
public void calculateValue(Select sel, JDBCStore store, public void calculateValue(Select sel, JDBCStore store,
Object[] params, Val other, JDBCFetchConfiguration fetch) { Object[] params, Val other, JDBCFetchConfiguration fetch) {
_val1.calculateValue(sel, store, params, null, fetch); _val1.calculateValue(sel, store, params, null, fetch);
@ -153,5 +149,12 @@ class Substring
store.getDBDictionary().substring(sql, str, start, end); store.getDBDictionary().substring(sql, str, start, end);
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_val1.acceptVisit(visitor);
_val2.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -27,6 +27,7 @@ import org.apache.openjpa.jdbc.sql.Result;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.Filters; import org.apache.openjpa.kernel.Filters;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
import org.apache.openjpa.kernel.exps.Literal; import org.apache.openjpa.kernel.exps.Literal;
import org.apache.openjpa.meta.ClassMetaData; import org.apache.openjpa.meta.ClassMetaData;
@ -36,8 +37,7 @@ import org.apache.openjpa.meta.ClassMetaData;
* @author Marc Prud'hommeaux * @author Marc Prud'hommeaux
*/ */
class Trim class Trim
extends AbstractVal extends AbstractVal {
implements Val {
private final Val _val; private final Val _val;
private final Val _trimChar; private final Val _trimChar;
@ -133,10 +133,6 @@ class Trim
JavaSQLTypes.JDBC_DEFAULT, null), getType()); JavaSQLTypes.JDBC_DEFAULT, null), getType());
} }
public boolean hasVariable(Variable var) {
return _val.hasVariable(var);
}
public void calculateValue(Select sel, JDBCStore store, public void calculateValue(Select sel, JDBCStore store,
Object[] params, Val other, JDBCFetchConfiguration fetch) { Object[] params, Val other, JDBCFetchConfiguration fetch) {
_val.calculateValue(sel, store, params, null, fetch); _val.calculateValue(sel, store, params, null, fetch);
@ -192,5 +188,12 @@ class Trim
} }
} }
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_val.acceptVisit(visitor);
_trimChar.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -25,6 +25,7 @@ import org.apache.openjpa.jdbc.sql.Result;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.Filters; import org.apache.openjpa.kernel.Filters;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
import org.apache.openjpa.meta.ClassMetaData; import org.apache.openjpa.meta.ClassMetaData;
/** /**
@ -33,8 +34,7 @@ import org.apache.openjpa.meta.ClassMetaData;
* @author Abe White * @author Abe White
*/ */
abstract class UnaryOp abstract class UnaryOp
extends AbstractVal extends AbstractVal {
implements Val {
private final Val _val; private final Val _val;
private ClassMetaData _meta = null; private ClassMetaData _meta = null;
@ -123,10 +123,6 @@ abstract class UnaryOp
JavaSQLTypes.JDBC_DEFAULT, null), getType()); JavaSQLTypes.JDBC_DEFAULT, null), getType());
} }
public boolean hasVariable(Variable var) {
return _val.hasVariable(var);
}
public void calculateValue(Select sel, JDBCStore store, public void calculateValue(Select sel, JDBCStore store,
Object[] params, Val other, JDBCFetchConfiguration fetch) { Object[] params, Val other, JDBCFetchConfiguration fetch) {
_val.calculateValue(sel, store, params, null, fetch); _val.calculateValue(sel, store, params, null, fetch);
@ -167,5 +163,11 @@ abstract class UnaryOp
* Return the name of this operator. * Return the name of this operator.
*/ */
protected abstract String getOperator(); protected abstract String getOperator();
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_val.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -96,11 +96,6 @@ public interface Val
JDBCFetchConfiguration fetch) JDBCFetchConfiguration fetch)
throws SQLException; throws SQLException;
/**
* Return true if this value uses the given variable.
*/
public boolean hasVariable(Variable var);
/** /**
* Calculate and cache the SQL for this value. This method is called * Calculate and cache the SQL for this value. This method is called
* before <code>length</code> or any <code>append</code> methods. * before <code>length</code> or any <code>append</code> methods.

View File

@ -23,6 +23,7 @@ import org.apache.openjpa.jdbc.sql.Joins;
import org.apache.openjpa.jdbc.sql.Result; import org.apache.openjpa.jdbc.sql.Result;
import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.exps.ExpressionVisitor;
import org.apache.openjpa.meta.ClassMetaData; import org.apache.openjpa.meta.ClassMetaData;
/** /**
@ -37,7 +38,7 @@ import org.apache.openjpa.meta.ClassMetaData;
* @author Abe White * @author Abe White
*/ */
class Variable class Variable
implements Val { extends AbstractVal {
private final String _name; private final String _name;
private final Class _type; private final Class _type;
@ -143,10 +144,6 @@ class Variable
return null; return null;
} }
public boolean hasVariable(Variable var) {
return this == var;
}
public void calculateValue(Select sel, JDBCStore store, public void calculateValue(Select sel, JDBCStore store,
Object[] params, Val other, JDBCFetchConfiguration fetch) { Object[] params, Val other, JDBCFetchConfiguration fetch) {
if (_path != null) if (_path != null)
@ -185,4 +182,11 @@ class Variable
public void appendIsNotNull(SQLBuffer sql, Select sel, public void appendIsNotNull(SQLBuffer sql, Select sel,
JDBCStore store, Object[] params, JDBCFetchConfiguration fetch) { JDBCStore store, Object[] params, JDBCFetchConfiguration fetch) {
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
if (_path != null)
_path.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -23,6 +23,7 @@ import java.util.Map;
import org.apache.commons.collections.map.LinkedMap; import org.apache.commons.collections.map.LinkedMap;
import org.apache.openjpa.conf.OpenJPAConfiguration; import org.apache.openjpa.conf.OpenJPAConfiguration;
import org.apache.openjpa.kernel.exps.AbstractExpressionVisitor;
import org.apache.openjpa.kernel.exps.AggregateListener; import org.apache.openjpa.kernel.exps.AggregateListener;
import org.apache.openjpa.kernel.exps.ExpressionFactory; import org.apache.openjpa.kernel.exps.ExpressionFactory;
import org.apache.openjpa.kernel.exps.ExpressionParser; import org.apache.openjpa.kernel.exps.ExpressionParser;
@ -396,16 +397,16 @@ public class ExpressionStoreQuery
if (_exps[0].projections.length == 0) if (_exps[0].projections.length == 0)
_projTypes = StoreQuery.EMPTY_CLASSES; _projTypes = StoreQuery.EMPTY_CLASSES;
else { else {
AssertNoVariablesExpressionVisitor novars = new
AssertNoVariablesExpressionVisitor(q.getContext());
_projTypes = new Class[_exps[0].projections.length]; _projTypes = new Class[_exps[0].projections.length];
for (int i = 0; i < _exps[0].projections.length; i++) { for (int i = 0; i < _exps[0].projections.length; i++) {
_projTypes[i] = _exps[0].projections[i].getType(); _projTypes[i] = _exps[0].projections[i].getType();
assertNotContainer(_exps[0].projections[i], q); assertNotContainer(_exps[0].projections[i], q);
assertNotVariable((Val) _exps[0].projections[i], _exps[0].projections[i].acceptVisit(novars);
q.getContext());
} }
for (int i = 0; i < _exps[0].grouping.length; i++) for (int i = 0; i < _exps[0].grouping.length; i++)
assertNotVariable((Val) _exps[0].grouping[i], _exps[0].grouping[i].acceptVisit(novars);
q.getContext());
} }
} }
@ -413,17 +414,6 @@ public class ExpressionStoreQuery
return _exps; return _exps;
} }
/**
* We can't handle in-memory projections or grouping that uses
* variables.
*/
private static void assertNotVariable(Val val, QueryContext ctx) {
// we can't handle in-mem results that use variables
if (val.hasVariables())
throw new UnsupportedException(_loc.get("inmem-agg-proj-var",
ctx.getCandidateType(), ctx.getQueryString()));
}
public ResultObjectProvider executeQuery(StoreQuery q, public ResultObjectProvider executeQuery(StoreQuery q,
Object[] params, boolean lrs, long startIdx, long endIdx) { Object[] params, boolean lrs, long startIdx, long endIdx) {
// execute in memory for candidate collection; // execute in memory for candidate collection;
@ -517,6 +507,26 @@ public class ExpressionStoreQuery
public Class[] getProjectionTypes(StoreQuery q) { public Class[] getProjectionTypes(StoreQuery q) {
return _projTypes; return _projTypes;
} }
/**
* Throws an exception if a variable is found.
*/
private static class AssertNoVariablesExpressionVisitor
extends AbstractExpressionVisitor {
private final QueryContext _ctx;
public AssertNoVariablesExpressionVisitor(QueryContext ctx) {
_ctx = ctx;
}
public void enter(Value val) {
if (!val.isVariable())
return;
throw new UnsupportedException(_loc.get("inmem-agg-proj-var",
_ctx.getCandidateType(), _ctx.getQueryString()));
}
}
} }
/** /**

View File

@ -90,8 +90,8 @@ class SingleFieldManager
if (proxy == null) { if (proxy == null) {
proxy = (Proxy) _sm.newFieldProxy(field); proxy = (Proxy) _sm.newFieldProxy(field);
if (objval != null) if (objval != null)
((Calendar) proxy) ((Calendar) proxy).setTime(((Calendar) objval).
.setTime(((Calendar) objval).getTime()); getTime());
ret = true; ret = true;
} }
break; break;

View File

@ -0,0 +1,24 @@
package org.apache.openjpa.kernel.exps;
/**
* No-op abstract visitor meant for easy extension.
*
* @author Abe White
* @nojavadoc
*/
public abstract class AbstractExpressionVisitor
implements ExpressionVisitor {
public void enter(Expression exp) {
}
public void exit(Expression exp) {
}
public void enter(Value val) {
}
public void exit(Value val) {
}
}

View File

@ -43,10 +43,6 @@ class Aggregate
_arg = arg; _arg = arg;
} }
public boolean isVariable() {
return false;
}
public Class getType() { public Class getType() {
return _listener.getType(getArgTypes()); return _listener.getType(getArgTypes());
} }
@ -54,10 +50,6 @@ class Aggregate
public void setImplicitType(Class type) { public void setImplicitType(Class type) {
} }
public boolean hasVariables() {
return (_arg == null) ? false : _arg.hasVariables();
}
protected Object eval(Object candidate, Object orig, protected Object eval(Object candidate, Object orig,
StoreContext ctx, Object[] params) { StoreContext ctx, Object[] params) {
if (candidate == null) if (candidate == null)
@ -88,4 +80,11 @@ class Aggregate
return ((Args) _arg).getTypes(); return ((Args) _arg).getTypes();
return new Class[]{ _arg.getType() }; return new Class[]{ _arg.getType() };
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
if (_arg != null)
_arg.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -42,10 +42,6 @@ abstract class AggregateVal
_val = val; _val = val;
} }
public boolean isVariable() {
return false;
}
public Class getType() { public Class getType() {
return getType(_val.getType()); return getType(_val.getType());
} }
@ -53,10 +49,6 @@ abstract class AggregateVal
public void setImplicitType(Class type) { public void setImplicitType(Class type) {
} }
public boolean hasVariables() {
return _val.hasVariables();
}
protected Object eval(Object candidate, Object orig, protected Object eval(Object candidate, Object orig,
StoreContext ctx, Object[] params) { StoreContext ctx, Object[] params) {
if (candidate == null) if (candidate == null)
@ -85,4 +77,10 @@ abstract class AggregateVal
* Aggregate the given values. * Aggregate the given values.
*/ */
protected abstract Object operate(Collection os, Class c); protected abstract Object operate(Collection os, Class c);
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_val.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -57,5 +57,12 @@ class AndExpression
return _exp1.evaluate(candidates, ctx, params) return _exp1.evaluate(candidates, ctx, params)
&& _exp2.evaluate(candidates, ctx, params); && _exp2.evaluate(candidates, ctx, params);
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_exp1.acceptVisit(visitor);
_exp2.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -49,10 +49,6 @@ class Args
return (Value[]) _args.toArray(new Value[_args.size()]); return (Value[]) _args.toArray(new Value[_args.size()]);
} }
public boolean isVariable() {
return false;
}
public Class getType() { public Class getType() {
return Object[].class; return Object[].class;
} }
@ -67,13 +63,6 @@ class Args
public void setImplicitType(Class type) { public void setImplicitType(Class type) {
} }
public boolean hasVariables() {
for (int i = 0; i < _args.size(); i++)
if (((Val) _args.get(i)).hasVariables())
return true;
return false;
}
protected Object eval(Object candidate, Object orig, protected Object eval(Object candidate, Object orig,
StoreContext ctx, Object[] params) { StoreContext ctx, Object[] params) {
Object[] vals = new Object[_args.size()]; Object[] vals = new Object[_args.size()];
@ -81,4 +70,11 @@ class Args
vals[i] = ((Val) _args.get(i)).eval(candidate, orig, ctx, params); vals[i] = ((Val) _args.get(i)).eval(candidate, orig, ctx, params);
return vals; return vals;
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
for (int i = 0; i < _args.size(); i++)
((Val) _args.get(i)).acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -79,5 +79,12 @@ class BindVariableExpression
Object obj = candidates.iterator().next(); Object obj = candidates.iterator().next();
return eval(obj, obj, ctx, params); return eval(obj, obj, ctx, params);
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_var.acceptVisit(visitor);
_val.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -63,10 +63,6 @@ class BoundVariable
_type = type; _type = type;
} }
public boolean hasVariables() {
return true;
}
/** /**
* Cast this value to the given type. * Cast this value to the given type.
*/ */

View File

@ -48,10 +48,6 @@ class CandidatePath
_actions.add(new Traversal(field, nullTraversal)); _actions.add(new Traversal(field, nullTraversal));
} }
public boolean isVariable() {
return false;
}
public Class getType() { public Class getType() {
if (_actions == null) if (_actions == null)
return getCandidateType(); return getCandidateType();
@ -73,10 +69,6 @@ class CandidatePath
public void setImplicitType(Class type) { public void setImplicitType(Class type) {
} }
public boolean hasVariables() {
return false;
}
public FieldMetaData last() { public FieldMetaData last() {
if (_actions == null) if (_actions == null)
return null; return null;

View File

@ -41,10 +41,6 @@ class Cast
_cast = cast; _cast = cast;
} }
public boolean isVariable() {
return _val.isVariable();
}
public Class getType() { public Class getType() {
return _cast; return _cast;
} }
@ -52,10 +48,6 @@ class Cast
public void setImplicitType(Class type) { public void setImplicitType(Class type) {
} }
public boolean hasVariables() {
return _val.hasVariables();
}
protected Object eval(Object candidate, Object orig, protected Object eval(Object candidate, Object orig,
StoreContext ctx, Object[] params) { StoreContext ctx, Object[] params) {
return Filters.convert(_val.eval(candidate, orig, ctx, params), _cast); return Filters.convert(_val.eval(candidate, orig, ctx, params), _cast);
@ -72,4 +64,10 @@ class Cast
casts.add(Filters.convert(itr.next(), _cast)); casts.add(Filters.convert(itr.next(), _cast));
return casts; return casts;
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_val.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -72,4 +72,11 @@ abstract class CompareExpression
* Compare the two values. * Compare the two values.
*/ */
protected abstract boolean compare(Object o1, Object o2); protected abstract boolean compare(Object o1, Object o2);
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_val1.acceptVisit(visitor);
_val2.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -37,10 +37,6 @@ class Concat
_args = args; _args = args;
} }
public boolean isVariable() {
return false;
}
public Class getType() { public Class getType() {
return String.class; return String.class;
} }
@ -48,10 +44,6 @@ class Concat
public void setImplicitType(Class type) { public void setImplicitType(Class type) {
} }
public boolean hasVariables() {
return _val.hasVariables() || _args.hasVariables();
}
protected Object eval(Object candidate, Object orig, protected Object eval(Object candidate, Object orig,
StoreContext ctx, Object[] params) { StoreContext ctx, Object[] params) {
Object str = _val.eval(candidate, orig, ctx, params); Object str = _val.eval(candidate, orig, ctx, params);
@ -66,5 +58,12 @@ class Concat
return cat.toString(); return cat.toString();
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_val.acceptVisit(visitor);
_args.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -70,5 +70,12 @@ class ContainsExpression
protected Collection getCollection(Object obj) { protected Collection getCollection(Object obj) {
return (Collection) obj; return (Collection) obj;
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_val1.acceptVisit(visitor);
_val2.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -27,14 +27,6 @@ import org.apache.openjpa.kernel.StoreContext;
class CurrentDate class CurrentDate
extends Val { extends Val {
public boolean hasVariables() {
return false;
}
public boolean isVariable() {
return false;
}
public Class getType() { public Class getType() {
return Date.class; return Date.class;
} }

View File

@ -38,10 +38,6 @@ class Distinct
_val = val; _val = val;
} }
public boolean isVariable() {
return false;
}
public Class getType() { public Class getType() {
return Collection.class; return Collection.class;
} }
@ -49,18 +45,12 @@ class Distinct
public void setImplicitType(Class type) { public void setImplicitType(Class type) {
} }
public boolean hasVariables() {
return _val.hasVariables();
}
protected Object eval(Object candidate, Object orig, protected Object eval(Object candidate, Object orig,
StoreContext ctx, Object[] params) { StoreContext ctx, Object[] params) {
if (candidate == null) if (candidate == null)
candidate = Collections.EMPTY_LIST; candidate = Collections.EMPTY_LIST;
Collection arg = candidate instanceof Collection Collection arg = candidate instanceof Collection
? (Collection) candidate : Collections.singleton(candidate); ? (Collection) candidate : Collections.singleton(candidate);
return eval(arg, orig, ctx, params).iterator().next(); return eval(arg, orig, ctx, params).iterator().next();
} }
@ -69,5 +59,11 @@ class Distinct
Collection args = _val.eval(candidates, orig, ctx, params); Collection args = _val.eval(candidates, orig, ctx, params);
return new HashSet(args); return new HashSet(args);
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_val.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -71,4 +71,9 @@ class Exp
Object[] params) { Object[] params) {
return true; return true;
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
visitor.exit(this);
}
} }

View File

@ -16,11 +16,15 @@
package org.apache.openjpa.kernel.exps; package org.apache.openjpa.kernel.exps;
/** /**
* Marker interface for a set of conditions that must be met for the query * Interface for a set of conditions that must be met for the query
* to be true. * to be true.
* *
* @author Abe White * @author Abe White
*/ */
public interface Expression { public interface Expression {
/**
* Accept a visit from a tree visitor.
*/
public void acceptVisit(ExpressionVisitor visitor);
} }

View File

@ -0,0 +1,31 @@
package org.apache.openjpa.kernel.exps;
/**
* Visits nodes of a query expression tree.
*
* @author Abe White
*/
public interface ExpressionVisitor {
/**
* Enter an expression. The expression will then invoke visits on its
* components.
*/
public void enter(Expression exp);
/**
* Leave an expression.
*/
public void exit(Expression exp);
/**
* Enter a value. The value will then invoke visits on its components.
*/
public void enter(Value val);
/**
* Leave a value.
*/
public void exit(Value val);
}

View File

@ -39,10 +39,6 @@ class Extension
_arg = arg; _arg = arg;
} }
public boolean isVariable() {
return false;
}
public Class getType() { public Class getType() {
Class targetClass = (_target == null) ? null : _target.getType(); Class targetClass = (_target == null) ? null : _target.getType();
return _listener.getType(targetClass, getArgTypes()); return _listener.getType(targetClass, getArgTypes());
@ -51,11 +47,6 @@ class Extension
public void setImplicitType(Class type) { public void setImplicitType(Class type) {
} }
public boolean hasVariables() {
return _target != null && _target.hasVariables()
|| _arg != null && _arg.hasVariables();
}
protected Object eval(Object candidate, Object orig, protected Object eval(Object candidate, Object orig,
StoreContext ctx, Object[] params) { StoreContext ctx, Object[] params) {
Object target = null; Object target = null;
@ -86,5 +77,14 @@ class Extension
return (Object[]) arg; return (Object[]) arg;
return new Object[]{ arg }; return new Object[]{ arg };
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
if (_target != null)
_target.acceptVisit(visitor);
if (_arg != null)
_arg.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -34,10 +34,6 @@ class GetObjectId
_val = val; _val = val;
} }
public boolean isVariable() {
return false;
}
public Class getType() { public Class getType() {
return Object.class; return Object.class;
} }
@ -45,12 +41,14 @@ class GetObjectId
public void setImplicitType(Class type) { public void setImplicitType(Class type) {
} }
public boolean hasVariables() {
return _val.hasVariables();
}
protected Object eval(Object candidate, Object orig, protected Object eval(Object candidate, Object orig,
StoreContext ctx, Object[] params) { StoreContext ctx, Object[] params) {
return ctx.getObjectId(_val.eval(candidate, orig, ctx, params)); return ctx.getObjectId(_val.eval(candidate, orig, ctx, params));
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_val.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -38,10 +38,6 @@ class IndexOf
_args = args; _args = args;
} }
public boolean isVariable() {
return false;
}
public Class getType() { public Class getType() {
return int.class; return int.class;
} }
@ -49,10 +45,6 @@ class IndexOf
public void setImplicitType(Class type) { public void setImplicitType(Class type) {
} }
public boolean hasVariables() {
return _val.hasVariables() || _args.hasVariables();
}
protected Object eval(Object candidate, Object orig, protected Object eval(Object candidate, Object orig,
StoreContext ctx, Object[] params) { StoreContext ctx, Object[] params) {
Object str = _val.eval(candidate, orig, ctx, params); Object str = _val.eval(candidate, orig, ctx, params);
@ -66,4 +58,11 @@ class IndexOf
idx = str.toString().indexOf(arg.toString()); idx = str.toString().indexOf(arg.toString());
return Numbers.valueOf(idx); return Numbers.valueOf(idx);
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_val.acceptVisit(visitor);
_args.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -57,4 +57,10 @@ class InstanceofExpression
Object o = (c == null || c.isEmpty()) ? null : c.iterator().next(); Object o = (c == null || c.isEmpty()) ? null : c.iterator().next();
return _cls.isInstance(o); return _cls.isInstance(o);
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_val.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -63,5 +63,11 @@ class IsEmptyExpression
return ((Map) obj).isEmpty(); return ((Map) obj).isEmpty();
return false; return false;
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_val.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -38,10 +38,6 @@ class Lit
_ptype = ptype; _ptype = ptype;
} }
public boolean isVariable() {
return false;
}
public Object getValue() { public Object getValue() {
return _val; return _val;
} }
@ -66,10 +62,6 @@ class Lit
_val = Filters.convert(_val, type); _val = Filters.convert(_val, type);
} }
public boolean hasVariables() {
return false;
}
protected Object eval(Object candidate, Object orig, protected Object eval(Object candidate, Object orig,
StoreContext ctx, Object[] params) { StoreContext ctx, Object[] params) {
return _val; return _val;

View File

@ -37,10 +37,6 @@ abstract class MathVal
_val2 = val2; _val2 = val2;
} }
public boolean isVariable() {
return false;
}
public Class getType() { public Class getType() {
Class c1 = _val1.getType(); Class c1 = _val1.getType();
Class c2 = _val2.getType(); Class c2 = _val2.getType();
@ -50,10 +46,6 @@ abstract class MathVal
public void setImplicitType(Class type) { public void setImplicitType(Class type) {
} }
public boolean hasVariables() {
return _val1.hasVariables() || _val2.hasVariables();
}
protected Object eval(Object candidate, Object orig, protected Object eval(Object candidate, Object orig,
StoreContext ctx, Object[] params) { StoreContext ctx, Object[] params) {
Object o1 = _val1.eval(candidate, orig, ctx, params); Object o1 = _val1.eval(candidate, orig, ctx, params);
@ -66,4 +58,11 @@ abstract class MathVal
*/ */
protected abstract Object operate(Object o1, Class c1, Object o2, protected abstract Object operate(Object o1, Class c1, Object o2,
Class c2); Class c2);
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_val1.acceptVisit(visitor);
_val2.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -45,5 +45,11 @@ class NotExpression
Object[] params) { Object[] params) {
return !_exp.evaluate(candidates, ctx, params); return !_exp.evaluate(candidates, ctx, params);
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_exp.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -25,14 +25,6 @@ import org.apache.openjpa.kernel.StoreContext;
class Null class Null
extends Val { extends Val {
public boolean hasVariables() {
return false;
}
public boolean isVariable() {
return false;
}
public Class getType() { public Class getType() {
return Object.class; return Object.class;
} }

View File

@ -49,5 +49,12 @@ class OrExpression
return _exp1.evaluate(candidates, ctx, params) return _exp1.evaluate(candidates, ctx, params)
|| _exp2.evaluate(candidates, ctx, params); || _exp2.evaluate(candidates, ctx, params);
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_exp1.acceptVisit(visitor);
_exp2.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -42,10 +42,6 @@ class Param
return _name; return _name;
} }
public boolean isVariable() {
return false;
}
public Class getType() { public Class getType() {
return _type; return _type;
} }
@ -54,10 +50,6 @@ class Param
_type = type; _type = type;
} }
public boolean hasVariables() {
return false;
}
public void setIndex(int index) { public void setIndex(int index) {
_index = index; _index = index;
} }

View File

@ -19,6 +19,7 @@ import org.apache.openjpa.meta.FieldMetaData;
/** /**
* A path represents a traversal into fields of a candidate object. * A path represents a traversal into fields of a candidate object.
* Equivalent paths should compare equal.
* *
* @author Abe White * @author Abe White
*/ */

View File

@ -36,10 +36,6 @@ class StringLength
_val = val; _val = val;
} }
public boolean isVariable() {
return false;
}
public Class getType() { public Class getType() {
if (_cast != null) if (_cast != null)
return _cast; return _cast;
@ -50,10 +46,6 @@ class StringLength
_cast = type; _cast = type;
} }
public boolean hasVariables() {
return _val.hasVariables();
}
protected Object eval(Object candidate, Object orig, protected Object eval(Object candidate, Object orig,
StoreContext ctx, Object[] params) { StoreContext ctx, Object[] params) {
Object eval = _val.eval(candidate, orig, ctx, params); Object eval = _val.eval(candidate, orig, ctx, params);
@ -62,5 +54,11 @@ class StringLength
return Numbers.valueOf(eval.toString().length()); return Numbers.valueOf(eval.toString().length());
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_val.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -46,10 +46,6 @@ class SubQ
long endIdx) { long endIdx) {
} }
public boolean isVariable() {
return false;
}
public Class getType() { public Class getType() {
return _type; return _type;
} }
@ -58,10 +54,6 @@ class SubQ
_type = type; _type = type;
} }
public boolean hasVariables() {
return false;
}
protected Object eval(Object candidate, Object orig, protected Object eval(Object candidate, Object orig,
StoreContext ctx, Object[] params) { StoreContext ctx, Object[] params) {
throw new UnsupportedException(_loc.get("in-mem-subquery")); throw new UnsupportedException(_loc.get("in-mem-subquery"));

View File

@ -37,10 +37,6 @@ class Substring
_args = args; _args = args;
} }
public boolean isVariable() {
return false;
}
public Class getType() { public Class getType() {
return String.class; return String.class;
} }
@ -48,10 +44,6 @@ class Substring
public void setImplicitType(Class type) { public void setImplicitType(Class type) {
} }
public boolean hasVariables() {
return _val.hasVariables() || _args.hasVariables();
}
protected Object eval(Object candidate, Object orig, protected Object eval(Object candidate, Object orig,
StoreContext ctx, Object[] params) { StoreContext ctx, Object[] params) {
Object str = _val.eval(candidate, orig, ctx, params); Object str = _val.eval(candidate, orig, ctx, params);
@ -63,4 +55,11 @@ class Substring
} }
return str.toString().substring(((Number) arg).intValue()); return str.toString().substring(((Number) arg).intValue());
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_val.acceptVisit(visitor);
_args.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -25,14 +25,6 @@ import org.apache.openjpa.kernel.StoreContext;
class This class This
extends Val { extends Val {
public boolean hasVariables() {
return false;
}
public boolean isVariable() {
return false;
}
public void setImplicitType(Class type) { public void setImplicitType(Class type) {
} }

View File

@ -34,10 +34,6 @@ class ToLowerCase
_val = val; _val = val;
} }
public boolean isVariable() {
return false;
}
public Class getType() { public Class getType() {
return String.class; return String.class;
} }
@ -45,13 +41,14 @@ class ToLowerCase
public void setImplicitType(Class type) { public void setImplicitType(Class type) {
} }
public boolean hasVariables() {
return _val.hasVariables();
}
protected Object eval(Object candidate, Object orig, protected Object eval(Object candidate, Object orig,
StoreContext ctx, Object[] params) { StoreContext ctx, Object[] params) {
return _val.eval(candidate, orig, ctx, params).toString(). return _val.eval(candidate, orig, ctx, params).toString().toLowerCase();
toLowerCase(); }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_val.acceptVisit(visitor);
visitor.exit(this);
} }
} }

View File

@ -34,10 +34,6 @@ class ToUpperCase
_val = val; _val = val;
} }
public boolean isVariable() {
return false;
}
public Class getType() { public Class getType() {
return String.class; return String.class;
} }
@ -45,13 +41,15 @@ class ToUpperCase
public void setImplicitType(Class type) { public void setImplicitType(Class type) {
} }
public boolean hasVariables() {
return _val.hasVariables();
}
protected Object eval(Object candidate, Object orig, protected Object eval(Object candidate, Object orig,
StoreContext ctx, Object[] params) { StoreContext ctx, Object[] params) {
return _val.eval(candidate, orig, ctx, params).toString(). return _val.eval(candidate, orig, ctx, params).toString().
toUpperCase(); toUpperCase();
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_val.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -38,10 +38,6 @@ class Trim
_where = where; _where = where;
} }
public boolean isVariable() {
return false;
}
public Class getType() { public Class getType() {
return String.class; return String.class;
} }
@ -49,20 +45,14 @@ class Trim
public void setImplicitType(Class type) { public void setImplicitType(Class type) {
} }
public boolean hasVariables() {
return _val.hasVariables();
}
protected Object eval(Object candidate, Object orig, protected Object eval(Object candidate, Object orig,
StoreContext ctx, Object[] params) { StoreContext ctx, Object[] params) {
Object eval = _val.eval(candidate, orig, ctx, params); Object eval = _val.eval(candidate, orig, ctx, params);
if (eval == null) if (eval == null)
return null; return null;
String toTrim = _trimChar.eval(candidate, orig, ctx, params). String toTrim = _trimChar.eval(candidate, orig, ctx, params).
toString(); toString();
String str = eval.toString(); String str = eval.toString();
// null indicates both, TRUE indicates leading // null indicates both, TRUE indicates leading
@ -76,8 +66,14 @@ class Trim
while (str.endsWith(toTrim)) while (str.endsWith(toTrim))
str = str.substring(0, str.length() - toTrim.length()); str = str.substring(0, str.length() - toTrim.length());
} }
return str; return str;
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_val.acceptVisit(visitor);
_trimChar.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -34,10 +34,6 @@ abstract class UnaryMathVal
_val = val; _val = val;
} }
public boolean isVariable() {
return false;
}
public Class getType() { public Class getType() {
return getType(_val.getType()); return getType(_val.getType());
} }
@ -45,10 +41,6 @@ abstract class UnaryMathVal
public void setImplicitType(Class type) { public void setImplicitType(Class type) {
} }
public boolean hasVariables() {
return _val.hasVariables();
}
protected Object eval(Object candidate, Object orig, protected Object eval(Object candidate, Object orig,
StoreContext ctx, Object[] params) { StoreContext ctx, Object[] params) {
Object o1 = _val.eval(candidate, orig, ctx, params); Object o1 = _val.eval(candidate, orig, ctx, params);
@ -65,4 +57,10 @@ abstract class UnaryMathVal
* Return the result of this mathematical operation on the given value. * Return the result of this mathematical operation on the given value.
*/ */
protected abstract Object operate(Object o, Class c); protected abstract Object operate(Object o, Class c);
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_val.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -58,10 +58,6 @@ class UnboundVariable
_val = value; _val = value;
} }
public boolean hasVariables() {
return true;
}
protected Object eval(Object candidate, Object orig, protected Object eval(Object candidate, Object orig,
StoreContext ctx, Object[] params) { StoreContext ctx, Object[] params) {
return _val; return _val;

View File

@ -66,11 +66,6 @@ public abstract class Val
} }
} }
/**
* Return true if this value involves the use of variables.
*/
public abstract boolean hasVariables();
/** /**
* Return this value for the given candidate. * Return this value for the given candidate.
*/ */
@ -103,4 +98,13 @@ public abstract class Val
public void setMetaData(ClassMetaData meta) { public void setMetaData(ClassMetaData meta) {
_meta = meta; _meta = meta;
} }
public boolean isVariable() {
return false;
}
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
visitor.exit(this);
}
} }

View File

@ -48,4 +48,10 @@ class ValExpression
Object o = (c == null || c.isEmpty()) ? null : c.iterator().next(); Object o = (c == null || c.isEmpty()) ? null : c.iterator().next();
return o != null && ((Boolean) o).booleanValue(); return o != null && ((Boolean) o).booleanValue();
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_val.acceptVisit(visitor);
visitor.exit(this);
}
} }

View File

@ -52,4 +52,9 @@ public interface Value {
* Associate a persistent type with this value. * Associate a persistent type with this value.
*/ */
public void setMetaData(ClassMetaData meta); public void setMetaData(ClassMetaData meta);
/**
* Accept a visit from a tree visitor.
*/
public void acceptVisit(ExpressionVisitor visitor);
} }

View File

@ -38,15 +38,17 @@ class ValuePath
return _val.getType(); return _val.getType();
} }
public boolean hasVariables() {
return _val.hasVariables();
}
protected Object eval(Object candidate, Object orig, protected Object eval(Object candidate, Object orig,
StoreContext ctx, Object[] params) { StoreContext ctx, Object[] params) {
// evaluate with the value's value // evaluate with the value's value
return super.eval(_val.eval(candidate, orig, ctx, params), orig, return super.eval(_val.eval(candidate, orig, ctx, params), orig,
ctx, params); ctx, params);
} }
public void acceptVisit(ExpressionVisitor visitor) {
visitor.enter(this);
_val.acceptVisit(visitor);
visitor.exit(this);
}
} }