*/
public void setTemporalConfig(TemporalConfig temporal);
+ /**
+ * @return the currently configured NumericConfig
+ */
+ public NumericConfig getNumericConfig();
+
+ /**
+ * Sets the NumericConfig for use when evaluating expressions. The default
+ * date/time formatting is US based, so this may need to be modified when
+ * interacting with {@link Database} instances from other locales.
+ */
+ public void setNumericConfig(NumericConfig numeric);
+
/**
* @return the currently configured FunctionLookup
*/
* @return a detailed string which indicates how the expression was
* interpreted by the expression evaluation engine.
*/
- public String toDebugString();
+ public String toDebugString(LocaleContext ctx);
/**
- * @return the original, unparsed expression string. By contrast, the {@link
- * Object#toString} result may return a value which has been cleaned
- * up with respect to the original expression.
+ * @return a parsed and re-formated version of the expression. This may
+ * look slightly different than the original, raw string, although
+ * it should be an equivalent expression.
+ */
+ public String toCleanString(LocaleContext ctx);
+
+ /**
+ * @return the original, unparsed expression string. This is the same as
+ * the value which will be returned by {@link Object#toString}.
*/
public String toRawString();
package com.healthmarketscience.jackcess.expr;
import java.text.SimpleDateFormat;
+import java.util.Calendar;
/**
* LocaleContext encapsulates all shared localization state for expression
*/
public SimpleDateFormat createDateFormat(String formatStr);
+ /**
+ * @return an appropriately configured (i.e. TimeZone and other date/time
+ * flags) Calendar.
+ */
+ public Calendar getCalendar();
+
+ /**
+ * @return the currently configured NumericConfig (from the
+ * {@link EvalConfig})
+ */
+ public NumericConfig getNumericConfig();
}
--- /dev/null
+/*
+Copyright (c) 2018 James Ahlborn
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package com.healthmarketscience.jackcess.expr;
+
+import java.text.DecimalFormatSymbols;
+import java.util.Locale;
+
+/**
+ * A NumericConfig encapsulates number formatting options for expression
+ * evaluation. The default {@link #US_NUMERIC_CONFIG} instance provides US
+ * specific locale configuration. Databases which have been built for other
+ * locales can utilize custom implementations of NumericConfig in order to
+ * evaluate expressions correctly.
+ *
+ * @author James Ahlborn
+ */
+public class NumericConfig
+{
+ public static final NumericConfig US_NUMERIC_CONFIG = new NumericConfig(
+ Locale.US);
+
+ private final DecimalFormatSymbols _symbols;
+
+ public NumericConfig(Locale locale) {
+ _symbols = DecimalFormatSymbols.getInstance(locale);
+ }
+
+ public DecimalFormatSymbols getDecimalFormatSymbols() {
+ return _symbols;
+ }
+}
/**
* @return this primitive value converted to a boolean
*/
- public boolean getAsBoolean();
+ public boolean getAsBoolean(LocaleContext ctx);
/**
* @return this primitive value converted to a String
*/
- public String getAsString();
+ public String getAsString(LocaleContext ctx);
/**
* @return this primitive value converted to a Date
*/
- public Date getAsDateTime(EvalContext ctx);
+ public Date getAsDateTime(LocaleContext ctx);
/**
* @return this primitive value converted (rounded) to an int
*/
- public Integer getAsLongInt();
+ public Integer getAsLongInt(LocaleContext ctx);
/**
* @return this primitive value converted (rounded) to a double
*/
- public Double getAsDouble();
+ public Double getAsDouble(LocaleContext ctx);
/**
* @return this primitive value converted to a BigDecimal
*/
- public BigDecimal getAsBigDecimal();
+ public BigDecimal getAsBigDecimal(LocaleContext ctx);
}
* evaluation context for a given {@link com.healthmarketscience.jackcess.Database} instance.</li>
* <li>{@link com.healthmarketscience.jackcess.expr.TemporalConfig} encapsulates date/time formatting options for
* expression evaluation.</li>
+ * <li>{@link com.healthmarketscience.jackcess.expr.NumericConfig} encapsulates number formatting options for
+ * expression evaluation.</li>
* <li>{@link com.healthmarketscience.jackcess.expr.FunctionLookup} provides a source for {@link com.healthmarketscience.jackcess.expr.Function} instances
* used during expression evaluation.</li>
* <li>{@link com.healthmarketscience.jackcess.expr.EvalException} wrapper exception thrown for failures which occur
import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
+import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.EnumMap;
import com.healthmarketscience.jackcess.expr.EvalException;
import com.healthmarketscience.jackcess.expr.Expression;
import com.healthmarketscience.jackcess.expr.Identifier;
+import com.healthmarketscience.jackcess.expr.LocaleContext;
+import com.healthmarketscience.jackcess.expr.NumericConfig;
import com.healthmarketscience.jackcess.expr.TemporalConfig;
import com.healthmarketscience.jackcess.expr.Value;
import com.healthmarketscience.jackcess.impl.expr.Expressionator;
return _dbCtx.createDateFormat(formatStr);
}
+ public Calendar getCalendar() {
+ return _dbCtx.getCalendar();
+ }
+
+ public NumericConfig getNumericConfig() {
+ return _dbCtx.getNumericConfig();
+ }
+
public float getRandom(Integer seed) {
return _dbCtx.getRandom(seed);
}
case DATE:
case TIME:
case DATE_TIME:
- return ValueSupport.toValue(this, vType, (Date)val);
+ return ValueSupport.toValue(vType, (Date)val);
case LONG:
Integer i = ((val instanceof Integer) ? (Integer)val :
((Number)val).intValue());
return getExpr().eval(ctx);
}
- public String toDebugString() {
- return "<raw>{" + _exprStr + "}";
+ public String toDebugString(LocaleContext ctx) {
+ return getExpr().toDebugString(ctx);
}
public String toRawString() {
return _exprStr;
}
+ public String toCleanString(LocaleContext ctx) {
+ return getExpr().toCleanString(ctx);
+ }
+
public boolean isConstant() {
return getExpr().isConstant();
}
@Override
public String toString() {
- return _exprStr;
+ return toRawString();
}
}
}
package com.healthmarketscience.jackcess.impl;
import java.text.SimpleDateFormat;
+import java.util.Calendar;
import java.util.Map;
import javax.script.Bindings;
import javax.script.SimpleBindings;
import com.healthmarketscience.jackcess.expr.EvalConfig;
import com.healthmarketscience.jackcess.expr.Function;
import com.healthmarketscience.jackcess.expr.FunctionLookup;
+import com.healthmarketscience.jackcess.expr.NumericConfig;
import com.healthmarketscience.jackcess.expr.TemporalConfig;
import com.healthmarketscience.jackcess.impl.expr.DefaultFunctions;
import com.healthmarketscience.jackcess.impl.expr.Expressionator;
private FunctionLookup _funcs = DefaultFunctions.LOOKUP;
private Map<String,SimpleDateFormat> _sdfs;
private TemporalConfig _temporal;
+ private NumericConfig _numeric;
private final RandomContext _rndCtx = new RandomContext();
private Bindings _bindings = new SimpleBindings();
_temporal = temporal;
}
+ public Calendar getCalendar() {
+ return _db.getCalendar();
+ }
+
+ public NumericConfig getNumericConfig() {
+ return _numeric;
+ }
+
+ public void setNumericConfig(NumericConfig numeric) {
+ _numeric = numeric;
+ }
+
public FunctionLookup getFunctionLookup() {
return _funcs;
}
public float getRandom(Integer seed) {
return _rndCtx.getRandom(seed);
}
+
+ void resetDateTimeConfig() {
+ _sdfs = null;
+ }
}
import com.healthmarketscience.jackcess.util.ReadOnlyFileChannel;
import com.healthmarketscience.jackcess.util.SimpleColumnValidatorFactory;
import com.healthmarketscience.jackcess.util.TableIterableBuilder;
+import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
newTimeZone = getDefaultTimeZone();
}
_timeZone = newTimeZone;
- // clear cached calendar when timezone is changed
+ // clear cached calendar(s) when timezone is changed
_calendar = null;
+ if(_evalCtx != null) {
+ _evalCtx.resetDateTimeConfig();
+ }
}
public Charset getCharset()
* space, {@code false} otherwise.
*/
public static boolean isBlank(String name) {
- return((name == null) || (name.trim().length() == 0));
+ return StringUtils.isBlank(name);
}
/**
* null} or empty.
*/
public static String trimToNull(String str) {
- if(str == null) {
- return null;
- }
- str = str.trim();
- return((str.length() > 0) ? str : null);
+ return StringUtils.trimToNull(str);
}
@Override
+++ /dev/null
-/*
-Copyright (c) 2016 James Ahlborn
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package com.healthmarketscience.jackcess.impl.expr;
-
-import java.math.BigDecimal;
-import java.text.DateFormat;
-import java.util.Date;
-
-import com.healthmarketscience.jackcess.impl.ColumnImpl;
-import com.healthmarketscience.jackcess.expr.EvalContext;
-
-/**
- *
- * @author James Ahlborn
- */
-public abstract class BaseDateValue extends BaseValue
-{
- private final Date _val;
- private final DateFormat _fmt;
-
- public BaseDateValue(Date val, DateFormat fmt)
- {
- _val = val;
- _fmt = fmt;
- }
-
- public Object get() {
- return _val;
- }
-
- protected DateFormat getFormat() {
- return _fmt;
- }
-
- protected Double getNumber() {
- return ColumnImpl.toDateDouble(_val, _fmt.getCalendar());
- }
-
- @Override
- public boolean getAsBoolean() {
- // ms access seems to treat dates/times as "true"
- return true;
- }
-
- @Override
- public String getAsString() {
- return _fmt.format(_val);
- }
-
- @Override
- public Date getAsDateTime(EvalContext ctx) {
- return _val;
- }
-
- @Override
- public Integer getAsLongInt() {
- return roundToLongInt();
- }
-
- @Override
- public Double getAsDouble() {
- return getNumber();
- }
-
- @Override
- public BigDecimal getAsBigDecimal() {
- return BigDecimal.valueOf(getNumber());
- }
-}
import java.math.BigDecimal;
import java.util.Date;
-import com.healthmarketscience.jackcess.expr.EvalContext;
+import com.healthmarketscience.jackcess.expr.LocaleContext;
import com.healthmarketscience.jackcess.expr.Value;
/**
return getDelegate().get();
}
- public boolean getAsBoolean() {
- return getDelegate().getAsBoolean();
+ public boolean getAsBoolean(LocaleContext ctx) {
+ return getDelegate().getAsBoolean(ctx);
}
- public String getAsString() {
- return getDelegate().getAsString();
+ public String getAsString(LocaleContext ctx) {
+ return getDelegate().getAsString(ctx);
}
- public Date getAsDateTime(EvalContext ctx) {
+ public Date getAsDateTime(LocaleContext ctx) {
return getDelegate().getAsDateTime(ctx);
}
- public Integer getAsLongInt() {
- return getDelegate().getAsLongInt();
+ public Integer getAsLongInt(LocaleContext ctx) {
+ return getDelegate().getAsLongInt(ctx);
}
- public Double getAsDouble() {
- return getDelegate().getAsDouble();
+ public Double getAsDouble(LocaleContext ctx) {
+ return getDelegate().getAsDouble(ctx);
}
- public BigDecimal getAsBigDecimal() {
- return getDelegate().getAsBigDecimal();
+ public BigDecimal getAsBigDecimal(LocaleContext ctx) {
+ return getDelegate().getAsBigDecimal(ctx);
}
protected abstract Value eval();
import java.text.SimpleDateFormat;
import java.util.Date;
-import com.healthmarketscience.jackcess.expr.EvalContext;
+import com.healthmarketscience.jackcess.expr.LocaleContext;
import com.healthmarketscience.jackcess.impl.ColumnImpl;
/**
}
@Override
- public Integer getAsLongInt() {
- return roundToLongInt();
+ public Integer getAsLongInt(LocaleContext ctx) {
+ return roundToLongInt(ctx);
}
@Override
- public Double getAsDouble() {
+ public Double getAsDouble(LocaleContext ctx) {
return getNumber().doubleValue();
}
@Override
- public Date getAsDateTime(EvalContext ctx) {
+ public Date getAsDateTime(LocaleContext ctx) {
double d = getNumber().doubleValue();
-
- SimpleDateFormat sdf = ctx.createDateFormat(
- ctx.getTemporalConfig().getDefaultDateTimeFormat());
- return new Date(ColumnImpl.fromDateDouble(d, sdf.getCalendar()));
+ return new Date(ColumnImpl.fromDateDouble(d, ctx.getCalendar()));
}
protected abstract Number getNumber();
import java.util.Date;
import com.healthmarketscience.jackcess.expr.Value;
-import com.healthmarketscience.jackcess.expr.EvalContext;
import com.healthmarketscience.jackcess.expr.EvalException;
+import com.healthmarketscience.jackcess.expr.LocaleContext;
import com.healthmarketscience.jackcess.impl.NumberFormatter;
/**
return(getType() == Type.NULL);
}
- public boolean getAsBoolean() {
+ public boolean getAsBoolean(LocaleContext ctx) {
throw invalidConversion(Value.Type.LONG);
}
- public String getAsString() {
+ public String getAsString(LocaleContext ctx) {
throw invalidConversion(Value.Type.STRING);
}
- public Date getAsDateTime(EvalContext ctx) {
+ public Date getAsDateTime(LocaleContext ctx) {
throw invalidConversion(Value.Type.DATE_TIME);
}
- public Integer getAsLongInt() {
+ public Integer getAsLongInt(LocaleContext ctx) {
throw invalidConversion(Value.Type.LONG);
}
- public Double getAsDouble() {
+ public Double getAsDouble(LocaleContext ctx) {
throw invalidConversion(Value.Type.DOUBLE);
}
- public BigDecimal getAsBigDecimal() {
+ public BigDecimal getAsBigDecimal(LocaleContext ctx) {
throw invalidConversion(Value.Type.BIG_DEC);
}
getType() + " value cannot be converted to " + newType);
}
- protected Integer roundToLongInt() {
- return getAsBigDecimal().setScale(0, NumberFormatter.ROUND_MODE)
+ protected Integer roundToLongInt(LocaleContext ctx) {
+ return getAsBigDecimal(ctx).setScale(0, NumberFormatter.ROUND_MODE)
.intValueExact();
}
import java.math.BigDecimal;
+import com.healthmarketscience.jackcess.expr.LocaleContext;
import com.healthmarketscience.jackcess.impl.NumberFormatter;
/**
}
@Override
- public boolean getAsBoolean() {
+ public boolean getAsBoolean(LocaleContext ctx) {
return (_val.compareTo(BigDecimal.ZERO) != 0L);
}
@Override
- public String getAsString() {
+ public String getAsString(LocaleContext ctx) {
return NumberFormatter.format(_val);
}
@Override
- public BigDecimal getAsBigDecimal() {
+ public BigDecimal getAsBigDecimal(LocaleContext ctx) {
return _val;
}
}
import java.math.BigDecimal;
import java.util.regex.Pattern;
-import com.healthmarketscience.jackcess.expr.EvalContext;
import com.healthmarketscience.jackcess.expr.EvalException;
+import com.healthmarketscience.jackcess.expr.LocaleContext;
import com.healthmarketscience.jackcess.expr.Value;
import com.healthmarketscience.jackcess.impl.NumberFormatter;
import static com.healthmarketscience.jackcess.impl.expr.ValueSupport.*;
// - between, not, like, in
// - *NOT* concal op '&'
- public static Value negate(EvalContext ctx, Value param1) {
+ public static Value negate(LocaleContext ctx, Value param1) {
if(param1.isNull()) {
// null propagation
return NULL_VAL;
case TIME:
case DATE_TIME:
// dates/times get converted to date doubles for arithmetic
- double result = -param1.getAsDouble();
- return toDateValue(ctx, mathType, result, param1, null);
+ double result = -param1.getAsDouble(ctx);
+ return toDateValue(ctx, mathType, result);
case LONG:
- return toValue(-param1.getAsLongInt());
+ return toValue(-param1.getAsLongInt(ctx));
case DOUBLE:
- return toValue(-param1.getAsDouble());
+ return toValue(-param1.getAsDouble(ctx));
case STRING:
case BIG_DEC:
- return toValue(param1.getAsBigDecimal().negate(
+ return toValue(param1.getAsBigDecimal(ctx).negate(
NumberFormatter.DEC_MATH_CONTEXT));
default:
throw new EvalException("Unexpected type " + mathType);
}
}
- public static Value add(EvalContext ctx, Value param1, Value param2) {
+ public static Value add(LocaleContext ctx, Value param1, Value param2) {
if(anyParamIsNull(param1, param2)) {
// null propagation
return NULL_VAL;
}
- Value.Type mathType = getMathTypePrecedence(param1, param2,
+ Value.Type mathType = getMathTypePrecedence(ctx, param1, param2,
CoercionType.SIMPLE);
switch(mathType) {
case STRING:
// string '+' is a null-propagation (handled above) concat
- return nonNullConcat(param1, param2);
+ return nonNullConcat(ctx, param1, param2);
case DATE:
case TIME:
case DATE_TIME:
// dates/times get converted to date doubles for arithmetic
- double result = param1.getAsDouble() + param2.getAsDouble();
- return toDateValue(ctx, mathType, result, param1, param2);
+ double result = param1.getAsDouble(ctx) + param2.getAsDouble(ctx);
+ return toDateValue(ctx, mathType, result);
case LONG:
- return toValue(param1.getAsLongInt() + param2.getAsLongInt());
+ return toValue(param1.getAsLongInt(ctx) + param2.getAsLongInt(ctx));
case DOUBLE:
- return toValue(param1.getAsDouble() + param2.getAsDouble());
+ return toValue(param1.getAsDouble(ctx) + param2.getAsDouble(ctx));
case BIG_DEC:
- return toValue(param1.getAsBigDecimal().add(
- param2.getAsBigDecimal(),
+ return toValue(param1.getAsBigDecimal(ctx).add(
+ param2.getAsBigDecimal(ctx),
NumberFormatter.DEC_MATH_CONTEXT));
default:
throw new EvalException("Unexpected type " + mathType);
}
}
- public static Value subtract(EvalContext ctx, Value param1, Value param2) {
+ public static Value subtract(LocaleContext ctx, Value param1, Value param2) {
if(anyParamIsNull(param1, param2)) {
// null propagation
return NULL_VAL;
}
- Value.Type mathType = getMathTypePrecedence(param1, param2,
+ Value.Type mathType = getMathTypePrecedence(ctx, param1, param2,
CoercionType.SIMPLE);
switch(mathType) {
case TIME:
case DATE_TIME:
// dates/times get converted to date doubles for arithmetic
- double result = param1.getAsDouble() - param2.getAsDouble();
- return toDateValue(ctx, mathType, result, param1, param2);
+ double result = param1.getAsDouble(ctx) - param2.getAsDouble(ctx);
+ return toDateValue(ctx, mathType, result);
case LONG:
- return toValue(param1.getAsLongInt() - param2.getAsLongInt());
+ return toValue(param1.getAsLongInt(ctx) - param2.getAsLongInt(ctx));
case DOUBLE:
- return toValue(param1.getAsDouble() - param2.getAsDouble());
+ return toValue(param1.getAsDouble(ctx) - param2.getAsDouble(ctx));
case BIG_DEC:
- return toValue(param1.getAsBigDecimal().subtract(
- param2.getAsBigDecimal(),
+ return toValue(param1.getAsBigDecimal(ctx).subtract(
+ param2.getAsBigDecimal(ctx),
NumberFormatter.DEC_MATH_CONTEXT));
default:
throw new EvalException("Unexpected type " + mathType);
}
}
- public static Value multiply(Value param1, Value param2) {
+ public static Value multiply(LocaleContext ctx, Value param1, Value param2) {
if(anyParamIsNull(param1, param2)) {
// null propagation
return NULL_VAL;
}
- Value.Type mathType = getMathTypePrecedence(param1, param2,
+ Value.Type mathType = getMathTypePrecedence(ctx, param1, param2,
CoercionType.GENERAL);
switch(mathType) {
// case TIME: break; promoted to double
// case DATE_TIME: break; promoted to double
case LONG:
- return toValue(param1.getAsLongInt() * param2.getAsLongInt());
+ return toValue(param1.getAsLongInt(ctx) * param2.getAsLongInt(ctx));
case DOUBLE:
- return toValue(param1.getAsDouble() * param2.getAsDouble());
+ return toValue(param1.getAsDouble(ctx) * param2.getAsDouble(ctx));
case BIG_DEC:
- return toValue(param1.getAsBigDecimal().multiply(
- param2.getAsBigDecimal(),
+ return toValue(param1.getAsBigDecimal(ctx).multiply(
+ param2.getAsBigDecimal(ctx),
NumberFormatter.DEC_MATH_CONTEXT));
default:
throw new EvalException("Unexpected type " + mathType);
}
}
- public static Value divide(Value param1, Value param2) {
+ public static Value divide(LocaleContext ctx, Value param1, Value param2) {
if(anyParamIsNull(param1, param2)) {
// null propagation
return NULL_VAL;
}
- Value.Type mathType = getMathTypePrecedence(param1, param2,
+ Value.Type mathType = getMathTypePrecedence(ctx, param1, param2,
CoercionType.GENERAL);
switch(mathType) {
// case TIME: break; promoted to double
// case DATE_TIME: break; promoted to double
case LONG:
- int lp1 = param1.getAsLongInt();
- int lp2 = param2.getAsLongInt();
+ int lp1 = param1.getAsLongInt(ctx);
+ int lp2 = param2.getAsLongInt(ctx);
if((lp1 % lp2) == 0) {
return toValue(lp1 / lp2);
}
return toValue((double)lp1 / (double)lp2);
case DOUBLE:
- double d2 = param2.getAsDouble();
+ double d2 = param2.getAsDouble(ctx);
if(d2 == 0.0d) {
throw new ArithmeticException(DIV_BY_ZERO);
}
- return toValue(param1.getAsDouble() / d2);
+ return toValue(param1.getAsDouble(ctx) / d2);
case BIG_DEC:
- return toValue(divide(param1.getAsBigDecimal(), param2.getAsBigDecimal()));
+ return toValue(divide(param1.getAsBigDecimal(ctx), param2.getAsBigDecimal(ctx)));
default:
throw new EvalException("Unexpected type " + mathType);
}
}
- public static Value intDivide(Value param1, Value param2) {
+ public static Value intDivide(LocaleContext ctx, Value param1, Value param2) {
if(anyParamIsNull(param1, param2)) {
// null propagation
return NULL_VAL;
}
- Value.Type mathType = getMathTypePrecedence(param1, param2,
+ Value.Type mathType = getMathTypePrecedence(ctx, param1, param2,
CoercionType.GENERAL);
if(mathType == Value.Type.STRING) {
throw new EvalException("Unexpected type " + mathType);
}
- return toValue(param1.getAsLongInt() / param2.getAsLongInt());
+ return toValue(param1.getAsLongInt(ctx) / param2.getAsLongInt(ctx));
}
- public static Value exp(Value param1, Value param2) {
+ public static Value exp(LocaleContext ctx, Value param1, Value param2) {
if(anyParamIsNull(param1, param2)) {
// null propagation
return NULL_VAL;
}
- Value.Type mathType = getMathTypePrecedence(param1, param2,
+ Value.Type mathType = getMathTypePrecedence(ctx, param1, param2,
CoercionType.GENERAL);
if(mathType == Value.Type.BIG_DEC) {
// see if we can handle the limited options supported for BigDecimal
// (must be a positive int exponent)
try {
- BigDecimal result = param1.getAsBigDecimal().pow(
- param2.getAsBigDecimal().intValueExact(),
+ BigDecimal result = param1.getAsBigDecimal(ctx).pow(
+ param2.getAsBigDecimal(ctx).intValueExact(),
NumberFormatter.DEC_MATH_CONTEXT);
return toValue(result);
} catch(ArithmeticException ae) {
}
// jdk only supports general pow() as doubles, let's go with that
- double result = Math.pow(param1.getAsDouble(), param2.getAsDouble());
+ double result = Math.pow(param1.getAsDouble(ctx), param2.getAsDouble(ctx));
// attempt to convert integral types back to integrals if possible
if((mathType == Value.Type.LONG) && isIntegral(result)) {
return toValue(result);
}
- public static Value mod(Value param1, Value param2) {
+ public static Value mod(LocaleContext ctx, Value param1, Value param2) {
if(anyParamIsNull(param1, param2)) {
// null propagation
return NULL_VAL;
}
- Value.Type mathType = getMathTypePrecedence(param1, param2,
+ Value.Type mathType = getMathTypePrecedence(ctx, param1, param2,
CoercionType.GENERAL);
if(mathType == Value.Type.STRING) {
throw new EvalException("Unexpected type " + mathType);
}
- return toValue(param1.getAsLongInt() % param2.getAsLongInt());
+ return toValue(param1.getAsLongInt(ctx) % param2.getAsLongInt(ctx));
}
- public static Value concat(Value param1, Value param2) {
+ public static Value concat(LocaleContext ctx, Value param1, Value param2) {
// note, this op converts null to empty string
if(param1.isNull()) {
param2 = EMPTY_STR_VAL;
}
- return nonNullConcat(param1, param2);
+ return nonNullConcat(ctx, param1, param2);
}
- private static Value nonNullConcat(Value param1, Value param2) {
- return toValue(param1.getAsString().concat(param2.getAsString()));
+ private static Value nonNullConcat(
+ LocaleContext ctx, Value param1, Value param2) {
+ return toValue(param1.getAsString(ctx).concat(param2.getAsString(ctx)));
}
- public static Value not(Value param1) {
+ public static Value not(LocaleContext ctx, Value param1) {
if(param1.isNull()) {
// null propagation
return NULL_VAL;
}
- return toValue(!param1.getAsBoolean());
+ return toValue(!param1.getAsBoolean(ctx));
}
- public static Value lessThan(Value param1, Value param2) {
+ public static Value lessThan(LocaleContext ctx, Value param1, Value param2) {
if(anyParamIsNull(param1, param2)) {
// null propagation
return NULL_VAL;
}
- return toValue(nonNullCompareTo(param1, param2) < 0);
+ return toValue(nonNullCompareTo(ctx, param1, param2) < 0);
}
- public static Value greaterThan(Value param1, Value param2) {
+ public static Value greaterThan(
+ LocaleContext ctx, Value param1, Value param2) {
if(anyParamIsNull(param1, param2)) {
// null propagation
return NULL_VAL;
}
- return toValue(nonNullCompareTo(param1, param2) > 0);
+ return toValue(nonNullCompareTo(ctx, param1, param2) > 0);
}
- public static Value lessThanEq(Value param1, Value param2) {
+ public static Value lessThanEq(
+ LocaleContext ctx, Value param1, Value param2) {
if(anyParamIsNull(param1, param2)) {
// null propagation
return NULL_VAL;
}
- return toValue(nonNullCompareTo(param1, param2) <= 0);
+ return toValue(nonNullCompareTo(ctx, param1, param2) <= 0);
}
- public static Value greaterThanEq(Value param1, Value param2) {
+ public static Value greaterThanEq(
+ LocaleContext ctx, Value param1, Value param2) {
if(anyParamIsNull(param1, param2)) {
// null propagation
return NULL_VAL;
}
- return toValue(nonNullCompareTo(param1, param2) >= 0);
+ return toValue(nonNullCompareTo(ctx, param1, param2) >= 0);
}
- public static Value equals(Value param1, Value param2) {
+ public static Value equals(LocaleContext ctx, Value param1, Value param2) {
if(anyParamIsNull(param1, param2)) {
// null propagation
return NULL_VAL;
}
- return toValue(nonNullCompareTo(param1, param2) == 0);
+ return toValue(nonNullCompareTo(ctx, param1, param2) == 0);
}
- public static Value notEquals(Value param1, Value param2) {
+ public static Value notEquals(LocaleContext ctx, Value param1, Value param2) {
if(anyParamIsNull(param1, param2)) {
// null propagation
return NULL_VAL;
}
- return toValue(nonNullCompareTo(param1, param2) != 0);
+ return toValue(nonNullCompareTo(ctx, param1, param2) != 0);
}
- public static Value and(Value param1, Value param2) {
+ public static Value and(LocaleContext ctx, Value param1, Value param2) {
// "and" uses short-circuit logic
return NULL_VAL;
}
- boolean b1 = param1.getAsBoolean();
+ boolean b1 = param1.getAsBoolean(ctx);
if(!b1) {
return FALSE_VAL;
}
return NULL_VAL;
}
- return toValue(param2.getAsBoolean());
+ return toValue(param2.getAsBoolean(ctx));
}
- public static Value or(Value param1, Value param2) {
+ public static Value or(LocaleContext ctx, Value param1, Value param2) {
// "or" uses short-circuit logic
return NULL_VAL;
}
- boolean b1 = param1.getAsBoolean();
+ boolean b1 = param1.getAsBoolean(ctx);
if(b1) {
return TRUE_VAL;
}
return NULL_VAL;
}
- return toValue(param2.getAsBoolean());
+ return toValue(param2.getAsBoolean(ctx));
}
- public static Value eqv(Value param1, Value param2) {
+ public static Value eqv(LocaleContext ctx, Value param1, Value param2) {
if(anyParamIsNull(param1, param2)) {
// null propagation
return NULL_VAL;
}
- boolean b1 = param1.getAsBoolean();
- boolean b2 = param2.getAsBoolean();
+ boolean b1 = param1.getAsBoolean(ctx);
+ boolean b2 = param2.getAsBoolean(ctx);
return toValue(b1 == b2);
}
- public static Value xor(Value param1, Value param2) {
+ public static Value xor(LocaleContext ctx, Value param1, Value param2) {
if(anyParamIsNull(param1, param2)) {
// null propagation
return NULL_VAL;
}
- boolean b1 = param1.getAsBoolean();
- boolean b2 = param2.getAsBoolean();
+ boolean b1 = param1.getAsBoolean(ctx);
+ boolean b2 = param2.getAsBoolean(ctx);
return toValue(b1 ^ b2);
}
- public static Value imp(Value param1, Value param2) {
+ public static Value imp(LocaleContext ctx, Value param1, Value param2) {
// "imp" uses short-circuit logic
if(param1.isNull()) {
- if(param2.isNull() || !param2.getAsBoolean()) {
+ if(param2.isNull() || !param2.getAsBoolean(ctx)) {
// null propagation
return NULL_VAL;
}
return TRUE_VAL;
}
- boolean b1 = param1.getAsBoolean();
+ boolean b1 = param1.getAsBoolean(ctx);
if(!b1) {
return TRUE_VAL;
}
return NULL_VAL;
}
- return toValue(param2.getAsBoolean());
+ return toValue(param2.getAsBoolean(ctx));
}
public static Value isNull(Value param1) {
return toValue(!param1.isNull());
}
- public static Value like(Value param1, Pattern pattern) {
+ public static Value like(LocaleContext ctx, Value param1, Pattern pattern) {
if(param1.isNull()) {
// null propagation
return NULL_VAL;
}
- return toValue(pattern.matcher(param1.getAsString()).matches());
+ return toValue(pattern.matcher(param1.getAsString(ctx)).matches());
}
- public static Value notLike(Value param1, Pattern pattern) {
- return not(like(param1, pattern));
+ public static Value notLike(
+ LocaleContext ctx, Value param1, Pattern pattern) {
+ return not(ctx, like(ctx, param1, pattern));
}
- public static Value between(Value param1, Value param2, Value param3) {
+ public static Value between(
+ LocaleContext ctx, Value param1, Value param2, Value param3) {
// null propagate any param. uses short circuit eval of params
if(anyParamIsNull(param1, param2, param3)) {
// null propagation
// the between values can be in either order!?!
Value min = param2;
Value max = param3;
- Value gt = greaterThan(min, max);
- if(gt.getAsBoolean()) {
+ Value gt = greaterThan(ctx, min, max);
+ if(gt.getAsBoolean(ctx)) {
min = param3;
max = param2;
}
- return and(greaterThanEq(param1, min), lessThanEq(param1, max));
+ return and(ctx, greaterThanEq(ctx, param1, min), lessThanEq(ctx, param1, max));
}
- public static Value notBetween(Value param1, Value param2, Value param3) {
- return not(between(param1, param2, param3));
+ public static Value notBetween(
+ LocaleContext ctx, Value param1, Value param2, Value param3) {
+ return not(ctx, between(ctx, param1, param2, param3));
}
- public static Value in(Value param1, Value[] params) {
+ public static Value in(LocaleContext ctx, Value param1, Value[] params) {
// null propagate any param. uses short circuit eval of params
if(param1.isNull()) {
continue;
}
- Value eq = equals(param1, val);
- if(eq.getAsBoolean()) {
+ Value eq = equals(ctx, param1, val);
+ if(eq.getAsBoolean(ctx)) {
return TRUE_VAL;
}
}
return FALSE_VAL;
}
- public static Value notIn(Value param1, Value[] params) {
- return not(in(param1, params));
+ public static Value notIn(LocaleContext ctx, Value param1, Value[] params) {
+ return not(ctx, in(ctx, param1, params));
}
}
protected static int nonNullCompareTo(
- Value param1, Value param2)
+ LocaleContext ctx, Value param1, Value param2)
{
// note that comparison does not do string to num coercion
- Value.Type compareType = getMathTypePrecedence(param1, param2,
+ Value.Type compareType = getMathTypePrecedence(ctx, param1, param2,
CoercionType.COMPARE);
switch(compareType) {
if(param1.getType() != param2.getType()) {
throw new EvalException("Unexpected type " + compareType);
}
- return param1.getAsString().compareToIgnoreCase(param2.getAsString());
+ return param1.getAsString(ctx).compareToIgnoreCase(param2.getAsString(ctx));
// case DATE: break; promoted to double
// case TIME: break; promoted to double
// case DATE_TIME: break; promoted to double
case LONG:
- return param1.getAsLongInt().compareTo(param2.getAsLongInt());
+ return param1.getAsLongInt(ctx).compareTo(param2.getAsLongInt(ctx));
case DOUBLE:
- return param1.getAsDouble().compareTo(param2.getAsDouble());
+ return param1.getAsDouble(ctx).compareTo(param2.getAsDouble(ctx));
case BIG_DEC:
- return param1.getAsBigDecimal().compareTo(param2.getAsBigDecimal());
+ return param1.getAsBigDecimal(ctx).compareTo(param2.getAsBigDecimal(ctx));
default:
throw new EvalException("Unexpected type " + compareType);
}
}
private static Value.Type getMathTypePrecedence(
- Value param1, Value param2, CoercionType cType)
+ LocaleContext ctx, Value param1, Value param2, CoercionType cType)
{
Value.Type t1 = param1.getType();
Value.Type t2 = param2.getType();
if(cType._allowCoerceStringToNum) {
// see if this is mixed string/numeric and the string can be coerced
// to a number
- Value.Type numericType = coerceStringToNumeric(param1, param2, cType);
+ Value.Type numericType = coerceStringToNumeric(
+ ctx, param1, param2, cType);
if(numericType != null) {
// string can be coerced to number
return numericType;
}
private static Value.Type coerceStringToNumeric(
- Value param1, Value param2, CoercionType cType) {
+ LocaleContext ctx, Value param1, Value param2, CoercionType cType) {
Value.Type t1 = param1.getType();
Value.Type t2 = param2.getType();
try {
// see if string can be coerced to a number
- strParam.getAsBigDecimal();
+ strParam.getAsBigDecimal(ctx);
if(prefType.isNumeric()) {
// seems like when strings are coerced to numbers, they are usually
// doubles, unless the current context is decimal
package com.healthmarketscience.jackcess.impl.expr;
-import java.text.DateFormat;
+import java.math.BigDecimal;
import java.util.Date;
+import com.healthmarketscience.jackcess.impl.ColumnImpl;
+import com.healthmarketscience.jackcess.expr.LocaleContext;
+
/**
*
* @author James Ahlborn
*/
-public class DateTimeValue extends BaseDateValue
+public class DateTimeValue extends BaseValue
{
+ private final Type _type;
+ private final Date _val;
- public DateTimeValue(Date val, DateFormat fmt)
- {
- super(val, fmt);
+ public DateTimeValue(Type type, Date val) {
+ if(!type.isTemporal()) {
+ throw new IllegalArgumentException("invalid date/time type");
+ }
+ _type = type;
+ _val = val;
}
public Type getType() {
- return Type.DATE_TIME;
+ return _type;
+ }
+
+ public Object get() {
+ return _val;
+ }
+
+ protected Double getNumber(LocaleContext ctx) {
+ return ColumnImpl.toDateDouble(_val, ctx.getCalendar());
+ }
+
+ @Override
+ public boolean getAsBoolean(LocaleContext ctx) {
+ // ms access seems to treat dates/times as "true"
+ return true;
+ }
+
+ @Override
+ public String getAsString(LocaleContext ctx) {
+ return ValueSupport.getDateFormatForType(ctx, getType()).format(_val);
+ }
+
+ @Override
+ public Date getAsDateTime(LocaleContext ctx) {
+ return _val;
+ }
+
+ @Override
+ public Integer getAsLongInt(LocaleContext ctx) {
+ return roundToLongInt(ctx);
+ }
+
+ @Override
+ public Double getAsDouble(LocaleContext ctx) {
+ return getNumber(ctx);
+ }
+
+ @Override
+ public BigDecimal getAsBigDecimal(LocaleContext ctx) {
+ return BigDecimal.valueOf(getNumber(ctx));
}
}
+++ /dev/null
-/*
-Copyright (c) 2016 James Ahlborn
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package com.healthmarketscience.jackcess.impl.expr;
-
-import java.text.DateFormat;
-import java.util.Date;
-
-/**
- *
- * @author James Ahlborn
- */
-public class DateValue extends BaseDateValue
-{
- public DateValue(Date val, DateFormat fmt)
- {
- super(val, fmt);
- }
-
- public Type getType() {
- return Type.DATE;
- }
-}
import com.healthmarketscience.jackcess.expr.EvalContext;
import com.healthmarketscience.jackcess.expr.EvalException;
import com.healthmarketscience.jackcess.expr.Function;
+import com.healthmarketscience.jackcess.expr.LocaleContext;
import com.healthmarketscience.jackcess.expr.TemporalConfig;
import com.healthmarketscience.jackcess.expr.Value;
import com.healthmarketscience.jackcess.impl.ColumnImpl;
public static final Function DATE = registerFunc(new Func0("Date") {
@Override
protected Value eval0(EvalContext ctx) {
- DateFormat fmt = ValueSupport.getDateFormatForType(ctx, Value.Type.DATE);
- double dd = dateOnly(currentTimeDouble(fmt));
- return ValueSupport.toValue(Value.Type.DATE, dd, fmt);
+ double dd = dateOnly(currentTimeDouble(ctx));
+ return ValueSupport.toDateValue(ctx, Value.Type.DATE, dd);
}
});
if(dv.getType() == Value.Type.DATE) {
return dv;
}
- double dd = dateOnly(dv.getAsDouble());
- DateFormat fmt = ValueSupport.getDateFormatForType(ctx, Value.Type.DATE);
- return ValueSupport.toValue(Value.Type.DATE, dd, fmt);
+ double dd = dateOnly(dv.getAsDouble(ctx));
+ return ValueSupport.toDateValue(ctx, Value.Type.DATE, dd);
}
});
public static final Function DATESERIAL = registerFunc(new Func3("DateSerial") {
@Override
protected Value eval3(EvalContext ctx, Value param1, Value param2, Value param3) {
- int year = param1.getAsLongInt();
- int month = param2.getAsLongInt();
- int day = param3.getAsLongInt();
+ int year = param1.getAsLongInt(ctx);
+ int month = param2.getAsLongInt(ctx);
+ int day = param3.getAsLongInt(ctx);
// "default" two digit year handling
if(year < 100) {
year += ((year <= 29) ? 2000 : 1900);
}
- DateFormat fmt = ValueSupport.getDateFormatForType(ctx, Value.Type.DATE);
- Calendar cal = fmt.getCalendar();
+ Calendar cal = ctx.getCalendar();
cal.clear();
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, month - 1);
cal.set(Calendar.DAY_OF_MONTH, day);
- return ValueSupport.toValue(Value.Type.DATE, cal.getTime(), fmt);
+ return ValueSupport.toValue(Value.Type.DATE, cal.getTime());
}
});
public static final Function NOW = registerFunc(new Func0("Now") {
@Override
protected Value eval0(EvalContext ctx) {
- DateFormat fmt = ValueSupport.getDateFormatForType(ctx, Value.Type.DATE_TIME);
- return ValueSupport.toValue(Value.Type.DATE_TIME, new Date(), fmt);
+ return ValueSupport.toValue(Value.Type.DATE_TIME, new Date());
}
});
public static final Function TIME = registerFunc(new Func0("Time") {
@Override
protected Value eval0(EvalContext ctx) {
- DateFormat fmt = ValueSupport.getDateFormatForType(ctx, Value.Type.TIME);
- double dd = timeOnly(currentTimeDouble(fmt));
- return ValueSupport.toValue(Value.Type.TIME, dd, fmt);
+ double dd = timeOnly(currentTimeDouble(ctx));
+ return ValueSupport.toDateValue(ctx, Value.Type.TIME, dd);
}
});
if(dv.getType() == Value.Type.TIME) {
return dv;
}
- double dd = timeOnly(dv.getAsDouble());
- DateFormat fmt = ValueSupport.getDateFormatForType(ctx, Value.Type.TIME);
- return ValueSupport.toValue(Value.Type.TIME, dd, fmt);
+ double dd = timeOnly(dv.getAsDouble(ctx));
+ return ValueSupport.toDateValue(ctx, Value.Type.TIME, dd);
}
});
public static final Function TIMER = registerFunc(new Func0("Timer") {
@Override
protected Value eval0(EvalContext ctx) {
- DateFormat fmt = ValueSupport.getDateFormatForType(ctx, Value.Type.TIME);
- double dd = timeOnly(currentTimeDouble(fmt)) * DSECONDS_PER_DAY;
+ double dd = timeOnly(currentTimeDouble(ctx)) * DSECONDS_PER_DAY;
return ValueSupport.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();
+ int hours = param1.getAsLongInt(ctx);
+ int minutes = param2.getAsLongInt(ctx);
+ int seconds = param3.getAsLongInt(ctx);
long totalSeconds = (hours * SECONDS_PER_HOUR) +
(minutes * SECONDS_PER_MINUTE) + seconds;
totalSeconds %= SECONDS_PER_DAY;
}
- DateFormat fmt = ValueSupport.getDateFormatForType(ctx, Value.Type.TIME);
double dd = totalSeconds / DSECONDS_PER_DAY;
- return ValueSupport.toValue(Value.Type.TIME, dd, fmt);
+ return ValueSupport.toDateValue(ctx, Value.Type.TIME, dd);
}
});
return null;
}
// convert from 1 based to 0 based value
- int month = param1.getAsLongInt() - 1;
+ int month = param1.getAsLongInt(ctx) - 1;
- boolean abbreviate = getOptionalBooleanParam(params, 1);
+ boolean abbreviate = getOptionalBooleanParam(ctx, params, 1);
- DateFormatSymbols syms = ctx.createDateFormat(
- ctx.getTemporalConfig().getDateFormat()).getDateFormatSymbols();
+ DateFormatSymbols syms = ctx.getTemporalConfig().getDateFormatSymbols();
String[] monthNames = (abbreviate ?
syms.getShortMonths() : syms.getMonths());
// note, the array is 1 based
}
int dayOfWeek = nonNullToCalendarField(ctx, param1, Calendar.DAY_OF_WEEK);
- int firstDay = getFirstDayParam(params, 1);
+ int firstDay = getFirstDayParam(ctx, params, 1);
return ValueSupport.toValue(dayOfWeekToWeekDay(dayOfWeek, firstDay));
}
if(param1 == null) {
return null;
}
- int weekday = param1.getAsLongInt();
+ int weekday = param1.getAsLongInt(ctx);
- boolean abbreviate = getOptionalBooleanParam(params, 1);
+ boolean abbreviate = getOptionalBooleanParam(ctx, params, 1);
- int firstDay = getFirstDayParam(params, 2);
+ int firstDay = getFirstDayParam(ctx, params, 2);
int dayOfWeek = weekDayToDayOfWeek(weekday, firstDay);
- DateFormatSymbols syms = ctx.createDateFormat(
- ctx.getTemporalConfig().getDateFormat()).getDateFormatSymbols();
+ DateFormatSymbols syms = ctx.getTemporalConfig().getDateFormatSymbols();
String[] weekdayNames = (abbreviate ?
syms.getShortWeekdays() : syms.getWeekdays());
// note, the array is 1 based
origParam + "'");
}
- Calendar cal = getDateValueFormat(ctx, param).getCalendar();
+ Calendar cal = ctx.getCalendar();
cal.setTime(param.getAsDateTime(ctx));
return cal;
}
if(type == Value.Type.STRING) {
// see if we can coerce to date/time or double
- String valStr = param.getAsString();
+ String valStr = param.getAsString(ctx);
TemporalConfig.Type valTempType = ExpressionTokenizer.determineDateType(
valStr, ctx);
if(valTempType != null) {
try {
- DateFormat parseDf = ExpressionTokenizer.createParseDateFormat(
+ DateFormat parseDf = ExpressionTokenizer.createParseDateTimeFormat(
valTempType, ctx);
Date dateVal = ExpressionTokenizer.parseComplete(parseDf, valStr);
- return ValueSupport.toValue(ctx, valTempType.getValueType(),
- dateVal);
+ return ValueSupport.toValue(valTempType.getValueType(), dateVal);
} catch(java.text.ParseException pe) {
// not a valid date string, not a date/time
return null;
// see if string can be coerced to number
try {
- return numberToDateValue(ctx, param.getAsDouble());
+ return numberToDateValue(ctx, param.getAsDouble(ctx));
} catch(NumberFormatException ignored) {
// not a number, not a date/time
return null;
}
// must be a number
- return numberToDateValue(ctx, param.getAsDouble());
+ return numberToDateValue(ctx, param.getAsDouble(ctx));
}
private static Value numberToDateValue(EvalContext ctx, double dd) {
Value.Type type = (hasDate ? (hasTime ? Value.Type.DATE_TIME :
Value.Type.DATE) :
Value.Type.TIME);
- DateFormat fmt = ValueSupport.getDateFormatForType(ctx, type);
- return ValueSupport.toValue(type, dd, fmt);
- }
-
- private static DateFormat getDateValueFormat(EvalContext ctx, Value param) {
- return ((param instanceof BaseDateValue) ?
- ((BaseDateValue)param).getFormat() :
- ValueSupport.getDateFormatForType(ctx, param.getType()));
+ return ValueSupport.toDateValue(ctx, type, dd);
}
private static double dateOnly(double dd) {
return new BigDecimal(dd).remainder(BigDecimal.ONE).doubleValue();
}
- private static double currentTimeDouble(DateFormat fmt) {
- return ColumnImpl.toDateDouble(System.currentTimeMillis(), fmt.getCalendar());
+ private static double currentTimeDouble(LocaleContext ctx) {
+ return ColumnImpl.toDateDouble(System.currentTimeMillis(), ctx.getCalendar());
}
private static int dayOfWeekToWeekDay(int day, int firstDay) {
return (((firstDay - 1) + (weekday - 1)) % 7) + 1;
}
- private static int getFirstDayParam(Value[] params, int idx) {
+ private static int getFirstDayParam(
+ LocaleContext ctx, Value[] params, int idx) {
// vbSunday (default)
int firstDay = 1;
if(params.length > idx) {
- firstDay = params[idx].getAsLongInt();
+ firstDay = params[idx].getAsLongInt(ctx);
if(firstDay == 0) {
// 0 == vbUseSystem, so we will use the default "sunday"
firstDay = 1;
return firstDay;
}
- private static boolean getOptionalBooleanParam(Value[] params, int idx) {
+ private static boolean getOptionalBooleanParam(
+ LocaleContext ctx, Value[] params, int idx) {
if(params.length > idx) {
- return params[idx].getAsBoolean();
+ return params[idx].getAsBoolean(ctx);
}
return false;
}
public static final Function NPER = registerFunc(new FuncVar("NPer", 3, 5) {
@Override
protected Value evalVar(EvalContext ctx, Value[] params) {
- double rate = params[0].getAsDouble();
- double pmt = params[1].getAsDouble();
- double pv = params[2].getAsDouble();
+ double rate = params[0].getAsDouble(ctx);
+ double pmt = params[1].getAsDouble(ctx);
+ double pv = params[2].getAsDouble(ctx);
double fv = 0d;
if(params.length > 3) {
- fv = params[3].getAsDouble();
+ fv = params[3].getAsDouble(ctx);
}
int pmtType = PMT_END_MNTH;
if(params.length > 4) {
- pmtType = params[4].getAsLongInt();
+ pmtType = params[4].getAsLongInt(ctx);
}
double result = calculateLoanPaymentPeriods(rate, pmt, pv, pmtType);
public static final Function FV = registerFunc(new FuncVar("FV", 3, 5) {
@Override
protected Value evalVar(EvalContext ctx, Value[] params) {
- double rate = params[0].getAsDouble();
- double nper = params[1].getAsDouble();
- double pmt = params[2].getAsDouble();
+ double rate = params[0].getAsDouble(ctx);
+ double nper = params[1].getAsDouble(ctx);
+ double pmt = params[2].getAsDouble(ctx);
double pv = 0d;
if(params.length > 3) {
- pv = params[3].getAsDouble();
+ pv = params[3].getAsDouble(ctx);
}
int pmtType = PMT_END_MNTH;
if(params.length > 4) {
- pmtType = params[4].getAsLongInt();
+ pmtType = params[4].getAsLongInt(ctx);
}
if(pv != 0d) {
public static final Function PV = registerFunc(new FuncVar("PV", 3, 5) {
@Override
protected Value evalVar(EvalContext ctx, Value[] params) {
- double rate = params[0].getAsDouble();
- double nper = params[1].getAsDouble();
- double pmt = params[2].getAsDouble();
+ double rate = params[0].getAsDouble(ctx);
+ double nper = params[1].getAsDouble(ctx);
+ double pmt = params[2].getAsDouble(ctx);
double fv = 0d;
if(params.length > 3) {
- fv = params[3].getAsDouble();
+ fv = params[3].getAsDouble(ctx);
}
int pmtType = PMT_END_MNTH;
if(params.length > 4) {
- pmtType = params[4].getAsLongInt();
+ pmtType = params[4].getAsLongInt(ctx);
}
if(fv != 0d) {
public static final Function PMT = registerFunc(new FuncVar("Pmt", 3, 5) {
@Override
protected Value evalVar(EvalContext ctx, Value[] params) {
- double rate = params[0].getAsDouble();
- double nper = params[1].getAsDouble();
- double pv = params[2].getAsDouble();
+ double rate = params[0].getAsDouble(ctx);
+ double nper = params[1].getAsDouble(ctx);
+ double pv = params[2].getAsDouble(ctx);
double fv = 0d;
if(params.length > 3) {
- fv = params[3].getAsDouble();
+ fv = params[3].getAsDouble(ctx);
}
int pmtType = PMT_END_MNTH;
if(params.length > 4) {
- pmtType = params[4].getAsLongInt();
+ pmtType = params[4].getAsLongInt(ctx);
}
double result = calculateLoanPayment(rate, nper, pv, pmtType);
// public static final Function IPMT = registerFunc(new FuncVar("IPmt", 4, 6) {
// @Override
// protected Value evalVar(EvalContext ctx, Value[] params) {
- // double rate = params[0].getAsDouble();
- // double per = params[1].getAsDouble();
- // double nper = params[2].getAsDouble();
- // double pv = params[3].getAsDouble();
+ // double rate = params[0].getAsDouble(ctx);
+ // double per = params[1].getAsDouble(ctx);
+ // double nper = params[2].getAsDouble(ctx);
+ // double pv = params[3].getAsDouble(ctx);
// double fv = 0d;
// if(params.length > 4) {
- // fv = params[4].getAsDouble();
+ // fv = params[4].getAsDouble(ctx);
// }
// int pmtType = PMT_END_MNTH;
// if(params.length > 5) {
- // pmtType = params[5].getAsLongInt();
+ // pmtType = params[5].getAsLongInt(ctx);
// }
// double pmt = calculateLoanPayment(rate, nper, pv, pmtType);
// public static final Function PPMT = registerFunc(new FuncVar("PPmt", 4, 6) {
// @Override
// protected Value evalVar(EvalContext ctx, Value[] params) {
- // double rate = params[0].getAsDouble();
- // double per = params[1].getAsDouble();
- // double nper = params[2].getAsDouble();
- // double pv = params[3].getAsDouble();
+ // double rate = params[0].getAsDouble(ctx);
+ // double per = params[1].getAsDouble(ctx);
+ // double nper = params[2].getAsDouble(ctx);
+ // double pv = params[3].getAsDouble(ctx);
// double fv = 0d;
// if(params.length > 4) {
- // fv = params[4].getAsDouble();
+ // fv = params[4].getAsDouble(ctx);
// }
// int pmtType = PMT_END_MNTH;
// if(params.length > 5) {
- // pmtType = params[5].getAsLongInt();
+ // pmtType = params[5].getAsLongInt(ctx);
// }
// double pmt = calculateLoanPayment(rate, nper, pv, pmtType);
// public static final Function DDB = registerFunc(new FuncVar("DDB", 4, 5) {
// @Override
// protected Value evalVar(EvalContext ctx, Value[] params) {
- // double cost = params[0].getAsDouble();
- // double salvage = params[1].getAsDouble();
- // double life = params[2].getAsDouble();
- // double period = params[3].getAsDouble();
+ // double cost = params[0].getAsDouble(ctx);
+ // double salvage = params[1].getAsDouble(ctx);
+ // double life = params[2].getAsDouble(ctx);
+ // double period = params[3].getAsDouble(ctx);
// double factor = 2d;
// if(params.length > 4) {
- // factor = params[4].getAsDouble();
+ // factor = params[4].getAsDouble(ctx);
// }
// double result = 0d;
// public static final Function SLN = registerFunc(new FuncVar("SLN", 3, 3) {
// @Override
// protected Value evalVar(EvalContext ctx, Value[] params) {
- // double cost = params[0].getAsDouble();
- // double salvage = params[1].getAsDouble();
- // double life = params[2].getAsDouble();
+ // double cost = params[0].getAsDouble(ctx);
+ // double salvage = params[1].getAsDouble(ctx);
+ // double life = params[2].getAsDouble(ctx);
// double result = calculateStraightLineDepreciation(cost, salvage, life);
// public static final Function SYD = registerFunc(new FuncVar("SYD", 4, 4) {
// @Override
// protected Value evalVar(EvalContext ctx, Value[] params) {
- // double cost = params[0].getAsDouble();
- // double salvage = params[1].getAsDouble();
- // double life = params[2].getAsDouble();
- // double period = params[3].getAsDouble();
+ // double cost = params[0].getAsDouble(ctx);
+ // double salvage = params[1].getAsDouble(ctx);
+ // double life = params[2].getAsDouble(ctx);
+ // double period = params[3].getAsDouble(ctx);
// double result = calculateSumOfYearsDepreciation(
// cost, salvage, life, period);
protected Value eval3(EvalContext ctx,
Value param1, Value param2, Value param3) {
// null is false
- return ((!param1.isNull() && param1.getAsBoolean()) ? param2 : param3);
+ return ((!param1.isNull() && param1.getAsBoolean(ctx)) ? param2 : param3);
}
});
@Override
protected Value eval1(EvalContext ctx, Value param1) {
if((param1.getType() == Value.Type.STRING) &&
- (param1.getAsString().length() == 0)) {
+ (param1.getAsString(ctx).length() == 0)) {
return ValueSupport.ZERO_VAL;
}
- int lv = param1.getAsLongInt();
+ int lv = param1.getAsLongInt(ctx);
return ValueSupport.toValue(Integer.toHexString(lv).toUpperCase());
}
});
@Override
protected Value evalVar(EvalContext ctx, Value[] params) {
Value param1 = params[0];
- int idx = param1.getAsLongInt();
+ int idx = param1.getAsLongInt(ctx);
if((idx < 1) || (idx >= params.length)) {
return ValueSupport.NULL_VAL;
}
throw new EvalException("Odd number of parameters");
}
for(int i = 0; i < params.length; i+=2) {
- if(params[i].getAsBoolean()) {
+ if(params[i].getAsBoolean(ctx)) {
return params[i + 1];
}
}
@Override
protected Value eval1(EvalContext ctx, Value param1) {
if((param1.getType() == Value.Type.STRING) &&
- (param1.getAsString().length() == 0)) {
+ (param1.getAsString(ctx).length() == 0)) {
return ValueSupport.ZERO_VAL;
}
- int lv = param1.getAsLongInt();
+ int lv = param1.getAsLongInt(ctx);
return ValueSupport.toValue(Integer.toOctalString(lv));
}
});
public static final Function CBOOL = registerFunc(new Func1("CBool") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- boolean b = param1.getAsBoolean();
+ boolean b = param1.getAsBoolean(ctx);
return ValueSupport.toValue(b);
}
});
public static final Function CBYTE = registerFunc(new Func1("CByte") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- int lv = param1.getAsLongInt();
+ int lv = param1.getAsLongInt(ctx);
if((lv < 0) || (lv > 255)) {
throw new EvalException("Byte code '" + lv + "' out of range ");
}
public static final Function CCUR = registerFunc(new Func1("CCur") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- BigDecimal bd = param1.getAsBigDecimal();
+ BigDecimal bd = param1.getAsBigDecimal(ctx);
bd = bd.setScale(4, NumberFormatter.ROUND_MODE);
return ValueSupport.toValue(bd);
}
public static final Function CDBL = registerFunc(new Func1("CDbl") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- Double dv = param1.getAsDouble();
+ Double dv = param1.getAsDouble(ctx);
return ValueSupport.toValue(dv);
}
});
public static final Function CDEC = registerFunc(new Func1("CDec") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- BigDecimal bd = param1.getAsBigDecimal();
+ BigDecimal bd = param1.getAsBigDecimal(ctx);
return ValueSupport.toValue(bd);
}
});
public static final Function CINT = registerFunc(new Func1("CInt") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- int lv = param1.getAsLongInt();
+ int lv = param1.getAsLongInt(ctx);
if((lv < Short.MIN_VALUE) || (lv > Short.MAX_VALUE)) {
throw new EvalException("Int value '" + lv + "' out of range ");
}
public static final Function CLNG = registerFunc(new Func1("CLng") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- int lv = param1.getAsLongInt();
+ int lv = param1.getAsLongInt(ctx);
return ValueSupport.toValue(lv);
}
});
public static final Function CSNG = registerFunc(new Func1("CSng") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- Double dv = param1.getAsDouble();
+ Double dv = param1.getAsDouble(ctx);
if((dv < Float.MIN_VALUE) || (dv > Float.MAX_VALUE)) {
throw new EvalException("Single value '" + dv + "' out of range ");
}
public static final Function CSTR = registerFunc(new Func1("CStr") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- return ValueSupport.toValue(param1.getAsString());
+ return ValueSupport.toValue(param1.getAsString(ctx));
}
});
if(param1.getType() == Value.Type.STRING) {
try {
- param1.getAsBigDecimal();
+ param1.getAsBigDecimal(ctx);
return ValueSupport.TRUE_VAL;
} catch(NumberFormatException ignored) {
// fall through to FALSE_VAL
case TIME:
case DATE_TIME:
// dates/times get converted to date doubles for arithmetic
- double result = Math.abs(param1.getAsDouble());
- return ValueSupport.toDateValue(ctx, mathType, result, param1, null);
+ double result = Math.abs(param1.getAsDouble(ctx));
+ return ValueSupport.toDateValue(ctx, mathType, result);
case LONG:
- return ValueSupport.toValue(Math.abs(param1.getAsLongInt()));
+ return ValueSupport.toValue(Math.abs(param1.getAsLongInt(ctx)));
case DOUBLE:
- return ValueSupport.toValue(Math.abs(param1.getAsDouble()));
+ return ValueSupport.toValue(Math.abs(param1.getAsDouble(ctx)));
case STRING:
case BIG_DEC:
- return ValueSupport.toValue(param1.getAsBigDecimal().abs(
+ return ValueSupport.toValue(param1.getAsBigDecimal(ctx).abs(
NumberFormatter.DEC_MATH_CONTEXT));
default:
throw new EvalException("Unexpected type " + mathType);
public static final Function ATAN = registerFunc(new Func1("Atan") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- return ValueSupport.toValue(Math.atan(param1.getAsDouble()));
+ return ValueSupport.toValue(Math.atan(param1.getAsDouble(ctx)));
}
});
public static final Function COS = registerFunc(new Func1("Cos") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- return ValueSupport.toValue(Math.cos(param1.getAsDouble()));
+ return ValueSupport.toValue(Math.cos(param1.getAsDouble(ctx)));
}
});
public static final Function EXP = registerFunc(new Func1("Exp") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- return ValueSupport.toValue(Math.exp(param1.getAsDouble()));
+ return ValueSupport.toValue(Math.exp(param1.getAsDouble(ctx)));
}
});
if(param1.getType().isIntegral()) {
return param1;
}
- return ValueSupport.toValue(param1.getAsDouble().intValue());
+ return ValueSupport.toValue(param1.getAsDouble(ctx).intValue());
}
});
if(param1.getType().isIntegral()) {
return param1;
}
- return ValueSupport.toValue((int)Math.floor(param1.getAsDouble()));
+ return ValueSupport.toValue((int)Math.floor(param1.getAsDouble(ctx)));
}
});
public static final Function LOG = registerFunc(new Func1("Log") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- return ValueSupport.toValue(Math.log(param1.getAsDouble()));
+ return ValueSupport.toValue(Math.log(param1.getAsDouble(ctx)));
}
});
}
@Override
protected Value evalVar(EvalContext ctx, Value[] params) {
- Integer seed = ((params.length > 0) ? params[0].getAsLongInt() : null);
+ Integer seed = ((params.length > 0) ? params[0].getAsLongInt(ctx) : null);
return ValueSupport.toValue(ctx.getRandom(seed));
}
});
}
int scale = 0;
if(params.length > 1) {
- scale = params[1].getAsLongInt();
+ scale = params[1].getAsLongInt(ctx);
}
- BigDecimal bd = param1.getAsBigDecimal()
+ BigDecimal bd = param1.getAsBigDecimal(ctx)
.setScale(scale, NumberFormatter.ROUND_MODE);
return ValueSupport.toValue(bd);
}
protected Value eval1(EvalContext ctx, Value param1) {
int val = 0;
if(param1.getType().isIntegral()) {
- val = param1.getAsLongInt();
+ val = param1.getAsLongInt(ctx);
} else {
- val = param1.getAsBigDecimal().signum();
+ val = param1.getAsBigDecimal(ctx).signum();
}
return ((val > 0) ? ValueSupport.ONE_VAL :
((val < 0) ? ValueSupport.NEG_ONE_VAL :
public static final Function SQR = registerFunc(new Func1("Sqr") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- double dv = param1.getAsDouble();
+ double dv = param1.getAsDouble(ctx);
if(dv < 0.0d) {
throw new EvalException("Invalid value '" + dv + "'");
}
public static final Function SIN = registerFunc(new Func1("Sin") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- return ValueSupport.toValue(Math.sin(param1.getAsDouble()));
+ return ValueSupport.toValue(Math.sin(param1.getAsDouble(ctx)));
}
});
public static final Function TAN = registerFunc(new Func1("Tan") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- return ValueSupport.toValue(Math.tan(param1.getAsDouble()));
+ return ValueSupport.toValue(Math.tan(param1.getAsDouble(ctx)));
}
});
import com.healthmarketscience.jackcess.expr.EvalContext;
import com.healthmarketscience.jackcess.expr.EvalException;
import com.healthmarketscience.jackcess.expr.Function;
+import com.healthmarketscience.jackcess.expr.LocaleContext;
import com.healthmarketscience.jackcess.expr.Value;
import static com.healthmarketscience.jackcess.impl.expr.DefaultFunctions.*;
import static com.healthmarketscience.jackcess.impl.expr.FunctionSupport.*;
public static final Function ASC = registerFunc(new Func1("Asc") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- String str = param1.getAsString();
+ String str = param1.getAsString(ctx);
int len = str.length();
if(len == 0) {
throw new EvalException("No characters in string");
public static final Function ASCW = registerFunc(new Func1("AscW") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- String str = param1.getAsString();
+ String str = param1.getAsString(ctx);
int len = str.length();
if(len == 0) {
throw new EvalException("No characters in string");
public static final Function CHR = registerStringFunc(new Func1NullIsNull("Chr") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- int lv = param1.getAsLongInt();
+ int lv = param1.getAsLongInt(ctx);
if((lv < 0) || (lv > 255)) {
throw new EvalException("Character code '" + lv +
"' out of range ");
public static final Function CHRW = registerStringFunc(new Func1NullIsNull("ChrW") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- int lv = param1.getAsLongInt();
+ int lv = param1.getAsLongInt(ctx);
char[] cs = Character.toChars(lv);
return ValueSupport.toValue(new String(cs));
}
public static final Function STR = registerStringFunc(new Func1NullIsNull("Str") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- BigDecimal bd = param1.getAsBigDecimal();
+ BigDecimal bd = param1.getAsBigDecimal(ctx);
String str = bd.toPlainString();
if(bd.compareTo(BigDecimal.ZERO) >= 0) {
str = " " + str;
int start = 0;
if(params.length > 2) {
// 1 based offsets
- start = params[0].getAsLongInt() - 1;
+ start = params[0].getAsLongInt(ctx) - 1;
++idx;
}
Value param1 = params[idx++];
if(param1.isNull()) {
return param1;
}
- String s1 = param1.getAsString();
+ String s1 = param1.getAsString(ctx);
int s1Len = s1.length();
if(s1Len == 0) {
return ValueSupport.ZERO_VAL;
if(param2.isNull()) {
return param2;
}
- String s2 = param2.getAsString();
+ String s2 = param2.getAsString(ctx);
int s2Len = s2.length();
if(s2Len == 0) {
// 1 based offsets
}
boolean ignoreCase = true;
if(params.length > 3) {
- ignoreCase = doIgnoreCase(params[3]);
+ ignoreCase = doIgnoreCase(ctx, params[3]);
}
int end = s1Len - s2Len;
while(start < end) {
if(param1.isNull()) {
return param1;
}
- String s1 = param1.getAsString();
+ String s1 = param1.getAsString(ctx);
int s1Len = s1.length();
if(s1Len == 0) {
return ValueSupport.ZERO_VAL;
if(param2.isNull()) {
return param2;
}
- String s2 = param2.getAsString();
+ String s2 = param2.getAsString(ctx);
int s2Len = s2.length();
int start = s1Len - 1;
if(s2Len == 0) {
return ValueSupport.toValue(start + 1);
}
if(params.length > 2) {
- start = params[2].getAsLongInt();
+ start = params[2].getAsLongInt(ctx);
if(start == -1) {
start = s1Len;
}
}
boolean ignoreCase = true;
if(params.length > 3) {
- ignoreCase = doIgnoreCase(params[3]);
+ ignoreCase = doIgnoreCase(ctx, params[3]);
}
start = Math.min(s1Len - s2Len, start - s2Len + 1);
while(start >= 0) {
public static final Function LCASE = registerStringFunc(new Func1NullIsNull("LCase") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- String str = param1.getAsString();
+ String str = param1.getAsString(ctx);
return ValueSupport.toValue(str.toLowerCase());
}
});
public static final Function UCASE = registerStringFunc(new Func1NullIsNull("UCase") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- String str = param1.getAsString();
+ String str = param1.getAsString(ctx);
return ValueSupport.toValue(str.toUpperCase());
}
});
if(param1.isNull()) {
return param1;
}
- String str = param1.getAsString();
- int len = Math.min(str.length(), param2.getAsLongInt());
+ String str = param1.getAsString(ctx);
+ int len = Math.min(str.length(), param2.getAsLongInt(ctx));
return ValueSupport.toValue(str.substring(0, len));
}
});
if(param1.isNull()) {
return param1;
}
- String str = param1.getAsString();
+ String str = param1.getAsString(ctx);
int strLen = str.length();
- int len = Math.min(strLen, param2.getAsLongInt());
+ int len = Math.min(strLen, param2.getAsLongInt(ctx));
return ValueSupport.toValue(str.substring(strLen - len, strLen));
}
});
if(param1.isNull()) {
return param1;
}
- String str = param1.getAsString();
+ String str = param1.getAsString(ctx);
int strLen = str.length();
// 1 based offsets
- int start = Math.min(strLen, params[1].getAsLongInt() - 1);
+ int start = Math.min(strLen, params[1].getAsLongInt(ctx) - 1);
int len = Math.min(
- ((params.length > 2) ? params[2].getAsLongInt() : strLen),
+ ((params.length > 2) ? params[2].getAsLongInt(ctx) : strLen),
(strLen - start));
return ValueSupport.toValue(str.substring(start, start + len));
}
public static final Function LEN = registerFunc(new Func1NullIsNull("Len") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- String str = param1.getAsString();
+ String str = param1.getAsString(ctx);
return ValueSupport.toValue(str.length());
}
});
public static final Function LTRIM = registerStringFunc(new Func1NullIsNull("LTrim") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- String str = param1.getAsString();
+ String str = param1.getAsString(ctx);
return ValueSupport.toValue(trim(str, true, false));
}
});
public static final Function RTRIM = registerStringFunc(new Func1NullIsNull("RTrim") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- String str = param1.getAsString();
+ String str = param1.getAsString(ctx);
return ValueSupport.toValue(trim(str, false, true));
}
});
public static final Function TRIM = registerStringFunc(new Func1NullIsNull("Trim") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- String str = param1.getAsString();
+ String str = param1.getAsString(ctx);
return ValueSupport.toValue(trim(str, true, true));
}
});
public static final Function SPACE = registerStringFunc(new Func1("Space") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- int lv = param1.getAsLongInt();
+ int lv = param1.getAsLongInt(ctx);
return ValueSupport.toValue(nchars(lv, ' '));
}
});
if(param1.isNull() || param2.isNull()) {
return ValueSupport.NULL_VAL;
}
- String s1 = param1.getAsString();
- String s2 = param2.getAsString();
+ String s1 = param1.getAsString(ctx);
+ String s2 = param2.getAsString(ctx);
boolean ignoreCase = true;
if(params.length > 2) {
- ignoreCase = doIgnoreCase(params[2]);
+ ignoreCase = doIgnoreCase(ctx, params[2]);
}
int cmp = (ignoreCase ?
s1.compareToIgnoreCase(s2) : s1.compareTo(s2));
if(param1.isNull() || param2.isNull()) {
return ValueSupport.NULL_VAL;
}
- int lv = param1.getAsLongInt();
- char c = (char)(param2.getAsString().charAt(0) % 256);
+ int lv = param1.getAsLongInt(ctx);
+ char c = (char)(param2.getAsString(ctx).charAt(0) % 256);
return ValueSupport.toValue(nchars(lv, c));
}
});
public static final Function STRREVERSE = registerFunc(new Func1("StrReverse") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
- String str = param1.getAsString();
+ String str = param1.getAsString(ctx);
return ValueSupport.toValue(
new StringBuilder(str).reverse().toString());
}
return str.substring(start, end);
}
- private static boolean doIgnoreCase(Value paramCmp) {
- int cmpType = paramCmp.getAsLongInt();
+ private static boolean doIgnoreCase(LocaleContext ctx, Value paramCmp) {
+ int cmpType = paramCmp.getAsLongInt(ctx);
switch(cmpType) {
case -1:
// vbUseCompareOption -> default is binary
import java.math.BigDecimal;
+import com.healthmarketscience.jackcess.expr.LocaleContext;
import com.healthmarketscience.jackcess.impl.NumberFormatter;
/**
}
@Override
- public boolean getAsBoolean() {
+ public boolean getAsBoolean(LocaleContext ctx) {
return (_val.doubleValue() != 0.0d);
}
@Override
- public Double getAsDouble() {
+ public Double getAsDouble(LocaleContext ctx) {
return _val;
}
@Override
- public BigDecimal getAsBigDecimal() {
+ public BigDecimal getAsBigDecimal(LocaleContext ctx) {
return BigDecimal.valueOf(_val);
}
@Override
- public String getAsString() {
+ public String getAsString(LocaleContext ctx) {
return NumberFormatter.format(_val);
}
}
private static final String AM_SUFFIX = " am";
private static final String PM_SUFFIX = " pm";
// access times are based on this date (not the UTC base)
- private static final String BASE_DATE = "12/30/1899 ";
+ private static final String BASE_DATE = "12/30/1899";
private static final String BASE_DATE_FMT = "M/d/yyyy";
private static final byte IS_OP_FLAG = 0x01;
// note that although we may parse in the time "24" format, we will
// display as the default time format
- DateFormat parseDf = buf.getDateTimeFormat(type);
- DateFormat df = buf.getDateTimeFormat(type.getDefaultType());
+ DateFormat parseDf = buf.getParseDateTimeFormat(type);
try {
return new Token(TokenType.LITERAL, parseComplete(parseDf, dateStr),
- dateStr, type.getValueType(), df);
+ dateStr, type.getValueType());
} catch(java.text.ParseException pe) {
throw new ParseException(
"Invalid date/time literal " + dateStr + " " + buf, pe);
return null;
}
- static DateFormat createParseDateFormat(TemporalConfig.Type type,
- LocaleContext ctx)
+ static DateFormat createParseDateTimeFormat(TemporalConfig.Type type,
+ LocaleContext ctx)
{
- TemporalConfig cfg = ctx.getTemporalConfig();
- DateFormat df = ctx.createDateFormat(cfg.getDateTimeFormat(type));
-
- TemporalConfig.Type parseType = null;
switch(type) {
case TIME:
- parseType = TemporalConfig.Type.DATE_TIME;
- break;
+ return createParseTimeFormat(TemporalConfig.Type.DATE_TIME, ctx);
case TIME_12:
- parseType = TemporalConfig.Type.DATE_TIME_12;
- break;
+ return createParseTimeFormat(TemporalConfig.Type.DATE_TIME_12, ctx);
case TIME_24:
- parseType = TemporalConfig.Type.DATE_TIME_24;
- break;
+ return createParseTimeFormat(TemporalConfig.Type.DATE_TIME_24, ctx);
default:
+ // use normal formatter
}
- if(parseType != null) {
- // we need to use a special DateFormat impl which handles parsing
- // separately from formatting
- String baseDate = getBaseDatePrefix(ctx);
- DateFormat parseDf = ctx.createDateFormat(
- cfg.getDateTimeFormat(parseType));
- df = new TimeFormat(parseDf, df, baseDate);
- }
+ TemporalConfig cfg = ctx.getTemporalConfig();
+ return ctx.createDateFormat(cfg.getDateTimeFormat(type));
+ }
- return df;
+ private static DateFormat createParseTimeFormat(TemporalConfig.Type parseType,
+ LocaleContext ctx)
+ {
+ TemporalConfig cfg = ctx.getTemporalConfig();
+ // we need to use a special DateFormat impl which manipulates the parsed
+ // time-only value so it becomes the right Date value
+ String baseDate = getBaseDatePrefix(ctx);
+ DateFormat parseDf = ctx.createDateFormat(
+ cfg.getDateTimeFormat(parseType));
+ return new ParseTimeFormat(parseDf, baseDate);
}
private static String getBaseDatePrefix(LocaleContext ctx) {
return _ctx;
}
- public DateFormat getDateTimeFormat(TemporalConfig.Type type) {
+ public DateFormat getParseDateTimeFormat(TemporalConfig.Type type) {
DateFormat df = _dateTimeFmts.get(type);
if(df == null) {
- df = createParseDateFormat(type, _ctx);
+ df = createParseDateTimeFormat(type, _ctx);
_dateTimeFmts.put(type, df);
}
return df;
private final Object _val;
private final String _valStr;
private final Value.Type _valType;
- private final DateFormat _sdf;
private Token(TokenType type, String val) {
this(type, val, val);
}
private Token(TokenType type, Object val, String valStr) {
- this(type, val, valStr, null, null);
+ this(type, val, valStr, null);
}
private Token(TokenType type, Object val, String valStr, Value.Type valType) {
- this(type, val, valStr, valType, null);
- }
-
- private Token(TokenType type, Object val, String valStr, Value.Type valType,
- DateFormat sdf) {
_type = type;
_val = ((val != null) ? val : valStr);
_valStr = valStr;
_valType = valType;
- _sdf = sdf;
}
public TokenType getType() {
return _valType;
}
- public DateFormat getDateFormat() {
- return _sdf;
- }
-
@Override
public String toString() {
if(_type == TokenType.SPACE) {
* Special date/time format which will parse time-only strings "correctly"
* according to how access handles time-only values.
*/
- private static final class TimeFormat extends DateFormat
+ private static final class ParseTimeFormat extends DateFormat
{
private static final long serialVersionUID = 0L;
private final DateFormat _parseDelegate;
- private final DateFormat _fmtDelegate;
private final String _baseDate;
- private TimeFormat(DateFormat parseDelegate, DateFormat fmtDelegate,
- String baseDate)
+ private ParseTimeFormat(DateFormat parseDelegate, String baseDate)
{
_parseDelegate = parseDelegate;
- _fmtDelegate = fmtDelegate;
_baseDate = baseDate;
}
@Override
public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) {
- return _fmtDelegate.format(date, toAppendTo, fieldPosition);
+ throw new UnsupportedOperationException();
}
@Override
@Override
public Calendar getCalendar() {
- return _fmtDelegate.getCalendar();
+ return _parseDelegate.getCalendar();
}
@Override
public TimeZone getTimeZone() {
- return _fmtDelegate.getTimeZone();
+ return _parseDelegate.getTimeZone();
}
}
import com.healthmarketscience.jackcess.expr.Value;
import com.healthmarketscience.jackcess.impl.expr.ExpressionTokenizer.Token;
import com.healthmarketscience.jackcess.impl.expr.ExpressionTokenizer.TokenType;
+import org.apache.commons.lang.StringUtils;
/**
},
NOT("Not", true) {
@Override public Value eval(EvalContext ctx, Value param1) {
- return BuiltinOperators.not(param1);
+ return BuiltinOperators.not(ctx, param1);
}
},
// when a '-' immediately precedes a number, it needs "highest" precedence
},
MULT("*") {
@Override public Value eval(EvalContext ctx, Value param1, Value param2) {
- return BuiltinOperators.multiply(param1, param2);
+ return BuiltinOperators.multiply(ctx, param1, param2);
}
},
DIV("/") {
@Override public Value eval(EvalContext ctx, Value param1, Value param2) {
- return BuiltinOperators.divide(param1, param2);
+ return BuiltinOperators.divide(ctx, param1, param2);
}
},
INT_DIV("\\") {
@Override public Value eval(EvalContext ctx, Value param1, Value param2) {
- return BuiltinOperators.intDivide(param1, param2);
+ return BuiltinOperators.intDivide(ctx, param1, param2);
}
},
EXP("^") {
@Override public Value eval(EvalContext ctx, Value param1, Value param2) {
- return BuiltinOperators.exp(param1, param2);
+ return BuiltinOperators.exp(ctx, param1, param2);
}
},
CONCAT("&") {
@Override public Value eval(EvalContext ctx, Value param1, Value param2) {
- return BuiltinOperators.concat(param1, param2);
+ return BuiltinOperators.concat(ctx, param1, param2);
}
},
MOD("Mod") {
@Override public Value eval(EvalContext ctx, Value param1, Value param2) {
- return BuiltinOperators.mod(param1, param2);
+ return BuiltinOperators.mod(ctx, param1, param2);
}
};
private enum CompOp implements OpType {
LT("<") {
- @Override public Value eval(Value param1, Value param2) {
- return BuiltinOperators.lessThan(param1, param2);
+ @Override public Value eval(EvalContext ctx, Value param1, Value param2) {
+ return BuiltinOperators.lessThan(ctx, param1, param2);
}
},
LTE("<=") {
- @Override public Value eval(Value param1, Value param2) {
- return BuiltinOperators.lessThanEq(param1, param2);
+ @Override public Value eval(EvalContext ctx, Value param1, Value param2) {
+ return BuiltinOperators.lessThanEq(ctx, param1, param2);
}
},
GT(">") {
- @Override public Value eval(Value param1, Value param2) {
- return BuiltinOperators.greaterThan(param1, param2);
+ @Override public Value eval(EvalContext ctx, Value param1, Value param2) {
+ return BuiltinOperators.greaterThan(ctx, param1, param2);
}
},
GTE(">=") {
- @Override public Value eval(Value param1, Value param2) {
- return BuiltinOperators.greaterThanEq(param1, param2);
+ @Override public Value eval(EvalContext ctx, Value param1, Value param2) {
+ return BuiltinOperators.greaterThanEq(ctx, param1, param2);
}
},
EQ("=") {
- @Override public Value eval(Value param1, Value param2) {
- return BuiltinOperators.equals(param1, param2);
+ @Override public Value eval(EvalContext ctx, Value param1, Value param2) {
+ return BuiltinOperators.equals(ctx, param1, param2);
}
},
NE("<>") {
- @Override public Value eval(Value param1, Value param2) {
- return BuiltinOperators.notEquals(param1, param2);
+ @Override public Value eval(EvalContext ctx, Value param1, Value param2) {
+ return BuiltinOperators.notEquals(ctx, param1, param2);
}
};
return _str;
}
- public abstract Value eval(Value param1, Value param2);
+ public abstract Value eval(EvalContext ctx, Value param1, Value param2);
}
private enum LogOp implements OpType {
AND("And") {
- @Override public Value eval(Value param1, Value param2) {
- return BuiltinOperators.and(param1, param2);
+ @Override public Value eval(EvalContext ctx, Value param1, Value param2) {
+ return BuiltinOperators.and(ctx, param1, param2);
}
},
OR("Or") {
- @Override public Value eval(Value param1, Value param2) {
- return BuiltinOperators.or(param1, param2);
+ @Override public Value eval(EvalContext ctx, Value param1, Value param2) {
+ return BuiltinOperators.or(ctx, param1, param2);
}
},
EQV("Eqv") {
- @Override public Value eval(Value param1, Value param2) {
- return BuiltinOperators.eqv(param1, param2);
+ @Override public Value eval(EvalContext ctx, Value param1, Value param2) {
+ return BuiltinOperators.eqv(ctx, param1, param2);
}
},
XOR("Xor") {
- @Override public Value eval(Value param1, Value param2) {
- return BuiltinOperators.xor(param1, param2);
+ @Override public Value eval(EvalContext ctx, Value param1, Value param2) {
+ return BuiltinOperators.xor(ctx, param1, param2);
}
},
IMP("Imp") {
- @Override public Value eval(Value param1, Value param2) {
- return BuiltinOperators.imp(param1, param2);
+ @Override public Value eval(EvalContext ctx, Value param1, Value param2) {
+ return BuiltinOperators.imp(ctx, param1, param2);
}
};
return _str;
}
- public abstract Value eval(Value param1, Value param2);
+ public abstract Value eval(EvalContext ctx, Value param1, Value param2);
}
private enum SpecOp implements OpType {
// note, "NOT" is not actually used as a special operation, always
// replaced with UnaryOp.NOT
NOT("Not") {
- @Override public Value eval(Value param1, Object param2, Object param3) {
+ @Override public Value eval(EvalContext ctx, Value param1, Object param2, Object param3) {
throw new UnsupportedOperationException();
}
},
IS_NULL("Is Null") {
- @Override public Value eval(Value param1, Object param2, Object param3) {
+ @Override public Value eval(EvalContext ctx, Value param1, Object param2, Object param3) {
return BuiltinOperators.isNull(param1);
}
},
IS_NOT_NULL("Is Not Null") {
- @Override public Value eval(Value param1, Object param2, Object param3) {
+ @Override public Value eval(EvalContext ctx, Value param1, Object param2, Object param3) {
return BuiltinOperators.isNotNull(param1);
}
},
LIKE("Like") {
- @Override public Value eval(Value param1, Object param2, Object param3) {
- return BuiltinOperators.like(param1, (Pattern)param2);
+ @Override public Value eval(EvalContext ctx, Value param1, Object param2, Object param3) {
+ return BuiltinOperators.like(ctx, param1, (Pattern)param2);
}
},
NOT_LIKE("Not Like") {
- @Override public Value eval(Value param1, Object param2, Object param3) {
- return BuiltinOperators.notLike(param1, (Pattern)param2);
+ @Override public Value eval(EvalContext ctx, Value param1, Object param2, Object param3) {
+ return BuiltinOperators.notLike(ctx, param1, (Pattern)param2);
}
},
BETWEEN("Between") {
- @Override public Value eval(Value param1, Object param2, Object param3) {
- return BuiltinOperators.between(param1, (Value)param2, (Value)param3);
+ @Override public Value eval(EvalContext ctx, Value param1, Object param2, Object param3) {
+ return BuiltinOperators.between(ctx, param1, (Value)param2, (Value)param3);
}
},
NOT_BETWEEN("Not Between") {
- @Override public Value eval(Value param1, Object param2, Object param3) {
- return BuiltinOperators.notBetween(param1, (Value)param2, (Value)param3);
+ @Override public Value eval(EvalContext ctx, Value param1, Object param2, Object param3) {
+ return BuiltinOperators.notBetween(ctx, param1, (Value)param2, (Value)param3);
}
},
IN("In") {
- @Override public Value eval(Value param1, Object param2, Object param3) {
- return BuiltinOperators.in(param1, (Value[])param2);
+ @Override public Value eval(EvalContext ctx, Value param1, Object param2, Object param3) {
+ return BuiltinOperators.in(ctx, param1, (Value[])param2);
}
},
NOT_IN("Not In") {
- @Override public Value eval(Value param1, Object param2, Object param3) {
- return BuiltinOperators.notIn(param1, (Value[])param2);
+ @Override public Value eval(EvalContext ctx, Value param1, Object param2, Object param3) {
+ return BuiltinOperators.notIn(ctx, param1, (Value[])param2);
}
};
return _str;
}
- public abstract Value eval(Value param1, Object param2, Object param3);
+ public abstract Value eval(EvalContext ctx, Value param1, Object param2, Object param3);
}
private static final Map<OpType, Integer> PRECENDENCE =
// this is handled as a literal string value, not an expression. no
// need to memo-ize cause it's a simple literal value
return new ExprWrapper(exprStr,
- new ELiteralValue(Value.Type.STRING, exprStr, null), resultType);
+ new ELiteralValue(Value.Type.STRING, exprStr), resultType);
}
// normal expression handling
case LITERAL:
- buf.setPendingExpr(new ELiteralValue(t.getValueType(), t.getValue(),
- t.getDateFormat()));
+ buf.setPendingExpr(new ELiteralValue(t.getValueType(), t.getValue()));
break;
case OP:
throw new ParseException("Unexpected op string " + t.getValueStr());
}
+ private static StringBuilder appendLeadingExpr(
+ Expr expr, LocaleContext ctx, StringBuilder sb, boolean isDebug)
+ {
+ int len = sb.length();
+ expr.toString(ctx, sb, isDebug);
+ if(sb.length() > len) {
+ // only add space if the leading expr added some text
+ sb.append(" ");
+ }
+ return sb;
+ }
+
private static final class TokBuf
{
private final Type _exprType;
private final List<Token> _tokens;
private final TokBuf _parent;
private final int _parentOff;
- private final ParseContext _context;
+ private final ParseContext _ctx;
private int _pos;
private Expr _pendingExpr;
}
private TokBuf(List<Token> tokens, TokBuf parent, int parentOff) {
- this(parent._exprType, tokens, parent, parentOff, parent._context);
+ this(parent._exprType, tokens, parent, parentOff, parent._ctx);
}
private TokBuf(Type exprType, List<Token> tokens, TokBuf parent,
_tokens = tokens;
_parent = parent;
_parentOff = parentOff;
- _context = context;
+ _ctx = context;
}
public Type getExprType() {
}
public Function getFunction(String funcName) {
- return _context.getFunctionLookup().getFunction(funcName);
+ return _ctx.getFunctionLookup().getFunction(funcName);
}
@Override
sb.append(")");
if(_pendingExpr != null) {
- sb.append(" [pending '").append(_pendingExpr.toDebugString())
+ sb.append(" [pending '").append(_pendingExpr.toDebugString(_ctx))
.append("']");
}
}
private static void exprListToString(
- List<Expr> exprs, String sep, StringBuilder sb, boolean isDebug) {
+ List<Expr> exprs, String sep, LocaleContext ctx, StringBuilder sb,
+ boolean isDebug) {
Iterator<Expr> iter = exprs.iterator();
- iter.next().toString(sb, isDebug);
+ iter.next().toString(ctx, sb, isDebug);
while(iter.hasNext()) {
sb.append(sep);
- iter.next().toString(sb, isDebug);
+ iter.next().toString(ctx, sb, isDebug);
}
}
private static void literalStrToString(String str, StringBuilder sb) {
sb.append("\"")
- .append(str.replace("\"", "\"\""))
+ .append(StringUtils.replace(str, "\"", "\"\""))
.append("\"");
}
}
}
- private static Value toLiteralValue(Value.Type valType, Object value,
- DateFormat sdf)
- {
+ private static Value toLiteralValue(Value.Type valType, Object value) {
switch(valType) {
case STRING:
return ValueSupport.toValue((String)value);
case DATE:
- return new DateValue((Date)value, sdf);
case TIME:
- return new TimeValue((Date)value, sdf);
case DATE_TIME:
- return new DateTimeValue((Date)value, sdf);
+ return ValueSupport.toValue(valType, (Date)value);
case LONG:
return ValueSupport.toValue((Integer)value);
case DOUBLE:
private static abstract class Expr
{
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- toString(sb, false);
- return sb.toString();
+ public String toCleanString(LocaleContext ctx) {
+ return toString(ctx, new StringBuilder(), false).toString();
}
- public String toDebugString() {
- StringBuilder sb = new StringBuilder();
- toString(sb, true);
- return sb.toString();
+ public String toDebugString(LocaleContext ctx) {
+ return toString(ctx, new StringBuilder(), true).toString();
}
protected boolean isValidationExpr() {
return false;
}
- protected void toString(StringBuilder sb, boolean isDebug) {
+ protected StringBuilder toString(
+ LocaleContext ctx, StringBuilder sb, boolean isDebug) {
if(isDebug) {
sb.append("<").append(getClass().getSimpleName()).append(">{");
}
- toExprString(sb, isDebug);
+ toExprString(ctx, sb, isDebug);
if(isDebug) {
sb.append("}");
}
+ return sb;
}
protected Expr resolveOrderOfOperations() {
public abstract void collectIdentifiers(Collection<Identifier> identifiers);
- protected abstract void toExprString(StringBuilder sb, boolean isDebug);
+ protected abstract void toExprString(
+ LocaleContext ctx, StringBuilder sb, boolean isDebug);
}
private static final class EConstValue extends Expr
}
@Override
- protected void toExprString(StringBuilder sb, boolean isDebug) {
+ protected void toExprString(
+ LocaleContext ctx, StringBuilder sb, boolean isDebug) {
sb.append(_str);
}
}
// none
}
@Override
- protected void toExprString(StringBuilder sb, boolean isDebug) {
- sb.append("<THIS_COL>");
+ protected void toExprString(
+ LocaleContext ctx, StringBuilder sb, boolean isDebug) {
+ if(isDebug) {
+ sb.append("<THIS_COL>");
+ }
}
}
{
private final Value _val;
- private ELiteralValue(Value.Type valType, Object value,
- DateFormat sdf) {
- _val = toLiteralValue(valType, value, sdf);
+ private ELiteralValue(Value.Type valType, Object value) {
+ _val = toLiteralValue(valType, value);
}
@Override
}
@Override
- protected void toExprString(StringBuilder sb, boolean isDebug) {
+ protected void toExprString(
+ LocaleContext ctx, StringBuilder sb, boolean isDebug) {
if(_val.getType() == Value.Type.STRING) {
literalStrToString((String)_val.get(), sb);
} else if(_val.getType().isTemporal()) {
- sb.append("#").append(_val.getAsString()).append("#");
+ sb.append("#").append(_val.getAsString(ctx)).append("#");
} else {
sb.append(_val.get());
}
}
@Override
- protected void toExprString(StringBuilder sb, boolean isDebug) {
+ protected void toExprString(
+ LocaleContext ctx, StringBuilder sb, boolean isDebug) {
sb.append(_identifier);
}
}
}
@Override
- protected void toExprString(StringBuilder sb, boolean isDebug) {
+ protected void toExprString(
+ LocaleContext ctx, StringBuilder sb, boolean isDebug) {
sb.append("(");
- _expr.toString(sb, isDebug);
+ _expr.toString(ctx, sb, isDebug);
sb.append(")");
}
}
}
@Override
- protected void toExprString(StringBuilder sb, boolean isDebug) {
+ protected void toExprString(
+ LocaleContext ctx, StringBuilder sb, boolean isDebug) {
sb.append(_func.getName()).append("(");
if(!_params.isEmpty()) {
- exprListToString(_params, ",", sb, isDebug);
+ exprListToString(_params, ",", ctx, sb, isDebug);
}
sb.append(")");
}
@Override
- protected void toExprString(StringBuilder sb, boolean isDebug) {
- _left.toString(sb, isDebug);
- sb.append(" ").append(_op).append(" ");
- _right.toString(sb, isDebug);
+ protected void toExprString(
+ LocaleContext ctx, StringBuilder sb, boolean isDebug) {
+ appendLeadingExpr(_left, ctx, sb, isDebug)
+ .append(_op).append(" ");
+ _right.toString(ctx, sb, isDebug);
}
}
}
@Override
- protected void toExprString(StringBuilder sb, boolean isDebug) {
+ protected void toExprString(
+ LocaleContext ctx, StringBuilder sb, boolean isDebug) {
sb.append(_op);
if(isDebug || ((UnaryOp)_op).needsSpace()) {
sb.append(" ");
}
- _expr.toString(sb, isDebug);
+ _expr.toString(ctx, sb, isDebug);
}
}
@Override
public Value eval(EvalContext ctx) {
- return ((CompOp)_op).eval(_left.eval(ctx), _right.eval(ctx));
+ return ((CompOp)_op).eval(ctx, _left.eval(ctx), _right.eval(ctx));
}
}
}
@Override
- protected void toExprString(StringBuilder sb, boolean isDebug) {
+ protected void toExprString(
+ LocaleContext ctx, StringBuilder sb, boolean isDebug) {
// only output the full "implicit" comparison in debug mode
if(isDebug) {
- super.toExprString(sb, isDebug);
+ super.toExprString(ctx, sb, isDebug);
} else {
// just output the explicit part of the expression
- _right.toString(sb, isDebug);
+ _right.toString(ctx, sb, isDebug);
}
}
}
// logical operations do short circuit evaluation, so we need to delay
// computing results until necessary
- return ((LogOp)_op).eval(new DelayedValue(_left, ctx),
+ return ((LogOp)_op).eval(ctx, new DelayedValue(_left, ctx),
new DelayedValue(_right, ctx));
}
}
@Override
public Value eval(EvalContext ctx) {
- return _op.eval(_expr.eval(ctx), null, null);
+ return _op.eval(ctx, _expr.eval(ctx), null, null);
}
@Override
- protected void toExprString(StringBuilder sb, boolean isDebug) {
- _expr.toString(sb, isDebug);
- sb.append(" ").append(_op);
+ protected void toExprString(
+ LocaleContext ctx, StringBuilder sb, boolean isDebug) {
+ appendLeadingExpr(_expr, ctx, sb, isDebug)
+ .append(_op);
}
}
@Override
public Value eval(EvalContext ctx) {
- return _op.eval(_expr.eval(ctx), getPattern(), null);
+ return _op.eval(ctx, _expr.eval(ctx), getPattern(), null);
}
@Override
- protected void toExprString(StringBuilder sb, boolean isDebug) {
- _expr.toString(sb, isDebug);
- sb.append(" ").append(_op).append(" ");
+ protected void toExprString(
+ LocaleContext ctx, StringBuilder sb, boolean isDebug) {
+ appendLeadingExpr(_expr, ctx, sb, isDebug)
+ .append(_op).append(" ");
literalStrToString(_patternStr, sb);
if(isDebug) {
sb.append("(").append(getPattern()).append(")");
@Override
public Value eval(EvalContext ctx) {
- return _op.eval(_expr.eval(ctx),
+ return _op.eval(ctx, _expr.eval(ctx),
exprListToDelayedValues(_exprs, ctx), null);
}
}
@Override
- protected void toExprString(StringBuilder sb, boolean isDebug) {
- _expr.toString(sb, isDebug);
- sb.append(" ").append(_op).append(" (");
- exprListToString(_exprs, ",", sb, isDebug);
+ protected void toExprString(
+ LocaleContext ctx, StringBuilder sb, boolean isDebug) {
+ appendLeadingExpr(_expr, ctx, sb, isDebug)
+ .append(_op).append(" (");
+ exprListToString(_exprs, ",", ctx, sb, isDebug);
sb.append(")");
}
}
@Override
public Value eval(EvalContext ctx) {
- return _op.eval(_expr.eval(ctx),
+ return _op.eval(ctx, _expr.eval(ctx),
new DelayedValue(_startRangeExpr, ctx),
new DelayedValue(_endRangeExpr, ctx));
}
}
@Override
- protected void toExprString(StringBuilder sb, boolean isDebug) {
- _expr.toString(sb, isDebug);
- sb.append(" ").append(_op).append(" ");
- _startRangeExpr.toString(sb, isDebug);
+ protected void toExprString(
+ LocaleContext ctx, StringBuilder sb, boolean isDebug) {
+ appendLeadingExpr(_expr, ctx, sb, isDebug)
+ .append(_op).append(" ");
+ _startRangeExpr.toString(ctx, sb, isDebug);
sb.append(" And ");
- _endRangeExpr.toString(sb, isDebug);
+ _endRangeExpr.toString(ctx, sb, isDebug);
}
}
_expr = expr;
}
- public String toDebugString() {
- return _expr.toDebugString();
+ public String toDebugString(LocaleContext ctx) {
+ return _expr.toDebugString(ctx);
}
public String toRawString() {
return _rawExprStr;
}
+ public String toCleanString(LocaleContext ctx) {
+ return _expr.toCleanString(ctx);
+ }
+
public boolean isConstant() {
return _expr.isConstant();
}
@Override
public String toString() {
- return _expr.toString();
+ return toRawString();
}
protected Object evalValue(Value.Type resultType, EvalContext ctx) {
// FIXME possibly do some type coercion. are there conversions here which don't work elsewhere? (string -> date, string -> number)?
switch(resultType) {
case STRING:
- return val.getAsString();
+ return val.getAsString(ctx);
case DATE:
case TIME:
case DATE_TIME:
return val.getAsDateTime(ctx);
case LONG:
- return val.getAsLongInt();
+ return val.getAsLongInt(ctx);
case DOUBLE:
- return val.getAsDouble();
+ return val.getAsDouble(ctx);
case BIG_DEC:
- return val.getAsBigDecimal();
+ return val.getAsBigDecimal(ctx);
default:
throw new IllegalStateException("unexpected result type " + resultType);
}
throw new EvalException("Condition evaluated to Null");
}
- return val.getAsBoolean();
+ return val.getAsBoolean(ctx);
}
}
if(result.isNull()) {
// non-variant version does not do null-propagation, so force
// exception to be thrown here
- result.getAsString();
+ result.getAsString(ctx);
}
return result;
}
import java.math.BigDecimal;
+import com.healthmarketscience.jackcess.expr.LocaleContext;
+
/**
*
* @author James Ahlborn
}
@Override
- public boolean getAsBoolean() {
+ public boolean getAsBoolean(LocaleContext ctx) {
return (_val.longValue() != 0L);
}
@Override
- public Integer getAsLongInt() {
+ public Integer getAsLongInt(LocaleContext ctx) {
return _val;
}
@Override
- public BigDecimal getAsBigDecimal() {
+ public BigDecimal getAsBigDecimal(LocaleContext ctx) {
return BigDecimal.valueOf(_val);
}
@Override
- public String getAsString() {
+ public String getAsString(LocaleContext ctx) {
return _val.toString();
}
}
import java.math.BigInteger;
import java.util.regex.Pattern;
+import com.healthmarketscience.jackcess.expr.LocaleContext;
+import org.apache.commons.lang.CharUtils;
+import org.apache.commons.lang.StringUtils;
+
/**
*
* @author James Ahlborn
}
@Override
- public boolean getAsBoolean() {
+ public boolean getAsBoolean(LocaleContext ctx) {
// ms access seems to treat strings as "true"
return true;
}
@Override
- public String getAsString() {
+ public String getAsString(LocaleContext ctx) {
return _val;
}
@Override
- public Integer getAsLongInt() {
- return roundToLongInt();
+ public Integer getAsLongInt(LocaleContext ctx) {
+ return roundToLongInt(ctx);
}
@Override
- public Double getAsDouble() {
- return getNumber().doubleValue();
+ public Double getAsDouble(LocaleContext ctx) {
+ return getNumber(ctx).doubleValue();
}
@Override
- public BigDecimal getAsBigDecimal() {
- return getNumber();
+ public BigDecimal getAsBigDecimal(LocaleContext ctx) {
+ return getNumber(ctx);
}
- protected BigDecimal getNumber() {
+ protected BigDecimal getNumber(LocaleContext ctx) {
if(_num instanceof BigDecimal) {
return (BigDecimal)_num;
}
if(tmpVal.length() > 0) {
if(tmpVal.charAt(0) != NUMBER_BASE_PREFIX) {
- // parse using standard numeric support
- // FIXME, this should handle grouping separator, but needs ctx
+ // parse using standard numeric support, after discarding any
+ // grouping separators
+ char groupSepChar = ctx.getNumericConfig().getDecimalFormatSymbols()
+ .getGroupingSeparator();
+ tmpVal = StringUtils.remove(tmpVal, groupSepChar);
_num = ValueSupport.normalize(new BigDecimal(tmpVal));
return (BigDecimal)_num;
}
+++ /dev/null
-/*
-Copyright (c) 2016 James Ahlborn
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package com.healthmarketscience.jackcess.impl.expr;
-
-import java.text.DateFormat;
-import java.util.Date;
-
-/**
- *
- * @author James Ahlborn
- */
-public class TimeValue extends BaseDateValue
-{
-
- public TimeValue(Date val, DateFormat fmt)
- {
- super(val, fmt);
- }
-
- public Type getType() {
- return Type.TIME;
- }
-}
return new BigDecimalValue(normalize(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(LocaleContext ctx, Value.Type type, Date d) {
- return toValue(type, d, getDateFormatForType(ctx, type));
- }
-
- public static Value toValue(Value.Type type, Date d, DateFormat fmt) {
- switch(type) {
- case DATE:
- return new DateValue(d, fmt);
- case TIME:
- return new TimeValue(d, fmt);
- case DATE_TIME:
- return new DateTimeValue(d, fmt);
- default:
- throw new EvalException("Unexpected date/time type " + type);
- }
- }
-
- static Value toDateValue(LocaleContext ctx, Value.Type type, double v,
- Value param1, Value param2)
+ public static Value toDateValue(LocaleContext ctx, Value.Type type, double dd)
{
- DateFormat fmt = null;
- if((param1 instanceof BaseDateValue) && (param1.getType() == type)) {
- fmt = ((BaseDateValue)param1).getFormat();
- } else if((param2 instanceof BaseDateValue) && (param2.getType() == type)) {
- fmt = ((BaseDateValue)param2).getFormat();
- } else {
- fmt = getDateFormatForType(ctx, type);
- }
-
- Date d = new Date(ColumnImpl.fromDateDouble(v, fmt.getCalendar()));
+ return toValue(type, new Date(
+ ColumnImpl.fromDateDouble(dd, ctx.getCalendar())));
+ }
- return toValue(type, d, fmt);
+ public static Value toValue(Value.Type type, Date d) {
+ return new DateTimeValue(type, d);
}
- static DateFormat getDateFormatForType(LocaleContext ctx, Value.Type type) {
+ public static DateFormat getDateFormatForType(LocaleContext ctx, Value.Type type) {
String fmtStr = null;
switch(type) {
case DATE:
import java.io.FileReader;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
+import java.util.Calendar;
import java.util.Date;
import javax.script.Bindings;
import javax.script.SimpleBindings;
import com.healthmarketscience.jackcess.expr.Expression;
import com.healthmarketscience.jackcess.expr.FunctionLookup;
import com.healthmarketscience.jackcess.expr.Identifier;
+import com.healthmarketscience.jackcess.expr.NumericConfig;
import com.healthmarketscience.jackcess.expr.ParseException;
import com.healthmarketscience.jackcess.expr.TemporalConfig;
import com.healthmarketscience.jackcess.expr.Value;
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");
+ validateExpr("<=1 And >=0", "<ELogicalOp>{<ECompOp>{<EThisValue>{<THIS_COL>} <= <ELiteralValue>{1}} And <ECompOp>{<EThisValue>{<THIS_COL>} >= <ELiteralValue>{0}}}", "<= 1 And >= 0");
}
private static void doTestSimpleBinOp(String opName, String... ops) throws Exception
assertEquals(37d, eval("=\" &h1A \" + 11"));
assertEquals(37d, eval("=\" &h1a \" + 11"));
assertEquals(37d, eval("=\" &O32 \" + 11"));
+ assertEquals(1037d, eval("=\"1,025\" + 12"));
evalFail(("=12 - \"foo\""), RuntimeException.class);
evalFail(("=\"foo\" - 12"), RuntimeException.class);
public void testLikeExpression() throws Exception
{
validateExpr("Like \"[abc]*\"", "<ELikeOp>{<EThisValue>{<THIS_COL>} Like \"[abc]*\"([abc].*)}",
- "<THIS_COL> Like \"[abc]*\"");
+ "Like \"[abc]*\"");
assertTrue(evalCondition("Like \"[abc]*\"", "afcd"));
assertFalse(evalCondition("Like \"[abc]*\"", "fcd"));
- validateExpr("Like \"[abc*\"", "<ELikeOp>{<EThisValue>{<THIS_COL>} Like \"[abc*\"((?!))}",
- "<THIS_COL> Like \"[abc*\"");
+ validateExpr("Like \"[abc*\"", "<ELikeOp>{<EThisValue>{<THIS_COL>} Like \"[abc*\"((?!))}",
+ "Like \"[abc*\"");
assertFalse(evalCondition("Like \"[abc*\"", "afcd"));
assertFalse(evalCondition("Like \"[abc*\"", "fcd"));
assertTrue(evalCondition("Not Like \"[abc*\"", "fcd"));
private static void validateExpr(String exprStr, String debugStr,
String cleanStr) {
+ TestContext ctx = new TestContext();
Expression expr = Expressionator.parse(
- Expressionator.Type.FIELD_VALIDATOR, exprStr, null,
- new TestContext());
- String foundDebugStr = expr.toDebugString();
+ Expressionator.Type.FIELD_VALIDATOR, exprStr, null, ctx);
+ String foundDebugStr = expr.toDebugString(ctx);
if(foundDebugStr.startsWith("<EImplicitCompOp>")) {
assertEquals("<EImplicitCompOp>{<EThisValue>{<THIS_COL>} = " +
debugStr + "}", foundDebugStr);
} else {
assertEquals(debugStr, foundDebugStr);
}
- assertEquals(cleanStr, expr.toString());
+ assertEquals(cleanStr, expr.toCleanString(ctx));
assertEquals(exprStr, expr.toRawString());
}
return sdf;
}
+ public Calendar getCalendar() {
+ return createDateFormat(getTemporalConfig().getDefaultDateTimeFormat())
+ .getCalendar();
+ }
+
+ public NumericConfig getNumericConfig() {
+ return NumericConfig.US_NUMERIC_CONFIG;
+ }
+
public FunctionLookup getFunctionLookup() {
return DefaultFunctions.LOOKUP;
}