aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Ahlborn <jtahlborn@yahoo.com>2016-12-31 17:37:13 +0000
committerJames Ahlborn <jtahlborn@yahoo.com>2016-12-31 17:37:13 +0000
commit68c982c48f75f121112b780c829e000acc036f0c (patch)
tree865f0e7b13d7f9511b4f0a9e777bfd621383e8b1
parent1260b3bff1855161ec5f129695cb690356d72ca8 (diff)
downloadjackcess-68c982c48f75f121112b780c829e000acc036f0c.tar.gz
jackcess-68c982c48f75f121112b780c829e000acc036f0c.zip
change evaluation context
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/branches/exprs@1076 f203690c-595d-4dc9-a70b-905162fa7fd2
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/expr/EvalContext.java (renamed from src/main/java/com/healthmarketscience/jackcess/expr/RowContext.java)8
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/expr/Expression.java4
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/expr/Function.java2
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/impl/expr/BaseDateValue.java4
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/impl/expr/BuiltinOperators.java45
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/impl/expr/DefaultFunctions.java26
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/impl/expr/Expressionator.java209
-rw-r--r--src/test/java/com/healthmarketscience/jackcess/impl/expr/ExpressionatorTest.java4
8 files changed, 175 insertions, 127 deletions
diff --git a/src/main/java/com/healthmarketscience/jackcess/expr/RowContext.java b/src/main/java/com/healthmarketscience/jackcess/expr/EvalContext.java
index cc60f4d..3ec3a88 100644
--- a/src/main/java/com/healthmarketscience/jackcess/expr/RowContext.java
+++ b/src/main/java/com/healthmarketscience/jackcess/expr/EvalContext.java
@@ -16,12 +16,18 @@ limitations under the License.
package com.healthmarketscience.jackcess.expr;
+import java.text.SimpleDateFormat;
+
/**
*
* @author James Ahlborn
*/
-public interface RowContext
+public interface EvalContext
{
+ public Value.Type getResultType();
+
+ public SimpleDateFormat createDateFormat(String formatStr);
+
public Value getThisColumnValue();
public Value getRowValue(String collectionName, String objName,
diff --git a/src/main/java/com/healthmarketscience/jackcess/expr/Expression.java b/src/main/java/com/healthmarketscience/jackcess/expr/Expression.java
index 99d695f..9e9b836 100644
--- a/src/main/java/com/healthmarketscience/jackcess/expr/Expression.java
+++ b/src/main/java/com/healthmarketscience/jackcess/expr/Expression.java
@@ -22,9 +22,7 @@ package com.healthmarketscience.jackcess.expr;
*/
public interface Expression
{
- public Object evalDefault();
-
- public Boolean evalCondition(RowContext ctx);
+ public Object eval(EvalContext ctx);
public String toDebugString();
diff --git a/src/main/java/com/healthmarketscience/jackcess/expr/Function.java b/src/main/java/com/healthmarketscience/jackcess/expr/Function.java
index 10ecc2b..0d94dde 100644
--- a/src/main/java/com/healthmarketscience/jackcess/expr/Function.java
+++ b/src/main/java/com/healthmarketscience/jackcess/expr/Function.java
@@ -23,6 +23,6 @@ package com.healthmarketscience.jackcess.expr;
public interface Function
{
public String getName();
- public Value eval(Value... params);
+ public Value eval(EvalContext ctx, Value... params);
public boolean isPure();
}
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/expr/BaseDateValue.java b/src/main/java/com/healthmarketscience/jackcess/impl/expr/BaseDateValue.java
index 4cca8d2..68ad69f 100644
--- a/src/main/java/com/healthmarketscience/jackcess/impl/expr/BaseDateValue.java
+++ b/src/main/java/com/healthmarketscience/jackcess/impl/expr/BaseDateValue.java
@@ -43,6 +43,10 @@ public abstract class BaseDateValue extends BaseValue
return _val;
}
+ protected DateFormat getFormat() {
+ return _fmt;
+ }
+
protected Double getNumber() {
return ColumnImpl.toDateDouble(_val, _fmt.getCalendar());
}
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/expr/BuiltinOperators.java b/src/main/java/com/healthmarketscience/jackcess/impl/expr/BuiltinOperators.java
index c295208..b05bc16 100644
--- a/src/main/java/com/healthmarketscience/jackcess/impl/expr/BuiltinOperators.java
+++ b/src/main/java/com/healthmarketscience/jackcess/impl/expr/BuiltinOperators.java
@@ -23,6 +23,7 @@ import java.text.Format;
import java.util.Date;
import java.util.regex.Pattern;
+import com.healthmarketscience.jackcess.expr.EvalContext;
import com.healthmarketscience.jackcess.expr.Value;
import com.healthmarketscience.jackcess.impl.ColumnImpl;
@@ -54,7 +55,7 @@ public class BuiltinOperators
private BuiltinOperators() {}
- // FIXME, null propagation:
+ // null propagation rules:
// http://www.utteraccess.com/wiki/index.php/Nulls_And_Their_Behavior
// https://theaccessbuddy.wordpress.com/2012/10/24/6-logical-operators-in-ms-access-that-you-must-know-operator-types-3-of-5/
// - number ops
@@ -64,9 +65,8 @@ public class BuiltinOperators
// - Or - can be true if one arg is true
// - between, not, like, in
// - *NOT* concal op '&'
- // FIXME, Imp operator?
- public static Value negate(Value param1) {
+ public static Value negate(EvalContext ctx, Value param1) {
if(param1.isNull()) {
// null propagation
return NULL_VAL;
@@ -81,7 +81,7 @@ public class BuiltinOperators
case DATE_TIME:
// dates/times get converted to date doubles for arithmetic
double result = -param1.getAsDouble();
- return toDateValue(mathType, result, param1, null);
+ return toDateValue(ctx, mathType, result, param1, null);
case LONG:
return toValue(-param1.getAsLong());
case DOUBLE:
@@ -95,7 +95,7 @@ public class BuiltinOperators
}
}
- public static Value add(Value param1, Value param2) {
+ public static Value add(EvalContext ctx, Value param1, Value param2) {
if(anyParamIsNull(param1, param2)) {
// null propagation
return NULL_VAL;
@@ -112,7 +112,7 @@ public class BuiltinOperators
case DATE_TIME:
// dates/times get converted to date doubles for arithmetic
double result = param1.getAsDouble() + param2.getAsDouble();
- return toDateValue(mathType, result, param1, param2);
+ return toDateValue(ctx, mathType, result, param1, param2);
case LONG:
return toValue(param1.getAsLong() + param2.getAsLong());
case DOUBLE:
@@ -126,7 +126,7 @@ public class BuiltinOperators
}
}
- public static Value subtract(Value param1, Value param2) {
+ public static Value subtract(EvalContext ctx, Value param1, Value param2) {
if(anyParamIsNull(param1, param2)) {
// null propagation
return NULL_VAL;
@@ -141,7 +141,7 @@ public class BuiltinOperators
case DATE_TIME:
// dates/times get converted to date doubles for arithmetic
double result = param1.getAsDouble() - param2.getAsDouble();
- return toDateValue(mathType, result, param1, param2);
+ return toDateValue(ctx, mathType, result, param1, param2);
case LONG:
return toValue(param1.getAsLong() - param2.getAsLong());
case DOUBLE:
@@ -622,16 +622,31 @@ public class BuiltinOperators
return new BigDecimalValue(s);
}
- private static Value toDateValue(Value.Type type, double v,
+ private static Value toDateValue(EvalContext ctx, Value.Type type, double v,
Value param1, Value param2)
{
- // FIXME find format from first matching param
DateFormat fmt = null;
- // if(param1.getType() == type) {
- // fmt = (DateFormat)param1.getFormat();
- // } else if(param2 != null) {
- // fmt = (DateFormat)param2.getFormat();
- // }
+ if((param1 instanceof BaseDateValue) && (param1.getType() == type)) {
+ fmt = ((BaseDateValue)param1).getFormat();
+ } else if((param2 instanceof BaseDateValue) && (param2.getType() == type)) {
+ fmt = ((BaseDateValue)param2).getFormat();
+ } else {
+ String fmtStr = null;
+ switch(type) {
+ case DATE:
+ fmtStr = ExpressionTokenizer.DATE_FORMAT;
+ break;
+ case TIME:
+ fmtStr = ExpressionTokenizer.TIME_FORMAT_24;
+ break;
+ case DATE_TIME:
+ fmtStr = ExpressionTokenizer.DATE_TIME_FORMAT_24;
+ break;
+ default:
+ throw new RuntimeException("Unexpected type " + type);
+ }
+ fmt = ctx.createDateFormat(fmtStr);
+ }
Date d = new Date(ColumnImpl.fromDateDouble(v, fmt.getCalendar()));
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/expr/DefaultFunctions.java b/src/main/java/com/healthmarketscience/jackcess/impl/expr/DefaultFunctions.java
index 17e8d10..fbcd683 100644
--- a/src/main/java/com/healthmarketscience/jackcess/impl/expr/DefaultFunctions.java
+++ b/src/main/java/com/healthmarketscience/jackcess/impl/expr/DefaultFunctions.java
@@ -22,6 +22,7 @@ import java.util.Map;
import com.healthmarketscience.jackcess.expr.Value;
import com.healthmarketscience.jackcess.expr.Function;
+import com.healthmarketscience.jackcess.expr.EvalContext;
/**
*
@@ -83,12 +84,12 @@ public class DefaultFunctions
super(name, 1, 1);
}
- public final Value eval(Value... params) {
+ public final Value eval(EvalContext ctx, Value... params) {
validateNumParams(params);
- return eval1(params[0]);
+ return eval1(ctx, params[0]);
}
- protected abstract Value eval1(Value param);
+ protected abstract Value eval1(EvalContext ctx, Value param);
}
public static abstract class Func2 extends BaseFunction
@@ -97,12 +98,12 @@ public class DefaultFunctions
super(name, 2, 2);
}
- public final Value eval(Value... params) {
+ public final Value eval(EvalContext ctx, Value... params) {
validateNumParams(params);
- return eval2(params[0], params[1]);
+ return eval2(ctx, params[0], params[1]);
}
- protected abstract Value eval2(Value param1, Value param2);
+ protected abstract Value eval2(EvalContext ctx, Value param1, Value param2);
}
public static abstract class Func3 extends BaseFunction
@@ -111,18 +112,21 @@ public class DefaultFunctions
super(name, 3, 3);
}
- public final Value eval(Value... params) {
+ public final Value eval(EvalContext ctx, Value... params) {
validateNumParams(params);
- return eval3(params[0], params[1], params[2]);
+ return eval3(ctx, params[0], params[1], params[2]);
}
- protected abstract Value eval3(Value param1, Value param2, Value param3);
+ protected abstract Value eval3(EvalContext ctx,
+ Value param1, Value param2, Value param3);
}
public static final Function IIF = registerFunc(new Func3("IIf") {
@Override
- protected Value eval3(Value param1, Value param2, Value param3) {
- return (param1.getAsBoolean() ? param2 : param3);
+ protected Value eval3(EvalContext ctx,
+ Value param1, Value param2, Value param3) {
+ // null is false
+ return ((!param1.isNull() && param1.getAsBoolean()) ? param2 : param3);
}
});
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/expr/Expressionator.java b/src/main/java/com/healthmarketscience/jackcess/impl/expr/Expressionator.java
index 5a9686f..ab45eda 100644
--- a/src/main/java/com/healthmarketscience/jackcess/impl/expr/Expressionator.java
+++ b/src/main/java/com/healthmarketscience/jackcess/impl/expr/Expressionator.java
@@ -36,7 +36,7 @@ import java.util.regex.Pattern;
import com.healthmarketscience.jackcess.DatabaseBuilder;
import com.healthmarketscience.jackcess.expr.Expression;
import com.healthmarketscience.jackcess.expr.Function;
-import com.healthmarketscience.jackcess.expr.RowContext;
+import com.healthmarketscience.jackcess.expr.EvalContext;
import com.healthmarketscience.jackcess.expr.Value;
import com.healthmarketscience.jackcess.impl.expr.ExpressionTokenizer.Token;
import com.healthmarketscience.jackcess.impl.expr.ExpressionTokenizer.TokenType;
@@ -104,12 +104,12 @@ public class Expressionator
private enum UnaryOp implements OpType {
NEG("-", false) {
- @Override public Value eval(Value param1) {
- return BuiltinOperators.negate(param1);
+ @Override public Value eval(EvalContext ctx, Value param1) {
+ return BuiltinOperators.negate(ctx, param1);
}
},
NOT("Not", true) {
- @Override public Value eval(Value param1) {
+ @Override public Value eval(EvalContext ctx, Value param1) {
return BuiltinOperators.not(param1);
}
};
@@ -131,47 +131,47 @@ public class Expressionator
return _str;
}
- public abstract Value eval(Value param1);
+ public abstract Value eval(EvalContext ctx, Value param1);
}
private enum BinaryOp implements OpType {
PLUS("+") {
- @Override public Value eval(Value param1, Value param2) {
- return BuiltinOperators.add(param1, param2);
+ @Override public Value eval(EvalContext ctx, Value param1, Value param2) {
+ return BuiltinOperators.add(ctx, param1, param2);
}
},
MINUS("-") {
- @Override public Value eval(Value param1, Value param2) {
- return BuiltinOperators.subtract(param1, param2);
+ @Override public Value eval(EvalContext ctx, Value param1, Value param2) {
+ return BuiltinOperators.subtract(ctx, param1, param2);
}
},
MULT("*") {
- @Override public Value eval(Value param1, Value param2) {
+ @Override public Value eval(EvalContext ctx, Value param1, Value param2) {
return BuiltinOperators.multiply(param1, param2);
}
},
DIV("/") {
- @Override public Value eval(Value param1, Value param2) {
+ @Override public Value eval(EvalContext ctx, Value param1, Value param2) {
return BuiltinOperators.divide(param1, param2);
}
},
INT_DIV("\\") {
- @Override public Value eval(Value param1, Value param2) {
+ @Override public Value eval(EvalContext ctx, Value param1, Value param2) {
return BuiltinOperators.intDivide(param1, param2);
}
},
EXP("^") {
- @Override public Value eval(Value param1, Value param2) {
+ @Override public Value eval(EvalContext ctx, Value param1, Value param2) {
return BuiltinOperators.exp(param1, param2);
}
},
CONCAT("&") {
- @Override public Value eval(Value param1, Value param2) {
+ @Override public Value eval(EvalContext ctx, Value param1, Value param2) {
return BuiltinOperators.concat(param1, param2);
}
},
MOD("Mod") {
- @Override public Value eval(Value param1, Value param2) {
+ @Override public Value eval(EvalContext ctx, Value param1, Value param2) {
return BuiltinOperators.mod(param1, param2);
}
};
@@ -187,7 +187,7 @@ public class Expressionator
return _str;
}
- public abstract Value eval(Value param1, Value param2);
+ public abstract Value eval(EvalContext ctx, Value param1, Value param2);
}
private enum CompOp implements OpType {
@@ -363,7 +363,7 @@ public class Expressionator
@Override public boolean isPure() {
return false;
}
- @Override protected Value eval(RowContext ctx) {
+ @Override public Value eval(EvalContext ctx) {
return ctx.getThisColumnValue();
}
@Override protected void toExprString(StringBuilder sb, boolean isDebug) {
@@ -421,12 +421,11 @@ public class Expressionator
}
Expr expr = parseExpression(new TokBuf(exprType, tokens, context), false);
- if(expr.isPure()) {
- // for now, just cache at top-level for speed (could in theory cache
- // intermediate values?)
- expr = new MemoizedPureExpression(expr);
- }
- return expr;
+ return (expr.isPure() ?
+ // for now, just cache at top-level for speed (could in theory cache
+ // intermediate values?)
+ new MemoizedExprWrapper(exprType, expr) :
+ new ExprWrapper(exprType, expr));
}
private static List<Token> trimSpaces(List<Token> tokens) {
@@ -1162,7 +1161,7 @@ public class Expressionator
}
private static Value[] exprListToValues(
- List<Expr> exprs, RowContext ctx) {
+ List<Expr> exprs, EvalContext ctx) {
Value[] paramVals = new Value[exprs.size()];
for(int i = 0; i < exprs.size(); ++i) {
paramVals[i] = exprs.get(i).eval(ctx);
@@ -1171,7 +1170,7 @@ public class Expressionator
}
private static Value[] exprListToDelayedValues(
- List<Expr> exprs, RowContext ctx) {
+ List<Expr> exprs, EvalContext ctx) {
Value[] paramVals = new Value[exprs.size()];
for(int i = 0; i < exprs.size(); ++i) {
paramVals[i] = new DelayedValue(exprs.get(i), ctx);
@@ -1300,52 +1299,22 @@ public class Expressionator
private static final class DelayedValue extends BaseDelayedValue
{
private final Expr _expr;
- private final RowContext _ctx;
+ private final EvalContext _ctx;
- private DelayedValue(Expr expr, RowContext ctx) {
+ private DelayedValue(Expr expr, EvalContext ctx) {
_expr = expr;
_ctx = ctx;
}
@Override
- protected Value eval() {
+ public Value eval() {
return _expr.eval(_ctx);
}
}
- private static abstract class Expr implements Expression
+ private static abstract class Expr
{
- public Object evalDefault() {
- Value val = eval(null);
-
- if(val.isNull()) {
- return null;
- }
-
- // FIXME, booleans seem to go to -1 (true),0 (false) ...?
-
- return val.get();
- }
-
- public Boolean evalCondition(RowContext ctx) {
- Value val = eval(ctx);
-
- if(val.isNull()) {
- return null;
- }
-
- // FIXME, is this only true for non-numeric...?
- // if(val.getType() != Value.Type.BOOLEAN) {
- // // a single value as a conditional expression seems to act like an
- // // implicit "="
- // // FIXME, what about row validators?
- // val = BuiltinOperators.equals(val, ctx.getThisColumnValue());
- // }
-
- return val.getAsBoolean();
- }
-
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
@@ -1427,7 +1396,7 @@ public class Expressionator
public abstract boolean isPure();
- protected abstract Value eval(RowContext ctx);
+ public abstract Value eval(EvalContext ctx);
protected abstract void toExprString(StringBuilder sb, boolean isDebug);
}
@@ -1448,7 +1417,7 @@ public class Expressionator
}
@Override
- protected Value eval(RowContext ctx) {
+ public Value eval(EvalContext ctx) {
return _val;
}
@@ -1473,7 +1442,7 @@ public class Expressionator
}
@Override
- public Value eval(RowContext ctx) {
+ public Value eval(EvalContext ctx) {
return _val;
}
@@ -1508,7 +1477,7 @@ public class Expressionator
}
@Override
- public Value eval(RowContext ctx) {
+ public Value eval(EvalContext ctx) {
return ctx.getRowValue(_collectionName, _objName, _fieldName);
}
@@ -1538,7 +1507,7 @@ public class Expressionator
}
@Override
- protected Value eval(RowContext ctx) {
+ public Value eval(EvalContext ctx) {
return _expr.eval(ctx);
}
@@ -1566,8 +1535,8 @@ public class Expressionator
}
@Override
- protected Value eval(RowContext ctx) {
- return _func.eval(exprListToValues(_params, ctx));
+ public Value eval(EvalContext ctx) {
+ return _func.eval(ctx, exprListToValues(_params, ctx));
}
@Override
@@ -1635,8 +1604,8 @@ public class Expressionator
}
@Override
- protected Value eval(RowContext ctx) {
- return ((BinaryOp)_op).eval(_left.eval(ctx), _right.eval(ctx));
+ public Value eval(EvalContext ctx) {
+ return ((BinaryOp)_op).eval(ctx, _left.eval(ctx), _right.eval(ctx));
}
}
@@ -1669,8 +1638,8 @@ public class Expressionator
}
@Override
- protected Value eval(RowContext ctx) {
- return ((UnaryOp)_op).eval(_expr.eval(ctx));
+ public Value eval(EvalContext ctx) {
+ return ((UnaryOp)_op).eval(ctx, _expr.eval(ctx));
}
@Override
@@ -1690,7 +1659,7 @@ public class Expressionator
}
@Override
- protected Value eval(RowContext ctx) {
+ public Value eval(EvalContext ctx) {
return ((CompOp)_op).eval(_left.eval(ctx), _right.eval(ctx));
}
}
@@ -1702,7 +1671,7 @@ public class Expressionator
}
@Override
- protected Value eval(final RowContext ctx) {
+ public Value eval(final EvalContext ctx) {
// logical operations do short circuit evaluation, so we need to delay
// computing results until necessary
@@ -1747,7 +1716,7 @@ public class Expressionator
}
@Override
- protected Value eval(RowContext ctx) {
+ public Value eval(EvalContext ctx) {
return _op.eval(_expr.eval(ctx), null, null);
}
@@ -1771,7 +1740,7 @@ public class Expressionator
}
@Override
- protected Value eval(RowContext ctx) {
+ public Value eval(EvalContext ctx) {
return _op.eval(_expr.eval(ctx), _pattern, null);
}
@@ -1801,7 +1770,7 @@ public class Expressionator
}
@Override
- protected Value eval(RowContext ctx) {
+ public Value eval(EvalContext ctx) {
return _op.eval(_expr.eval(ctx),
exprListToDelayedValues(_exprs, ctx), null);
}
@@ -1842,7 +1811,7 @@ public class Expressionator
}
@Override
- protected Value eval(RowContext ctx) {
+ public Value eval(EvalContext ctx) {
return _op.eval(_expr.eval(ctx),
new DelayedValue(_startRangeExpr, ctx),
new DelayedValue(_endRangeExpr, ctx));
@@ -1859,40 +1828,92 @@ public class Expressionator
}
/**
- * Wrapper for a <i>pure</i> Expr which caches the result of evaluation.
+ * Expression wrapper for an Expr which caches the result of evaluation.
*/
- private static final class MemoizedPureExpression extends Expr
+ private static class ExprWrapper implements Expression
{
+ private final Type _type;
private final Expr _expr;
- private Value _val;
- private MemoizedPureExpression(Expr expr) {
+ private ExprWrapper(Type type, Expr expr) {
+ _type = type;
_expr = expr;
- }
+ }
- @Override
- protected Value eval(RowContext ctx) {
- if(_val == null) {
- // since expr is pure, row context should not be used
- _val = _expr.eval(null);
+ public Object eval(EvalContext ctx) {
+ switch(_type) {
+ case DEFAULT_VALUE:
+ return evalDefault(ctx);
+ case FIELD_VALIDATOR:
+ case RECORD_VALIDATOR:
+ return evalCondition(ctx);
+ default:
+ throw new RuntimeException("unexpected expression type " + _type);
}
- return _val;
}
- @Override
+ public String toDebugString() {
+ return _expr.toDebugString();
+ }
+
public boolean isPure() {
- return true;
+ return _expr.isPure();
}
@Override
- protected void toString(StringBuilder sb, boolean isDebug) {
- // don't display this class in debug string
- _expr.toString(sb, isDebug);
+ public String toString() {
+ return _expr.toString();
+ }
+
+ private Object evalDefault(EvalContext ctx) {
+ Value val = _expr.eval(ctx);
+
+ if(val.isNull()) {
+ return null;
+ }
+
+ // FIXME, booleans seem to go to -1 (true),0 (false) ...?
+
+ return val.get();
+ }
+
+ private Boolean evalCondition(EvalContext ctx) {
+ Value val = _expr.eval(ctx);
+
+ if(val.isNull()) {
+ return null;
+ }
+
+ // FIXME, is this only true for non-numeric...?
+ // if(val.getType() != Value.Type.BOOLEAN) {
+ // // a single value as a conditional expression seems to act like an
+ // // implicit "="
+ // // FIXME, what about row validators?
+ // val = BuiltinOperators.equals(val, ctx.getThisColumnValue());
+ // }
+
+ return val.getAsBoolean();
}
+ }
+
+ /**
+ * Expression wrapper for a <i>pure</i> Expr which caches the result of
+ * evaluation.
+ */
+ private static final class MemoizedExprWrapper extends ExprWrapper
+ {
+ private Object _val;
+
+ private MemoizedExprWrapper(Type type, Expr expr) {
+ super(type, expr);
+ }
@Override
- protected void toExprString(StringBuilder sb, boolean isDebug) {
- throw new UnsupportedOperationException();
+ public Object eval(EvalContext ctx) {
+ if(_val == null) {
+ _val = super.eval(ctx);
+ }
+ return _val;
}
}
}
diff --git a/src/test/java/com/healthmarketscience/jackcess/impl/expr/ExpressionatorTest.java b/src/test/java/com/healthmarketscience/jackcess/impl/expr/ExpressionatorTest.java
index 3109ea4..ffcf901 100644
--- a/src/test/java/com/healthmarketscience/jackcess/impl/expr/ExpressionatorTest.java
+++ b/src/test/java/com/healthmarketscience/jackcess/impl/expr/ExpressionatorTest.java
@@ -264,14 +264,14 @@ public class ExpressionatorTest extends TestCase
private static Object eval(String exprStr) {
Expression expr = Expressionator.parse(
Expressionator.Type.DEFAULT_VALUE, exprStr, new TestContext());
- return expr.evalDefault();
+ return expr.eval(null);
}
private static void evalFail(String exprStr, Class<? extends Exception> failure) {
Expression expr = Expressionator.parse(
Expressionator.Type.DEFAULT_VALUE, exprStr, new TestContext());
try {
- expr.evalDefault();
+ expr.eval(null);
fail(failure + " should have been thrown");
} catch(Exception e) {
assertTrue(failure.isInstance(e));