blob: 68bd2208a12c8204caf8e35dbd55b2c359f1aa1d [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.asterix.external.classad;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.asterix.external.classad.ExprTree.NodeKind;
import org.apache.asterix.external.classad.Value.ValueType;
import org.apache.asterix.external.classad.object.pool.ClassAdObjectPool;
import org.apache.asterix.external.library.ClassAdParser;
import org.apache.asterix.om.base.AMutableDouble;
import org.apache.asterix.om.base.AMutableInt32;
import org.apache.asterix.om.base.AMutableInt64;
import org.apache.commons.lang3.mutable.MutableBoolean;
import org.apache.hyracks.api.exceptions.HyracksDataException;
public class BuiltinClassAdFunctions {
public static final ClassAdFunc IsType = new ClassAdFunc() {
@Override
public boolean call(String name, ExprList argList, EvalState state, Value val, ClassAdObjectPool objectPool)
throws HyracksDataException {
// need a single argument
if (argList.size() != 1) {
val.setErrorValue();
return true;
}
// Evaluate the argument
if (!argList.getExprList().get(0).publicEvaluate(state, val)) {
val.setErrorValue();
return false;
}
// check if the value was of the required type
switch (name.toLowerCase()) {
case "isundefined":
val.setBooleanValue(val.isUndefinedValue());
break;
case "iserror":
val.setBooleanValue(val.isErrorValue());
break;
case "isinteger":
val.setBooleanValue(val.isIntegerValue());
break;
case "isstring":
val.setBooleanValue(val.isStringValue());
break;
case "isreal":
val.setBooleanValue(val.isRealValue());
break;
case "isboolean":
val.setBooleanValue(val.isBooleanValue());
break;
case "isclassad":
val.setBooleanValue(val.isClassAdValue());
break;
case "islist":
val.setBooleanValue(val.isListValue());
break;
case "isabstime":
val.setBooleanValue(val.isAbsoluteTimeValue());
break;
case "isreltime":
val.setBooleanValue(val.isRelativeTimeValue());
break;
default:
val.setErrorValue();
}
return (true);
}
};
public static final ClassAdFunc TestMember = new ClassAdFunc() {
@Override
public boolean call(String name, ExprList argList, EvalState state, Value val, ClassAdObjectPool objectPool)
throws HyracksDataException {
Value arg0 = objectPool.valuePool.get();
Value arg1 = objectPool.valuePool.get();
Value cArg = objectPool.valuePool.get();
ExprList el = objectPool.exprListPool.get();
MutableBoolean b = objectPool.boolPool.get();
boolean useIS = name.equalsIgnoreCase("identicalmember");
// need two arguments
if (argList.size() != 2) {
val.setErrorValue();
return (true);
}
// Evaluate the arg list
if (!argList.get(0).publicEvaluate(state, arg0) || !argList.get(1).publicEvaluate(state, arg1)) {
val.setErrorValue();
return false;
}
// if the second arg (a list) is undefined, or the first arg is
// undefined and we're supposed to test for strict comparison, the
// result is 'undefined'
if (arg1.isUndefinedValue() || (!useIS && arg0.isUndefinedValue())) {
val.setUndefinedValue();
return true;
}
// Swap
if (arg0.isListValue() && !arg1.isListValue()) {
Value swap = objectPool.valuePool.get();
swap.setValue(arg0);
arg0.setValue(arg1);
arg1.setValue(swap);
}
// arg1 must be a list; arg0 must be comparable
if (!arg1.isListValue() || arg0.isListValue() || arg0.isClassAdValue()) {
val.setErrorValue();
return true;
}
// if we're using strict comparison, arg0 can't be 'error'
if (!useIS && arg0.isErrorValue()) {
val.setErrorValue();
return (true);
}
// check for membership
arg1.isListValue(el);
for (ExprTree tree : el.getExprList()) {
if (!tree.publicEvaluate(state, cArg)) {
val.setErrorValue();
return (false);
}
Operation.operate(useIS ? Operation.OpKind_IS_OP : Operation.OpKind_EQUAL_OP, cArg, arg0, val,
objectPool);
if (val.isBooleanValue(b) && b.booleanValue()) {
return true;
}
}
val.setBooleanValue(false);
return true;
}
};
public static final ClassAdFunc Size = new ClassAdFunc() {
@Override
public boolean call(String name, ExprList argList, EvalState state, Value val, ClassAdObjectPool objectPool)
throws HyracksDataException {
Value arg = objectPool.valuePool.get();
ExprList listToSize = objectPool.exprListPool.get();
ClassAd classadToSize = objectPool.classAdPool.get();
AMutableInt32 length = objectPool.int32Pool.get();
length.setValue(0);
// we accept only one argument
if (argList.size() != 1) {
val.setErrorValue();
return (true);
}
if (!argList.get(0).publicEvaluate(state, arg)) {
val.setErrorValue();
return false;
} else if (arg.isUndefinedValue()) {
val.setUndefinedValue();
return true;
} else if (arg.isListValue(listToSize)) {
val.setIntegerValue(listToSize.size());
return true;
} else if (arg.isClassAdValue(classadToSize)) {
val.setIntegerValue(classadToSize.size());
return true;
} else if (arg.isStringValue(length)) {
val.setIntegerValue(length.getIntegerValue().intValue());
return true;
} else {
val.setErrorValue();
return true;
}
}
};
public static final ClassAdFunc SumAvg = new ClassAdFunc() {
@Override
public boolean call(String name, ExprList argList, EvalState state, Value val, ClassAdObjectPool objectPool)
throws HyracksDataException {
Value listElementValue = objectPool.valuePool.get();
Value listVal = objectPool.valuePool.get();
Value numElements = objectPool.valuePool.get();
Value result = objectPool.valuePool.get();
ExprList listToSum = objectPool.exprListPool.get();
MutableBoolean first = objectPool.boolPool.get();
AMutableInt64 len = objectPool.int64Pool.get();
len.setValue(0);
boolean onlySum = name.equalsIgnoreCase("sum");
// we accept only one argument
if (argList.size() != 1) {
val.setErrorValue();
return (true);
}
// argument must Evaluate to a list
if (!argList.get(0).publicEvaluate(state, listVal)) {
val.setErrorValue();
return false;
} else if (listVal.isUndefinedValue()) {
val.setUndefinedValue();
return true;
} else if (!listVal.isListValue(listToSum)) {
val.setErrorValue();
return (true);
}
result.setUndefinedValue();
len.setValue(0);
first.setValue(true);
// Walk over each element in the list, and sum.
for (ExprTree listElement : listToSum.getExprList()) {
len.setValue(len.getLongValue() + 1);;
// Make sure this element is a number.
if (!listElement.publicEvaluate(state, listElementValue)) {
val.setErrorValue();
return false;
} else if (!listElementValue.isRealValue() && !listElementValue.isIntegerValue()) {
val.setErrorValue();
return true;
}
// Either take the number if it's the first,
// or add to the running sum.
if (first.booleanValue()) {
result.setValue(listElementValue);
first.setValue(false);
} else {
Operation.operate(Operation.OpKind_ADDITION_OP, result, listElementValue, result, objectPool);
}
}
// if the sum() function was called, we don't need to find the average
if (onlySum) {
val.setValue(result);
return true;
}
if (len.getLongValue() > 0) {
numElements.setRealValue(len.getLongValue());
Operation.operate(Operation.OpKind_DIVISION_OP, result, numElements, result, objectPool);
} else {
val.setUndefinedValue();
}
val.setValue(result);
return true;
}
};
public static final ClassAdFunc MinMax = new ClassAdFunc() {
@Override
public boolean call(String fn, ExprList argList, EvalState state, Value val, ClassAdObjectPool objectPool)
throws HyracksDataException {
Value listElementValue = objectPool.valuePool.get();
Value listVal = objectPool.valuePool.get();
Value cmp = objectPool.valuePool.get();
Value result = objectPool.valuePool.get();
ExprList listToBound = objectPool.exprListPool.get();
boolean first = true;
MutableBoolean b = objectPool.boolPool.get();
b.setValue(false);
int comparisonOperator;
// we accept only one argument
if (argList.size() != 1) {
val.setErrorValue();
return true;
}
// first argument must Evaluate to a list
if (!argList.get(0).publicEvaluate(state, listVal)) {
val.setErrorValue();
return false;
} else if (listVal.isUndefinedValue()) {
val.setUndefinedValue();
return true;
} else if (!listVal.isListValue(listToBound)) {
val.setErrorValue();
return true;
}
// fn is either "min..." or "max..."
if (Character.toLowerCase(fn.charAt(1)) == 'i') {
comparisonOperator = Operation.OpKind_LESS_THAN_OP;
} else {
comparisonOperator = Operation.OpKind_GREATER_THAN_OP;
}
result.setUndefinedValue();
// Walk over the list, calculating the bound the whole way.
for (ExprTree listElement : listToBound.getExprList()) {
// For this element of the list, make sure it is
// acceptable.
if (!listElement.publicEvaluate(state, listElementValue)) {
val.setErrorValue();
return false;
} else if (!listElementValue.isRealValue() && !listElementValue.isIntegerValue()) {
val.setErrorValue();
return true;
}
// If it's the first element, copy it to the bound,
// otherwise compare to decide what to do.
if (first) {
result.setValue(listElementValue);
first = false;
} else {
Operation.operate(comparisonOperator, listElementValue, result, cmp, objectPool);
if (cmp.isBooleanValue(b) && b.booleanValue()) {
result.setValue(listElementValue);
}
}
}
val.setValue(result);
return true;
}
};
public static final ClassAdFunc ListCompare = new ClassAdFunc() {
@Override
public boolean call(String fn, ExprList argList, EvalState state, Value val, ClassAdObjectPool objectPool)
throws HyracksDataException {
Value listElementValue = objectPool.valuePool.get();
Value listVal = objectPool.valuePool.get();
Value compareVal = objectPool.valuePool.get();
Value stringValue = objectPool.valuePool.get();
ExprList listToCompare = objectPool.exprListPool.get();
boolean needAllMatch;
AMutableCharArrayString comparison_string = objectPool.strPool.get();
int comparisonOperator;
// We take three arguments:
// The operator to use, as a string.
// The list
// The thing we are comparing against.
if (argList.size() != 3) {
val.setErrorValue();
return true;
}
// The first argument must be a string
if (!argList.get(0).publicEvaluate(state, stringValue)) {
val.setErrorValue();
return false;
} else if (stringValue.isUndefinedValue()) {
val.setUndefinedValue();
return true;
} else if (!stringValue.isStringValue(comparison_string)) {
val.setErrorValue();
return true;
}
// Decide which comparison to do, or give an error
switch (comparison_string.toString()) {
case "<":
comparisonOperator = Operation.OpKind_LESS_THAN_OP;
break;
case "<=":
comparisonOperator = Operation.OpKind_LESS_OR_EQUAL_OP;
break;
case "!=":
comparisonOperator = Operation.OpKind_NOT_EQUAL_OP;
break;
case "==":
comparisonOperator = Operation.OpKind_EQUAL_OP;
break;
case ">":
comparisonOperator = Operation.OpKind_GREATER_THAN_OP;
break;
case ">=":
comparisonOperator = Operation.OpKind_GREATER_OR_EQUAL_OP;
break;
case "is":
comparisonOperator = Operation.OpKind_META_EQUAL_OP;
break;
case "isnt":
comparisonOperator = Operation.OpKind_META_NOT_EQUAL_OP;
break;
default:
val.setErrorValue();
return true;
}
// The second argument must Evaluate to a list
if (!argList.get(1).publicEvaluate(state, listVal)) {
val.setErrorValue();
return false;
} else if (listVal.isUndefinedValue()) {
val.setUndefinedValue();
return true;
} else if (!listVal.isListValue(listToCompare)) {
val.setErrorValue();
return true;
}
// The third argument is something to compare against.
if (!argList.get(2).publicEvaluate(state, compareVal)) {
val.setErrorValue();
return false;
} else if (listVal.isUndefinedValue()) {
val.setUndefinedValue();
return true;
}
// Finally, we decide what to do exactly, based on our name.
if (fn.equalsIgnoreCase("anycompare")) {
needAllMatch = false;
val.setBooleanValue(false);
} else {
needAllMatch = true;
val.setBooleanValue(true);
}
// Walk over the list
for (ExprTree listElement : listToCompare.getExprList()) {
// For this element of the list, make sure it is
// acceptable.
if (!listElement.publicEvaluate(state, listElementValue)) {
val.setErrorValue();
return false;
} else {
Value compareResult = objectPool.valuePool.get();
MutableBoolean b = objectPool.boolPool.get();
Operation.operate(comparisonOperator, listElementValue, compareVal, compareResult, objectPool);
if (!compareResult.isBooleanValue(b)) {
if (compareResult.isUndefinedValue()) {
if (needAllMatch) {
val.setBooleanValue(false);
return true;
}
} else {
val.setErrorValue();
return true;
}
return true;
} else if (b.booleanValue()) {
if (!needAllMatch) {
val.setBooleanValue(true);
return true;
}
} else {
if (needAllMatch) {
// we failed, because it didn't match
val.setBooleanValue(false);
return true;
}
}
}
}
if (needAllMatch) {
// They must have all matched, because nothing failed,
// which would have returned.
val.setBooleanValue(true);
} else {
// Nothing must have matched, since we would have already
// returned.
val.setBooleanValue(false);
}
return true;
}
};
public static final ClassAdFunc timeZoneOffset = new ClassAdFunc() {
@Override
public boolean call(String name, ExprList argList, EvalState state, Value val, ClassAdObjectPool objectPool)
throws HyracksDataException {
// no arguments
if (argList.size() > 0) {
val.setErrorValue();
return (true);
}
val.setRelativeTimeValue(objectPool.classAdTimePool.get());
return (true);
}
};
public static final ClassAdFunc debug = new ClassAdFunc() {
@Override
public boolean call(String name, ExprList argList, EvalState state, Value result, ClassAdObjectPool objectPool)
throws HyracksDataException {
return false;
}
};
public static final ClassAdFunc formatTime = new ClassAdFunc() {
@Override
public boolean call(String name, ExprList argList, EvalState state, Value result, ClassAdObjectPool objectPool)
throws HyracksDataException {
Value time_arg = objectPool.valuePool.get();
Value format_arg = objectPool.valuePool.get();
AMutableInt64 int64 = objectPool.int64Pool.get();
int64.setValue(0);
ClassAdTime epoch_time = objectPool.classAdTimePool.get();
ClassAdTime time_components = objectPool.classAdTimePool.get();
time_components.setTimeZone("GMT");
ClassAd splitClassAd = objectPool.classAdPool.get();
String format;
int number_of_args;
boolean did_eval;
did_eval = true;
number_of_args = argList.size();
if (number_of_args == 0) {
epoch_time.setEpochTime();
Util.getLocalTime(epoch_time, time_components);
format = "%c";
make_formatted_time(time_components, format, result);
} else if (number_of_args < 3) {
// The first argument should be our time and should
// not be a relative time.
if (!argList.get(0).publicEvaluate(state, time_arg)) {
did_eval = false;
} else if (time_arg.isRelativeTimeValue()) {
result.setErrorValue();
} else if (time_arg.isAbsoluteTimeValue(time_components)) {
} else if (!time_arg.isClassAdValue(splitClassAd) /* doSplitTime(time_arg, splitClassAd) */) {
result.setErrorValue();
} else {
if (!splitClassAd.evaluateAttrInt("Seconds", int64)) {
time_components.setSeconds(0);
} else {
time_components.setSeconds((int) int64.getLongValue());
}
if (!splitClassAd.evaluateAttrInt("Minutes", int64)) {
time_components.setMinutes(0);
} else {
time_components.setMinutes((int) int64.getLongValue());
}
if (!splitClassAd.evaluateAttrInt("Hours", int64)) {
time_components.setHours(0);
} else {
time_components.setHours((int) int64.getLongValue());
}
if (!splitClassAd.evaluateAttrInt("Day", int64)) {
time_components.setDayOfMonth(0);
} else {
time_components.setDayOfMonth((int) int64.getLongValue());
}
if (!splitClassAd.evaluateAttrInt("Month", int64)) {
time_components.setMonth(0);
} else {
time_components.setMonth((int) int64.getLongValue() - 1);
}
if (!splitClassAd.evaluateAttrInt("Year", int64)) {
time_components.setYear(0);
} else {
time_components.setYear((int) int64.getLongValue());
}
}
// The second argument, if provided, must be a string
if (number_of_args == 1) {
format = "EEE MMM dd HH:mm:ss yyyy";
make_formatted_time(time_components, format, result);
} else {
if (!argList.get(1).publicEvaluate(state, format_arg)) {
did_eval = false;
} else {
AMutableCharArrayString formatString = objectPool.strPool.get();
if (!format_arg.isStringValue(formatString)) {
result.setErrorValue();
} else {
make_formatted_time(time_components, formatString.toString(), result);
}
}
}
} else {
result.setErrorValue();
}
if (!did_eval) {
result.setErrorValue();
}
return did_eval;
}
};
public static void make_formatted_time(ClassAdTime time_components, String format, Value result) {
//replace c++ format elements with java elements
format = format.replace("%m", "MM");
format = format.replace("%d", "dd");
format = format.replace("%Y", "yyyy");
format = format.replace("%M", "mm");
format = format.replace("%S", "ss");
format = format.replace("%A", "EEEE");
format = format.replace("%a", "EEE");
format = format.replace("%B", "MMMM");
format = format.replace("%b", "MMM");
format = format.replace("%H", "HH");
format = format.replace("%Y", "y");
format = format.replace("%", "");
DateFormat df = new SimpleDateFormat(format);
df.setTimeZone(TimeZone.getTimeZone("GMT"));
result.setStringValue(df.format(time_components.getCalendar().getTime()));
}
public static final ClassAdFunc getField = new ClassAdFunc() {
@Override
public boolean call(String name, ExprList argList, EvalState state, Value val, ClassAdObjectPool objectPool)
throws HyracksDataException {
Value arg = objectPool.valuePool.get();
ClassAdTime asecs = objectPool.classAdTimePool.get();
ClassAdTime rsecs = objectPool.classAdTimePool.get();
ClassAdTime clock = objectPool.classAdTimePool.get();
ClassAdTime tms = objectPool.classAdTimePool.get();
if (argList.size() != 1) {
val.setErrorValue();
return (true);
}
if (!argList.get(0).publicEvaluate(state, arg)) {
val.setErrorValue();
return false;
}
if (arg.isAbsoluteTimeValue(asecs)) {
clock.setValue(asecs);
Util.getLocalTime(clock, tms);
switch (name) {
case "getyear":
// tm_year is years since 1900 --- make it y2k compliant :-)
val.setIntegerValue(tms.getYear());
break;
case "getmonth":
val.setIntegerValue(tms.getMonth() + 1);
break;
case "getdayofyear":
val.setIntegerValue(tms.getDayOfYear());
break;
case "getdayofmonth":
val.setIntegerValue(tms.getDayOfMonth());
break;
case "getdayofweek":
val.setIntegerValue(tms.getDayOfWeek());
break;
case "gethours":
val.setIntegerValue(tms.getHours());
break;
case "getminutes":
val.setIntegerValue(tms.getMinutes());
break;
case "getseconds":
val.setIntegerValue(tms.getSeconds());
break;
case "getdays":
case "getuseconds":
// not meaningful for abstimes
val.setErrorValue();
return true;
default:
throw new HyracksDataException("Should not reach here");
}
return (true);
} else if (arg.isRelativeTimeValue(rsecs)) {
switch (name.toLowerCase()) {
case "getyear":
case "getmonth":
case "getdayofmonth":
case "getdayofweek":
case "getdayofyear":
// not meaningful for reltimes
val.setErrorValue();
return true;
case "getdays":
val.setIntegerValue(rsecs.getRelativeTime() / 86400);
break;
case "gethours":
val.setIntegerValue((rsecs.getRelativeTime() % 86400) / 3600);
break;
case "getminutes":
val.setIntegerValue((rsecs.getRelativeTime() % 3600) / 60);
break;
case "getseconds":
val.setIntegerValue(rsecs.getRelativeTime() % 60);
break;
default:
throw new HyracksDataException("Should not reach here");
}
return true;
}
val.setErrorValue();
return (true);
}
};
public static final ClassAdFunc currentTime = new ClassAdFunc() {
@Override
public boolean call(String name, ExprList argList, EvalState state, Value val, ClassAdObjectPool objectPool)
throws HyracksDataException {
// no arguments
if (argList.size() > 0) {
val.setErrorValue();
return (true);
}
Literal time_literal = Literal.createAbsTime(objectPool.classAdTimePool.get(), objectPool);
time_literal.GetValue(val);
return true;
}
};
public static final ClassAdFunc splitTime = new ClassAdFunc() {
@Override
public boolean call(String name, ExprList argList, EvalState state, Value result, ClassAdObjectPool objectPool)
throws HyracksDataException {
Value arg = objectPool.valuePool.get();
ClassAd split = objectPool.classAdPool.get();
if (argList.size() != 1) {
result.setErrorValue();
return true;
}
if (!argList.get(0).publicEvaluate(state, arg)) {
result.setErrorValue();
return false;
}
if (!arg.isClassAdValue() && doSplitTime(arg, split, objectPool)) {
result.setClassAdValue(split);
} else {
result.setErrorValue();
}
return true;
}
};
public static boolean doSplitTime(Value time, ClassAd splitClassAd, ClassAdObjectPool objectPool)
throws HyracksDataException {
boolean did_conversion;
AMutableInt64 integer = objectPool.int64Pool.get();
integer.setValue(0);
AMutableDouble real = objectPool.doublePool.get();
real.setValue(0);
ClassAdTime asecs = objectPool.classAdTimePool.get();
ClassAdTime rsecs = objectPool.classAdTimePool.get();
ClassAd classad = objectPool.classAdPool.get();
did_conversion = true;
if (time.isIntegerValue(integer)) {
asecs.setValue(integer.getLongValue());
asecs.makeLocalAbsolute();
absTimeToClassAd(asecs, splitClassAd);
} else if (time.isRealValue(real)) {
asecs.setValue((long) real.getDoubleValue());
asecs.makeAbsolute(true);
absTimeToClassAd(asecs, splitClassAd);
} else if (time.isAbsoluteTimeValue(asecs)) {
absTimeToClassAd(asecs, splitClassAd);
} else if (time.isRelativeTimeValue(rsecs)) {
relTimeToClassAd((rsecs.getRelativeTime() / 1000.0), splitClassAd);
} else if (time.isClassAdValue(classad)) {
splitClassAd = objectPool.classAdPool.get();
splitClassAd.copyFrom(classad);
} else {
did_conversion = false;
}
return did_conversion;
}
public static void relTimeToClassAd(double rsecs, ClassAd splitClassAd) throws HyracksDataException {
int days, hrs, mins;
double secs;
boolean is_negative;
if (rsecs < 0) {
rsecs = -rsecs;
is_negative = true;
} else {
is_negative = false;
}
days = (int) rsecs;
hrs = days % 86400;
mins = hrs % 3600;
secs = (mins % 60) + (rsecs - Math.floor(rsecs));
days = days / 86400;
hrs = hrs / 3600;
mins = mins / 60;
if (is_negative) {
if (days > 0) {
days = -days;
} else if (hrs > 0) {
hrs = -hrs;
} else if (mins > 0) {
mins = -mins;
} else {
secs = -secs;
}
}
splitClassAd.insertAttr("Type", "RelativeTime");
splitClassAd.insertAttr("Days", days);
splitClassAd.insertAttr("Hours", hrs);
splitClassAd.insertAttr("Minutes", mins);
splitClassAd.insertAttr("Seconds", secs);
return;
}
public static void absTimeToClassAd(ClassAdTime asecs, ClassAd splitClassAd) throws HyracksDataException {
ClassAdTime tms = asecs.getGMTCopy();
splitClassAd.insertAttr("Type", "AbsoluteTime");
splitClassAd.insertAttr("Year", tms.getYear());
splitClassAd.insertAttr("Month", tms.getMonth() + 1);
splitClassAd.insertAttr("Day", tms.getDayOfMonth());
splitClassAd.insertAttr("Hours", tms.getHours());
splitClassAd.insertAttr("Minutes", tms.getMinutes());
splitClassAd.insertAttr("Seconds", tms.getSeconds());
// Note that we convert the timezone from seconds to minutes.
splitClassAd.insertAttr("Offset", asecs.getOffset() / 1000);
return;
}
public static final ClassAdFunc dayTime = new ClassAdFunc() {
@Override
public boolean call(String name, ExprList argList, EvalState state, Value val, ClassAdObjectPool objectPool)
throws HyracksDataException {
val.setRelativeTimeValue(objectPool.classAdTimePool.get());
return (true);
}
};
public static final ClassAdFunc epochTime = new ClassAdFunc() {
@Override
public boolean call(String name, ExprList argList, EvalState state, Value val, ClassAdObjectPool objectPool)
throws HyracksDataException {
// no arguments
if (argList.size() > 0) {
val.setErrorValue();
return (true);
}
val.setIntegerValue(0);
return (true);
}
};
public static final ClassAdFunc strCat = new ClassAdFunc() {
@Override
public boolean call(String name, ExprList argList, EvalState state, Value result, ClassAdObjectPool objectPool)
throws HyracksDataException {
AMutableCharArrayString buf = objectPool.strPool.get();
AMutableCharArrayString s = objectPool.strPool.get();
boolean errorFlag = false;
boolean undefFlag = false;
boolean rval = false;
Value val = objectPool.valuePool.get();
Value stringVal = objectPool.valuePool.get();
for (int i = 0; i < argList.size(); i++) {
s.reset();
if (!(rval = argList.get(i).publicEvaluate(state, val))) {
break;
}
if (val.isStringValue(s)) {
buf.appendString(s);
} else {
Value.convertValueToStringValue(val, stringVal, objectPool);
if (stringVal.isUndefinedValue()) {
undefFlag = true;
break;
} else if (stringVal.isErrorValue()) {
errorFlag = true;
result.setErrorValue();
break;
} else if (stringVal.isStringValue(s)) {
buf.appendString(s);
} else {
errorFlag = true;
break;
}
}
}
// failed evaluating some argument
if (!rval) {
result.setErrorValue();
return (false);
}
// type error
if (errorFlag) {
result.setErrorValue();
return (true);
}
// some argument was undefined
if (undefFlag) {
result.setUndefinedValue();
return (true);
}
result.setStringValue(buf);
return (true);
}
};
public static final ClassAdFunc changeCase = new ClassAdFunc() {
@Override
public boolean call(String name, ExprList argList, EvalState state, Value result, ClassAdObjectPool objectPool)
throws HyracksDataException {
Value val = objectPool.valuePool.get();
Value stringVal = objectPool.valuePool.get();
AMutableCharArrayString str = objectPool.strPool.get();
boolean lower = name.equalsIgnoreCase("tolower");
int len;
// only one argument
if (argList.size() != 1) {
result.setErrorValue();
return true;
}
// check for evaluation failure
if (!argList.get(0).publicEvaluate(state, val)) {
result.setErrorValue();
return false;
}
if (!val.isStringValue(str)) {
Value.convertValueToStringValue(val, stringVal, objectPool);
if (stringVal.isUndefinedValue()) {
result.setUndefinedValue();
return true;
} else if (stringVal.isErrorValue()) {
result.setErrorValue();
return true;
} else if (!stringVal.isStringValue(str)) {
result.setErrorValue();
return true;
}
}
len = str.size();
for (int i = 0; i <= len; i++) {
str.setChar(i, lower ? Character.toLowerCase(str.charAt(i)) : Character.toUpperCase(str.charAt(i)));
}
result.setStringValue(str);
return (true);
}
};
public static final ClassAdFunc subString = new ClassAdFunc() {
@Override
public boolean call(String name, ExprList argList, EvalState state, Value result, ClassAdObjectPool objectPool)
throws HyracksDataException {
Value arg0 = objectPool.valuePool.get();
Value arg1 = objectPool.valuePool.get();
Value arg2 = objectPool.valuePool.get();
AMutableCharArrayString buf = objectPool.strPool.get();
AMutableInt64 offset = objectPool.int64Pool.get();
offset.setValue(0);
AMutableInt64 len = objectPool.int64Pool.get();
len.setValue(0);
AMutableInt64 alen = objectPool.int64Pool.get();
len.setValue(0);
// two or three arguments
if (argList.size() < 2 || argList.size() > 3) {
result.setErrorValue();
return (true);
}
// Evaluate all arguments
if (!argList.get(0).publicEvaluate(state, arg0) || !argList.get(1).publicEvaluate(state, arg1)
|| (argList.size() > 2 && !argList.get(2).publicEvaluate(state, arg2))) {
result.setErrorValue();
return (false);
}
// strict on undefined
if (arg0.isUndefinedValue() || arg1.isUndefinedValue() || (argList.size() > 2 && arg2.isUndefinedValue())) {
result.setUndefinedValue();
return (true);
}
// arg0 must be string, arg1 must be int, arg2 (if given) must be int
if (!arg0.isStringValue(buf) || !arg1.isIntegerValue(offset)
|| (argList.size() > 2 && !arg2.isIntegerValue(len))) {
result.setErrorValue();
return (true);
}
// perl-like substr; negative offsets and lengths count from the end
// of the string
alen.setValue(buf.size());
if (offset.getLongValue() < 0) {
offset.setValue(alen.getLongValue() + offset.getLongValue());
} else if (offset.getLongValue() >= alen.getLongValue()) {
offset.setValue(alen.getLongValue());
}
if (len.getLongValue() <= 0) {
len.setValue(alen.getLongValue() - offset.getLongValue() + len.getLongValue());
if (len.getLongValue() < 0) {
len.setValue(0);
}
} else if (len.getLongValue() > alen.getLongValue() - offset.getLongValue()) {
len.setValue(alen.getLongValue() - offset.getLongValue());
}
// to make sure that if length is specified as 0 explicitly
// then, len is set to 0
if (argList.size() == 3) {
AMutableInt64 templen = objectPool.int64Pool.get();
templen.setValue(0);
arg2.isIntegerValue(templen);
if (templen.getLongValue() == 0) {
len.setValue(0);
}
}
result.setStringValue(buf.substr((int) offset.getLongValue(), (int) len.getLongValue()));
return (true);
}
};
public static final ClassAdFunc convInt = new ClassAdFunc() {
@Override
public boolean call(String name, ExprList argList, EvalState state, Value result, ClassAdObjectPool objectPool)
throws HyracksDataException {
Value arg = objectPool.valuePool.get();
// takes exactly one argument
if (argList.size() != 1) {
result.setErrorValue();
return (true);
}
if (!argList.get(0).publicEvaluate(state, arg)) {
result.setErrorValue();
return (false);
}
Value.convertValueToIntegerValue(arg, result, objectPool);
return true;
}
};
public static final ClassAdFunc compareString = new ClassAdFunc() {
@Override
public boolean call(String name, ExprList argList, EvalState state, Value result, ClassAdObjectPool objectPool)
throws HyracksDataException {
Value arg0 = objectPool.valuePool.get();
Value arg1 = objectPool.valuePool.get();
Value arg0_s = objectPool.valuePool.get();
Value arg1_s = objectPool.valuePool.get();
// Must have two arguments
if (argList.size() != 2) {
result.setErrorValue();
return (true);
}
// Evaluate both arguments
if (!argList.get(0).publicEvaluate(state, arg0) || !argList.get(1).publicEvaluate(state, arg1)) {
result.setErrorValue();
return false;
}
// If either argument is undefined, then the result is
// undefined.
if (arg0.isUndefinedValue() || arg1.isUndefinedValue()) {
result.setUndefinedValue();
return true;
}
AMutableCharArrayString s0 = objectPool.strPool.get();
AMutableCharArrayString s1 = objectPool.strPool.get();
if (Value.convertValueToStringValue(arg0, arg0_s, objectPool)
&& Value.convertValueToStringValue(arg1, arg1_s, objectPool) && arg0_s.isStringValue(s0)
&& arg1_s.isStringValue(s1)) {
int order;
if (name.equalsIgnoreCase("strcmp")) {
order = s0.compareTo(s1);
if (order < 0) {
order = -1;
} else if (order > 0) {
order = 1;
}
} else {
order = s0.compareToIgnoreCase(s1);
if (order < 0) {
order = -1;
} else if (order > 0) {
order = 1;
}
}
result.setIntegerValue(order);
} else {
result.setErrorValue();
}
return (true);
}
};
public static final ClassAdFunc matchPattern = new ClassAdFunc() {
@Override
public boolean call(String name, ExprList argList, EvalState state, Value result, ClassAdObjectPool objectPool)
throws HyracksDataException {
boolean have_options;
Value arg0 = objectPool.valuePool.get();
Value arg1 = objectPool.valuePool.get();
Value arg2 = objectPool.valuePool.get();
AMutableCharArrayString pattern = objectPool.strPool.get();
AMutableCharArrayString target = objectPool.strPool.get();
AMutableCharArrayString options_string = objectPool.strPool.get();
// need two or three arguments: pattern, string, optional settings
if (argList.size() != 2 && argList.size() != 3) {
result.setErrorValue();
return (true);
}
if (argList.size() == 2) {
have_options = false;
} else {
have_options = true;
}
// Evaluate args
if (!argList.get(0).publicEvaluate(state, arg0) || !argList.get(1).publicEvaluate(state, arg1)) {
result.setErrorValue();
return (false);
}
if (have_options && !argList.get(2).publicEvaluate(state, arg2)) {
result.setErrorValue();
return (false);
}
// if either arg is error, the result is error
if (arg0.isErrorValue() || arg1.isErrorValue()) {
result.setErrorValue();
return (true);
}
if (have_options && arg2.isErrorValue()) {
result.setErrorValue();
return (true);
}
// if either arg is undefined, the result is undefined
if (arg0.isUndefinedValue() || arg1.isUndefinedValue()) {
result.setUndefinedValue();
return (true);
}
if (have_options && arg2.isUndefinedValue()) {
result.setUndefinedValue();
return (true);
} else if (have_options && !arg2.isStringValue(options_string)) {
result.setErrorValue();
return (true);
}
// if either argument is not a string, the result is an error
if (!arg0.isStringValue(pattern) || !arg1.isStringValue(target)) {
result.setErrorValue();
return (true);
}
return regexp_helper(pattern.toString(), target, null, have_options, options_string.toString(), result);
}
};
private static boolean regexp_helper(String pattern, AMutableCharArrayString target, String replace,
boolean have_options, String options_string, Value result) {
int options = 0;
//pattern = pattern.replaceAll("");
//pattern = pattern.replaceAll("?", ".");
Pattern re;
if (have_options) {
// We look for the options we understand, and ignore
// any others that we might find, hopefully allowing
// forwards compatibility.
if (options_string.contains("i")) {
options |= Pattern.CASE_INSENSITIVE;
}
}
// compile the patern
re = Pattern.compile(pattern, options);
Matcher matcher = re.matcher(target.toString());
if (matcher.matches()) {
result.setBooleanValue(true);
return (true);
} else {
result.setBooleanValue(false);
return (true);
}
}
public static final ClassAdFunc matchPatternMember = null;
public static final ClassAdFunc substPattern = null;
public static final ClassAdFunc convReal = new ClassAdFunc() {
@Override
public boolean call(String name, ExprList argList, EvalState state, Value result, ClassAdObjectPool objectPool)
throws HyracksDataException {
Value arg = objectPool.valuePool.get();
// takes exactly one argument
if (argList.size() != 1) {
result.setErrorValue();
return (true);
}
if (!argList.get(0).publicEvaluate(state, arg)) {
result.setErrorValue();
return (false);
}
Value.convertValueToRealValue(arg, result, objectPool);
return true;
}
};
public static final ClassAdFunc convString = new ClassAdFunc() {
@Override
public boolean call(String name, ExprList argList, EvalState state, Value result, ClassAdObjectPool objectPool)
throws HyracksDataException {
Value arg = objectPool.valuePool.get();
// takes exactly one argument
if (argList.size() != 1) {
result.setErrorValue();
return (true);
}
if (!argList.get(0).publicEvaluate(state, arg)) {
result.setErrorValue();
return (false);
}
Value.convertValueToStringValue(arg, result, objectPool);
return true;
}
};
public static final ClassAdFunc unparse = new ClassAdFunc() {
@Override
public boolean call(String name, ExprList argList, EvalState state, Value result, ClassAdObjectPool objectPool)
throws HyracksDataException {
if (argList.size() != 1 || argList.get(0).getKind() != NodeKind.ATTRREF_NODE) {
result.setErrorValue();
} else {
// use the printpretty on arg0 to spew out
PrettyPrint unp = objectPool.prettyPrintPool.get();
AMutableCharArrayString szAttribute = objectPool.strPool.get();
AMutableCharArrayString szValue = objectPool.strPool.get();
ExprTree pTree;
unp.unparse(szAttribute, argList.get(0));
// look them up argument within context of the ad.
if (state.getCurAd() != null && (pTree = state.getCurAd().lookup(szAttribute.toString())) != null) {
unp.unparse(szValue, pTree);
}
result.setStringValue(szValue);
}
return (true);
}
};
public static final ClassAdFunc convBool = new ClassAdFunc() {
@Override
public boolean call(String name, ExprList argList, EvalState state, Value result, ClassAdObjectPool objectPool)
throws HyracksDataException {
Value arg = objectPool.valuePool.get();
// takes exactly one argument
if (argList.size() != 1) {
result.setErrorValue();
return (true);
}
if (!argList.get(0).publicEvaluate(state, arg)) {
result.setErrorValue();
return (false);
}
switch (arg.getType()) {
case UNDEFINED_VALUE:
result.setUndefinedValue();
return (true);
case ERROR_VALUE:
case CLASSAD_VALUE:
case LIST_VALUE:
case SLIST_VALUE:
case ABSOLUTE_TIME_VALUE:
result.setErrorValue();
return (true);
case BOOLEAN_VALUE:
result.setValue(arg);
return (true);
case INTEGER_VALUE: {
AMutableInt64 ival = objectPool.int64Pool.get();
ival.setValue(0);
arg.isIntegerValue(ival);
result.setBooleanValue(ival.getLongValue() != 0);
return (true);
}
case REAL_VALUE: {
AMutableDouble rval = objectPool.doublePool.get();
arg.isRealValue(rval);
result.setBooleanValue(rval.getDoubleValue() != 0.0);
return (true);
}
case STRING_VALUE: {
AMutableCharArrayString buf = objectPool.strPool.get();
arg.isStringValue(buf);
if (buf.equalsIgnoreCase("false") || buf.size() == 0) {
result.setBooleanValue(false);
} else {
result.setBooleanValue(true);
}
return (true);
}
case RELATIVE_TIME_VALUE: {
ClassAdTime rsecs = objectPool.classAdTimePool.get();
arg.isRelativeTimeValue(rsecs);
result.setBooleanValue(rsecs.getTimeInMillis() != 0);
return (true);
}
default:
throw new HyracksDataException("Should not reach here");
}
}
};
public static final ClassAdFunc convTime = new ClassAdFunc() {
@Override
public boolean call(String name, ExprList argList, EvalState state, Value result, ClassAdObjectPool objectPool)
throws HyracksDataException {
Value arg = objectPool.valuePool.get();
Value arg2 = objectPool.valuePool.get();
boolean relative = name.equalsIgnoreCase("reltime");
boolean secondarg = false; // says whether a 2nd argument exists
AMutableInt64 arg2num = objectPool.int64Pool.get();
arg2num.setValue(0);
if (argList.size() == 0 && !relative) {
// absTime with no arguments returns the current time.
return currentTime.call(name, argList, state, result, objectPool);
}
if ((argList.size() < 1) || (argList.size() > 2)) {
result.setErrorValue();
return (true);
}
if (!argList.get(0).publicEvaluate(state, arg)) {
result.setErrorValue();
return (false);
}
if (argList.size() == 2) { // we have a 2nd argument
secondarg = true;
if (!argList.get(1).publicEvaluate(state, arg2)) {
result.setErrorValue();
return (false);
}
AMutableInt64 ivalue2 = objectPool.int64Pool.get();
ivalue2.setValue(0);
AMutableDouble rvalue2 = objectPool.doublePool.get();
ClassAdTime rsecs = objectPool.classAdTimePool.get();
if (relative) {// 2nd argument is N/A for reltime
result.setErrorValue();
return (true);
}
// 2nd arg should be integer, real or reltime
else if (arg2.isIntegerValue(ivalue2)) {
arg2num.setValue(ivalue2.getLongValue());
} else if (arg2.isRealValue(rvalue2)) {
arg2num.setValue((long) rvalue2.getDoubleValue());
} else if (arg2.isRelativeTimeValue(rsecs)) {
arg2num.setValue(rsecs.getTimeInMillis());
} else {
result.setErrorValue();
return (true);
}
} else {
secondarg = false;
arg2num.setValue(0);
}
switch (arg.getType()) {
case UNDEFINED_VALUE:
result.setUndefinedValue();
return (true);
case ERROR_VALUE:
case CLASSAD_VALUE:
case LIST_VALUE:
case SLIST_VALUE:
case BOOLEAN_VALUE:
result.setErrorValue();
return (true);
case INTEGER_VALUE: {
AMutableInt64 ivalue = objectPool.int64Pool.get();
ivalue.setValue(0);
arg.isIntegerValue(ivalue);
if (relative) {
ClassAdTime time = objectPool.classAdTimePool.get();
time.setRelativeTime(ivalue.getLongValue());
result.setRelativeTimeValue(time);
} else {
ClassAdTime atvalue = objectPool.classAdTimePool.get();
atvalue.setValue(ivalue.getLongValue());
if (secondarg) {
atvalue.setTimeZone((int) arg2num.getLongValue());
} else {
// the default offset is the current timezone
atvalue.setTimeZone(Literal.findOffset(atvalue));
}
if (atvalue.getOffset() == -1) {
result.setErrorValue();
return (false);
} else {
result.setAbsoluteTimeValue(atvalue);
}
}
return (true);
}
case REAL_VALUE: {
AMutableDouble rvalue = objectPool.doublePool.get();
arg.isRealValue(rvalue);
if (relative) {
ClassAdTime time = objectPool.classAdTimePool.get();
time.setRelativeTime((long) (1000 * rvalue.getDoubleValue()));
result.setRelativeTimeValue(time);
} else {
ClassAdTime atvalue = objectPool.classAdTimePool.get();
atvalue.setValue((long) rvalue.getDoubleValue());
if (secondarg) {
atvalue.setTimeZone((int) arg2num.getLongValue());
} else {
// the default offset is the current timezone
atvalue.setTimeZone(Literal.findOffset(atvalue));
}
result.setAbsoluteTimeValue(atvalue);
}
return (true);
}
case STRING_VALUE: {
//should'nt come here
// a string argument to this function is transformed to a literal directly
}
case ABSOLUTE_TIME_VALUE: {
ClassAdTime secs = objectPool.classAdTimePool.get();
arg.isAbsoluteTimeValue(secs);
if (relative) {
result.setRelativeTimeValue(secs);
} else {
result.setValue(arg);
}
return (true);
}
case RELATIVE_TIME_VALUE: {
if (relative) {
result.setValue(arg);
} else {
ClassAdTime secs = objectPool.classAdTimePool.get();
arg.isRelativeTimeValue(secs);
ClassAdTime atvalue = objectPool.classAdTimePool.get();
atvalue.setValue(secs);
if (secondarg) {
atvalue.setTimeZone((int) arg2num.getLongValue());
} else {
// the default offset is the current timezone
atvalue.setTimeZone(Literal.findOffset(atvalue));
}
result.setAbsoluteTimeValue(atvalue);
}
return (true);
}
default:
throw new HyracksDataException("Should not reach here");
}
}
};
public static final ClassAdFunc doRound = new ClassAdFunc() {
@Override
public boolean call(String name, ExprList argList, EvalState state, Value result, ClassAdObjectPool objectPool)
throws HyracksDataException {
Value arg = objectPool.valuePool.get();
Value realValue = objectPool.valuePool.get();
// takes exactly one argument
if (argList.size() != 1) {
result.setErrorValue();
return (true);
}
if (!argList.get(0).publicEvaluate(state, arg)) {
result.setErrorValue();
return (false);
}
if (arg.getType() == ValueType.INTEGER_VALUE) {
result.setValue(arg);
} else {
if (!Value.convertValueToRealValue(arg, realValue, objectPool)) {
result.setErrorValue();
} else {
AMutableDouble rvalue = objectPool.doublePool.get();
realValue.isRealValue(rvalue);
if (name.equalsIgnoreCase("floor")) {
result.setIntegerValue((long) Math.floor(rvalue.getDoubleValue()));
} else if (name.equalsIgnoreCase("ceil") || name.equalsIgnoreCase("ceiling")) {
result.setIntegerValue((long) Math.ceil(rvalue.getDoubleValue()));
} else if (name.equalsIgnoreCase("round")) {
result.setIntegerValue(Math.round(rvalue.getDoubleValue()));
} else {
result.setErrorValue();
}
}
}
return true;
}
};
public static final ClassAdFunc doMath2 = new ClassAdFunc() {
@Override
public boolean call(String name, ExprList argList, EvalState state, Value result, ClassAdObjectPool objectPool)
throws HyracksDataException {
Value arg = objectPool.valuePool.get();
Value arg2 = objectPool.valuePool.get();
// takes 2 arguments pow(val,base)
if (argList.size() != 2) {
result.setErrorValue();
return (true);
}
if (!argList.get(0).publicEvaluate(state, arg) || !argList.get(1).publicEvaluate(state, arg2)) {
result.setErrorValue();
return (false);
}
if (name.equalsIgnoreCase("pow")) {
// take arg2 to the power of arg2
AMutableInt64 ival = objectPool.int64Pool.get();
ival.setValue(0);
AMutableInt64 ibase = objectPool.int64Pool.get();
ibase.setValue(0);
if (arg.isIntegerValue(ival) && arg2.isIntegerValue(ibase) && ibase.getLongValue() >= 0) {
ival.setValue((long) (Math.pow(ival.getLongValue(), ibase.getLongValue())));
result.setIntegerValue(ival.getLongValue());
} else {
Value realValue = objectPool.valuePool.get();
Value realBase = objectPool.valuePool.get();
if (!Value.convertValueToRealValue(arg, realValue, objectPool)
|| !Value.convertValueToRealValue(arg2, realBase, objectPool)) {
result.setErrorValue();
} else {
AMutableDouble rvalue = objectPool.doublePool.get();
rvalue.setValue(0);
AMutableDouble rbase = objectPool.doublePool.get();
rbase.setValue(1);
realValue.isRealValue(rvalue);
realBase.isRealValue(rbase);
result.setRealValue(Math.pow(rvalue.getDoubleValue(), rbase.getDoubleValue()));
}
}
} else if (name.equalsIgnoreCase("quantize")) {
// quantize arg1 to the next integral multiple of arg2
// if arg2 is a list, choose the first item from the list that is larger than arg1
// if arg1 is larger than all of the items in the list, the result is an error.
Value val = objectPool.valuePool.get();
Value base = objectPool.valuePool.get();
if (!Value.convertValueToRealValue(arg, val, objectPool)) {
result.setErrorValue();
} else {
// get the value to quantize into rval.
AMutableDouble rval = objectPool.doublePool.get();
AMutableDouble rbase = objectPool.doublePool.get();
val.isRealValue(rval);
if (arg2.isListValue()) {
ExprList list = objectPool.exprListPool.get();
arg2.isListValue(list);
base.setRealValue(0.0);
rbase.setValue(0.0); // treat an empty list as 'don't quantize'
for (ExprTree expr : list.getExprList()) {
if (!expr.publicEvaluate(state, base)) {
result.setErrorValue();
return false; // eval should not fail
}
if (Value.convertValueToRealValue(base, val, objectPool)) {
val.isRealValue(rbase);
if (rbase.getDoubleValue() >= rval.getDoubleValue()) {
result.setValue(base);
return true;
}
} else {
//TJ: should we ignore values that can't be converted?
result.setErrorValue();
return true;
}
}
// at this point base is the value of the last expression in the list.
// and rbase is the real value of it and rval > rbase.
// when this happens we want to quantize on multiples of the last
// list value, as if on a single value were passed rather than a list.
arg2.setValue(base);
} else {
// if arg2 is not a list, then it must evaluate to a real value
// or we can't use it. (note that if it's an int, we still want
// to return an int, but we assume that all ints can be converted to real)
if (!Value.convertValueToRealValue(arg2, base, objectPool)) {
result.setErrorValue();
return true;
}
base.isRealValue(rbase);
}
// at this point rbase should contain the real value of either arg2 or the
// last entry in the list. and rval should contain the value to be quantized.
AMutableInt64 ival = objectPool.int64Pool.get();
ival.setValue(0);
AMutableInt64 ibase = objectPool.int64Pool.get();
ibase.setValue(0);
if (arg2.isIntegerValue(ibase)) {
// quantize to an integer base,
if (ibase.getLongValue() == 0L) {
result.setValue(arg);
} else if (arg.isIntegerValue(ival)) {
ival.setValue(((ival.getLongValue() + ibase.getLongValue() - 1) / ibase.getLongValue())
* ibase.getLongValue());
result.setIntegerValue(ival.getLongValue());
} else {
rval.setValue(
Math.ceil(rval.getDoubleValue() / ibase.getLongValue()) * ibase.getLongValue());
result.setRealValue(rval);
}
} else {
double epsilon = 1e-8;
if (rbase.getDoubleValue() >= -epsilon && rbase.getDoubleValue() <= epsilon) {
result.setValue(arg);
} else {
// we already have the real-valued base in rbase so just use it here.
rval.setValue(
Math.ceil(rval.getDoubleValue() / rbase.getDoubleValue()) * rbase.getDoubleValue());
result.setRealValue(rval);
}
}
}
} else {
// unknown 2 argument math function
result.setErrorValue();
}
return true;
}
};
public static final ClassAdFunc random = new ClassAdFunc() {
private Random randomGenerator = new Random(System.currentTimeMillis());
@Override
public boolean call(String name, ExprList argList, EvalState state, Value result, ClassAdObjectPool objectPool)
throws HyracksDataException {
Value arg = objectPool.valuePool.get();;
// takes exactly one argument
if (argList.size() > 1) {
result.setErrorValue();
return (true);
} else if (argList.size() == 0) {
arg.setRealValue(1.0);
} else if (!argList.get(0).publicEvaluate(state, arg)) {
result.setErrorValue();
return (false);
}
AMutableInt64 int_max = objectPool.int64Pool.get();
int_max.setValue(0);
AMutableDouble double_max = objectPool.doublePool.get();
if (arg.isIntegerValue(int_max)) {
int random_int = randomGenerator.nextInt((int) int_max.getLongValue());
result.setIntegerValue(random_int);
} else if (arg.isRealValue(double_max)) {
double random_double = double_max.getDoubleValue() * randomGenerator.nextDouble();
result.setRealValue(random_double);
} else {
result.setErrorValue();
}
return true;
}
};
public static final ClassAdFunc ifThenElse = new ClassAdFunc() {
@Override
public boolean call(String name, ExprList argList, EvalState state, Value result, ClassAdObjectPool objectPool)
throws HyracksDataException {
Value arg1 = objectPool.valuePool.get();
MutableBoolean arg1_bool = objectPool.boolPool.get();
// takes exactly three arguments
if (argList.size() != 3) {
result.setErrorValue();
return (true);
}
if (!argList.get(0).publicEvaluate(state, arg1)) {
result.setErrorValue();
return (false);
}
switch (arg1.getType()) {
case BOOLEAN_VALUE:
if (!arg1.isBooleanValue(arg1_bool)) {
result.setErrorValue();
return (false);
}
break;
case INTEGER_VALUE: {
AMutableInt64 intval = objectPool.int64Pool.get();
intval.setValue(0);
if (!arg1.isIntegerValue(intval)) {
result.setErrorValue();
return (false);
}
arg1_bool.setValue(intval.getLongValue() != 0L);
break;
}
case REAL_VALUE: {
AMutableDouble realval = objectPool.doublePool.get();
if (!arg1.isRealValue(realval)) {
result.setErrorValue();
return (false);
}
arg1_bool.setValue(realval.getDoubleValue() != 0.0);
break;
}
case UNDEFINED_VALUE:
result.setUndefinedValue();
return (true);
case ERROR_VALUE:
case CLASSAD_VALUE:
case LIST_VALUE:
case SLIST_VALUE:
case STRING_VALUE:
case ABSOLUTE_TIME_VALUE:
case RELATIVE_TIME_VALUE:
case NULL_VALUE:
result.setErrorValue();
return (true);
}
if (arg1_bool.booleanValue()) {
if (!argList.get(1).publicEvaluate(state, result)) {
result.setErrorValue();
return (false);
}
} else {
if (!argList.get(2).publicEvaluate(state, result)) {
result.setErrorValue();
return (false);
}
}
return true;
}
};
public static final ClassAdFunc stringListsIntersect = new ClassAdFunc() {
@Override
public boolean call(String name, ExprList argList, EvalState state, Value result, ClassAdObjectPool objectPool)
throws HyracksDataException {
Value arg0 = objectPool.valuePool.get();
Value arg1 = objectPool.valuePool.get();
Value arg2 = objectPool.valuePool.get();
boolean have_delimiter;
AMutableCharArrayString str0 = objectPool.strPool.get();
AMutableCharArrayString str1 = objectPool.strPool.get();
AMutableCharArrayString delimiter_string = objectPool.strPool.get();
// need two or three arguments: pattern, list, optional settings
if (argList.size() != 2 && argList.size() != 3) {
result.setErrorValue();
return true;
}
if (argList.size() == 2) {
have_delimiter = false;
} else {
have_delimiter = true;
}
// Evaluate args
if (!argList.get(0).publicEvaluate(state, arg0) || !argList.get(1).publicEvaluate(state, arg1)) {
result.setErrorValue();
return true;
}
if (have_delimiter && !argList.get(2).publicEvaluate(state, arg2)) {
result.setErrorValue();
return true;
}
// if either arg is error, the result is error
if (arg0.isErrorValue() || arg1.isErrorValue()) {
result.setErrorValue();
return true;
}
if (have_delimiter && arg2.isErrorValue()) {
result.setErrorValue();
return true;
}
// if either arg is undefined, the result is undefined
if (arg0.isUndefinedValue() || arg1.isUndefinedValue()) {
result.setUndefinedValue();
return true;
}
if (have_delimiter && arg2.isUndefinedValue()) {
result.setUndefinedValue();
return true;
} else if (have_delimiter && !arg2.isStringValue(delimiter_string)) {
result.setErrorValue();
return true;
}
// if the arguments are not of the correct types, the result
// is an error
if (!arg0.isStringValue(str0) || !arg1.isStringValue(str1)) {
result.setErrorValue();
return true;
}
result.setBooleanValue(false);
List<String> list0 = objectPool.stringArrayListPool.get();
Set<String> set1 = new HashSet<String>();
split_string_list(str0, have_delimiter ? delimiter_string.charAt(0) : ',', list0);
split_string_set(str1, have_delimiter ? delimiter_string.charAt(0) : ',', set1);
for (String str : list0) {
if (set1.contains(str)) {
result.setBooleanValue(true);
break;
}
}
return true;
}
};
public static final ClassAdFunc interval = new ClassAdFunc() {
@Override
public boolean call(String name, ExprList argList, EvalState state, Value result, ClassAdObjectPool objectPool)
throws HyracksDataException {
Value arg = objectPool.valuePool.get();
Value intarg = objectPool.valuePool.get();
AMutableInt64 tot_secs = objectPool.int64Pool.get();
tot_secs.setValue(0);
// takes exactly one argument
if (argList.size() != 1) {
result.setErrorValue();
return (true);
}
if (!argList.get(0).publicEvaluate(state, arg)) {
result.setErrorValue();
return (false);
}
if (!Value.convertValueToIntegerValue(arg, intarg, objectPool)) {
result.setErrorValue();
return (true);
}
if (!intarg.isIntegerValue(tot_secs)) {
result.setErrorValue();
return (true);
}
long days = tot_secs.getLongValue() / (3600 * 24);
tot_secs.setValue(tot_secs.getLongValue() % (3600 * 24));
long hours = tot_secs.getLongValue() / 3600;
tot_secs.setValue(tot_secs.getLongValue() % 3600);
long min = tot_secs.getLongValue() / 60;
long secs = tot_secs.getLongValue() % 60;
String strval;
if (days != 0) {
strval = String.format("%d+%02d:%02d:%02d", days, Math.abs(hours), Math.abs(min), Math.abs(secs));
} else if (hours != 0) {
strval = String.format("%d:%02d:%02d", hours, Math.abs(min), Math.abs(secs));
} else if (min != 0) {
strval = String.format("%d:%02d", min, Math.abs(secs));
} else {
strval = String.format("%d", secs);
}
result.setStringValue(strval);
return true;
}
};
public static final ClassAdFunc eval = new ClassAdFunc() {
@Override
public boolean call(String name, ExprList argList, EvalState state, Value result, ClassAdObjectPool objectPool)
throws HyracksDataException {
Value arg = objectPool.valuePool.get();
Value strarg = objectPool.valuePool.get();
// takes exactly one argument
if (argList.size() != 1) {
result.setErrorValue();
return true;
}
if (!argList.get(0).publicEvaluate(state, arg)) {
result.setErrorValue();
return false;
}
ClassAdParser parser = objectPool.classAdParserPool.get();
ExprTreeHolder expr = objectPool.mutableExprPool.get();
AMutableCharArrayString s = objectPool.strPool.get();
if (!Value.convertValueToStringValue(arg, strarg, objectPool) || !strarg.isStringValue(s)) {
result.setErrorValue();
return true;
}
if (state.getDepthRemaining() <= 0) {
result.setErrorValue();
return false;
}
expr.reset();
try {
if (!parser.parseExpression(s.toString(), expr, true) || (expr.getInnerTree() == null)) {
result.setErrorValue();
return true;
}
} catch (IOException e) {
throw new HyracksDataException(e);
}
state.decrementDepth();
expr.setParentScope(state.getCurAd());
boolean eval_ok = expr.publicEvaluate(state, result);
state.incrementDepth();
if (!eval_ok) {
result.setErrorValue();
return false;
}
return true;
}
};
public static void split_string_list(AMutableCharArrayString amutableString, char delim, List<String> list) {
if (amutableString.getLength() == 0) {
return;
}
int index = 0;
int lastIndex = 0;
while (index < amutableString.getLength()) {
index = amutableString.firstIndexOf(delim, lastIndex);
if (index > 0) {
list.add(amutableString.substr(lastIndex, index - lastIndex).trim());
lastIndex = index + 1;
} else {
if (amutableString.getLength() > lastIndex) {
list.add(amutableString.substr(lastIndex).trim());
}
break;
}
}
}
public static void split_string_set(AMutableCharArrayString amutableString, char delim, Set<String> set) {
if (amutableString.getLength() == 0) {
return;
}
int index = 0;
int lastIndex = 0;
while (index < amutableString.getLength()) {
index = amutableString.firstIndexOf(delim, lastIndex);
if (index > 0) {
set.add(amutableString.substr(lastIndex, index - lastIndex).trim());
lastIndex = index + 1;
} else {
if (amutableString.getLength() > lastIndex) {
set.add(amutableString.substr(lastIndex).trim());
}
break;
}
}
}
}