Java tutorial
/* * 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 asterix.parser.classad; import org.apache.asterix.om.base.AMutableDouble; import org.apache.asterix.om.base.AMutableInt32; import org.apache.asterix.om.base.AMutableInt64; import asterix.parser.classad.Value.ValueType; import org.apache.commons.lang3.mutable.MutableBoolean; import org.apache.hyracks.api.exceptions.HyracksDataException; /** * Represents a node of the expression tree which is an operation applied to * expression operands, like 3 + 2 */ public class Operation extends ExprTree { enum SigValues { SIG_NONE, SIG_CHLD1, SIG_CHLD2, SIG_DUMMY, SIG_CHLD3 }; /// List of supported operators public static final int OpKind_NO_OP = 0; public static final int OpKind_FIRST_OP = 1; // Comparison public static final int OpKind_COMPARISON_START = OpKind_FIRST_OP; /** @name Strict comparison operators */ public static final int OpKind_LESS_THAN_OP = OpKind_COMPARISON_START; public static final int OpKind_LESS_OR_EQUAL_OP = OpKind_LESS_THAN_OP + 1; public static final int OpKind_NOT_EQUAL_OP = OpKind_LESS_OR_EQUAL_OP + 1; public static final int OpKind_EQUAL_OP = OpKind_NOT_EQUAL_OP + 1; public static final int OpKind_GREATER_OR_EQUAL_OP = OpKind_EQUAL_OP + 1; public static final int OpKind_GREATER_THAN_OP = OpKind_GREATER_OR_EQUAL_OP + 1; /** @name Non-strict comparison operators */ public static final int OpKind_META_EQUAL_OP = OpKind_GREATER_THAN_OP + 1; public static final int OpKind_IS_OP = OpKind_META_EQUAL_OP; public static final int OpKind_META_NOT_EQUAL_OP = OpKind_IS_OP + 1; public static final int OpKind_ISNT_OP = OpKind_META_NOT_EQUAL_OP; public static final int OpKind_COMPARISON_END = OpKind_ISNT_OP; /** @name Arithmetic operators */ public static final int OpKind_ARITHMETIC_START = OpKind_COMPARISON_END + 1; public static final int OpKind_UNARY_PLUS_OP = OpKind_ARITHMETIC_START; public static final int OpKind_UNARY_MINUS_OP = OpKind_UNARY_PLUS_OP + 1; public static final int OpKind_ADDITION_OP = OpKind_UNARY_MINUS_OP + 1; public static final int OpKind_SUBTRACTION_OP = OpKind_ADDITION_OP + 1; public static final int OpKind_MULTIPLICATION_OP = OpKind_SUBTRACTION_OP + 1; public static final int OpKind_DIVISION_OP = OpKind_MULTIPLICATION_OP + 1; public static final int OpKind_MODULUS_OP = OpKind_DIVISION_OP + 1; public static final int OpKind_ARITHMETIC_END = OpKind_MODULUS_OP; /** @name Logical operators */ public static final int OpKind_LOGIC_START = OpKind_ARITHMETIC_END + 1; public static final int OpKind_LOGICAL_NOT_OP = OpKind_LOGIC_START; public static final int OpKind_LOGICAL_OR_OP = OpKind_LOGICAL_NOT_OP + 1; public static final int OpKind_LOGICAL_AND_OP = OpKind_LOGICAL_OR_OP + 1; public static final int OpKind_LOGIC_END = OpKind_LOGICAL_AND_OP; /** @name Bitwise operators */ public static final int OpKind_BITWISE_START = OpKind_LOGIC_END + 1; public static final int OpKind_BITWISE_NOT_OP = OpKind_BITWISE_START; public static final int OpKind_BITWISE_OR_OP = OpKind_BITWISE_NOT_OP + 1; public static final int OpKind_BITWISE_XOR_OP = OpKind_BITWISE_OR_OP + 1; public static final int OpKind_BITWISE_AND_OP = OpKind_BITWISE_XOR_OP + 1; public static final int OpKind_LEFT_SHIFT_OP = OpKind_BITWISE_AND_OP + 1; public static final int OpKind_RIGHT_SHIFT_OP = OpKind_LEFT_SHIFT_OP + 1; public static final int OpKind_URIGHT_SHIFT_OP = OpKind_RIGHT_SHIFT_OP + 1; public static final int OpKind_BITWISE_END = OpKind_URIGHT_SHIFT_OP; /** @name Miscellaneous operators */ public static final int OpKind_MISC_START = OpKind_BITWISE_END + 1; public static final int OpKind_PARENTHESES_OP = OpKind_MISC_START; public static final int OpKind_SUBSCRIPT_OP = OpKind_PARENTHESES_OP + 1; public static final int OpKind_TERNARY_OP = OpKind_SUBSCRIPT_OP + 1; public static final int OpKind_MISC_END = OpKind_TERNARY_OP; public static final int OpKind_LAST_OP = OpKind_MISC_END; private int opKind; private ExprTree child1; private ExprTree child2; private ExprTree child3; /// node type @Override public NodeKind getKind() { return NodeKind.OP_NODE; } public int getOpKind() { return opKind; } /** * Factory method to create an operation expression node * * @param kind * The kind of operation. * @param e1 * The first sub-expression child of the node. * @param e2 * The second sub-expression child of the node (if any). * @param e3 * The third sub-expression child of the node (if any). * @return The constructed operation */ public static Operation createOperation(int opkind, ExprTree e1, ExprTree e2) { return createOperation(opkind, e1, e2, null); } public static Operation createOperation(int opkind, ExprTree e1) { return createOperation(opkind, e1, null, null); } // public access to operation function /** * Convenience method which operates on binary operators. * * @param op * The kind of operation. * @param op1 * The first operand. * @param op2 * The second operand. * @param result * The result of the operation. * @see OpKind, Value */ /** * Convenience method which operates on ternary operators. * * @param op * The kind of operation. * @param op1 * The first operand. * @param op2 * The second operand. * @param op3 * The third operand. * @param result * The result of the operation. * @see OpKind, Value */ /** * Predicate which tests if an operator is strict. * * @param op * The operator to be tested. * @return true if the operator is strict, false otherwise. */ public Operation() { opKind = OpKind_NO_OP; child1 = null; child2 = null; child3 = null; } public Operation(Operation op) throws HyracksDataException { copyFrom(op); return; } public ExprTree copy() throws HyracksDataException { Operation newTree = new Operation(); newTree.copyFrom(this); return newTree; } public boolean copyFrom(Operation op) throws HyracksDataException { boolean success = true; if (op.child1 == null) { child1 = null; } else { if (child1 == null) { child1 = new ExprTreeHolder(); } child1.copyFrom(op.child1); child1 = child1.self(); } if (op.child2 == null) { child2 = null; } else { if (child2 == null) { child2 = new ExprTreeHolder(); } child2.copyFrom(op.child2); child2 = child2.self(); } if (op.child3 == null) { child3 = null; } else { if (child3 == null) { child3 = new ExprTreeHolder(); } child3.copyFrom(op.child3); child3 = child3.self(); } this.opKind = op.opKind; super.copyFrom(op); return success; } @Override public boolean sameAs(ExprTree tree) { boolean is_same = false; Operation other_op; ExprTree pSelfTree = tree.self(); if (pSelfTree.getKind() != NodeKind.OP_NODE) { is_same = false; } else { other_op = (Operation) pSelfTree; if (opKind == other_op.opKind && sameChild(child1, other_op.child1) && sameChild(child2, other_op.child2) && sameChild(child3, other_op.child3)) { is_same = true; } else { is_same = false; } } return is_same; } public boolean sameChild(ExprTree tree1, ExprTree tree2) { boolean is_same = false; if (tree1 == null) { if (tree2 == null) { is_same = true; } else { is_same = false; } } else if (tree2 == null) { is_same = false; } else { is_same = tree1.sameAs(tree2); } return is_same; } public void privateSetParentScope(ClassAd parent) { if (child1 != null) { child1.setParentScope(parent); } if (child2 != null) { child2.setParentScope(parent); } if (child3 != null) { child3.setParentScope(parent); } } public static void operate(int opKind, Value op1, Value op2, Value result) throws HyracksDataException { Value dummy = new Value(); privateDoOperation(opKind, op1, op2, dummy, true, true, false, result, null); } public void operate(int op, Value op1, Value op2, Value op3, Value result) throws HyracksDataException { privateDoOperation(op, op1, op2, op3, true, true, true, result, null); } public static int privateDoOperation(int op, Value val1, Value val2, Value val3, boolean valid1, boolean valid2, boolean valid3, Value result) throws HyracksDataException { return privateDoOperation(op, val1, val2, val3, valid1, valid2, valid3, result, null); } public static int privateDoOperation(int op, Value val1, Value val2, Value val3, boolean valid1, boolean valid2, boolean valid3, Value result, EvalState es) throws HyracksDataException { ValueType vt1; ValueType vt2; ValueType vt3; // get the types of the values vt1 = val1.getType(); vt2 = val2.getType(); vt3 = val3.getType(); // take care of the easy cases if (op == OpKind_NO_OP || op == OpKind_PARENTHESES_OP) { result.copyFrom(val1); return SigValues.SIG_CHLD1.ordinal(); } else if (op == OpKind_UNARY_PLUS_OP) { if (vt1 == ValueType.BOOLEAN_VALUE || vt1 == ValueType.STRING_VALUE || val1.isListValue() || vt1 == ValueType.CLASSAD_VALUE || vt1 == ValueType.ABSOLUTE_TIME_VALUE) { result.setErrorValue(); } else { // applies for ERROR, UNDEFINED and Numbers result.copyFrom(val1); } return SigValues.SIG_CHLD1.ordinal(); } // test for cases when evaluation is strict if (isStrictOperator(op)) { // check for error values if (vt1 == ValueType.ERROR_VALUE) { result.setErrorValue(); return SigValues.SIG_CHLD1.ordinal(); } if (valid2 && vt2 == ValueType.ERROR_VALUE) { result.setErrorValue(); return SigValues.SIG_CHLD2.ordinal(); } if (valid3 && vt3 == ValueType.ERROR_VALUE) { result.setErrorValue(); return SigValues.SIG_CHLD3.ordinal(); } // check for undefined values. we need to check if the corresponding // tree exists, because these values would be undefined" anyway then. if (valid1 && vt1 == ValueType.UNDEFINED_VALUE) { result.setUndefinedValue(); return SigValues.SIG_CHLD1.ordinal(); } if (valid2 && vt2 == ValueType.UNDEFINED_VALUE) { result.setUndefinedValue(); return SigValues.SIG_CHLD2.ordinal(); } if (valid3 && vt3 == ValueType.UNDEFINED_VALUE) { result.setUndefinedValue(); return SigValues.SIG_CHLD3.ordinal(); } } // comparison operations (binary, one unary) if (op >= OpKind_COMPARISON_START && op <= OpKind_COMPARISON_END) { return (doComparison(op, val1, val2, result)); } // arithmetic operations (binary) if (op >= OpKind_ARITHMETIC_START && op <= OpKind_ARITHMETIC_END) { return (doArithmetic(op, val1, val2, result)); } // logical operators (binary, one unary) if (op >= OpKind_LOGIC_START && op <= OpKind_LOGIC_END) { return (doLogical(op, val1, val2, result)); } // bitwise operators (binary, one unary) if (op >= OpKind_BITWISE_START && op <= OpKind_BITWISE_END) { return (doBitwise(op, val1, val2, result)); } // misc. if (op == OpKind_TERNARY_OP) { // ternary (if-operator) MutableBoolean b = new MutableBoolean(false); // if the selector is UNDEFINED, the result is undefined if (vt1 == ValueType.UNDEFINED_VALUE) { result.setUndefinedValue(); return SigValues.SIG_CHLD1.ordinal(); } if (!val1.isBooleanValueEquiv(b)) { result.setErrorValue(); return SigValues.SIG_CHLD1.ordinal(); } else if (b.booleanValue()) { result.copyFrom(val2); return (SigValues.SIG_CHLD2.ordinal()); } else { result.copyFrom(val3); return (SigValues.SIG_CHLD3.ordinal()); } } else if (op == OpKind_SUBSCRIPT_OP) { // subscripting from a list (strict) if (vt1 == ValueType.CLASSAD_VALUE && vt2 == ValueType.STRING_VALUE) { ClassAd classad = new ClassAd(); AMutableCharArrayString index = new AMutableCharArrayString(); val1.isClassAdValue(classad); val2.isStringValue(index); if (classad.lookup(index.toString()) == null) { result.setErrorValue(); return SigValues.SIG_CHLD2.ordinal(); } if (!classad.evaluateAttr(index.toString(), result)) { result.setErrorValue(); return SigValues.SIG_CHLD2.ordinal(); } return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); } else if (val1.isListValue() && vt2 == ValueType.INTEGER_VALUE) { AMutableInt64 index = new AMutableInt64(0); ExprList elist = new ExprList(); val1.isListValue(elist); val2.isIntegerValue(index); // check bounds if (index.getLongValue() < 0 || index.getLongValue() >= elist.getExprList().size()) { result.setErrorValue(); return SigValues.SIG_CHLD2.ordinal(); } // get value elist.getValue(result, elist.get((int) index.getLongValue()), es); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); } // should not reach here throw new HyracksDataException("Should not get here"); } return -1; } public boolean privateEvaluate(EvalState state, Value result) throws HyracksDataException { Value val1 = new Value(); Value val2 = new Value(); Value val3 = new Value(); boolean valid1, valid2, valid3; int rval = 0; valid1 = false; valid2 = false; valid3 = false; AMutableInt32 operationKind = new AMutableInt32(OpKind_NO_OP); ExprTreeHolder child1 = new ExprTreeHolder(); ExprTreeHolder child2 = new ExprTreeHolder(); ExprTreeHolder child3 = new ExprTreeHolder(); getComponents(operationKind, child1, child2, child3); // Evaluate all valid children if (child1.getInnerTree() != null) { if (!child1.publicEvaluate(state, val1)) { result.setErrorValue(); return (false); } valid1 = true; if (shortCircuit(state, val1, result)) { return true; } } if (child2.getInnerTree() != null) { if (!child2.publicEvaluate(state, val2)) { result.setErrorValue(); return (false); } valid2 = true; } if (child3.getInnerTree() != null) { if (!child3.publicEvaluate(state, val3)) { result.setErrorValue(); return (false); } valid3 = true; } rval = privateDoOperation(opKind, val1, val2, val3, valid1, valid2, valid3, result, state); return (rval != SigValues.SIG_NONE.ordinal()); } public boolean shortCircuit(EvalState state, Value arg1, Value result) throws HyracksDataException { MutableBoolean arg1_bool = new MutableBoolean(); switch (opKind) { case OpKind_LOGICAL_OR_OP: if (arg1.isBooleanValueEquiv(arg1_bool) && arg1_bool.booleanValue()) { result.setBooleanValue(true); return true; } break; case OpKind_LOGICAL_AND_OP: if (arg1.isBooleanValueEquiv(arg1_bool) && !arg1_bool.booleanValue()) { result.setBooleanValue(false); return true; } break; case OpKind_TERNARY_OP: if (arg1.isBooleanValueEquiv(arg1_bool)) { if (arg1_bool.booleanValue()) { if (child2 != null) { return child2.publicEvaluate(state, result); } } else { if (child3 != null) { return child3.publicEvaluate(state, result); } } } break; default: // no-op break; } return false; } public boolean privateEvaluate(EvalState state, Value result, ExprTreeHolder tree) throws HyracksDataException { int sig; Value val1 = new Value(); Value val2 = new Value(); Value val3 = new Value(); ExprTreeHolder t1 = new ExprTreeHolder(); ExprTreeHolder t2 = new ExprTreeHolder(); ExprTreeHolder t3 = new ExprTreeHolder(); boolean valid1 = false, valid2 = false, valid3 = false; AMutableInt32 opKind = new AMutableInt32(OpKind_NO_OP); ExprTreeHolder child1 = new ExprTreeHolder(); ExprTreeHolder child2 = new ExprTreeHolder(); ExprTreeHolder child3 = new ExprTreeHolder(); getComponents(opKind, child1, child2, child3); // Evaluate all valid children tree = new ExprTreeHolder(); if (child1.getInnerTree() != null) { if (!child1.publicEvaluate(state, val1, t1)) { result.setErrorValue(); return (false); } valid1 = true; } if (child2.getInnerTree() != null) { if (!child2.publicEvaluate(state, val2, t2)) { result.setErrorValue(); return (false); } valid2 = true; } if (child3.getInnerTree() != null) { if (!child3.publicEvaluate(state, val3, t3)) { result.setErrorValue(); return (false); } valid3 = true; } // do evaluation sig = privateDoOperation(opKind.getIntegerValue().intValue(), val1, val2, val3, valid1, valid2, valid3, result, state); // delete trees which were not significant if (valid1 && 0 != (sig & SigValues.SIG_CHLD1.ordinal())) { t1 = null; } if (valid2 && 0 != (sig & SigValues.SIG_CHLD2.ordinal())) { t2 = null; } if (valid3 && 0 != (sig & SigValues.SIG_CHLD3.ordinal())) { t3 = null; } if (sig == SigValues.SIG_NONE.ordinal()) { result.setErrorValue(); tree.setInnerTree(null); ; return (false); } // in case of strict operators, if a subexpression is significant and the // corresponding value is UNDEFINED or ERROR, propagate only that tree if (isStrictOperator(opKind.getIntegerValue().intValue())) { // strict unary operators: unary -, unary +, !, ~, () if (opKind.getIntegerValue().intValue() == OpKind_UNARY_MINUS_OP || opKind.getIntegerValue().intValue() == OpKind_UNARY_PLUS_OP || opKind.getIntegerValue().intValue() == OpKind_LOGICAL_NOT_OP || opKind.getIntegerValue().intValue() == OpKind_BITWISE_NOT_OP || opKind.getIntegerValue().intValue() == OpKind_PARENTHESES_OP) { if (val1.isExceptional()) { // the operator is only propagating the value; only the // subexpression is significant tree.setInnerTree(t1); } else { // the node operated on the value; the operator is also // significant tree.setInnerTree(createOperation(opKind.getIntegerValue().intValue(), t1)); } return (true); } else { // strict binary operators if (val1.isExceptional() || val2.isExceptional()) { // exceptional values are only being propagated if (0 != (SigValues.values()[sig].ordinal() & SigValues.SIG_CHLD1.ordinal())) { tree.setInnerTree(t1); return (true); } else if (0 != (SigValues.values()[sig].ordinal() & SigValues.SIG_CHLD2.ordinal())) { tree.setInnerTree(t2); return (true); } throw new HyracksDataException("Should not reach here"); } else { // the node is also significant tree.setInnerTree(createOperation(opKind.getIntegerValue().intValue(), t1, t2)); return (true); } } } else { // non-strict operators if (opKind.getIntegerValue().intValue() == OpKind_IS_OP || opKind.getIntegerValue().intValue() == OpKind_ISNT_OP) { // the operation is *always* significant for IS and ISNT tree.setInnerTree(createOperation(opKind.getIntegerValue().intValue(), t1, t2)); return (true); } // other non-strict binary operators if (opKind.getIntegerValue().intValue() == OpKind_LOGICAL_AND_OP || opKind.getIntegerValue().intValue() == OpKind_LOGICAL_OR_OP) { if ((SigValues.values()[sig].ordinal() & SigValues.SIG_CHLD1.ordinal()) != 0 && (SigValues.values()[sig].ordinal() & SigValues.SIG_CHLD2.ordinal()) != 0) { tree.setInnerTree(createOperation(opKind.getIntegerValue().intValue(), t1, t2)); return (true); } else if ((SigValues.values()[sig].ordinal() & SigValues.SIG_CHLD1.ordinal()) != 0) { tree.setInnerTree(t1); return (true); } else if ((SigValues.values()[sig].ordinal() & SigValues.SIG_CHLD2.ordinal()) != 0) { tree.setInnerTree(t2); return (true); } else { throw new HyracksDataException("Shouldn't reach here"); } } // non-strict ternary operator (conditional operator) s ? t : f // selector is always significant (???) if (opKind.getIntegerValue().intValue() == OpKind_TERNARY_OP) { Value tmpVal = new Value(); tmpVal.setUndefinedValue(); tree.setInnerTree(Literal.createLiteral(tmpVal)); // "true" consequent taken if ((SigValues.values()[sig].ordinal() & SigValues.SIG_CHLD2.ordinal()) != 0) { tree.setInnerTree(t2); return (true); } else if ((SigValues.values()[sig].ordinal() & SigValues.SIG_CHLD3.ordinal()) != 0) { tree.setInnerTree(t3); return (true); } // neither consequent; selector was exceptional; return ( s ) tree.setInnerTree(t1); return (true); } } throw new HyracksDataException("Should not reach here"); } public boolean privateFlatten(EvalState state, Value val, ExprTreeHolder tree, AMutableInt32 opPtr) throws HyracksDataException { AMutableInt32 childOp1 = new AMutableInt32(OpKind_NO_OP); AMutableInt32 childOp2 = new AMutableInt32(OpKind_NO_OP); ExprTreeHolder fChild1 = new ExprTreeHolder(); ExprTreeHolder fChild2 = new ExprTreeHolder(); ; Value val1 = new Value(); Value val2 = new Value(); Value val3 = new Value(); AMutableInt32 newOp = new AMutableInt32(opKind); int op = opKind; tree.setInnerTree(null); ; // Just to be safe... wenger 2003-12-11. // if op is binary, but not associative or commutative, disallow splitting if ((op >= OpKind_COMPARISON_START && op <= OpKind_COMPARISON_END) || op == OpKind_SUBTRACTION_OP || op == OpKind_DIVISION_OP || op == OpKind_MODULUS_OP || op == OpKind_LEFT_SHIFT_OP || op == OpKind_RIGHT_SHIFT_OP || op == OpKind_URIGHT_SHIFT_OP) { if (opPtr != null) opPtr.setValue(OpKind_NO_OP); if (child1.publicFlatten(state, val1, fChild1) && child2.publicFlatten(state, val2, fChild2)) { if (fChild1.getInnerTree() == null && fChild2.getInnerTree() == null) { privateDoOperation(op, val1, val2, val3, true, true, false, val); tree.setInnerTree(null); return true; } else if (fChild1.getInnerTree() != null && fChild2.getInnerTree() != null) { tree.setInnerTree(Operation.createOperation(op, fChild1, fChild2)); return true; } else if (fChild1.getInnerTree() != null) { tree.setInnerTree(Operation.createOperation(op, fChild1, val2)); return true; } else if (fChild2.getInnerTree() != null) { tree.setInnerTree(Operation.createOperation(op, val1, fChild2)); return true; } } else { tree.setInnerTree(null); return false; } } else // now catch all non-binary operators if (op == OpKind_TERNARY_OP || op == OpKind_SUBSCRIPT_OP || op == OpKind_UNARY_PLUS_OP || op == OpKind_UNARY_MINUS_OP || op == OpKind_PARENTHESES_OP || op == OpKind_LOGICAL_NOT_OP || op == OpKind_BITWISE_NOT_OP) { return flattenSpecials(state, val, tree); } // any op that got past the above is binary, commutative and associative // Flatten sub expressions if ((child1 != null && !child1.publicFlatten(state, val1, fChild1, childOp1)) || (child2 != null && !child2.publicFlatten(state, val2, fChild2, childOp2))) { tree.setInnerTree(null); return false; } // NOTE: combine() deletes fChild1 and/or fChild2 if they are not // included in tree if (!combine(newOp, val, tree, childOp1, val1, fChild1, childOp2, val2, fChild2)) { tree.setInnerTree(null); if (opPtr != null) { opPtr.setValue(OpKind_NO_OP); } return false; } // if splitting is disallowed, fold the value and tree into a tree if (opPtr == null && newOp.getIntegerValue().intValue() != OpKind_NO_OP) { tree.setInnerTree(Operation.createOperation(newOp.getIntegerValue().intValue(), val, tree)); if (tree.getInnerTree() == null) { return false; } return true; } else if (opPtr != null) { opPtr.setValue(newOp.getIntegerValue().intValue()); } return true; } public boolean combine(AMutableInt32 op, Value val, ExprTreeHolder tree, AMutableInt32 op1, Value val1, ExprTreeHolder tree1, AMutableInt32 op2, Value val2, ExprTreeHolder tree2) throws HyracksDataException { Operation newOp = new Operation(); Value dummy = new Value(); // undefined // special don't care cases for logical operators with exactly one value if ((tree1.getInnerTree() == null || tree2.getInnerTree() == null) && (tree1.getInnerTree() != null || tree2.getInnerTree() != null) && (op.getIntegerValue() == OpKind_LOGICAL_OR_OP || op.getIntegerValue() == OpKind_LOGICAL_AND_OP)) { privateDoOperation(op.getIntegerValue().intValue(), tree1.getInnerTree() == null ? val1 : dummy, tree2.getInnerTree() == null ? val2 : dummy, dummy, true, true, false, val); if (val.isBooleanValue()) { tree.setInnerTree(null); op.setValue(OpKind_NO_OP); return true; } } if (tree1.getInnerTree() == null && tree2.getInnerTree() == null) { // left and rightsons are only values privateDoOperation(op.getIntegerValue().intValue(), val1, val2, dummy, true, true, false, val); tree.setInnerTree(null); op.setValue(OpKind_NO_OP); return true; } else if (tree1.getInnerTree() == null && (tree2.getInnerTree() != null && op2.getIntegerValue().intValue() == OpKind_NO_OP)) { // leftson is a value, rightson is a tree tree.setInnerTree(tree2.getInnerTree()); val.copyFrom(val1); return true; } else if (tree2.getInnerTree() == null && (tree1.getInnerTree() != null && op1.getIntegerValue().intValue() == OpKind_NO_OP)) { // rightson is a value, leftson is a tree tree.setInnerTree(tree1.getInnerTree()); val.copyFrom(val2); return true; } else if ((tree1.getInnerTree() != null && op1.getIntegerValue().intValue() == OpKind_NO_OP) && (tree2.getInnerTree() != null && op2.getIntegerValue().intValue() == OpKind_NO_OP)) { // left and rightsons are trees only if (null != (newOp = createOperation(op.getIntegerValue().intValue(), tree1, tree2))) { return false; } tree.setInnerTree(newOp); op.setValue(OpKind_NO_OP); return true; } // cannot collapse values due to dissimilar ops if ((op1.getIntegerValue().intValue() != OpKind_NO_OP || op2.getIntegerValue().intValue() != OpKind_NO_OP) && !op.equals(op1) && !op.equals(op1)) { // at least one of them returned a value and a tree, and parent does // not share the same operation with either child ExprTreeHolder newOp1 = new ExprTreeHolder(); ExprTreeHolder newOp2 = new ExprTreeHolder(); if (op1.getIntegerValue().intValue() != OpKind_NO_OP) { newOp1.setInnerTree(Operation.createOperation(op1.getIntegerValue().intValue(), val1, tree1)); } else if (tree1.getInnerTree() != null) { newOp1.setInnerTree(tree1.getInnerTree()); } else { newOp1.setInnerTree(Literal.createLiteral(val1)); } if (op2.getIntegerValue().intValue() != OpKind_NO_OP) { newOp2.setInnerTree(Operation.createOperation(op2.getIntegerValue().intValue(), val2, tree2)); } else if (tree2.getInnerTree() != null) { newOp2.setInnerTree(tree2); } else { newOp2.setInnerTree(Literal.createLiteral(val2)); } if (newOp1.getInnerTree() == null || newOp2.getInnerTree() == null) { tree.setInnerTree(null); op.setValue(OpKind_NO_OP); return false; } newOp = createOperation(op.getIntegerValue().intValue(), newOp1, newOp2); if (newOp == null) { tree.setInnerTree(null); op.setValue(OpKind_NO_OP); return false; } op.setValue(OpKind_NO_OP); tree.setInnerTree(newOp); return true; } if (op.equals(op1) && op.equals(op2)) { // same operators on both children . since op!=NO_OP, neither are op1, // op2. so they both make tree and value contributions newOp = createOperation(op.getIntegerValue().intValue(), tree1, tree2); if (newOp == null) { return false; } privateDoOperation(op.getIntegerValue().intValue(), val1, val2, dummy, true, true, false, val); tree.setInnerTree(newOp); return true; } else if (op.equals(op1)) { // leftson makes a tree,value contribution if (tree2.getInnerTree() == null) { // rightson makes a value contribution privateDoOperation(op.getIntegerValue().intValue(), val1, val2, dummy, true, true, false, val); tree.setInnerTree(tree1); return true; } else { // rightson makes a tree contribution Operation local_newOp = createOperation(op.getIntegerValue().intValue(), tree1, tree2); if (local_newOp == null) { tree.setInnerTree(null); op.setValue(OpKind_NO_OP); return false; } val.copyFrom(val1); tree.setInnerTree(local_newOp); // NAC - BUG FIX return true; } } else if (op.equals(op2)) { // rightson makes a tree,value contribution if (tree1.getInnerTree() == null) { // leftson makes a value contribution privateDoOperation(op.getIntegerValue().intValue(), val1, val2, dummy, true, true, false, val); tree.setInnerTree(tree2); return true; } else { // leftson makes a tree contribution Operation local_newOp = createOperation(op.getIntegerValue().intValue(), tree1, tree2); if (local_newOp == null) { tree.setInnerTree(null); op.setValue(OpKind_NO_OP); return false; } tree.setInnerTree(local_newOp); // NAC BUG FIX val.copyFrom(val2); return true; } } throw new HyracksDataException("Should not reach here"); } public static int doComparison(int op, Value v1, Value v2, Value result) throws HyracksDataException { ValueType vt1; ValueType vt2; ValueType coerceResult; if (op == OpKind_META_EQUAL_OP || op == OpKind_META_NOT_EQUAL_OP) { // do not do type promotions for the meta operators vt1 = v1.getType(); vt2 = v2.getType(); coerceResult = vt1; } else { // do numerical type promotions --- other types/values are unchanged coerceResult = coerceToNumber(v1, v2); vt1 = v1.getType(); vt2 = v2.getType(); } // perform comparison for =?= ; true iff same types and same values if (op == OpKind_META_EQUAL_OP) { if (vt1 != vt2) { result.setBooleanValue(false); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); } // undefined or error if (vt1 == ValueType.UNDEFINED_VALUE || vt1 == ValueType.ERROR_VALUE) { result.setBooleanValue(true); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); } } // perform comparison for =!= ; negation of =?= if (op == OpKind_META_NOT_EQUAL_OP) { if (vt1 != vt2) { result.setBooleanValue(true); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); } // undefined or error if (vt1 == ValueType.UNDEFINED_VALUE || vt1 == ValueType.ERROR_VALUE) { result.setBooleanValue(false); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); } } switch (coerceResult) { // at least one of v1, v2 is a string case STRING_VALUE: // check if both are strings if (vt1 != ValueType.STRING_VALUE || vt2 != ValueType.STRING_VALUE) { // comparison between strings and non-exceptional non-string // values is error result.setErrorValue(); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); } compareStrings(op, v1, v2, result); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); case INTEGER_VALUE: compareIntegers(op, v1, v2, result); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); case REAL_VALUE: compareReals(op, v1, v2, result); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); case BOOLEAN_VALUE: // check if both are bools if (!v1.isBooleanValue() || !v2.isBooleanValue()) { result.setErrorValue(); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); } compareBools(op, v1, v2, result); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); case LIST_VALUE: case SLIST_VALUE: case CLASSAD_VALUE: result.setErrorValue(); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); case ABSOLUTE_TIME_VALUE: if (!v1.isAbsoluteTimeValue() || !v2.isAbsoluteTimeValue()) { result.setErrorValue(); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); } compareAbsoluteTimes(op, v1, v2, result); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); case RELATIVE_TIME_VALUE: if (!v1.isRelativeTimeValue() || !v2.isRelativeTimeValue()) { result.setErrorValue(); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); } compareRelativeTimes(op, v1, v2, result); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); default: // should not get here throw new HyracksDataException("Should not get here"); } } public static int doArithmetic(int op, Value v1, Value v2, Value result) throws HyracksDataException { AMutableInt64 i1 = new AMutableInt64(0); AMutableInt64 i2 = new AMutableInt64(0); ClassAdTime t1 = new ClassAdTime(); AMutableDouble r1 = new AMutableDouble(0); MutableBoolean b1 = new MutableBoolean(); // ensure the operands have arithmetic types if ((!v1.isIntegerValue() && !v1.isRealValue() && !v1.isAbsoluteTimeValue() && !v1.isRelativeTimeValue() && !v1.isBooleanValue()) || (op != OpKind_UNARY_MINUS_OP && !v2.isBooleanValue() && !v2.isIntegerValue() && !v2.isRealValue() && !v2.isAbsoluteTimeValue() && !v2.isRelativeTimeValue())) { result.setErrorValue(); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); } // take care of the unary arithmetic operators if (op == OpKind_UNARY_MINUS_OP) { if (v1.isIntegerValue(i1)) { result.setIntegerValue((-1L) * i1.getLongValue()); return SigValues.SIG_CHLD1.ordinal(); } else if (v1.isRealValue(r1)) { result.setRealValue((-1) * r1.getDoubleValue()); return SigValues.SIG_CHLD1.ordinal(); } else if (v1.isRelativeTimeValue(t1)) { t1.setValue((-1) * t1.getTimeInMillis()); result.setRelativeTimeValue(t1); return (SigValues.SIG_CHLD1.ordinal()); } else if (v1.isBooleanValue(b1)) { result.setBooleanValue(!b1.booleanValue()); } else if (v1.isExceptional()) { // undefined or error --- same as operand result.copyFrom(v1); return SigValues.SIG_CHLD1.ordinal(); } // unary minus not defined on any other operand type result.setErrorValue(); return (SigValues.SIG_CHLD1.ordinal()); } // perform type promotions and proceed with arithmetic switch (coerceToNumber(v1, v2)) { case INTEGER_VALUE: v1.isIntegerValue(i1); v2.isIntegerValue(i2); switch (op) { case OpKind_ADDITION_OP: result.setIntegerValue(i1.getLongValue() + i2.getLongValue()); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); case OpKind_SUBTRACTION_OP: result.setIntegerValue(i1.getLongValue() - i2.getLongValue()); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); case OpKind_MULTIPLICATION_OP: result.setIntegerValue(i1.getLongValue() * i2.getLongValue()); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); case OpKind_DIVISION_OP: if (i2.getLongValue() != 0L) { result.setIntegerValue(i1.getLongValue() / i2.getLongValue()); } else { result.setErrorValue(); } return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); case OpKind_MODULUS_OP: if (i2.getLongValue() != 0) { result.setIntegerValue(i1.getLongValue() % i2.getLongValue()); } else { result.setErrorValue(); } return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); default: // should not reach here throw new HyracksDataException("Should not get here"); } case REAL_VALUE: { return (doRealArithmetic(op, v1, v2, result)); } case ABSOLUTE_TIME_VALUE: case RELATIVE_TIME_VALUE: { return (doTimeArithmetic(op, v1, v2, result)); } default: // should not get here throw new HyracksDataException("Should not get here"); } } public static int doLogical(int op, Value v1, Value v2, Value result) throws HyracksDataException { MutableBoolean b1 = new MutableBoolean(); MutableBoolean b2 = new MutableBoolean(); // first coerece inputs to boolean if they are considered equivalent if (!v1.isBooleanValue(b1) && v1.isBooleanValueEquiv(b1)) { v1.setBooleanValue(b1.booleanValue()); } if (!v2.isBooleanValue(b2) && v2.isBooleanValueEquiv(b2)) { v2.setBooleanValue(b2); } ValueType vt1 = v1.getType(); ValueType vt2 = v2.getType(); if (vt1 != ValueType.UNDEFINED_VALUE && vt1 != ValueType.ERROR_VALUE && vt1 != ValueType.BOOLEAN_VALUE) { result.setErrorValue(); return SigValues.SIG_CHLD1.ordinal(); } if (vt2 != ValueType.UNDEFINED_VALUE && vt2 != ValueType.ERROR_VALUE && vt2 != ValueType.BOOLEAN_VALUE) { result.setErrorValue(); return SigValues.SIG_CHLD2.ordinal(); } // handle unary operator if (op == OpKind_LOGICAL_NOT_OP) { if (vt1 == ValueType.BOOLEAN_VALUE) { result.setBooleanValue(!b1.booleanValue()); } else { result.copyFrom(v1); } return SigValues.SIG_CHLD1.ordinal(); } if (op == OpKind_LOGICAL_OR_OP) { if (vt1 == ValueType.BOOLEAN_VALUE && b1.booleanValue()) { result.setBooleanValue(true); return SigValues.SIG_CHLD1.ordinal(); } else if (vt1 == ValueType.ERROR_VALUE) { result.setErrorValue(); return SigValues.SIG_CHLD1.ordinal(); } else if (vt1 == ValueType.BOOLEAN_VALUE && !b1.booleanValue()) { result.copyFrom(v2); } else if (vt2 != ValueType.BOOLEAN_VALUE) { result.copyFrom(v2); } else if (b2.booleanValue()) { result.setBooleanValue(true); } else { result.setUndefinedValue(); } return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); } else if (op == OpKind_LOGICAL_AND_OP) { if (vt1 == ValueType.BOOLEAN_VALUE && !b1.booleanValue()) { result.setBooleanValue(false); return SigValues.SIG_CHLD1.ordinal(); } else if (vt1 == ValueType.ERROR_VALUE) { result.setErrorValue(); return SigValues.SIG_CHLD1.ordinal(); } else if (vt1 == ValueType.BOOLEAN_VALUE && b1.booleanValue()) { result.copyFrom(v2); } else if (vt2 != ValueType.BOOLEAN_VALUE) { result.copyFrom(v2); } else if (!b2.booleanValue()) { result.setBooleanValue(false); } else { result.setUndefinedValue(); } return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); } throw new HyracksDataException("Shouldn't reach here"); } public static int doBitwise(int op, Value v1, Value v2, Value result) throws HyracksDataException { AMutableInt64 i1 = new AMutableInt64(0); AMutableInt64 i2 = new AMutableInt64(0); // bitwise operations are defined only on integers if (op == OpKind_BITWISE_NOT_OP) { if (!v1.isIntegerValue(i1)) { result.setErrorValue(); return SigValues.SIG_CHLD1.ordinal(); } } else if (!v1.isIntegerValue(i1) || !v2.isIntegerValue(i2)) { result.setErrorValue(); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); } switch (op) { case OpKind_BITWISE_NOT_OP: result.setIntegerValue(~(i1.getLongValue())); break; case OpKind_BITWISE_OR_OP: result.setIntegerValue(i1.getLongValue() | i2.getLongValue()); break; case OpKind_BITWISE_AND_OP: result.setIntegerValue(i1.getLongValue() & i2.getLongValue()); break; case OpKind_BITWISE_XOR_OP: result.setIntegerValue(i1.getLongValue() ^ i2.getLongValue()); break; case OpKind_LEFT_SHIFT_OP: result.setIntegerValue(i1.getLongValue() << i2.getLongValue()); break; case OpKind_URIGHT_SHIFT_OP: // if (i1 >= 0) { // Could probably just use >>> // sign bit is not on; >> will work fine result.setIntegerValue(i1.getLongValue() >>> i2.getLongValue()); break; // } else { // sign bit is on // val.setValue(i1 >> 1); // shift right 1; the sign bit *may* be on // val.setValue(val.getLongValue() & (~signMask)); // Clear the sign bit for sure // val.setValue(val.getLongValue() >>(i2.getLongValue() - 1)); // shift remaining Number of positions // result.SetIntegerValue (val.getLongValue()); // break; // } case OpKind_RIGHT_SHIFT_OP: // sign bit is off; >> will work fine result.setIntegerValue(i1.getLongValue() >> i2.getLongValue()); break; default: // should not get here throw new HyracksDataException("Should not get here"); } if (op == OpKind_BITWISE_NOT_OP) { return SigValues.SIG_CHLD1.ordinal(); } return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); } //out of domain value public static final int EDOM = 33; public static int doRealArithmetic(int op, Value v1, Value v2, Value result) throws HyracksDataException { AMutableDouble r1 = new AMutableDouble(0); AMutableDouble r2 = new AMutableDouble(0); double comp = 0; // we want to prevent FPE and set the ERROR value on the result; on Unix // trap sigfpe and set the ClassAdExprFPE flag to true; on NT check the // result against HUGE_VAL. check errno for EDOM and ERANGE for kicks. v1.isRealValue(r1); v2.isRealValue(r2); int errno = 0; switch (op) { case OpKind_ADDITION_OP: comp = r1.getDoubleValue() + r2.getDoubleValue(); break; case OpKind_SUBTRACTION_OP: comp = r1.getDoubleValue() - r2.getDoubleValue(); break; case OpKind_MULTIPLICATION_OP: comp = r1.getDoubleValue() * r2.getDoubleValue(); break; case OpKind_DIVISION_OP: comp = r1.getDoubleValue() / r2.getDoubleValue(); break; case OpKind_MODULUS_OP: errno = EDOM; break; default: // should not reach here throw new HyracksDataException("Should not get here"); } // check if anything bad happened if (errno == EDOM) { result.setErrorValue(); } else { result.setRealValue(comp); } return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); } public static int doTimeArithmetic(int op, Value v1, Value v2, Value result) { ClassAdTime asecs1 = new ClassAdTime(); ClassAdTime asecs2 = new ClassAdTime(); ValueType vt1 = v1.getType(); ValueType vt2 = v2.getType(); // addition if (op == OpKind_ADDITION_OP) { if (vt1 == ValueType.ABSOLUTE_TIME_VALUE && vt2 == ValueType.RELATIVE_TIME_VALUE) { v1.isAbsoluteTimeValue(asecs1); v2.isRelativeTimeValue(asecs2); asecs1.setValue(asecs1.getTimeInMillis() + asecs2.getTimeInMillis()); result.setAbsoluteTimeValue(asecs1); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); } if (vt1 == ValueType.RELATIVE_TIME_VALUE && vt2 == ValueType.ABSOLUTE_TIME_VALUE) { v1.isRelativeTimeValue(asecs1); v2.isAbsoluteTimeValue(asecs2); asecs2.setValue(asecs1.getTimeInMillis() + asecs2.getTimeInMillis()); result.setAbsoluteTimeValue(asecs2); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); } if (vt1 == ValueType.RELATIVE_TIME_VALUE && vt2 == ValueType.RELATIVE_TIME_VALUE) { v1.isRelativeTimeValue(asecs1); v2.isRelativeTimeValue(asecs2); result.setRelativeTimeValue(asecs1.plus(asecs2.getRelativeTime(), false)); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); } } if (op == OpKind_SUBTRACTION_OP) { if (vt1 == ValueType.ABSOLUTE_TIME_VALUE && vt2 == ValueType.ABSOLUTE_TIME_VALUE) { v1.isAbsoluteTimeValue(asecs1); v2.isAbsoluteTimeValue(asecs2); result.setRelativeTimeValue(asecs1.subtract(asecs2, false)); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); } if (vt1 == ValueType.ABSOLUTE_TIME_VALUE && vt2 == ValueType.RELATIVE_TIME_VALUE) { v1.isAbsoluteTimeValue(asecs1); v2.isRelativeTimeValue(asecs2); asecs1.setValue(asecs1.getTimeInMillis() - asecs2.getRelativeTime()); result.setAbsoluteTimeValue(asecs1); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); } if (vt1 == ValueType.RELATIVE_TIME_VALUE && vt2 == ValueType.RELATIVE_TIME_VALUE) { v1.isRelativeTimeValue(asecs1); v2.isRelativeTimeValue(asecs2); result.setRelativeTimeValue(asecs1.subtract(asecs2)); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); } } if (op == OpKind_MULTIPLICATION_OP || op == OpKind_DIVISION_OP) { if (vt1 == ValueType.RELATIVE_TIME_VALUE && vt2 == ValueType.INTEGER_VALUE) { AMutableInt64 num = new AMutableInt64(0); ClassAdTime msecs = new ClassAdTime(); v1.isRelativeTimeValue(asecs1); v2.isIntegerValue(num); if (op == OpKind_MULTIPLICATION_OP) { msecs.setValue(asecs1.multiply(num.getLongValue(), false)); } else { msecs.setValue(asecs1.divide(num.getLongValue(), false)); } result.setRelativeTimeValue(msecs); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); } if (vt1 == ValueType.RELATIVE_TIME_VALUE && vt2 == ValueType.REAL_VALUE) { AMutableDouble num = new AMutableDouble(0); AMutableDouble msecs = new AMutableDouble(0); v1.isRelativeTimeValue(asecs1); v2.isRealValue(num); if (op == OpKind_MULTIPLICATION_OP) { msecs.setValue(asecs1.getRelativeTime() * num.getDoubleValue()); } else { msecs.setValue(asecs1.getRelativeTime() * num.getDoubleValue()); } result.setRelativeTimeValue(new ClassAdTime(1000L * ((long) msecs.getDoubleValue()), false)); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); } if (vt1 == ValueType.INTEGER_VALUE && vt2 == ValueType.RELATIVE_TIME_VALUE && op == OpKind_MULTIPLICATION_OP) { AMutableInt64 num = new AMutableInt64(0); v1.isIntegerValue(num); v2.isRelativeTimeValue(asecs1); result.setRelativeTimeValue(new ClassAdTime(num.getLongValue() * asecs1.getRelativeTime(), false)); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); } if (vt2 == ValueType.RELATIVE_TIME_VALUE && vt1 == ValueType.REAL_VALUE && op == OpKind_MULTIPLICATION_OP) { AMutableDouble num = new AMutableDouble(0); v1.isRelativeTimeValue(asecs1); v2.isRealValue(num); result.setRelativeTimeValue( new ClassAdTime((long) (asecs1.getRelativeTime() * num.getDoubleValue()), false)); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); } } // no other operations are supported on times result.setErrorValue(); return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal()); } public static void compareStrings(int op, Value v1, Value v2, Value result) { AMutableCharArrayString s1 = new AMutableCharArrayString(); AMutableCharArrayString s2 = new AMutableCharArrayString(); int cmp; v1.isStringValue(s1); v2.isStringValue(s2); result.setBooleanValue(false); if (op == OpKind_META_EQUAL_OP || op == OpKind_META_NOT_EQUAL_OP) { cmp = s1.compareTo(s2); } else { cmp = s1.compareToIgnoreCase(s2); } if (cmp < 0) { // s1 < s2 if (op == OpKind_LESS_THAN_OP || op == OpKind_LESS_OR_EQUAL_OP || op == OpKind_META_NOT_EQUAL_OP || op == OpKind_NOT_EQUAL_OP) { result.setBooleanValue(true); } } else if (cmp == 0) { // s1 == s2 if (op == OpKind_LESS_OR_EQUAL_OP || op == OpKind_META_EQUAL_OP || op == OpKind_EQUAL_OP || op == OpKind_GREATER_OR_EQUAL_OP) { result.setBooleanValue(true); } } else { // s1 > s2 if (op == OpKind_GREATER_THAN_OP || op == OpKind_GREATER_OR_EQUAL_OP || op == OpKind_META_NOT_EQUAL_OP || op == OpKind_NOT_EQUAL_OP) { result.setBooleanValue(true); } } } public static void compareAbsoluteTimes(int op, Value v1, Value v2, Value result) throws HyracksDataException { ClassAdTime asecs1 = new ClassAdTime(); ClassAdTime asecs2 = new ClassAdTime(); boolean compResult = false; v1.isAbsoluteTimeValue(asecs1); v2.isAbsoluteTimeValue(asecs2); switch (op) { case OpKind_LESS_THAN_OP: compResult = (asecs1.getTimeInMillis() < asecs2.getTimeInMillis()); break; case OpKind_LESS_OR_EQUAL_OP: compResult = (asecs1.getTime() <= asecs2.getTime()); break; case OpKind_EQUAL_OP: compResult = (asecs1.getTime() == asecs2.getTime()); break; case OpKind_META_EQUAL_OP: compResult = (asecs1.getTime() == asecs2.getTime()) && (asecs1.getOffset() == asecs2.getOffset()); break; case OpKind_NOT_EQUAL_OP: compResult = (asecs1.getTime() != asecs2.getTime()); break; case OpKind_META_NOT_EQUAL_OP: compResult = (asecs1.getTime() != asecs2.getTime()) || (asecs1.getOffset() != asecs2.getOffset()); break; case OpKind_GREATER_THAN_OP: compResult = (asecs1.getTime() > asecs2.getTime()); break; case OpKind_GREATER_OR_EQUAL_OP: compResult = (asecs1.getTime() >= asecs2.getTime()); break; default: // should not get here throw new HyracksDataException("Should not get here"); } result.setBooleanValue(compResult); } public static void compareRelativeTimes(int op, Value v1, Value v2, Value result) throws HyracksDataException { ClassAdTime rsecs1 = new ClassAdTime(); ClassAdTime rsecs2 = new ClassAdTime(); boolean compResult = false; v1.isRelativeTimeValue(rsecs1); v2.isRelativeTimeValue(rsecs2); switch (op) { case OpKind_LESS_THAN_OP: compResult = (rsecs1.getRelativeTime() < rsecs2.getRelativeTime()); break; case OpKind_LESS_OR_EQUAL_OP: compResult = (rsecs1.getRelativeTime() <= rsecs2.getRelativeTime()); break; case OpKind_EQUAL_OP: case OpKind_META_EQUAL_OP: compResult = (rsecs1.getRelativeTime() == rsecs2.getRelativeTime()); break; case OpKind_NOT_EQUAL_OP: case OpKind_META_NOT_EQUAL_OP: compResult = (rsecs1.getRelativeTime() != rsecs2.getRelativeTime()); break; case OpKind_GREATER_THAN_OP: compResult = (rsecs1.getRelativeTime() > rsecs2.getRelativeTime()); break; case OpKind_GREATER_OR_EQUAL_OP: compResult = (rsecs1.getRelativeTime() >= rsecs2.getRelativeTime()); break; default: // should not get here throw new HyracksDataException("Should not get here"); } result.setBooleanValue(compResult); } public static void compareBools(int op, Value v1, Value v2, Value result) throws HyracksDataException { MutableBoolean b1 = new MutableBoolean(); MutableBoolean b2 = new MutableBoolean(); boolean compResult = false; v1.isBooleanValue(b1); v2.isBooleanValue(b2); switch (op) { case OpKind_LESS_THAN_OP: compResult = (b1.compareTo(b2) < 0); break; case OpKind_LESS_OR_EQUAL_OP: compResult = (b1.compareTo(b2) <= 0); break; case OpKind_EQUAL_OP: compResult = (b1.booleanValue() == b2.booleanValue()); break; case OpKind_META_EQUAL_OP: compResult = (b1.booleanValue() == b2.booleanValue()); break; case OpKind_NOT_EQUAL_OP: compResult = (b1.booleanValue() != b2.booleanValue()); break; case OpKind_META_NOT_EQUAL_OP: compResult = (b1.booleanValue() != b2.booleanValue()); break; case OpKind_GREATER_THAN_OP: compResult = (b1.compareTo(b2) > 0); break; case OpKind_GREATER_OR_EQUAL_OP: compResult = (b1.compareTo(b2) >= 0); break; default: // should not get here throw new HyracksDataException("Should not get here"); } result.setBooleanValue(compResult); } public static void compareIntegers(int op, Value v1, Value v2, Value result) throws HyracksDataException { AMutableInt64 i1 = new AMutableInt64(0); AMutableInt64 i2 = new AMutableInt64(0); boolean compResult = false; v1.isIntegerValue(i1); v2.isIntegerValue(i2); switch (op) { case OpKind_LESS_THAN_OP: compResult = (i1.getLongValue() < i2.getLongValue()); break; case OpKind_LESS_OR_EQUAL_OP: compResult = (i1.getLongValue() <= i2.getLongValue()); break; case OpKind_EQUAL_OP: compResult = (i1.getLongValue() == i2.getLongValue()); break; case OpKind_META_EQUAL_OP: compResult = (i1.getLongValue() == i2.getLongValue()); break; case OpKind_NOT_EQUAL_OP: compResult = (i1.getLongValue() != i2.getLongValue()); break; case OpKind_META_NOT_EQUAL_OP: compResult = (i1.getLongValue() != i2.getLongValue()); break; case OpKind_GREATER_THAN_OP: compResult = (i1.getLongValue() > i2.getLongValue()); break; case OpKind_GREATER_OR_EQUAL_OP: compResult = (i1.getLongValue() >= i2.getLongValue()); break; default: // should not get here throw new HyracksDataException("Should not get here"); } result.setBooleanValue(compResult); } public static void compareReals(int op, Value v1, Value v2, Value result) throws HyracksDataException { AMutableDouble r1 = new AMutableDouble(0); AMutableDouble r2 = new AMutableDouble(0); boolean compResult = false; v1.isRealValue(r1); v2.isRealValue(r2); switch (op) { case OpKind_LESS_THAN_OP: compResult = (r1.getDoubleValue() < r2.getDoubleValue()); break; case OpKind_LESS_OR_EQUAL_OP: compResult = (r1.getDoubleValue() <= r2.getDoubleValue()); break; case OpKind_EQUAL_OP: compResult = (r1.getDoubleValue() == r2.getDoubleValue()); break; case OpKind_META_EQUAL_OP: compResult = (r1.getDoubleValue() == r2.getDoubleValue()); break; case OpKind_NOT_EQUAL_OP: compResult = (r1.getDoubleValue() != r2.getDoubleValue()); break; case OpKind_META_NOT_EQUAL_OP: compResult = (r1.getDoubleValue() != r2.getDoubleValue()); break; case OpKind_GREATER_THAN_OP: compResult = (r1.getDoubleValue() > r2.getDoubleValue()); break; case OpKind_GREATER_OR_EQUAL_OP: compResult = (r1.getDoubleValue() >= r2.getDoubleValue()); break; default: // should not get here throw new HyracksDataException("Should not get here"); } result.setBooleanValue(compResult); } // This function performs type promotions so that both v1 and v2 are of the // same numerical type: (v1 and v2 are not ERROR or UNDEFINED) // + if both v1 and v2 are Numbers and of the same type, return type // + if v1 is an int and v2 is a real, convert v1 to real; return REAL_VALUE // + if v1 is a real and v2 is an int, convert v2 to real; return REAL_VALUE public static ValueType coerceToNumber(Value v1, Value v2) { AMutableInt64 i = new AMutableInt64(0); AMutableDouble r = new AMutableDouble(0); MutableBoolean b = new MutableBoolean(); // either of v1, v2 not numerical? if (v1.isClassAdValue() || v2.isClassAdValue()) return ValueType.CLASSAD_VALUE; if (v1.isListValue() || v2.isListValue()) return ValueType.LIST_VALUE; if (v1.isStringValue() || v2.isStringValue()) return ValueType.STRING_VALUE; if (v1.isUndefinedValue() || v2.isUndefinedValue()) return ValueType.UNDEFINED_VALUE; if (v1.isErrorValue() || v2.isErrorValue()) return ValueType.ERROR_VALUE; if (v1.isAbsoluteTimeValue() || v2.isAbsoluteTimeValue()) return ValueType.ABSOLUTE_TIME_VALUE; if (v1.isRelativeTimeValue() || v2.isRelativeTimeValue()) return ValueType.RELATIVE_TIME_VALUE; // promote booleans to integers if (v1.isBooleanValue(b)) { if (b.booleanValue()) { v1.setIntegerValue(1); } else { v1.setIntegerValue(0); } } if (v2.isBooleanValue(b)) { if (b.booleanValue()) { v2.setIntegerValue(1); } else { v2.setIntegerValue(0); } } // both v1 and v2 of same numerical type if (v1.isIntegerValue(i) && v2.isIntegerValue(i)) return ValueType.INTEGER_VALUE; if (v1.isRealValue(r) && v2.isRealValue(r)) return ValueType.REAL_VALUE; // type promotions required if (v1.isIntegerValue(i) && v2.isRealValue(r)) v1.setRealValue((double) i.getLongValue()); else if (v1.isRealValue(r) && v2.isIntegerValue(i)) v2.setRealValue((double) i.getLongValue()); return ValueType.REAL_VALUE; } public Operation(int op, ExprTreeHolder e1, ExprTreeHolder e2, ExprTreeHolder e3) { this.opKind = op; this.child1 = e1 == null ? null : e1.self(); this.child2 = e2 == null ? null : e2.self(); this.child3 = e3 == null ? null : e3.self(); } public static Operation createOperation(int op, ExprTree e1, ExprTree e2, ExprTree e3) { Operation opnode = new Operation(); opnode.opKind = op; opnode.child1 = e1 == null ? null : e1.self(); opnode.child2 = e2 == null ? null : e2.self(); opnode.child3 = e3 == null ? null : e3.self(); return opnode; } public static void createOperation(int op, ExprTree e1, ExprTree e2, ExprTree e3, Operation opnode) { opnode.opKind = op; opnode.child1 = e1 == null ? null : e1.self(); opnode.child2 = e2 == null ? null : e2.self(); opnode.child3 = e3 == null ? null : e3.self(); } public void getComponents(AMutableInt32 op, ExprTreeHolder e1, ExprTreeHolder e2, ExprTreeHolder e3) { op.setValue(opKind); e1.setInnerTree(child1); e2.setInnerTree(child2); e3.setInnerTree(child3); } public static Operation createOperation(int op, Value val, ExprTreeHolder tree) throws HyracksDataException { if (tree.getInnerTree() == null) { return null; } Literal lit = Literal.createLiteral(val); if (lit == null) { return null; } Operation newOp = createOperation(op, lit, tree); return newOp; } public static Operation createOperation(int op, ExprTreeHolder tree, Value val) throws HyracksDataException { if (tree.getInnerTree() == null) { return null; } Literal lit = Literal.createLiteral(val); if (lit == null) { return null; } Operation newOp = createOperation(op, lit, tree); return newOp; } public boolean flattenSpecials(EvalState state, Value val, ExprTreeHolder tree) throws HyracksDataException { ExprTreeHolder fChild1 = new ExprTreeHolder(); ExprTreeHolder fChild2 = new ExprTreeHolder(); ExprTreeHolder fChild3 = new ExprTreeHolder(); Value eval1 = new Value(); Value eval2 = new Value(); Value eval3 = new Value(); switch (opKind) { case OpKind_UNARY_PLUS_OP: case OpKind_UNARY_MINUS_OP: case OpKind_PARENTHESES_OP: case OpKind_LOGICAL_NOT_OP: case OpKind_BITWISE_NOT_OP: if (!child1.publicFlatten(state, eval1, fChild1)) { tree.setInnerTree(null); return false; } if (fChild1.getInnerTree() != null) { tree.setInnerTree(Operation.createOperation(opKind, fChild1)); return (tree.getInnerTree() != null); } else { privateDoOperation(opKind, eval1, null, null, true, false, false, val); tree.setInnerTree(null); eval1.clear(); return true; } case OpKind_TERNARY_OP: // Flatten the selector expression if (!child1.publicFlatten(state, eval1, fChild1)) { tree.setInnerTree(null); return false; } // check if selector expression collapsed to a non-undefined value if (fChild1.getInnerTree() == null && !eval1.isUndefinedValue()) { MutableBoolean b = new MutableBoolean(); // if the selector is not boolean-equivalent, propagate error if (!eval1.isBooleanValueEquiv(b)) { val.setErrorValue(); eval1.clear(); tree.setInnerTree(null); return true; } // eval1 is either a real or an integer if (b.booleanValue()) { return child2.publicFlatten(state, val, tree); } else { return child3.publicFlatten(state, val, tree); } } else { // Flatten arms of the if expression if (!child2.publicFlatten(state, eval2, fChild2) || !child3.publicFlatten(state, eval3, fChild3)) { // clean up tree.setInnerTree(null); return false; } // if any arm collapsed into a value, make it a Literal if (fChild2.getInnerTree() == null) fChild2.setInnerTree(Literal.createLiteral(eval2)); if (fChild3.getInnerTree() == null) fChild3.setInnerTree(Literal.createLiteral(eval3)); if (fChild2.getInnerTree() == null || fChild3.getInnerTree() == null) { tree.setInnerTree(null); ; return false; } // fChild1 may be NULL if child1 Flattened to UNDEFINED if (fChild1.getInnerTree() == null) { fChild1.setInnerTree(child1.copy()); } tree.setInnerTree(Operation.createOperation(opKind, fChild1, fChild2, fChild3)); if (tree.getInnerTree() == null) { return false; } return true; } case OpKind_SUBSCRIPT_OP: // Flatten both arguments if (!child1.publicFlatten(state, eval1, fChild1) || !child2.publicFlatten(state, eval2, fChild2)) { tree.setInnerTree(null); return false; } // if both arguments Flattened to values, Evaluate now if (fChild1.getInnerTree() == null && fChild2.getInnerTree() == null) { privateDoOperation(opKind, eval1, eval2, null, true, true, false, val); tree.setInnerTree(null); return true; } // otherwise convert Flattened values into literals if (fChild1.getInnerTree() == null) fChild1.setInnerTree(Literal.createLiteral(eval1)); if (fChild2.getInnerTree() == null) fChild2.setInnerTree(Literal.createLiteral(eval2)); if (fChild1.getInnerTree() == null || fChild2.getInnerTree() == null) { tree.setInnerTree(null); return false; } tree.setInnerTree(Operation.createOperation(opKind, fChild1, fChild2)); if (tree.getInnerTree() == null) { return false; } return true; default: throw new HyracksDataException("Should not get here"); } } public static boolean isStrictOperator(int op) { switch (op) { case OpKind_META_EQUAL_OP: case OpKind_META_NOT_EQUAL_OP: case OpKind_LOGICAL_AND_OP: case OpKind_LOGICAL_OR_OP: case OpKind_TERNARY_OP: return false; default: return true; } } // get precedence levels for operators (see K&R p.53 ) public static int precedenceLevel(int op) { switch (op) { case OpKind_SUBSCRIPT_OP: return (12); case OpKind_LOGICAL_NOT_OP: case OpKind_BITWISE_NOT_OP: case OpKind_UNARY_PLUS_OP: case OpKind_UNARY_MINUS_OP: return (11); case OpKind_MULTIPLICATION_OP: case OpKind_DIVISION_OP: case OpKind_MODULUS_OP: return (10); case OpKind_ADDITION_OP: case OpKind_SUBTRACTION_OP: return (9); case OpKind_LEFT_SHIFT_OP: case OpKind_RIGHT_SHIFT_OP: case OpKind_URIGHT_SHIFT_OP: return (8); case OpKind_LESS_THAN_OP: case OpKind_LESS_OR_EQUAL_OP: case OpKind_GREATER_OR_EQUAL_OP: case OpKind_GREATER_THAN_OP: return (7); case OpKind_NOT_EQUAL_OP: case OpKind_EQUAL_OP: case OpKind_IS_OP: case OpKind_ISNT_OP: return (6); case OpKind_BITWISE_AND_OP: return (5); case OpKind_BITWISE_XOR_OP: return (4); case OpKind_BITWISE_OR_OP: return (3); case OpKind_LOGICAL_AND_OP: return (2); case OpKind_LOGICAL_OR_OP: return (1); case OpKind_TERNARY_OP: return (0); default: return (-1); } } @Override public void reset() { opKind = OpKind_NO_OP; if (child1 != null) child1.reset(); if (child2 != null) child2.reset(); if (child3 != null) child3.reset(); } }