]> source.dussan.org Git - jackcess.git/commitdiff
implement various functions
authorJames Ahlborn <jtahlborn@yahoo.com>
Thu, 17 Aug 2017 02:41:12 +0000 (02:41 +0000)
committerJames Ahlborn <jtahlborn@yahoo.com>
Thu, 17 Aug 2017 02:41:12 +0000 (02:41 +0000)
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/branches/exprs@1112 f203690c-595d-4dc9-a70b-905162fa7fd2

src/main/java/com/healthmarketscience/jackcess/impl/expr/BuiltinOperators.java
src/main/java/com/healthmarketscience/jackcess/impl/expr/DefaultFunctions.java

index 5a3d7b5942d699b28247217fbcd7713af97ebb1c..93b4bf22769ee408c1d095f35ffe001ae8ace483 100644 (file)
@@ -51,6 +51,7 @@ public class BuiltinOperators
   public static final Value TRUE_VAL = new LongValue(-1L);
   public static final Value FALSE_VAL = new LongValue(0L);
   public static final Value EMPTY_STR_VAL = new StringValue("");
+  public static final Value ZERO_VAL = FALSE_VAL;
 
   private enum CoercionType {
     SIMPLE(true, true), GENERAL(false, true), COMPARE(false, false);
index fbcd6833c03a8c550410d8bd0c5caf555739e94d..49fecb7fd2d3141e1c964fbb7b946e1c20a33796 100644 (file)
@@ -16,13 +16,14 @@ limitations under the License.
 
 package com.healthmarketscience.jackcess.impl.expr;
 
+import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.util.HashMap;
 import java.util.Map;
 
-
-import com.healthmarketscience.jackcess.expr.Value;
-import com.healthmarketscience.jackcess.expr.Function;
 import com.healthmarketscience.jackcess.expr.EvalContext;
+import com.healthmarketscience.jackcess.expr.Function;
+import com.healthmarketscience.jackcess.expr.Value;
 
 /**
  *
@@ -33,6 +34,8 @@ public class DefaultFunctions
   private static final Map<String,Function> FUNCS = 
     new HashMap<String,Function>();
 
+  private static final char NON_VAR_SUFFIX = '$';
+
   private DefaultFunctions() {}
 
   public static Function getFunction(String name) {
@@ -78,6 +81,20 @@ public class DefaultFunctions
     }
   }
 
+  public static abstract class Func0 extends BaseFunction
+  {
+    protected Func0(String name) {
+      super(name, 0, 9);
+    }
+
+    public final Value eval(EvalContext ctx, Value... params) {
+      validateNumParams(params);
+      return eval0(ctx);
+    }
+
+    protected abstract Value eval0(EvalContext ctx);
+  }
+
   public static abstract class Func1 extends BaseFunction
   {
     protected Func1(String name) {
@@ -130,15 +147,231 @@ public class DefaultFunctions
     }
   });
 
+  public static final Function ASC = registerFunc(new Func1("Asc") {
+    @Override
+    protected Value eval1(EvalContext ctx, Value param1) {
+      String str = param1.getAsString();
+      int len = str.length();
+      if(len == 0) {
+        throw new IllegalStateException("No characters in string");
+      } 
+      long lv = str.charAt(0);
+      if((lv < 0) || (lv > 255)) {
+        throw new IllegalStateException("Character code '" + lv +
+                                        "' out of range ");
+      }
+      return BuiltinOperators.toValue(lv);
+    }
+  });
+
+  public static final Function ASCW = registerFunc(new Func1("AscW") {
+    @Override
+    protected Value eval1(EvalContext ctx, Value param1) {
+      String str = param1.getAsString();
+      int len = str.length();
+      if(len == 0) {
+        throw new IllegalStateException("No characters in string");
+      } 
+      long lv = str.charAt(0);
+      return BuiltinOperators.toValue(lv);
+    }
+  });
+
+  public static final Function CHR = registerStringFunc(new Func1("Chr") {
+    @Override
+    protected Value eval1(EvalContext ctx, Value param1) {
+      long lv = param1.getAsLong();
+      if((lv < 0) || (lv > 255)) {
+        throw new IllegalStateException("Character code '" + lv +
+                                        "' out of range ");
+      }
+      char[] cs = Character.toChars((int)lv);
+      return BuiltinOperators.toValue(new String(cs));
+    }
+  });
+
+  public static final Function CHRW = registerStringFunc(new Func1("ChrW") {
+    @Override
+    protected Value eval1(EvalContext ctx, Value param1) {
+      long lv = param1.getAsLong();
+      char[] cs = Character.toChars((int)lv);
+      return BuiltinOperators.toValue(new String(cs));
+    }
+  });
+
+  public static final Function HEX = registerStringFunc(new Func1("Hex") {
+    @Override
+    protected Value eval1(EvalContext ctx, Value param1) {
+      if(param1.isNull()) {
+        return param1;
+      }
+      if((param1.getType() == Value.Type.STRING) &&
+         (param1.getAsString().length() == 0)) {
+        return BuiltinOperators.ZERO_VAL;
+      }
+      long lv = param1.getAsLong();
+      return BuiltinOperators.toValue(Long.toHexString(lv));
+    }
+  });
+
+  public static final Function NZ = registerFunc(new BaseFunction("Nz", 1, 2) {
+    public Value eval(EvalContext ctx, Value... params) {
+      validateNumParams(params);
+      Value param1 = params[0];
+      if(!param1.isNull()) {
+        return param1;
+      }
+      if(params.length > 1) {
+        return params[1];
+      }
+      Value.Type resultType = ctx.getResultType();
+      return (((resultType == null) ||
+               (resultType == Value.Type.STRING)) ?
+              BuiltinOperators.EMPTY_STR_VAL : BuiltinOperators.ZERO_VAL);
+    }
+  });
+
+  public static final Function OCT = registerStringFunc(new Func1("Oct") {
+    @Override
+    protected Value eval1(EvalContext ctx, Value param1) {
+      if(param1.isNull()) {
+        return param1;
+      }
+      if((param1.getType() == Value.Type.STRING) &&
+         (param1.getAsString().length() == 0)) {
+        return BuiltinOperators.ZERO_VAL;
+      }
+      long lv = param1.getAsLong();
+      return BuiltinOperators.toValue(Long.toOctalString(lv));
+    }
+  });
+  
+  public static final Function STR = registerStringFunc(new Func1("Str") {
+    @Override
+    protected Value eval1(EvalContext ctx, Value param1) {
+      BigDecimal bd = param1.getAsBigDecimal();
+      String str = bd.toPlainString();
+      if(bd.compareTo(BigDecimal.ZERO) >= 0) {
+        str = " " + str;
+      }
+      return BuiltinOperators.toValue(str);
+    }
+  });
+
+  public static final Function CBOOL = registerFunc(new Func1("CBool") {
+    @Override
+    protected Value eval1(EvalContext ctx, Value param1) {
+      boolean b = param1.getAsBoolean();
+      return BuiltinOperators.toValue(b);
+    }
+  });
+
+  public static final Function CBYTE = registerFunc(new Func1("CByte") {
+    @Override
+    protected Value eval1(EvalContext ctx, Value param1) {
+      Long lv = param1.getAsLong();
+      if((lv < 0) || (lv > 255)) {
+        throw new IllegalStateException("Byte code '" + lv + "' out of range ");
+      }
+      return BuiltinOperators.toValue(lv);
+    }
+  });
+
+  public static final Function CCUR = registerFunc(new Func1("CCur") {
+    @Override
+    protected Value eval1(EvalContext ctx, Value param1) {
+      BigDecimal bd = param1.getAsBigDecimal();
+      bd.setScale(4, RoundingMode.HALF_EVEN);
+      return BuiltinOperators.toValue(bd);
+    }
+  });
+
+  // public static final Function CDATE = registerFunc(new Func1("CDate") {
+  //   @Override
+  //   protected Value eval1(EvalContext ctx, Value param1) {
+  //   FIXME
+  //     BigDecimal bd = param1.getAsBigDecimal();
+  //     bd.setScale(4, RoundingMode.HALF_EVEN);
+  //     return BuiltinOperators.toValue(bd);
+  //   }
+  // });
+
+  public static final Function CDBL = registerFunc(new Func1("CDbl") {
+    @Override
+    protected Value eval1(EvalContext ctx, Value param1) {
+      Double db = param1.getAsDouble();
+      return BuiltinOperators.toValue(db);
+    }
+  });
+
+  public static final Function CDEC = registerFunc(new Func1("CDec") {
+    @Override
+    protected Value eval1(EvalContext ctx, Value param1) {
+      BigDecimal bd = param1.getAsBigDecimal();
+      return BuiltinOperators.toValue(bd);
+    }
+  });
+
+  public static final Function CINT = registerFunc(new Func1("CInt") {
+    @Override
+    protected Value eval1(EvalContext ctx, Value param1) {
+      // FIXME, fix rounding for this and clng
+      Long lv = param1.getAsLong();
+      if((lv < Short.MIN_VALUE) || (lv > Short.MAX_VALUE)) {
+        throw new IllegalStateException("Int value '" + lv + "' out of range ");
+      }
+      return BuiltinOperators.toValue(lv);
+    }
+  });
+
+  public static final Function CLNG = registerFunc(new Func1("CLng") {
+    @Override
+    protected Value eval1(EvalContext ctx, Value param1) {
+      Long lv = param1.getAsLong();
+      if((lv < Integer.MIN_VALUE) || (lv > Integer.MAX_VALUE)) {
+        throw new IllegalStateException("Long value '" + lv + "' out of range ");
+      }
+      return BuiltinOperators.toValue(lv);
+    }
+  });
+
+  public static final Function CSNG = registerFunc(new Func1("CSng") {
+    @Override
+    protected Value eval1(EvalContext ctx, Value param1) {
+      Double db = param1.getAsDouble();
+      if((db < Float.MIN_VALUE) || (db > Float.MAX_VALUE)) {
+        throw new IllegalStateException("Single value '" + db + "' out of range ");
+      }
+      return BuiltinOperators.toValue(db);
+    }
+  });
+
+  // FIXME, CSTR, CVAR
   
 
   // https://www.techonthenet.com/access/functions/
   // https://support.office.com/en-us/article/Access-Functions-by-category-b8b136c3-2716-4d39-94a2-658ce330ed83
 
   private static Function registerFunc(Function func) {
-    if(FUNCS.put(func.getName().toLowerCase(), func) != null) {
+    return registerFunc(false, func);
+  }
+
+  private static Function registerStringFunc(Function func) {
+    return registerFunc(true, func);
+  }
+
+  private static Function registerFunc(boolean includeNonVar, Function func) {
+    String fname = func.getName().toLowerCase();
+    if(FUNCS.put(fname, func) != null) {
       throw new IllegalStateException("Duplicate function " + func);
     }
+    if(includeNonVar) {
+      // for our purposes the non-variant versions are the same function
+      fname += NON_VAR_SUFFIX;
+      if(FUNCS.put(fname, func) != null) {
+        throw new IllegalStateException("Duplicate function " + func);
+      }
+    }
     return func;
   }
 }