public Value getRowValue(String collectionName, String objName,
String colName);
- public Random getRandom(Long seed);
+ public Random getRandom(Integer seed);
}
public Date getAsDateTime(EvalContext ctx);
- public Long getAsLong();
+ public Integer getAsLongInt();
public Double getAsDouble();
}
@Override
- public Long getAsLong() {
- return getNumber().longValue();
+ public Integer getAsLongInt() {
+ return roundToLongInt();
}
@Override
return getDelegate().getAsDateTime(ctx);
}
- public Long getAsLong() {
- return getDelegate().getAsLong();
+ public Integer getAsLongInt() {
+ return getDelegate().getAsLongInt();
}
public Double getAsDouble() {
}
@Override
- public Long getAsLong() {
- return getNumber().longValue();
+ public Integer getAsLongInt() {
+ return roundToLongInt();
}
@Override
throw invalidConversion(Value.Type.DATE_TIME);
}
- public Long getAsLong() {
+ public Integer getAsLongInt() {
throw invalidConversion(Value.Type.LONG);
}
getType() + " value cannot be converted to " + newType);
}
+ protected Integer roundToLongInt() {
+ return getAsBigDecimal().setScale(0, BuiltinOperators.ROUND_MODE)
+ .intValueExact();
+ }
+
@Override
public String toString() {
return "Value[" + getType() + "] '" + get() + "'";
package com.healthmarketscience.jackcess.impl.expr;
import java.math.BigDecimal;
-import java.math.BigInteger;
+import java.math.RoundingMode;
import java.text.DateFormat;
import java.util.Date;
import java.util.regex.Pattern;
{
private static final String DIV_BY_ZERO = "/ by zero";
+ private static final double MIN_INT = Integer.MIN_VALUE;
+ private static final double MAX_INT = Integer.MAX_VALUE;
+
public static final Value NULL_VAL = new BaseValue() {
@Override public boolean isNull() {
return true;
};
// access seems to like -1 for true and 0 for false (boolean values are
// basically an illusion)
- public static final Value TRUE_VAL = new LongValue(-1L);
- public static final Value FALSE_VAL = new LongValue(0L);
+ public static final Value TRUE_VAL = new LongValue(-1);
+ public static final Value FALSE_VAL = new LongValue(0);
public static final Value EMPTY_STR_VAL = new StringValue("");
public static final Value ZERO_VAL = FALSE_VAL;
+ public static final RoundingMode ROUND_MODE = RoundingMode.HALF_EVEN;
+
private enum CoercionType {
SIMPLE(true, true), GENERAL(false, true), COMPARE(false, false);
double result = -param1.getAsDouble();
return toDateValue(ctx, mathType, result, param1, null);
case LONG:
- return toValue(-param1.getAsLong());
+ return toValue(-param1.getAsLongInt());
case DOUBLE:
return toValue(-param1.getAsDouble());
case STRING:
double result = param1.getAsDouble() + param2.getAsDouble();
return toDateValue(ctx, mathType, result, param1, param2);
case LONG:
- return toValue(param1.getAsLong() + param2.getAsLong());
+ return toValue(param1.getAsLongInt() + param2.getAsLongInt());
case DOUBLE:
return toValue(param1.getAsDouble() + param2.getAsDouble());
case BIG_DEC:
double result = param1.getAsDouble() - param2.getAsDouble();
return toDateValue(ctx, mathType, result, param1, param2);
case LONG:
- return toValue(param1.getAsLong() - param2.getAsLong());
+ return toValue(param1.getAsLongInt() - param2.getAsLongInt());
case DOUBLE:
return toValue(param1.getAsDouble() - param2.getAsDouble());
case BIG_DEC:
// case TIME: break; promoted to double
// case DATE_TIME: break; promoted to double
case LONG:
- return toValue(param1.getAsLong() * param2.getAsLong());
+ return toValue(param1.getAsLongInt() * param2.getAsLongInt());
case DOUBLE:
return toValue(param1.getAsDouble() * param2.getAsDouble());
case BIG_DEC:
// case TIME: break; promoted to double
// case DATE_TIME: break; promoted to double
case LONG:
- long lp1 = param1.getAsLong();
- long lp2 = param2.getAsLong();
+ int lp1 = param1.getAsLongInt();
+ int lp2 = param2.getAsLongInt();
if((lp1 % lp2) == 0) {
return toValue(lp1 / lp2);
}
}
}
- @SuppressWarnings("fallthrough")
public static Value intDivide(Value param1, Value param2) {
if(anyParamIsNull(param1, param2)) {
// null propagation
Value.Type mathType = getMathTypePrecedence(param1, param2,
CoercionType.GENERAL);
-
- boolean wasDouble = false;
- switch(mathType) {
- // case STRING: break; unsupported
- // case DATE: break; promoted to double
- // case TIME: break; promoted to double
- // case DATE_TIME: break; promoted to double
- case LONG:
- return toValue(param1.getAsLong() / param2.getAsLong());
- case DOUBLE:
- wasDouble = true;
- // fallthrough
- case BIG_DEC:
- BigInteger result = getAsBigInteger(param1).divide(
- getAsBigInteger(param2));
- return (wasDouble ? toValue(result.longValue()) : toValue(result));
- default:
+ if(mathType == Value.Type.STRING) {
throw new RuntimeException("Unexpected type " + mathType);
}
+ return toValue(param1.getAsLongInt() / param2.getAsLongInt());
}
public static Value exp(Value param1, Value param2) {
// attempt to convert integral types back to integrals if possible
if((mathType == Value.Type.LONG) && isIntegral(result)) {
- return toValue((long)result);
+ return toValue((int)result);
}
return toValue(result);
}
- @SuppressWarnings("fallthrough")
public static Value mod(Value param1, Value param2) {
if(anyParamIsNull(param1, param2)) {
// null propagation
Value.Type mathType = getMathTypePrecedence(param1, param2,
CoercionType.GENERAL);
- boolean wasDouble = false;
- switch(mathType) {
- // case STRING: break; unsupported
- // case DATE: break; promoted to double
- // case TIME: break; promoted to double
- // case DATE_TIME: break; promoted to double
- case LONG:
- return toValue(param1.getAsLong() % param2.getAsLong());
- case DOUBLE:
- wasDouble = true;
- // fallthrough
- case BIG_DEC:
- BigInteger bi1 = getAsBigInteger(param1);
- BigInteger bi2 = getAsBigInteger(param2).abs();
- if(bi2.signum() == 0) {
- throw new ArithmeticException(DIV_BY_ZERO);
- }
- BigInteger result = bi1.mod(bi2);
- // BigInteger.mod differs from % when using negative values, need to
- // make them consistent
- if((bi1.signum() == -1) && (result.signum() == 1)) {
- result = result.subtract(bi2);
- }
- return (wasDouble ? toValue(result.longValue()) : toValue(result));
- default:
+ if(mathType == Value.Type.STRING) {
throw new RuntimeException("Unexpected type " + mathType);
}
+ return toValue(param1.getAsLongInt() % param2.getAsLongInt());
}
public static Value concat(Value param1, Value param2) {
// case TIME: break; promoted to double
// case DATE_TIME: break; promoted to double
case LONG:
- return param1.getAsLong().compareTo(param2.getAsLong());
+ return param1.getAsLongInt().compareTo(param2.getAsLongInt());
case DOUBLE:
return param1.getAsDouble().compareTo(param2.getAsDouble());
case BIG_DEC:
}
public static Value toValue(int i) {
- return new LongValue((long)i);
+ return new LongValue(i);
}
- public static Value toValue(long s) {
- return new LongValue(s);
- }
-
- public static Value toValue(Long s) {
- return new LongValue(s);
+ public static Value toValue(Integer i) {
+ return new LongValue(i);
}
public static Value toValue(float f) {
return new DoubleValue(s);
}
- public static Value toValue(BigInteger s) {
- return toValue(new BigDecimal(s));
- }
-
public static Value toValue(BigDecimal s) {
return new BigDecimalValue(s);
}
+ public static Value toValue(Value.Type type, double dd, DateFormat fmt) {
+ return toValue(type, new Date(ColumnImpl.fromDateDouble(dd, fmt.getCalendar())),
+ fmt);
+ }
+
public static Value toValue(Value.Type type, Date d, DateFormat fmt) {
switch(type) {
case DATE:
}
static boolean isIntegral(double d) {
- return ((d == Math.rint(d)) && !Double.isInfinite(d) && !Double.isNaN(d));
+ double id = Math.rint(d);
+ return ((d == id) && (d >= MIN_INT) && (d <= MAX_INT) &&
+ !Double.isInfinite(d) && !Double.isNaN(d));
}
- private static BigInteger getAsBigInteger(Value v) {
- return v.getAsBigDecimal().toBigInteger();
- }
}
private static final double MIN_DATE = -657434.0d;
// max, valid, recognizable date: December 31, 9999 A.D. 23:59:59
private static final double MAX_DATE = 2958465.999988426d;
+
+ private static final long SECONDS_PER_DAY = 24L * 60L * 60L;
+ private static final double DSECONDS_PER_DAY = SECONDS_PER_DAY;
+
+ private static final long SECONDS_PER_HOUR = 60L * 60L;
+ private static final long SECONDS_PER_MINUTE = 60L;
+ private static final long MILLIS_PER_SECOND = 1000L;
private DefaultDateFunctions() {}
}
public static final Function DATE = registerFunc(new Func0("Date") {
- @Override
- public boolean isPure() {
- return false;
- }
@Override
protected Value eval0(EvalContext ctx) {
- DateFormat df = BuiltinOperators.getDateFormatForType(ctx, Value.Type.DATE);
- double dd = ColumnImpl.toDateDouble(System.currentTimeMillis(), df.getCalendar());
- // the integral part of the date/time double is the date value. discard
- // the fractional portion
- dd = ((long)dd);
- return BuiltinOperators.toValue(Value.Type.DATE, new Date(), df);
+ DateFormat fmt = BuiltinOperators.getDateFormatForType(ctx, Value.Type.DATE);
+ double dd = dateOnly(currentTimeDouble(fmt));
+ return BuiltinOperators.toValue(Value.Type.DATE, dd, fmt);
}
});
- public static final Function NOW = registerFunc(new Func0("Now") {
+ public static final Function DATEVALUE = registerFunc(new Func1NullIsNull("DateValue") {
@Override
- public boolean isPure() {
- return false;
+ protected Value eval1(EvalContext ctx, Value param1) {
+ Value dv = nonNullToDateValue(ctx, param1);
+ if(dv.getType() == Value.Type.DATE) {
+ return dv;
+ }
+ double dd = dateOnly(dv.getAsDouble());
+ DateFormat fmt = BuiltinOperators.getDateFormatForType(ctx, Value.Type.DATE);
+ return BuiltinOperators.toValue(Value.Type.DATE, dd, fmt);
}
+ });
+
+ public static final Function NOW = registerFunc(new Func0("Now") {
@Override
protected Value eval0(EvalContext ctx) {
- DateFormat df = BuiltinOperators.getDateFormatForType(ctx, Value.Type.DATE_TIME);
- return BuiltinOperators.toValue(Value.Type.DATE_TIME, new Date(), df);
+ DateFormat fmt = BuiltinOperators.getDateFormatForType(ctx, Value.Type.DATE_TIME);
+ return BuiltinOperators.toValue(Value.Type.DATE_TIME, new Date(), fmt);
}
});
public static final Function TIME = registerFunc(new Func0("Time") {
@Override
- public boolean isPure() {
- return false;
+ protected Value eval0(EvalContext ctx) {
+ DateFormat fmt = BuiltinOperators.getDateFormatForType(ctx, Value.Type.TIME);
+ double dd = timeOnly(currentTimeDouble(fmt));
+ return BuiltinOperators.toValue(Value.Type.TIME, dd, fmt);
+ }
+ });
+
+ public static final Function TIMEVALUE = registerFunc(new Func1NullIsNull("TimeValue") {
+ @Override
+ protected Value eval1(EvalContext ctx, Value param1) {
+ Value dv = nonNullToDateValue(ctx, param1);
+ if(dv.getType() == Value.Type.TIME) {
+ return dv;
+ }
+ double dd = timeOnly(dv.getAsDouble());
+ DateFormat fmt = BuiltinOperators.getDateFormatForType(ctx, Value.Type.TIME);
+ return BuiltinOperators.toValue(Value.Type.TIME, dd, fmt);
}
+ });
+
+ public static final Function TIMER = registerFunc(new Func0("Timer") {
@Override
protected Value eval0(EvalContext ctx) {
- DateFormat df = BuiltinOperators.getDateFormatForType(ctx, Value.Type.TIME);
- double dd = ColumnImpl.toDateDouble(System.currentTimeMillis(), df.getCalendar());
- // the fractional part of the date/time double is the time value. discard
- // the integral portion
- dd = Math.IEEEremainder(dd, 1.0d);
- return BuiltinOperators.toValue(Value.Type.TIME, new Date(), df);
+ DateFormat fmt = BuiltinOperators.getDateFormatForType(ctx, Value.Type.TIME);
+ double dd = timeOnly(currentTimeDouble(fmt)) * DSECONDS_PER_DAY;
+ return BuiltinOperators.toValue(dd);
}
});
+ public static final Function TIMESERIAL = registerFunc(new Func3("TimeSerial") {
+ @Override
+ protected Value eval3(EvalContext ctx, Value param1, Value param2, Value param3) {
+ int hours = param1.getAsLongInt();
+ int minutes = param2.getAsLongInt();
+ int seconds = param3.getAsLongInt();
+
+ long totalSeconds = (hours * SECONDS_PER_HOUR) +
+ (minutes * SECONDS_PER_MINUTE) + seconds;
+ DateFormat fmt = BuiltinOperators.getDateFormatForType(ctx, Value.Type.TIME);
+ double dd = totalSeconds / DSECONDS_PER_DAY;
+ return BuiltinOperators.toValue(Value.Type.TIME, dd, fmt);
+ }
+ });
+
public static final Function HOUR = registerFunc(new Func1NullIsNull("Hour") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
throw new IllegalStateException("Invalid date/time expression '" + param + "'");
}
- Calendar cal =
- ((param instanceof BaseDateValue) ?
- ((BaseDateValue)param).getFormat().getCalendar() :
- BuiltinOperators.getDateFormatForType(ctx, param.getType()).getCalendar());
-
+ Calendar cal = getDateValueFormat(ctx, param).getCalendar();
cal.setTime(param.getAsDateTime(ctx));
return cal;
}
return null;
}
- boolean hasDate = (((long)dd) != 0L);
- boolean hasTime = (Math.IEEEremainder(dd, 1.0d) != 0.0d);
+ boolean hasDate = (dateOnly(dd) != 0.0d);
+ boolean hasTime = (timeOnly(dd) != 0.0d);
Value.Type type = (hasDate ? (hasTime ? Value.Type.DATE_TIME : Value.Type.DATE) :
Value.Type.TIME);
- DateFormat df = BuiltinOperators.getDateFormatForType(ctx, type);
- Date d = new Date(ColumnImpl.fromDateDouble(dd, df.getCalendar()));
- return BuiltinOperators.toValue(type, d, df);
+ DateFormat fmt = BuiltinOperators.getDateFormatForType(ctx, type);
+ return BuiltinOperators.toValue(type, dd, fmt);
+ }
+
+ private static DateFormat getDateValueFormat(EvalContext ctx, Value param) {
+ return ((param instanceof BaseDateValue) ?
+ ((BaseDateValue)param).getFormat() :
+ BuiltinOperators.getDateFormatForType(ctx, param.getType()));
+ }
+
+ private static double dateOnly(double dd) {
+ // the integral part of the date/time double is the date value. discard
+ // the fractional portion
+ return (long)dd;
+ }
+
+ private static double timeOnly(double dd) {
+ // the fractional part of the date/time double is the time value. discard
+ // the integral portion and convert to seconds
+ return new BigDecimal(dd).remainder(BigDecimal.ONE).doubleValue();
+ }
+
+ private static double currentTimeDouble(DateFormat fmt) {
+ return ColumnImpl.toDateDouble(System.currentTimeMillis(), fmt.getCalendar());
}
}
package com.healthmarketscience.jackcess.impl.expr;
import java.math.BigDecimal;
-import java.math.RoundingMode;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
new HashMap<String,Function>();
private static final char NON_VAR_SUFFIX = '$';
- static final RoundingMode DEFAULT_ROUND_MODE = RoundingMode.HALF_EVEN;
static {
// load all default functions
private final int _minParams;
private final int _maxParams;
- protected BaseFunction(String name)
- {
- this(name, 0, Integer.MAX_VALUE);
- }
-
protected BaseFunction(String name, int minParams, int maxParams)
{
_name = name;
super(name, 0, 0);
}
+ @Override
+ public boolean isPure() {
+ // 0-arg functions are usually not pure
+ return false;
+ }
+
public final Value eval(EvalContext ctx, Value... params) {
try {
validateNumParams(params);
public static abstract class FuncVar extends BaseFunction
{
+ protected FuncVar(String name) {
+ super(name, 0, Integer.MAX_VALUE);
+ }
+
protected FuncVar(String name, int minParams, int maxParams) {
super(name, minParams, maxParams);
}
(param1.getAsString().length() == 0)) {
return BuiltinOperators.ZERO_VAL;
}
- long lv = param1.getAsLong();
- return BuiltinOperators.toValue(Long.toHexString(lv).toUpperCase());
+ int lv = param1.getAsLongInt();
+ return BuiltinOperators.toValue(Integer.toHexString(lv).toUpperCase());
}
});
}
});
+ public static final Function CHOOSE = registerFunc(new FuncVar("Choose", 1, Integer.MAX_VALUE) {
+ @Override
+ protected Value evalVar(EvalContext ctx, Value[] params) {
+ Value param1 = params[0];
+ int idx = param1.getAsLongInt();
+ if((idx < 1) || (idx >= params.length)) {
+ return BuiltinOperators.NULL_VAL;
+ }
+ return params[idx];
+ }
+ });
+
+ public static final Function SWITCH = registerFunc(new FuncVar("Switch") {
+ @Override
+ protected Value evalVar(EvalContext ctx, Value[] params) {
+ if((params.length % 2) != 0) {
+ throw new IllegalStateException("Odd number of parameters");
+ }
+ for(int i = 0; i < params.length; i+=2) {
+ if(params[i].getAsBoolean()) {
+ return params[i + 1];
+ }
+ }
+ return BuiltinOperators.NULL_VAL;
+ }
+ });
+
public static final Function OCT = registerStringFunc(new Func1NullIsNull("Oct") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
(param1.getAsString().length() == 0)) {
return BuiltinOperators.ZERO_VAL;
}
- long lv = param1.getAsLong();
- return BuiltinOperators.toValue(Long.toOctalString(lv));
+ int lv = param1.getAsLongInt();
+ return BuiltinOperators.toValue(Integer.toOctalString(lv));
}
});
public static final Function CBYTE = registerFunc(new Func1("CByte") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- long lv = roundToLong(param1);
+ int lv = param1.getAsLongInt();
if((lv < 0) || (lv > 255)) {
throw new IllegalStateException("Byte code '" + lv + "' out of range ");
}
@Override
protected Value eval1(EvalContext ctx, Value param1) {
BigDecimal bd = param1.getAsBigDecimal();
- bd = bd.setScale(4, DEFAULT_ROUND_MODE);
+ bd = bd.setScale(4, BuiltinOperators.ROUND_MODE);
return BuiltinOperators.toValue(bd);
}
});
public static final Function CINT = registerFunc(new Func1("CInt") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- long lv = roundToLong(param1);
+ int lv = param1.getAsLongInt();
if((lv < Short.MIN_VALUE) || (lv > Short.MAX_VALUE)) {
throw new IllegalStateException("Int value '" + lv + "' out of range ");
}
public static final Function CLNG = registerFunc(new Func1("CLng") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- long lv = roundToLong(param1);
- if((lv < Integer.MIN_VALUE) || (lv > Integer.MAX_VALUE)) {
- throw new IllegalStateException("Long value '" + lv + "' out of range ");
- }
+ int lv = param1.getAsLongInt();
return BuiltinOperators.toValue(lv);
}
});
}
});
+ public static final Function VARTYPE = registerFunc(new Func1("VarType") {
+ @Override
+ protected Value eval1(EvalContext ctx, Value param1) {
+ Value.Type type = param1.getType();
+ int vType = 0;
+ switch(type) {
+ case NULL:
+ // vbNull
+ vType = 1;
+ break;
+ case STRING:
+ // vbString
+ vType = 8;
+ break;
+ case DATE:
+ case TIME:
+ case DATE_TIME:
+ // vbDate
+ vType = 7;
+ break;
+ case LONG:
+ // vbLong
+ vType = 3;
+ break;
+ case DOUBLE:
+ // vbDouble
+ vType = 5;
+ break;
+ case BIG_DEC:
+ // vbDecimal
+ vType = 14;
+ break;
+ default:
+ throw new RuntimeException("Unknown type " + type);
+ }
+ return BuiltinOperators.toValue(vType);
+ }
+ });
- private static long roundToLong(Value param) {
- if(param.getType().isIntegral()) {
- return param.getAsLong();
+ public static final Function TYPENAME = registerFunc(new Func1("TypeName") {
+ @Override
+ protected Value eval1(EvalContext ctx, Value param1) {
+ Value.Type type = param1.getType();
+ String tName = null;
+ switch(type) {
+ case NULL:
+ tName = "Null";
+ break;
+ case STRING:
+ tName = "String";
+ break;
+ case DATE:
+ case TIME:
+ case DATE_TIME:
+ tName = "Date";
+ break;
+ case LONG:
+ tName = "Long";
+ break;
+ case DOUBLE:
+ tName = "Double";
+ break;
+ case BIG_DEC:
+ tName = "Decimal";
+ break;
+ default:
+ throw new RuntimeException("Unknown type " + type);
+ }
+ return BuiltinOperators.toValue(tName);
}
- return param.getAsBigDecimal().setScale(0, DEFAULT_ROUND_MODE)
- .longValue();
- }
+ });
+
+
// https://www.techonthenet.com/access/functions/
// https://support.office.com/en-us/article/Access-Functions-by-category-b8b136c3-2716-4d39-94a2-658ce330ed83
double result = Math.abs(param1.getAsDouble());
return BuiltinOperators.toDateValue(ctx, mathType, result, param1, null);
case LONG:
- return BuiltinOperators.toValue(Math.abs(param1.getAsLong()));
+ return BuiltinOperators.toValue(Math.abs(param1.getAsLongInt()));
case DOUBLE:
return BuiltinOperators.toValue(Math.abs(param1.getAsDouble()));
case STRING:
if(param1.getType().isIntegral()) {
return param1;
}
- return BuiltinOperators.toValue(param1.getAsDouble().longValue());
+ return BuiltinOperators.toValue(param1.getAsDouble().intValue());
}
});
if(param1.getType().isIntegral()) {
return param1;
}
- return BuiltinOperators.toValue((long)Math.floor(param1.getAsDouble()));
+ return BuiltinOperators.toValue((int)Math.floor(param1.getAsDouble()));
}
});
}
@Override
protected Value evalVar(EvalContext ctx, Value[] params) {
- Long seed = ((params.length > 0) ? params[0].getAsLong() : null);
+ Integer seed = ((params.length > 0) ? params[0].getAsLongInt() : null);
return BuiltinOperators.toValue(ctx.getRandom(seed).nextFloat());
}
});
}
int scale = 0;
if(params.length > 1) {
- scale = params[1].getAsLong().intValue();
+ scale = params[1].getAsLongInt();
}
- BigDecimal bd = param1.getAsBigDecimal().setScale(scale, DEFAULT_ROUND_MODE);
+ BigDecimal bd = param1.getAsBigDecimal()
+ .setScale(scale, BuiltinOperators.ROUND_MODE);
return BuiltinOperators.toValue(bd);
}
});
protected Value eval1(EvalContext ctx, Value param1) {
int signum = 0;
if(param1.getType().isIntegral()) {
- long lv = param1.getAsLong();
+ int lv = param1.getAsLongInt();
signum = ((lv > 0) ? 1 : ((lv < 0) ? -1 : 0));
} else {
signum = param1.getAsBigDecimal().signum();
if(len == 0) {
throw new IllegalStateException("No characters in string");
}
- long lv = str.charAt(0);
+ int lv = str.charAt(0);
if((lv < 0) || (lv > 255)) {
throw new IllegalStateException("Character code '" + lv +
"' out of range ");
if(len == 0) {
throw new IllegalStateException("No characters in string");
}
- long lv = str.charAt(0);
+ int lv = str.charAt(0);
return BuiltinOperators.toValue(lv);
}
});
public static final Function CHR = registerStringFunc(new Func1("Chr") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- long lv = param1.getAsLong();
+ int lv = param1.getAsLongInt();
if((lv < 0) || (lv > 255)) {
throw new IllegalStateException("Character code '" + lv +
"' out of range ");
}
- char[] cs = Character.toChars((int)lv);
+ char[] cs = Character.toChars(lv);
return BuiltinOperators.toValue(new String(cs));
}
});
public static final Function CHRW = registerStringFunc(new Func1("ChrW") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- long lv = param1.getAsLong();
- char[] cs = Character.toChars((int)lv);
+ int lv = param1.getAsLongInt();
+ char[] cs = Character.toChars(lv);
return BuiltinOperators.toValue(new String(cs));
}
});
int start = 0;
if(params.length > 2) {
// 1 based offsets
- start = params[0].getAsLong().intValue() - 1;
+ start = params[0].getAsLongInt() - 1;
++idx;
}
Value param1 = params[idx++];
return BuiltinOperators.toValue(start + 1);
}
if(params.length > 2) {
- start = params[2].getAsLong().intValue();
+ start = params[2].getAsLongInt();
if(start == -1) {
start = s1Len;
}
return param1;
}
String str = param1.getAsString();
- int len = (int)Math.min(str.length(), param2.getAsLong());
+ int len = Math.min(str.length(), param2.getAsLongInt());
return BuiltinOperators.toValue(str.substring(0, len));
}
});
}
String str = param1.getAsString();
int strLen = str.length();
- int len = (int)Math.min(strLen, param2.getAsLong());
+ int len = Math.min(strLen, param2.getAsLongInt());
return BuiltinOperators.toValue(str.substring(strLen - len, strLen));
}
});
String str = param1.getAsString();
int strLen = str.length();
// 1 based offsets
- int start = (int)Math.max(strLen, params[1].getAsLong() - 1);
+ int start = Math.max(strLen, params[1].getAsLongInt() - 1);
int len = Math.max(
- ((params.length > 2) ? params[2].getAsLong().intValue() : strLen),
+ ((params.length > 2) ? params[2].getAsLongInt() : strLen),
(strLen - start));
return BuiltinOperators.toValue(str.substring(start, start + len));
}
public static final Function SPACE = registerStringFunc(new Func1("Space") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- int lv = param1.getAsLong().intValue();
+ int lv = param1.getAsLongInt();
return BuiltinOperators.toValue(nchars(lv, ' '));
}
});
if(param1.isNull() || param2.isNull()) {
return BuiltinOperators.NULL_VAL;
}
- int lv = param1.getAsLong().intValue();
+ int lv = param1.getAsLongInt();
char c = (char)(param2.getAsString().charAt(0) % 256);
return BuiltinOperators.toValue(nchars(lv, c));
}
}
private static boolean doIgnoreCase(Value paramCmp) {
- int cmpType = paramCmp.getAsLong().intValue();
+ int cmpType = paramCmp.getAsLongInt();
switch(cmpType) {
case -1:
// vbUseCompareOption -> default is binary
// what number type to use here?
Object num = (isFp ?
(Number)Double.valueOf(numStr) :
- (Number)Long.valueOf(numStr));
+ (Number)Integer.valueOf(numStr));
foundNum = true;
return new Token(TokenType.LITERAL, num, numStr,
(isFp ? Value.Type.DOUBLE : Value.Type.LONG));
case DATE_TIME:
return new DateTimeValue((Date)value, sdf);
case LONG:
- return new LongValue((Long)value);
+ return new LongValue((Integer)value);
case DOUBLE:
return new DoubleValue((Double)value);
case BIG_DEC:
case DATE_TIME:
return val.getAsDateTime(ctx);
case LONG:
- return val.getAsLong();
+ return val.getAsLongInt();
case DOUBLE:
return val.getAsDouble();
case BIG_DEC:
*/
public class LongValue extends BaseNumericValue
{
- private final Long _val;
+ private final Integer _val;
- public LongValue(Long val)
+ public LongValue(Integer val)
{
_val = val;
}
}
@Override
- public Long getAsLong() {
+ public Integer getAsLongInt() {
return _val;
}
}
@Override
- public Long getAsLong() {
- return getNumber().longValue();
+ public Integer getAsLongInt() {
+ return roundToLongInt();
}
@Override
{
assertEquals("foo", eval("=IIf(10 > 1, \"foo\", \"bar\")"));
assertEquals("bar", eval("=IIf(10 < 1, \"foo\", \"bar\")"));
- assertEquals(102L, eval("=Asc(\"foo\")"));
- assertEquals(9786L, eval("=AscW(\"\u263A\")"));
+ assertEquals(102, eval("=Asc(\"foo\")"));
+ assertEquals(9786, eval("=AscW(\"\u263A\")"));
assertEquals("f", eval("=Chr(102)"));
assertEquals("\u263A", eval("=ChrW(9786)"));
assertEquals("263A", eval("=Hex(9786)"));
assertEquals(" 9786", eval("=Str(9786)"));
assertEquals("-42", eval("=Str(-42)"));
- assertEquals(-1L, eval("=CBool(\"1\")"));
- assertEquals(13L, eval("=CByte(\"13\")"));
- assertEquals(14L, eval("=CByte(\"13.7\")"));
+ assertEquals(-1, eval("=CBool(\"1\")"));
+ assertEquals(13, eval("=CByte(\"13\")"));
+ assertEquals(14, eval("=CByte(\"13.7\")"));
assertEquals(new BigDecimal("57.1235"), eval("=CCur(\"57.12346\")"));
assertEquals(new Double("57.12345"), eval("=CDbl(\"57.12345\")"));
assertEquals(new BigDecimal("57.123456789"), eval("=CDec(\"57.123456789\")"));
- assertEquals(513L, eval("=CInt(\"513\")"));
- assertEquals(514L, eval("=CInt(\"513.7\")"));
- assertEquals(345513L, eval("=CLng(\"345513\")"));
- assertEquals(345514L, eval("=CLng(\"345513.7\")"));
+ assertEquals(513, eval("=CInt(\"513\")"));
+ assertEquals(514, eval("=CInt(\"513.7\")"));
+ assertEquals(345513, eval("=CLng(\"345513\")"));
+ assertEquals(345514, eval("=CLng(\"345513.7\")"));
assertEquals(new Float("57.12345").doubleValue(),
eval("=CSng(\"57.12345\")"));
assertEquals("9786", eval("=CStr(9786)"));
package com.healthmarketscience.jackcess.impl.expr;
+import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
public void testSimpleMathExpressions() throws Exception
{
- for(long i = -10L; i <= 10L; ++i) {
+ for(int i = -10; i <= 10; ++i) {
assertEquals(-i, eval("=-(" + i + ")"));
}
assertEquals(-i, eval("=-(" + i + ")"));
}
- for(long i = -10L; i <= 10L; ++i) {
- for(long j = -10L; j <= 10L; ++j) {
+ for(int i = -10; i <= 10; ++i) {
+ for(int j = -10; j <= 10; ++j) {
assertEquals((i + j), eval("=" + i + " + " + j));
}
}
}
}
- for(long i = -10L; i <= 10L; ++i) {
- for(long j = -10L; j <= 10L; ++j) {
+ for(int i = -10; i <= 10; ++i) {
+ for(int j = -10; j <= 10; ++j) {
assertEquals((i - j), eval("=" + i + " - " + j));
}
}
}
}
- for(long i = -10L; i <= 10L; ++i) {
- for(long j = -10L; j <= 10L; ++j) {
+ for(int i = -10; i <= 10; ++i) {
+ for(int j = -10; j <= 10; ++j) {
assertEquals((i * j), eval("=" + i + " * " + j));
}
}
}
}
- for(long i = -10L; i <= 10L; ++i) {
- for(long j = -10L; j <= 10L; ++j) {
+ for(int i = -10; i <= 10; ++i) {
+ for(int j = -10; j <= 10; ++j) {
if(j == 0L) {
evalFail("=" + i + " \\ " + j, ArithmeticException.class);
} else {
for(double i : DBLS) {
for(double j : DBLS) {
- if((long)j == 0L) {
+ if(roundToLongInt(j) == 0) {
evalFail("=" + i + " \\ " + j, ArithmeticException.class);
} else {
- assertEquals(((long)i / (long)j), eval("=" + i + " \\ " + j));
+ assertEquals((roundToLongInt(i) / roundToLongInt(j)),
+ eval("=" + i + " \\ " + j));
}
}
}
- for(long i = -10L; i <= 10L; ++i) {
- for(long j = -10L; j <= 10L; ++j) {
- if(j == 0L) {
+ for(int i = -10; i <= 10; ++i) {
+ for(int j = -10; j <= 10; ++j) {
+ if(j == 0) {
evalFail("=" + i + " Mod " + j, ArithmeticException.class);
} else {
assertEquals((i % j), eval("=" + i + " Mod " + j));
for(double i : DBLS) {
for(double j : DBLS) {
- if((long)j == 0L) {
+ if(roundToLongInt(j) == 0) {
evalFail("=" + i + " Mod " + j, ArithmeticException.class);
} else {
- assertEquals(((long)i % (long)j), eval("=" + i + " Mod " + j));
+ assertEquals((roundToLongInt(i) % roundToLongInt(j)),
+ eval("=" + i + " Mod " + j));
}
}
}
- for(long i = -10L; i <= 10L; ++i) {
- for(long j = -10L; j <= 10L; ++j) {
- if(j == 0L) {
+ for(int i = -10; i <= 10; ++i) {
+ for(int j = -10; j <= 10; ++j) {
+ if(j == 0) {
evalFail("=" + i + " / " + j, ArithmeticException.class);
} else {
double result = (double)i / (double)j;
- if((long)result == result) {
- assertEquals((long)result, eval("=" + i + " / " + j));
+ if((int)result == result) {
+ assertEquals((int)result, eval("=" + i + " / " + j));
} else {
assertEquals(result, eval("=" + i + " / " + j));
}
}
}
- for(long i = -10L; i <= 10L; ++i) {
- for(long j = -10L; j <= 10L; ++j) {
+ for(int i = -10; i <= 10; ++i) {
+ for(int j = -10; j <= 10; ++j) {
double result = Math.pow(i, j);
- if((long)result == result) {
- assertEquals((long)result, eval("=" + i + " ^ " + j));
+ if((int)result == result) {
+ assertEquals((int)result, eval("=" + i + " ^ " + j));
} else {
assertEquals(result, eval("=" + i + " ^ " + j));
}
assertEquals("12foo", eval("=12 + \"foo\""));
assertEquals("foo12", eval("=\"foo\" + 12"));
- assertEquals(37L, eval("=\"25\" + 12"));
- assertEquals(37L, eval("=12 + \"25\""));
+ assertEquals(37, eval("=\"25\" + 12"));
+ assertEquals(37, eval("=12 + \"25\""));
evalFail(("=12 - \"foo\""), RuntimeException.class);
evalFail(("=\"foo\" - 12"), RuntimeException.class);
assertEquals("25foo12", eval("=\"25foo\" + 12"));
assertEquals(new Date(1485579600000L), eval("=#1/1/2017# + 27"));
- assertEquals(128208L, eval("=#1/1/2017# * 3"));
+ assertEquals(128208, eval("=#1/1/2017# * 3"));
}
public void testLikeExpression() throws Exception
return (Boolean)expr.eval(new TestEvalContext(BuiltinOperators.toValue(thisVal)));
}
+ static int roundToLongInt(double d) {
+ return new BigDecimal(d).setScale(0, BuiltinOperators.ROUND_MODE)
+ .intValueExact();
+ }
+
private static final class TestParseContext implements Expressionator.ParseContext
{
public TemporalConfig getTemporalConfig() {
throw new UnsupportedOperationException();
}
- public Random getRandom(Long seed) {
+ public Random getRandom(Integer seed) {
if(seed == null) {
if(_defRnd == null) {
_defRnd = new Random(System.currentTimeMillis());