You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

DefaultFunctions.java 9.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. /*
  2. Copyright (c) 2016 James Ahlborn
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package com.healthmarketscience.jackcess.impl.expr;
  14. import java.math.BigDecimal;
  15. import java.util.HashMap;
  16. import java.util.Map;
  17. import com.healthmarketscience.jackcess.expr.EvalContext;
  18. import com.healthmarketscience.jackcess.expr.EvalException;
  19. import com.healthmarketscience.jackcess.expr.Function;
  20. import com.healthmarketscience.jackcess.expr.FunctionLookup;
  21. import com.healthmarketscience.jackcess.expr.Value;
  22. import com.healthmarketscience.jackcess.impl.DatabaseImpl;
  23. import com.healthmarketscience.jackcess.impl.NumberFormatter;
  24. import static com.healthmarketscience.jackcess.impl.expr.FunctionSupport.*;
  25. /**
  26. *
  27. * @author James Ahlborn
  28. */
  29. public class DefaultFunctions
  30. {
  31. private static final Map<String,Function> FUNCS =
  32. new HashMap<String,Function>();
  33. static {
  34. // load all default functions
  35. DefaultTextFunctions.init();
  36. DefaultNumberFunctions.init();
  37. DefaultDateFunctions.init();
  38. DefaultFinancialFunctions.init();
  39. }
  40. public static final FunctionLookup LOOKUP = new FunctionLookup() {
  41. public Function getFunction(String name) {
  42. return FUNCS.get(DatabaseImpl.toLookupName(name));
  43. }
  44. };
  45. private DefaultFunctions() {}
  46. public static final Function IIF = registerFunc(new Func3("IIf") {
  47. @Override
  48. protected Value eval3(EvalContext ctx,
  49. Value param1, Value param2, Value param3) {
  50. // null is false
  51. return ((!param1.isNull() && param1.getAsBoolean()) ? param2 : param3);
  52. }
  53. });
  54. public static final Function HEX = registerStringFunc(new Func1NullIsNull("Hex") {
  55. @Override
  56. protected Value eval1(EvalContext ctx, Value param1) {
  57. if((param1.getType() == Value.Type.STRING) &&
  58. (param1.getAsString().length() == 0)) {
  59. return ValueSupport.ZERO_VAL;
  60. }
  61. int lv = param1.getAsLongInt();
  62. return ValueSupport.toValue(Integer.toHexString(lv).toUpperCase());
  63. }
  64. });
  65. public static final Function NZ = registerFunc(new FuncVar("Nz", 1, 2) {
  66. @Override
  67. protected Value evalVar(EvalContext ctx, Value[] params) {
  68. Value param1 = params[0];
  69. if(!param1.isNull()) {
  70. return param1;
  71. }
  72. if(params.length > 1) {
  73. return params[1];
  74. }
  75. Value.Type resultType = ctx.getResultType();
  76. return (((resultType == null) ||
  77. (resultType == Value.Type.STRING)) ?
  78. ValueSupport.EMPTY_STR_VAL : ValueSupport.ZERO_VAL);
  79. }
  80. });
  81. public static final Function CHOOSE = registerFunc(new FuncVar("Choose", 1, Integer.MAX_VALUE) {
  82. @Override
  83. protected Value evalVar(EvalContext ctx, Value[] params) {
  84. Value param1 = params[0];
  85. int idx = param1.getAsLongInt();
  86. if((idx < 1) || (idx >= params.length)) {
  87. return ValueSupport.NULL_VAL;
  88. }
  89. return params[idx];
  90. }
  91. });
  92. public static final Function SWITCH = registerFunc(new FuncVar("Switch") {
  93. @Override
  94. protected Value evalVar(EvalContext ctx, Value[] params) {
  95. if((params.length % 2) != 0) {
  96. throw new EvalException("Odd number of parameters");
  97. }
  98. for(int i = 0; i < params.length; i+=2) {
  99. if(params[i].getAsBoolean()) {
  100. return params[i + 1];
  101. }
  102. }
  103. return ValueSupport.NULL_VAL;
  104. }
  105. });
  106. public static final Function OCT = registerStringFunc(new Func1NullIsNull("Oct") {
  107. @Override
  108. protected Value eval1(EvalContext ctx, Value param1) {
  109. if((param1.getType() == Value.Type.STRING) &&
  110. (param1.getAsString().length() == 0)) {
  111. return ValueSupport.ZERO_VAL;
  112. }
  113. int lv = param1.getAsLongInt();
  114. return ValueSupport.toValue(Integer.toOctalString(lv));
  115. }
  116. });
  117. public static final Function CBOOL = registerFunc(new Func1("CBool") {
  118. @Override
  119. protected Value eval1(EvalContext ctx, Value param1) {
  120. boolean b = param1.getAsBoolean();
  121. return ValueSupport.toValue(b);
  122. }
  123. });
  124. public static final Function CBYTE = registerFunc(new Func1("CByte") {
  125. @Override
  126. protected Value eval1(EvalContext ctx, Value param1) {
  127. int lv = param1.getAsLongInt();
  128. if((lv < 0) || (lv > 255)) {
  129. throw new EvalException("Byte code '" + lv + "' out of range ");
  130. }
  131. return ValueSupport.toValue(lv);
  132. }
  133. });
  134. public static final Function CCUR = registerFunc(new Func1("CCur") {
  135. @Override
  136. protected Value eval1(EvalContext ctx, Value param1) {
  137. BigDecimal bd = param1.getAsBigDecimal();
  138. bd = bd.setScale(4, NumberFormatter.ROUND_MODE);
  139. return ValueSupport.toValue(bd);
  140. }
  141. });
  142. public static final Function CDATE = registerFunc(new Func1("CDate") {
  143. @Override
  144. protected Value eval1(EvalContext ctx, Value param1) {
  145. return DefaultDateFunctions.nonNullToDateValue(ctx, param1);
  146. }
  147. });
  148. static {
  149. registerFunc("CVDate", CDATE);
  150. }
  151. public static final Function CDBL = registerFunc(new Func1("CDbl") {
  152. @Override
  153. protected Value eval1(EvalContext ctx, Value param1) {
  154. Double dv = param1.getAsDouble();
  155. return ValueSupport.toValue(dv);
  156. }
  157. });
  158. public static final Function CDEC = registerFunc(new Func1("CDec") {
  159. @Override
  160. protected Value eval1(EvalContext ctx, Value param1) {
  161. BigDecimal bd = param1.getAsBigDecimal();
  162. return ValueSupport.toValue(bd);
  163. }
  164. });
  165. public static final Function CINT = registerFunc(new Func1("CInt") {
  166. @Override
  167. protected Value eval1(EvalContext ctx, Value param1) {
  168. int lv = param1.getAsLongInt();
  169. if((lv < Short.MIN_VALUE) || (lv > Short.MAX_VALUE)) {
  170. throw new EvalException("Int value '" + lv + "' out of range ");
  171. }
  172. return ValueSupport.toValue(lv);
  173. }
  174. });
  175. public static final Function CLNG = registerFunc(new Func1("CLng") {
  176. @Override
  177. protected Value eval1(EvalContext ctx, Value param1) {
  178. int lv = param1.getAsLongInt();
  179. return ValueSupport.toValue(lv);
  180. }
  181. });
  182. public static final Function CSNG = registerFunc(new Func1("CSng") {
  183. @Override
  184. protected Value eval1(EvalContext ctx, Value param1) {
  185. Double dv = param1.getAsDouble();
  186. if((dv < Float.MIN_VALUE) || (dv > Float.MAX_VALUE)) {
  187. throw new EvalException("Single value '" + dv + "' out of range ");
  188. }
  189. return ValueSupport.toValue(dv.floatValue());
  190. }
  191. });
  192. public static final Function CSTR = registerFunc(new Func1("CStr") {
  193. @Override
  194. protected Value eval1(EvalContext ctx, Value param1) {
  195. return ValueSupport.toValue(param1.getAsString());
  196. }
  197. });
  198. public static final Function CVAR = registerFunc(new Func1("CVar") {
  199. @Override
  200. protected Value eval1(EvalContext ctx, Value param1) {
  201. return param1;
  202. }
  203. });
  204. public static final Function ISNULL = registerFunc(new Func1("IsNull") {
  205. @Override
  206. protected Value eval1(EvalContext ctx, Value param1) {
  207. return ValueSupport.toValue(param1.isNull());
  208. }
  209. });
  210. public static final Function ISDATE = registerFunc(new Func1("IsDate") {
  211. @Override
  212. protected Value eval1(EvalContext ctx, Value param1) {
  213. return ValueSupport.toValue(
  214. !param1.isNull() &&
  215. (DefaultDateFunctions.nonNullToDateValue(ctx, param1) != null));
  216. }
  217. });
  218. public static final Function VARTYPE = registerFunc(new Func1("VarType") {
  219. @Override
  220. protected Value eval1(EvalContext ctx, Value param1) {
  221. Value.Type type = param1.getType();
  222. int vType = 0;
  223. switch(type) {
  224. case NULL:
  225. // vbNull
  226. vType = 1;
  227. break;
  228. case STRING:
  229. // vbString
  230. vType = 8;
  231. break;
  232. case DATE:
  233. case TIME:
  234. case DATE_TIME:
  235. // vbDate
  236. vType = 7;
  237. break;
  238. case LONG:
  239. // vbLong
  240. vType = 3;
  241. break;
  242. case DOUBLE:
  243. // vbDouble
  244. vType = 5;
  245. break;
  246. case BIG_DEC:
  247. // vbDecimal
  248. vType = 14;
  249. break;
  250. default:
  251. throw new EvalException("Unknown type " + type);
  252. }
  253. return ValueSupport.toValue(vType);
  254. }
  255. });
  256. public static final Function TYPENAME = registerFunc(new Func1("TypeName") {
  257. @Override
  258. protected Value eval1(EvalContext ctx, Value param1) {
  259. Value.Type type = param1.getType();
  260. String tName = null;
  261. switch(type) {
  262. case NULL:
  263. tName = "Null";
  264. break;
  265. case STRING:
  266. tName = "String";
  267. break;
  268. case DATE:
  269. case TIME:
  270. case DATE_TIME:
  271. tName = "Date";
  272. break;
  273. case LONG:
  274. tName = "Long";
  275. break;
  276. case DOUBLE:
  277. tName = "Double";
  278. break;
  279. case BIG_DEC:
  280. tName = "Decimal";
  281. break;
  282. default:
  283. throw new EvalException("Unknown type " + type);
  284. }
  285. return ValueSupport.toValue(tName);
  286. }
  287. });
  288. // https://www.techonthenet.com/access/functions/
  289. // https://support.office.com/en-us/article/Access-Functions-by-category-b8b136c3-2716-4d39-94a2-658ce330ed83
  290. static Function registerFunc(Function func) {
  291. registerFunc(func.getName(), func);
  292. return func;
  293. }
  294. static Function registerStringFunc(Function func) {
  295. registerFunc(func.getName(), func);
  296. registerFunc(new StringFuncWrapper(func));
  297. return func;
  298. }
  299. private static void registerFunc(String fname, Function func) {
  300. String lookupFname = DatabaseImpl.toLookupName(fname);
  301. if(FUNCS.put(lookupFname, func) != null) {
  302. throw new IllegalStateException("Duplicate function " + fname);
  303. }
  304. }
  305. }