123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504 |
- /*
- Copyright (c) 2017 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 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 org.apache.commons.lang.WordUtils;
- import static com.healthmarketscience.jackcess.impl.expr.DefaultFunctions.*;
- import static com.healthmarketscience.jackcess.impl.expr.FunctionSupport.*;
-
- /**
- *
- * @author James Ahlborn
- */
- public class DefaultTextFunctions
- {
- // mask to separate the case conversion value (first two bits) from the char
- // conversion value for the StrConv() function
- private static final int STR_CONV_MASK = 0x03;
-
- private DefaultTextFunctions() {}
-
- static void init() {
- // dummy method to ensure this class is loaded
- }
-
- public static final Function ASC = registerFunc(new Func1("Asc") {
- @Override
- protected Value eval1(EvalContext ctx, Value param1) {
- String str = param1.getAsString(ctx);
- int len = str.length();
- if(len == 0) {
- throw new EvalException("No characters in string");
- }
- int lv = str.charAt(0);
- if((lv < 0) || (lv > 255)) {
- throw new EvalException("Character code '" + lv +
- "' out of range ");
- }
- return ValueSupport.toValue(lv);
- }
- });
-
- public static final Function ASCW = registerFunc(new Func1("AscW") {
- @Override
- protected Value eval1(EvalContext ctx, Value param1) {
- String str = param1.getAsString(ctx);
- int len = str.length();
- if(len == 0) {
- throw new EvalException("No characters in string");
- }
- int lv = str.charAt(0);
- return ValueSupport.toValue(lv);
- }
- });
-
- public static final Function CHR = registerStringFunc(new Func1NullIsNull("Chr") {
- @Override
- protected Value eval1(EvalContext ctx, Value param1) {
- int lv = param1.getAsLongInt(ctx);
- if((lv < 0) || (lv > 255)) {
- throw new EvalException("Character code '" + lv +
- "' out of range ");
- }
- char[] cs = Character.toChars(lv);
- return ValueSupport.toValue(new String(cs));
- }
- });
-
- public static final Function CHRW = registerStringFunc(new Func1NullIsNull("ChrW") {
- @Override
- protected Value eval1(EvalContext ctx, Value param1) {
- 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(ctx);
- String str = bd.toPlainString();
- if(bd.compareTo(BigDecimal.ZERO) >= 0) {
- str = " " + str;
- }
- return ValueSupport.toValue(str);
- }
- });
-
- public static final Function INSTR = registerFunc(new FuncVar("InStr", 2, 4) {
- @Override
- protected Value evalVar(EvalContext ctx, Value[] params) {
- int idx = 0;
- int start = 0;
- if(params.length > 2) {
- // 1 based offsets
- start = params[0].getAsLongInt(ctx) - 1;
- ++idx;
- }
- Value param1 = params[idx++];
- if(param1.isNull()) {
- return param1;
- }
- String s1 = param1.getAsString(ctx);
- int s1Len = s1.length();
- if(s1Len == 0) {
- return ValueSupport.ZERO_VAL;
- }
- Value param2 = params[idx++];
- if(param2.isNull()) {
- return param2;
- }
- String s2 = param2.getAsString(ctx);
- int s2Len = s2.length();
- if(s2Len == 0) {
- // 1 based offsets
- return ValueSupport.toValue(start + 1);
- }
- boolean ignoreCase = getIgnoreCase(ctx, params, 3);
- int end = s1Len - s2Len;
- while(start < end) {
- if(s1.regionMatches(ignoreCase, start, s2, 0, s2Len)) {
- // 1 based offsets
- return ValueSupport.toValue(start + 1);
- }
- ++start;
- }
- return ValueSupport.ZERO_VAL;
- }
- });
-
- public static final Function INSTRREV = registerFunc(new FuncVar("InStrRev", 2, 4) {
- @Override
- protected Value evalVar(EvalContext ctx, Value[] params) {
- Value param1 = params[0];
- if(param1.isNull()) {
- return param1;
- }
- String s1 = param1.getAsString(ctx);
- int s1Len = s1.length();
- if(s1Len == 0) {
- return ValueSupport.ZERO_VAL;
- }
- Value param2 = params[1];
- if(param2.isNull()) {
- return param2;
- }
- String s2 = param2.getAsString(ctx);
- int s2Len = s2.length();
- int start = s1Len - 1;
- if(s2Len == 0) {
- // 1 based offsets
- return ValueSupport.toValue(start + 1);
- }
- if(params.length > 2) {
- start = params[2].getAsLongInt(ctx);
- if(start == -1) {
- start = s1Len;
- }
- // 1 based offsets
- --start;
- }
- boolean ignoreCase = getIgnoreCase(ctx, params, 3);
- start = Math.min(s1Len - s2Len, start - s2Len + 1);
- while(start >= 0) {
- if(s1.regionMatches(ignoreCase, start, s2, 0, s2Len)) {
- // 1 based offsets
- return ValueSupport.toValue(start + 1);
- }
- --start;
- }
- return ValueSupport.ZERO_VAL;
- }
- });
-
- public static final Function LCASE = registerStringFunc(new Func1NullIsNull("LCase") {
- @Override
- protected Value eval1(EvalContext ctx, Value param1) {
- 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(ctx);
- return ValueSupport.toValue(str.toUpperCase());
- }
- });
-
- public static final Function LEFT = registerStringFunc(new Func2("Left") {
- @Override
- protected Value eval2(EvalContext ctx, Value param1, Value param2) {
- if(param1.isNull()) {
- return param1;
- }
- String str = param1.getAsString(ctx);
- int len = Math.min(str.length(), param2.getAsLongInt(ctx));
- return ValueSupport.toValue(str.substring(0, len));
- }
- });
-
- public static final Function RIGHT = registerStringFunc(new Func2("Right") {
- @Override
- protected Value eval2(EvalContext ctx, Value param1, Value param2) {
- if(param1.isNull()) {
- return param1;
- }
- String str = param1.getAsString(ctx);
- int strLen = str.length();
- int len = Math.min(strLen, param2.getAsLongInt(ctx));
- return ValueSupport.toValue(str.substring(strLen - len, strLen));
- }
- });
-
- public static final Function MID = registerStringFunc(new FuncVar("Mid", 2, 3) {
- @Override
- protected Value evalVar(EvalContext ctx, Value[] params) {
- Value param1 = params[0];
- if(param1.isNull()) {
- return param1;
- }
- String str = param1.getAsString(ctx);
- int strLen = str.length();
- // 1 based offsets
- int start = Math.min(strLen, params[1].getAsLongInt(ctx) - 1);
- int len = Math.min(
- ((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(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(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(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(ctx);
- return ValueSupport.toValue(trim(str, true, true));
- }
- });
-
- public static final Function REPLACE = registerStringFunc(new FuncVar("Replace", 3, 6) {
- @Override
- protected Value evalVar(EvalContext ctx, Value[] params) {
- String str = params[0].getAsString(ctx);
- String searchStr = params[1].getAsString(ctx);
- String replStr = params[2].getAsString(ctx);
-
- int strLen = str.length();
-
- int start = getOptionalIntParam(ctx, params, 3, 1) - 1;
- int count = getOptionalIntParam(ctx, params, 4, -1);
- boolean ignoreCase = getIgnoreCase(ctx, params, 5);
-
- if(start >= strLen) {
- return ValueSupport.EMPTY_STR_VAL;
- }
-
- int searchLen = searchStr.length();
- if((searchLen == 0) || (count == 0)) {
- String result = str;
- if(start > 0) {
- result = str.substring(start);
- }
- return ValueSupport.toValue(result);
- }
-
- if(count < 0) {
- count = strLen;
- }
-
- StringBuilder result = new StringBuilder(strLen);
-
- int matchCount = 0;
- for(int i = start; i < strLen; ++i) {
- if((matchCount < count) &&
- str.regionMatches(ignoreCase, i, searchStr, 0, searchLen)) {
- result.append(replStr);
- ++matchCount;
- i += searchLen - 1;
- } else {
- result.append(str.charAt(i));
- }
- }
-
- return ValueSupport.toValue(result.toString());
- }
- });
-
- public static final Function SPACE = registerStringFunc(new Func1("Space") {
- @Override
- protected Value eval1(EvalContext ctx, Value param1) {
- int lv = param1.getAsLongInt(ctx);
- return ValueSupport.toValue(nchars(lv, ' '));
- }
- });
-
- public static final Function STRCOMP = registerFunc(new FuncVar("StrComp", 2, 3) {
- @Override
- protected Value evalVar(EvalContext ctx, Value[] params) {
- Value param1 = params[0];
- Value param2 = params[1];
- if(param1.isNull() || param2.isNull()) {
- return ValueSupport.NULL_VAL;
- }
- String s1 = param1.getAsString(ctx);
- String s2 = param2.getAsString(ctx);
- boolean ignoreCase = getIgnoreCase(ctx, params, 2);
- int cmp = (ignoreCase ?
- s1.compareToIgnoreCase(s2) : s1.compareTo(s2));
- // stupid java doesn't return 1, -1, 0...
- return ((cmp < 0) ? ValueSupport.NEG_ONE_VAL :
- ((cmp > 0) ? ValueSupport.ONE_VAL :
- ValueSupport.ZERO_VAL));
- }
- });
-
- public static final Function STRCONV = registerStringFunc(new FuncVar("StrConv", 2, 3) {
- @Override
- protected Value evalVar(EvalContext ctx, Value[] params) {
- Value param1 = params[0];
- if(param1.isNull()) {
- return ValueSupport.NULL_VAL;
- }
-
- String str = param1.getAsString(ctx);
- int conversion = params[1].getAsLongInt(ctx);
- // TODO, for now, ignore locale id...?
- // int localeId = params[2];
-
- int caseConv = STR_CONV_MASK & conversion;
- int charConv = (~STR_CONV_MASK) & conversion;
-
- switch(caseConv) {
- case 1:
- // vbUpperCase
- str = str.toUpperCase();
- break;
- case 2:
- // vbLowerCase
- str = str.toLowerCase();
- break;
- case 3:
- // vbProperCase
- str = WordUtils.capitalize(str.toLowerCase());
- break;
- default:
- // do nothing
- }
-
- if(charConv != 0) {
- // 64 = vbUnicode, all java strings are already unicode,so nothing to do
- if(charConv != 64) {
- throw new EvalException("Unsupported character conversion " + charConv);
- }
- }
-
- return ValueSupport.toValue(str);
- }
- });
-
- public static final Function STRING = registerStringFunc(new Func2("String") {
- @Override
- protected Value eval2(EvalContext ctx, Value param1, Value param2) {
- if(param1.isNull() || param2.isNull()) {
- return ValueSupport.NULL_VAL;
- }
- 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(ctx);
- return ValueSupport.toValue(
- new StringBuilder(str).reverse().toString());
- }
- });
-
- public static final Function FORMAT = registerStringFunc(new FuncVar("Format", 1, 4) {
- @Override
- protected Value evalVar(EvalContext ctx, Value[] params) {
-
- Value expr = params[0];
- if(params.length < 2) {
- // no formatting, do simple string conversion
- if(expr.isNull()) {
- return ValueSupport.NULL_VAL;
- }
- return ValueSupport.toValue(expr.getAsString(ctx));
- }
-
- String fmtStr = params[1].getAsString(ctx);
- int firstDay = DefaultDateFunctions.getFirstDayParam(ctx, params, 2);
- int firstWeekType = DefaultDateFunctions.getFirstWeekTypeParam(ctx, params, 3);
-
- return FormatUtil.format(ctx, expr, fmtStr, firstDay, firstWeekType);
- }
- });
-
- private static String nchars(int num, char c) {
- StringBuilder sb = new StringBuilder(num);
- nchars(sb, num, c);
- return sb.toString();
- }
-
- static void nchars(StringBuilder sb, int num, char c) {
- for(int i = 0; i < num; ++i) {
- sb.append(c);
- }
- }
-
- private static String trim(String str, boolean doLeft, boolean doRight) {
- int start = 0;
- int end = str.length();
-
- if(doLeft) {
- while((start < end) && (str.charAt(start) == ' ')) {
- ++start;
- }
- }
- if(doRight) {
- while((start < end) && (str.charAt(end - 1) == ' ')) {
- --end;
- }
- }
- return str.substring(start, end);
- }
-
- private static boolean getIgnoreCase(EvalContext ctx, Value[] params, int idx) {
- boolean ignoreCase = true;
- if(params.length > idx) {
- ignoreCase = doIgnoreCase(ctx, params[idx]);
- }
- return ignoreCase;
- }
-
- private static boolean doIgnoreCase(LocaleContext ctx, Value paramCmp) {
- int cmpType = paramCmp.getAsLongInt(ctx);
- switch(cmpType) {
- case -1:
- // vbUseCompareOption -> default is binary
- case 0:
- // vbBinaryCompare
- return false;
- case 1:
- // vbTextCompare
- return true;
- default:
- // vbDatabaseCompare -> unsupported
- throw new EvalException("Unsupported compare type " + cmpType);
- }
- }
-
-
- }
|