You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@asterixdb.apache.org by am...@apache.org on 2016/02/22 23:35:03 UTC
[15/34] incubator-asterixdb git commit: Enabled Feed Tests and Added
External Library tests
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/ac683db0/asterix-external-data/src/test/java/org/apache/asterix/external/classad/BuiltinClassAdFunctions.java
----------------------------------------------------------------------
diff --git a/asterix-external-data/src/test/java/org/apache/asterix/external/classad/BuiltinClassAdFunctions.java b/asterix-external-data/src/test/java/org/apache/asterix/external/classad/BuiltinClassAdFunctions.java
new file mode 100644
index 0000000..97ebd6c
--- /dev/null
+++ b/asterix-external-data/src/test/java/org/apache/asterix/external/classad/BuiltinClassAdFunctions.java
@@ -0,0 +1,1927 @@
+/*
+ * 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.ArrayList;
+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.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) 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) throws HyracksDataException {
+ Value arg0 = new Value();
+ Value arg1 = new Value();
+ Value cArg = new Value();
+
+ ExprList el = new ExprList();
+ MutableBoolean b = new MutableBoolean();
+ 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 = new Value();
+ swap.copyFrom(arg0);
+ arg0.copyFrom(arg1);
+ arg1.copyFrom(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);
+ 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) throws HyracksDataException {
+ Value arg = new Value();
+ ExprList listToSize = new ExprList();
+ ClassAd classadToSize = new ClassAd();
+ AMutableInt32 length = new AMutableInt32(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) throws HyracksDataException {
+
+ Value listElementValue = new Value();
+ Value listVal = new Value();
+ Value numElements = new Value();
+ Value result = new Value();
+ ExprList listToSum = new ExprList();
+ MutableBoolean first = new MutableBoolean();
+ AMutableInt64 len = new AMutableInt64(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.copyFrom(listElementValue);
+ first.setValue(false);
+ } else {
+ Operation.operate(Operation.OpKind_ADDITION_OP, result, listElementValue, result);
+ }
+
+ }
+
+ // if the sum() function was called, we don't need to find the average
+ if (onlySum) {
+ val.copyFrom(result);
+ return true;
+ }
+
+ if (len.getLongValue() > 0) {
+ numElements.setRealValue(len.getLongValue());
+ Operation.operate(Operation.OpKind_DIVISION_OP, result, numElements, result);
+ } else {
+ val.setUndefinedValue();
+ }
+
+ val.copyFrom(result);
+ return true;
+ }
+
+ };
+ public static final ClassAdFunc MinMax = new ClassAdFunc() {
+
+ @Override
+ public boolean call(String fn, ExprList argList, EvalState state, Value val) throws HyracksDataException {
+ Value listElementValue = new Value();
+ Value listVal = new Value();
+ Value cmp = new Value();
+ Value result = new Value();
+ ExprList listToBound = new ExprList();
+ boolean first = true;
+ MutableBoolean b = new MutableBoolean(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.copyFrom(listElementValue);
+ first = false;
+ } else {
+ Operation.operate(comparisonOperator, listElementValue, result, cmp);
+ if (cmp.isBooleanValue(b) && b.booleanValue()) {
+ result.copyFrom(listElementValue);
+ }
+ }
+ }
+
+ val.copyFrom(result);
+ return true;
+ }
+
+ };
+ public static final ClassAdFunc ListCompare = new ClassAdFunc() {
+
+ @Override
+ public boolean call(String fn, ExprList argList, EvalState state, Value val) throws HyracksDataException {
+
+ Value listElementValue = new Value();
+ Value listVal = new Value();
+ Value compareVal = new Value();
+ Value stringValue = new Value();
+ ExprList listToCompare = new ExprList();
+ boolean needAllMatch;
+ AMutableCharArrayString comparison_string = new AMutableCharArrayString();
+ 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 = new Value();
+ MutableBoolean b = new MutableBoolean();
+
+ Operation.operate(comparisonOperator, listElementValue, compareVal, compareResult);
+ 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) throws HyracksDataException {
+ // no arguments
+ if (argList.size() > 0) {
+ val.setErrorValue();
+ return (true);
+ }
+ val.setRelativeTimeValue(new ClassAdTime());
+ return (true);
+ }
+ };
+ public static final ClassAdFunc debug = new ClassAdFunc() {
+ @Override
+ public boolean call(String name, ExprList argList, EvalState state, Value result) throws HyracksDataException {
+ return false;
+ }
+ };
+ public static final ClassAdFunc formatTime = new ClassAdFunc() {
+
+ @Override
+ public boolean call(String name, ExprList argList, EvalState state, Value result) throws HyracksDataException {
+ Value time_arg = new Value();
+ Value format_arg = new Value();
+ AMutableInt64 int64 = new AMutableInt64(0);
+ ClassAdTime epoch_time = new ClassAdTime();
+ ClassAdTime time_components = new ClassAdTime("GMT");
+ ClassAd splitClassAd = new ClassAd();
+ 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 = new AMutableCharArrayString();
+ 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) throws HyracksDataException {
+ Value arg = new Value();
+ ClassAdTime asecs = new ClassAdTime();
+ ClassAdTime rsecs = new ClassAdTime();
+ ClassAdTime clock = new ClassAdTime();
+ ClassAdTime tms = new ClassAdTime();
+
+ 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) throws HyracksDataException {
+ // no arguments
+ if (argList.size() > 0) {
+ val.setErrorValue();
+ return (true);
+ }
+ Literal time_literal = Literal.createAbsTime(new ClassAdTime());
+ 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) throws HyracksDataException {
+ Value arg = new Value();
+ ClassAd split = new ClassAd();
+
+ 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)) {
+ result.setClassAdValue(split);
+ } else {
+ result.setErrorValue();
+ }
+ return true;
+ }
+
+ };
+
+ public static boolean doSplitTime(Value time, ClassAd splitClassAd) throws HyracksDataException {
+ boolean did_conversion;
+ AMutableInt64 integer = new AMutableInt64(0);
+ AMutableDouble real = new AMutableDouble(0);
+ ClassAdTime asecs = new ClassAdTime();
+ ClassAdTime rsecs = new ClassAdTime();
+ ClassAd classad = new ClassAd();
+ 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 = new ClassAd();
+ 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) throws HyracksDataException {
+ val.setRelativeTimeValue(new ClassAdTime());
+ return (true);
+ }
+ };
+ public static final ClassAdFunc epochTime = new ClassAdFunc() {
+ @Override
+ public boolean call(String name, ExprList argList, EvalState state, Value val) 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) throws HyracksDataException {
+ AMutableCharArrayString buf = new AMutableCharArrayString();
+ AMutableCharArrayString s = new AMutableCharArrayString();
+ boolean errorFlag = false;
+ boolean undefFlag = false;
+ boolean rval = false;
+
+ Value val = new Value();
+ Value stringVal = new Value();
+
+ 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);
+ 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) throws HyracksDataException {
+ Value val = new Value();
+ Value stringVal = new Value();
+ AMutableCharArrayString str = new AMutableCharArrayString();
+ 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);
+ 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) throws HyracksDataException {
+ Value arg0 = new Value();
+ Value arg1 = new Value();
+ Value arg2 = new Value();
+ AMutableCharArrayString buf = new AMutableCharArrayString();
+ AMutableInt64 offset = new AMutableInt64(0);
+ AMutableInt64 len = new AMutableInt64(0);
+ AMutableInt64 alen = new AMutableInt64(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 = new AMutableInt64(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) throws HyracksDataException {
+ Value arg = new Value();
+ // 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);
+ return true;
+ }
+ };
+ public static final ClassAdFunc compareString = new ClassAdFunc() {
+
+ @Override
+ public boolean call(String name, ExprList argList, EvalState state, Value result) throws HyracksDataException {
+ Value arg0 = new Value();
+ Value arg1 = new Value();
+ Value arg0_s = new Value();
+ Value arg1_s = new Value();
+
+ // 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 = new AMutableCharArrayString();
+ AMutableCharArrayString s1 = new AMutableCharArrayString();
+ if (Value.convertValueToStringValue(arg0, arg0_s) && Value.convertValueToStringValue(arg1, arg1_s)
+ && 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) throws HyracksDataException {
+ boolean have_options;
+ Value arg0 = new Value();
+ Value arg1 = new Value();
+ Value arg2 = new Value();
+
+ AMutableCharArrayString pattern = new AMutableCharArrayString();
+ AMutableCharArrayString target = new AMutableCharArrayString();
+ AMutableCharArrayString options_string = new AMutableCharArrayString();
+
+ // 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) throws HyracksDataException {
+ Value arg = new Value();
+
+ // 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);
+ return true;
+ }
+ };
+ public static final ClassAdFunc convString = new ClassAdFunc() {
+
+ @Override
+ public boolean call(String name, ExprList argList, EvalState state, Value result) throws HyracksDataException {
+ Value arg = new Value();
+
+ // 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);
+ return true;
+ }
+ };
+ public static final ClassAdFunc unparse = new ClassAdFunc() {
+ @Override
+ public boolean call(String name, ExprList argList, EvalState state, Value result) 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 = new PrettyPrint();
+ AMutableCharArrayString szAttribute = new AMutableCharArrayString();
+ AMutableCharArrayString szValue = new AMutableCharArrayString();
+ 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) throws HyracksDataException {
+ Value arg = new Value();
+ // 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.copyFrom(arg);
+ return (true);
+
+ case INTEGER_VALUE: {
+ AMutableInt64 ival = new AMutableInt64(0);
+ arg.isIntegerValue(ival);
+ result.setBooleanValue(ival.getLongValue() != 0);
+ return (true);
+ }
+
+ case REAL_VALUE: {
+ AMutableDouble rval = new AMutableDouble(0);
+ arg.isRealValue(rval);
+ result.setBooleanValue(rval.getDoubleValue() != 0.0);
+ return (true);
+ }
+
+ case STRING_VALUE: {
+ AMutableCharArrayString buf = new AMutableCharArrayString();
+ 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 = new ClassAdTime();
+ 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) throws HyracksDataException {
+ Value arg = new Value();
+ Value arg2 = new Value();
+ boolean relative = name.equalsIgnoreCase("reltime");
+ boolean secondarg = false; // says whether a 2nd argument exists
+ AMutableInt64 arg2num = new AMutableInt64(0);
+
+ if (argList.size() == 0 && !relative) {
+ // absTime with no arguments returns the current time.
+ return currentTime.call(name, argList, state, result);
+ }
+ 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 = new AMutableInt64(0);
+ AMutableDouble rvalue2 = new AMutableDouble(0);
+ ClassAdTime rsecs = new ClassAdTime();
+ 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 = new AMutableInt64(0);
+ arg.isIntegerValue(ivalue);
+ if (relative) {
+ result.setRelativeTimeValue(new ClassAdTime(ivalue.getLongValue(), false));
+ } else {
+ ClassAdTime atvalue = new ClassAdTime(true);
+ atvalue.setValue(ivalue.getLongValue());
+ if (secondarg) //2nd arg is the offset in secs
+ 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 = new AMutableDouble(0);
+ arg.isRealValue(rvalue);
+ if (relative) {
+ result.setRelativeTimeValue(new ClassAdTime((long) (1000 * rvalue.getDoubleValue()), false));
+ } else {
+ ClassAdTime atvalue = new ClassAdTime();
+ atvalue.setValue((long) rvalue.getDoubleValue());
+ if (secondarg) //2nd arg is the offset in secs
+ 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 = new ClassAdTime();
+ arg.isAbsoluteTimeValue(secs);
+ if (relative) {
+ result.setRelativeTimeValue(secs);
+ } else {
+ result.copyFrom(arg);
+ }
+ return (true);
+ }
+ case RELATIVE_TIME_VALUE: {
+ if (relative) {
+ result.copyFrom(arg);
+ } else {
+ ClassAdTime secs = new ClassAdTime();
+ arg.isRelativeTimeValue(secs);
+ ClassAdTime atvalue = new ClassAdTime();
+ atvalue.setValue(secs);
+ if (secondarg) //2nd arg is the offset in secs
+ 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) throws HyracksDataException {
+ Value arg = new Value();
+ Value realValue = new Value();
+ // 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.copyFrom(arg);
+ } else {
+ if (!Value.convertValueToRealValue(arg, realValue)) {
+ result.setErrorValue();
+ } else {
+ AMutableDouble rvalue = new AMutableDouble(0);
+ 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) throws HyracksDataException {
+ Value arg = new Value();
+ Value arg2 = new Value();
+
+ // 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 = new AMutableInt64(0);
+ AMutableInt64 ibase = new AMutableInt64(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 = new Value();
+ Value realBase = new Value();
+ if (!Value.convertValueToRealValue(arg, realValue)
+ || !Value.convertValueToRealValue(arg2, realBase)) {
+ result.setErrorValue();
+ } else {
+ AMutableDouble rvalue = new AMutableDouble(0);
+ AMutableDouble rbase = new AMutableDouble(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 = new Value();
+ Value base = new Value();
+ if (!Value.convertValueToRealValue(arg, val)) {
+ result.setErrorValue();
+ } else {
+ // get the value to quantize into rval.
+ AMutableDouble rval = new AMutableDouble(0);
+ AMutableDouble rbase = new AMutableDouble(0);
+ val.isRealValue(rval);
+ if (arg2.isListValue()) {
+ ExprList list = new ExprList();
+ 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)) {
+ 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)) {
+ 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 = new AMutableInt64(0);
+ AMutableInt64 ibase = new AMutableInt64(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() {
+
+ @Override
+ public boolean call(String name, ExprList argList, EvalState state, Value result) throws HyracksDataException {
+ Value arg = new Value();;
+ // 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 = new AMutableInt64(0);
+ AMutableDouble double_max = new AMutableDouble(0);
+ Random randomGenerator = new Random(System.currentTimeMillis());
+ 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) throws HyracksDataException {
+ Value arg1 = new Value();
+ MutableBoolean arg1_bool = new MutableBoolean();
+ // 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 = new AMutableInt64(0);
+ if (!arg1.isIntegerValue(intval)) {
+ result.setErrorValue();
+ return (false);
+ }
+ arg1_bool.setValue(intval.getLongValue() != 0L);
+ break;
+ }
+ case REAL_VALUE: {
+ AMutableDouble realval = new AMutableDouble(0);
+ 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) throws HyracksDataException {
+ Value arg0 = new Value();
+ Value arg1 = new Value();
+ Value arg2 = new Value();
+ boolean have_delimiter;
+ AMutableCharArrayString str0 = new AMutableCharArrayString();
+ AMutableCharArrayString str1 = new AMutableCharArrayString();
+ AMutableCharArrayString delimiter_string = new AMutableCharArrayString();
+
+ // 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 = new ArrayList<String>();
+ 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) throws HyracksDataException {
+ Value arg = new Value();
+ Value intarg = new Value();
+ AMutableInt64 tot_secs = new AMutableInt64(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)) {
+ 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) throws HyracksDataException {
+ Value arg = new Value();
+ Value strarg = new Value();
+ // takes exactly one argument
+ if (argList.size() != 1) {
+ result.setErrorValue();
+ return true;
+ }
+ if (!argList.get(0).publicEvaluate(state, arg)) {
+ result.setErrorValue();
+ return false;
+ }
+ AMutableCharArrayString s = new AMutableCharArrayString();
+ if (!Value.convertValueToStringValue(arg, strarg) || !strarg.isStringValue(s)) {
+ result.setErrorValue();
+ return true;
+ }
+ if (state.getDepthRemaining() <= 0) {
+ result.setErrorValue();
+ return false;
+ }
+ ClassAdParser parser = new ClassAdParser();
+ ExprTreeHolder expr = new ExprTreeHolder();
+ 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;
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/ac683db0/asterix-external-data/src/test/java/org/apache/asterix/external/classad/CaseInsensitiveString.java
----------------------------------------------------------------------
diff --git a/asterix-external-data/src/test/java/org/apache/asterix/external/classad/CaseInsensitiveString.java b/asterix-external-data/src/test/java/org/apache/asterix/external/classad/CaseInsensitiveString.java
new file mode 100644
index 0000000..ecc69f8
--- /dev/null
+++ b/asterix-external-data/src/test/java/org/apache/asterix/external/classad/CaseInsensitiveString.java
@@ -0,0 +1,61 @@
+/*
+ * 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;
+
+public class CaseInsensitiveString implements Comparable<CaseInsensitiveString> {
+ private String aString;
+
+ public String get() {
+ return aString;
+ }
+
+ @Override
+ public String toString() {
+ return aString;
+ }
+
+ public void set(String aString) {
+ this.aString = aString;
+ }
+
+ public CaseInsensitiveString(String aString) {
+ this.aString = aString;
+ }
+
+ public CaseInsensitiveString() {
+ this.aString = null;
+ }
+
+ @Override
+ public int compareTo(CaseInsensitiveString o) {
+ return aString.compareToIgnoreCase(o.aString);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return (o instanceof CaseInsensitiveString) ? aString.equalsIgnoreCase(((CaseInsensitiveString) o).aString)
+ : false;
+ }
+
+ @Override
+ public int hashCode() {
+ return aString.toLowerCase().hashCode();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-asterixdb/blob/ac683db0/asterix-external-data/src/test/java/org/apache/asterix/external/classad/CharArrayLexerSource.java
----------------------------------------------------------------------
diff --git a/asterix-external-data/src/test/java/org/apache/asterix/external/classad/CharArrayLexerSource.java b/asterix-external-data/src/test/java/org/apache/asterix/external/classad/CharArrayLexerSource.java
new file mode 100644
index 0000000..3501953
--- /dev/null
+++ b/asterix-external-data/src/test/java/org/apache/asterix/external/classad/CharArrayLexerSource.java
@@ -0,0 +1,86 @@
+/*
+ * 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;
+
+public class CharArrayLexerSource extends LexerSource {
+
+ private char[] input;
+ private int offset;
+
+ @Override
+ public int getPosition() {
+ return offset;
+ }
+
+ public CharArrayLexerSource() {
+ offset = 0;
+ input = null;
+ }
+
+ public CharArrayLexerSource(char[] input, int offset) {
+ SetNewSource(input, offset);
+ }
+
+ private void SetNewSource(char[] input, int offset2) {
+ this.input = input;
+ this.offset = offset2;
+ }
+
+ @Override
+ public char readCharacter() throws IOException {
+ if (offset == input.length) {
+ previousCharacter = Lexer.EOF;
+ return previousCharacter;
+ } else {
+ previousCharacter = input[offset];
+ offset++;
+ return previousCharacter;
+ }
+ }
+
+ @Override
+ public void unreadCharacter() {
+ if (offset > 0) {
+ if (previousCharacter != Lexer.EOF) {
+ offset--;
+ }
+ }
+ }
+
+ @Override
+ public boolean atEnd() {
+ return offset == input.length;
+ }
+
+ public int GetCurrentLocation() {
+ return offset;
+ }
+
+ @Override
+ public void setNewSource(char[] buffer) {
+ SetNewSource(buffer, 0);
+ }
+
+ @Override
+ public char[] getBuffer() {
+ return input;
+ }
+}