}
}
- protected static Value.Type toValueType(DataType dType) {
+ public static Value.Type toValueType(DataType dType) {
Value.Type type = TYPE_MAP.get(dType);
return ((type == null) ? Value.Type.STRING : type);
}
// normal expression handling
Expr expr = parseExpression(buf, false);
- if((exprType == Type.FIELD_VALIDATOR) && !expr.isConditionalExpr()) {
- // a non-conditional expression for a FIELD_VALIDATOR treats the result
- // as an equality comparison with the field in question. so, transform
- // the expression accordingly
- expr = new EImplicitCompOp(expr);
- }
+ if((exprType == Type.FIELD_VALIDATOR) && !expr.isValidationExpr()) {
+ // a non-validation expression for a FIELD_VALIDATOR treats the result
+ // as an equality comparison with the field in question. so, transform
+ // the expression accordingly
+ expr = new EImplicitCompOp(expr);
+ }
switch(exprType) {
case DEFAULT_VALUE:
return sb.toString();
}
- protected boolean isConditionalExpr() {
+ protected boolean isValidationExpr() {
return false;
}
}
@Override
- protected boolean isConditionalExpr() {
- return _expr.isConditionalExpr();
+ protected boolean isValidationExpr() {
+ return _expr.isValidationExpr();
}
@Override
}
@Override
- protected boolean isConditionalExpr() {
+ protected boolean isValidationExpr() {
return true;
}
super(op, left, right);
}
+ @Override
+ protected boolean isValidationExpr() {
+ return true;
+ }
+
@Override
public Value eval(final EvalContext ctx) {
}
@Override
- protected boolean isConditionalExpr() {
+ protected boolean isValidationExpr() {
return true;
}
}
package com.healthmarketscience.jackcess.impl.expr;
+import java.io.BufferedReader;
+import java.io.FileReader;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.script.Bindings;
import javax.script.SimpleBindings;
+import com.healthmarketscience.jackcess.DataType;
import com.healthmarketscience.jackcess.DatabaseBuilder;
import com.healthmarketscience.jackcess.TestUtil;
import com.healthmarketscience.jackcess.expr.EvalContext;
import com.healthmarketscience.jackcess.expr.Expression;
-import com.healthmarketscience.jackcess.expr.Function;
import com.healthmarketscience.jackcess.expr.FunctionLookup;
import com.healthmarketscience.jackcess.expr.Identifier;
import com.healthmarketscience.jackcess.expr.TemporalConfig;
import com.healthmarketscience.jackcess.expr.Value;
+import com.healthmarketscience.jackcess.impl.BaseEvalContext;
import com.healthmarketscience.jackcess.impl.NumberFormatter;
import junit.framework.TestCase;
validateExpr("' \"A\" '", "<ELiteralValue>{\" \"\"A\"\" \"}",
"\" \"\"A\"\" \"");
+
+ validateExpr("<=1 And >=0", "<ELogicalOp>{<ECompOp>{<EThisValue>{<THIS_COL>} <= <ELiteralValue>{1}} And <ECompOp>{<EThisValue>{<THIS_COL>} >= <ELiteralValue>{0}}}", "<THIS_COL> <= 1 And <THIS_COL> >= 0");
}
private static void doTestSimpleBinOp(String opName, String... ops) throws Exception
assertEquals(-28d, eval("CDbl(9)-37", Value.Type.DOUBLE));
}
+ public void testParseSomeExprs() throws Exception
+ {
+ BufferedReader br = new BufferedReader(new FileReader("src/test/resources/test_exprs.txt"));
+
+ TestContext tc = new TestContext() {
+ @Override
+ public Value getThisColumnValue() {
+ return BuiltinOperators.toValue(23.0);
+ }
+
+ @Override
+ public Value getIdentifierValue(Identifier identifier) {
+ return BuiltinOperators.toValue(23.0);
+ }
+ };
+
+ String line = null;
+ while((line = br.readLine()) != null) {
+ line = line.trim();
+ if(line.isEmpty()) {
+ continue;
+ }
+
+ String[] parts = line.split(";", 3);
+ Expressionator.Type type = Expressionator.Type.valueOf(parts[0]);
+ DataType dType =
+ (("null".equals(parts[1])) ? null : DataType.valueOf(parts[1]));
+ String exprStr = parts[2];
+
+ Value.Type resultType = ((dType != null) ?
+ BaseEvalContext.toValueType(dType) : null);
+
+ Expression expr = Expressionator.parse(
+ type, exprStr, resultType, tc);
+
+ expr.eval(tc);
+ }
+
+ br.close();
+ }
+
private static void validateExpr(String exprStr, String debugStr) {
validateExpr(exprStr, debugStr, exprStr);
}
String cleanStr) {
Expression expr = Expressionator.parse(
Expressionator.Type.FIELD_VALIDATOR, exprStr, null,
- new TestParseContext());
+ new TestContext());
String foundDebugStr = expr.toDebugString();
if(foundDebugStr.startsWith("<EImplicitCompOp>")) {
assertEquals("<EImplicitCompOp>{<EThisValue>{<THIS_COL>} = " +
}
static Object eval(String exprStr, Value.Type resultType) {
+ TestContext tc = new TestContext();
Expression expr = Expressionator.parse(
- Expressionator.Type.DEFAULT_VALUE, exprStr, resultType,
- new TestParseContext());
- return expr.eval(new TestEvalContext(null));
+ Expressionator.Type.DEFAULT_VALUE, exprStr, resultType, tc);
+ return expr.eval(tc);
}
private static void evalFail(
String exprStr, Class<? extends Exception> failure)
{
+ TestContext tc = new TestContext();
Expression expr = Expressionator.parse(
- Expressionator.Type.DEFAULT_VALUE, exprStr, null,
- new TestParseContext());
+ Expressionator.Type.DEFAULT_VALUE, exprStr, null, tc);
try {
- expr.eval(new TestEvalContext(null));
+ expr.eval(tc);
fail(failure + " should have been thrown");
} catch(Exception e) {
assertTrue(failure.isInstance(e));
}
private static Boolean evalCondition(String exprStr, String thisVal) {
+ TestContext tc = new TestContext(BuiltinOperators.toValue(thisVal));
Expression expr = Expressionator.parse(
- Expressionator.Type.FIELD_VALIDATOR, exprStr, null,
- new TestParseContext());
- return (Boolean)expr.eval(new TestEvalContext(BuiltinOperators.toValue(thisVal)));
+ Expressionator.Type.FIELD_VALIDATOR, exprStr, null, tc);
+ return (Boolean)expr.eval(tc);
}
static int roundToLongInt(double d) {
return BuiltinOperators.normalize(bd);
}
- private static final class TestParseContext implements Expressionator.ParseContext
- {
- public TemporalConfig getTemporalConfig() {
- return TemporalConfig.US_TEMPORAL_CONFIG;
- }
- public SimpleDateFormat createDateFormat(String formatStr) {
- SimpleDateFormat sdf = DatabaseBuilder.createDateFormat(formatStr);
- sdf.setTimeZone(TestUtil.TEST_TZ);
- return sdf;
- }
- public FunctionLookup getFunctionLookup() {
- return DefaultFunctions.LOOKUP;
- }
- }
-
- private static final class TestEvalContext implements EvalContext
+ private static class TestContext
+ implements Expressionator.ParseContext, EvalContext
{
private final Value _thisVal;
private final RandomContext _rndCtx = new RandomContext();
private final Bindings _bindings = new SimpleBindings();
- private TestEvalContext(Value thisVal) {
+ private TestContext() {
+ this(null);
+ }
+
+ private TestContext(Value thisVal) {
_thisVal = thisVal;
}
return sdf;
}
+ public FunctionLookup getFunctionLookup() {
+ return DefaultFunctions.LOOKUP;
+ }
+
public Value getThisColumnValue() {
if(_thisVal == null) {
throw new UnsupportedOperationException();
--- /dev/null
+DEFAULT_VALUE;SHORT_DATE_TIME;Now()
+DEFAULT_VALUE;NUMERIC;0
+FIELD_VALIDATOR;DOUBLE;<=1 And >=0
+FIELD_VALIDATOR;SHORT_DATE_TIME;>=#1/1/1900#
+DEFAULT_VALUE;BOOLEAN;No
+DEFAULT_VALUE;SHORT_DATE_TIME;Null
+DEFAULT_VALUE;TEXT;NEW
+DEFAULT_VALUE;LONG;0.0
+DEFAULT_VALUE;LONG;1
+DEFAULT_VALUE;DOUBLE;1.0
+DEFAULT_VALUE;LONG;3
+DEFAULT_VALUE;LONG;-1
+DEFAULT_VALUE;GUID;GenGUID()
+FIELD_VALIDATOR;TEXT;Like "http://*"
+DEFAULT_VALUE;BOOLEAN;True
+DEFAULT_VALUE;SHORT_DATE_TIME;Date()
+DEFAULT_VALUE;TEXT;""
+DEFAULT_VALUE;BOOLEAN;False
+DEFAULT_VALUE;LONG;524287
+DEFAULT_VALUE;LONG;5
+DEFAULT_VALUE;LONG;10
+DEFAULT_VALUE;TEXT;' '
+EXPRESSION;MONEY;[UnitPrice]*[Quantity]
+DEFAULT_VALUE;TEXT;"UTC"
+EXPRESSION;BIG_INT;[BigNum]+10
+EXPRESSION;TEXT;IIf(IsNull([LastName]),IIf(IsNull([FirstName]),[Company],[FirstName]),IIf(IsNull([FirstName]),[LastName],[FirstName] & " " & [LastName]))
+EXPRESSION;TEXT;IIf(IsNull([LastName]),IIf(IsNull([FirstName]),[Company],[FirstName]),IIf(IsNull([FirstName]),[LastName],[LastName] & ", " & [FirstName]))
+RECORD_VALIDATOR;null;Not IsNull([Email] & [FullName] & [Login])
+DEFAULT_VALUE;DOUBLE;=0
+EXPRESSION;DOUBLE;[InitialLevel]+[Received]-[Shipped]-[Waste]
+EXPRESSION;DOUBLE;[OnHand]-[Allocated]
+EXPRESSION;DOUBLE;[Available]+[OnOrder]-[BackOrdered]
+EXPRESSION;DOUBLE;IIf([TargetLevel]-[CurrentLevel]>0,[TargetLevel]-[CurrentLevel],0)
+EXPRESSION;DOUBLE;IIf([BelowTargetLevel]>0,IIf([BelowTargetLevel]<[MinimumReorderQuantity],[MinimumReorderQuantity],[BelowTargetLevel]),0)
+EXPRESSION;MONEY;[SubTotal]+[Tax]+[Shipping]
+EXPRESSION;MONEY;[UnitPrice]*[Quantity]*(1-[Discount])
+DEFAULT_VALUE;TEXT;="None"
+EXPRESSION;BOOLEAN;([StatusID]=10)
+EXPRESSION;BOOLEAN;([StatusID]>=30)
+EXPRESSION;BOOLEAN;[StatusID]>=40
+EXPRESSION;BOOLEAN;[StatusID]>50
+EXPRESSION;BOOLEAN;([StatusID]=20)
+DEFAULT_VALUE;SHORT_DATE_TIME;=Date()
+EXPRESSION;DOUBLE;Month([OrderDate])
+EXPRESSION;DOUBLE;Year([OrderDate])
+EXPRESSION;MONEY;[OrderSubTotal]+[Tax]+[ShippingFee]
+EXPRESSION;DOUBLE;IIf([OrderMonth]<=3,1,IIf([OrderMonth]<=6,2,IIf([OrderMonth]<=9,3,4)))
+EXPRESSION;BOOLEAN;([StatusID]=0)
+EXPRESSION;BOOLEAN;([StatusID]=30) And (Not IsNull([ClosedDate]))
+EXPRESSION;BOOLEAN;([StatusID]>=20) And (Not IsNull([ShippedDate]))
+EXPRESSION;BOOLEAN;([StatusID]>=10)
+EXPRESSION;BOOLEAN;Not [IsCompleted]
+EXPRESSION;DOUBLE;[Quantity]*[UnitCost]
+DEFAULT_VALUE;BOOLEAN;=False
+EXPRESSION;MONEY;[OrderSubTotal]+[ShippingFee]+[Taxes]
+EXPRESSION;BOOLEAN;Not IsNull([ClosedDate])
+EXPRESSION;BOOLEAN;Not IsNull([SubmittedDate])
+EXPRESSION;BOOLEAN;Not [IsSubmitted]
+DEFAULT_VALUE;SHORT_DATE_TIME;=Now()
+DEFAULT_VALUE;LONG;=Int(13)
+FIELD_VALIDATOR;SHORT_DATE_TIME;<Date()
+FIELD_VALIDATOR;MONEY;>=0
+FIELD_VALIDATOR;INT;>0
+FIELD_VALIDATOR;FLOAT;Between 0 And 1
+DEFAULT_VALUE;BOOLEAN;=No
+EXPRESSION;TEXT;[LastName] & ", " & [FirstName]
+EXPRESSION;LONG;Len([LastFirst])
+EXPRESSION;MONEY;[Salary]/12
+EXPRESSION;BOOLEAN;[Salary]>100000
+EXPRESSION;MEMO;[LastName] & ", " & [FirstName] & "=" & [LastFirst]
+EXPRESSION;NUMERIC;[Salary]/52
+EXPRESSION;MONEY;[Salary]
+EXPRESSION;BOOLEAN;True
+EXPRESSION;NUMERIC;[Popularity]
+EXPRESSION;FLOAT;[Salary]*0.13/[DecimalTest]
+EXPRESSION;NUMERIC;([Salary]*[MonthlySalary]/[DecimalTest])*34.12342134
+DEFAULT_VALUE;COMPLEX_TYPE;"data4"
+EXPRESSION;DOUBLE;NPer(1,2,3,4,5)
+EXPRESSION;DOUBLE;[Time Field]
+DEFAULT_VALUE;TEXT;=Rnd(25)
+DEFAULT_VALUE;TEXT;=Rnd(13)
+DEFAULT_VALUE;TEXT;=Rnd(-1)
+DEFAULT_VALUE;TEXT;=Rnd(-2)
+DEFAULT_VALUE;TEXT;=Rnd()
+RECORD_VALIDATOR;null;[Field4]>10
+EXPRESSION;DOUBLE;[Field6]+3
+EXPRESSION;DOUBLE;[Table4].[Field1]+4
+EXPRESSION;LONG;[Field5]+5
+DEFAULT_VALUE;LONG;134217727
+DEFAULT_VALUE;TEXT;'+P-E'
+FIELD_VALIDATOR;TEXT;Is Not Null