blob: d3a74fbe2dacd682f1047c30ebe7bc57a28ee039 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.asterix.external.classad;
import org.apache.asterix.external.classad.Value.ValueType;
import org.apache.asterix.external.classad.object.pool.ClassAdObjectPool;
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;
/**
* 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 final ExprTreeHolder child1;
private final ExprTreeHolder child2;
private final ExprTreeHolder 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
* @throws HyracksDataException
*/
public static Operation createOperation(int opkind, ExprTree e1, ExprTree e2, ClassAdObjectPool objectPool)
throws HyracksDataException {
return createOperation(opkind, e1, e2, null, objectPool);
}
public static Operation createOperation(int opkind, ExprTree e1, ClassAdObjectPool objectPool)
throws HyracksDataException {
return createOperation(opkind, e1, null, null, objectPool);
}
// 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(ClassAdObjectPool objectPool) {
super(objectPool);
opKind = OpKind_NO_OP;
child1 = new ExprTreeHolder(objectPool);
child2 = new ExprTreeHolder(objectPool);
child3 = new ExprTreeHolder(objectPool);
}
public Operation(Operation op, ClassAdObjectPool objectPool) throws HyracksDataException {
super(objectPool);
child1 = new ExprTreeHolder(objectPool);
child2 = new ExprTreeHolder(objectPool);
child3 = new ExprTreeHolder(objectPool);
copyFrom(op);
}
@Override
public ExprTree copy() throws HyracksDataException {
Operation newTree = objectPool.operationPool.get();
newTree.copyFrom(this);
return newTree;
}
public boolean copyFrom(Operation op) throws HyracksDataException {
child1.copyFrom(op.child1);
child2.copyFrom(op.child2);
child3.copyFrom(op.child3);
this.opKind = op.opKind;
super.copyFrom(op);
return true;
}
@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;
}
@Override
public void privateSetParentScope(ClassAd parent) {
child1.setParentScope(parent);
child2.setParentScope(parent);
child3.setParentScope(parent);
}
public static void operate(int opKind, Value op1, Value op2, Value result, ClassAdObjectPool objectPool)
throws HyracksDataException {
Value dummy = objectPool.valuePool.get();
privateDoOperation(opKind, op1, op2, dummy, true, true, false, result, null, objectPool);
}
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, objectPool);
}
public static int privateDoOperation(int op, Value val1, Value val2, Value val3, boolean valid1, boolean valid2,
boolean valid3, Value result, ClassAdObjectPool objectPool) throws HyracksDataException {
return privateDoOperation(op, val1, val2, val3, valid1, valid2, valid3, result, null, objectPool);
}
public static int privateDoOperation(int op, Value val1, Value val2, Value val3, boolean valid1, boolean valid2,
boolean valid3, Value result, EvalState es, ClassAdObjectPool objectPool) 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.setValue(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.setValue(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, objectPool));
}
// arithmetic operations (binary)
if (op >= OpKind_ARITHMETIC_START && op <= OpKind_ARITHMETIC_END) {
return (doArithmetic(op, val1, val2, result, objectPool));
}
// logical operators (binary, one unary)
if (op >= OpKind_LOGIC_START && op <= OpKind_LOGIC_END) {
return (doLogical(op, val1, val2, result, objectPool));
}
// bitwise operators (binary, one unary)
if (op >= OpKind_BITWISE_START && op <= OpKind_BITWISE_END) {
return (doBitwise(op, val1, val2, result, objectPool));
}
// misc.
if (op == OpKind_TERNARY_OP) {
// ternary (if-operator)
MutableBoolean b = objectPool.boolPool.get();
// 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.setValue(val2);
return (SigValues.SIG_CHLD2.ordinal());
} else {
result.setValue(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 = objectPool.classAdPool.get();
AMutableCharArrayString index = objectPool.strPool.get();
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 = objectPool.int64Pool.get();
ExprList elist = objectPool.exprListPool.get();
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;
}
@Override
public boolean privateEvaluate(EvalState state, Value result) throws HyracksDataException {
Value val1 = objectPool.valuePool.get();
Value val2 = objectPool.valuePool.get();
Value val3 = objectPool.valuePool.get();
boolean valid1, valid2, valid3;
int rval = 0;
valid1 = false;
valid2 = false;
valid3 = false;
AMutableInt32 operationKind = objectPool.int32Pool.get();
ExprTreeHolder child1 = objectPool.mutableExprPool.get();
ExprTreeHolder child2 = objectPool.mutableExprPool.get();
ExprTreeHolder child3 = objectPool.mutableExprPool.get();
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, objectPool);
return (rval != SigValues.SIG_NONE.ordinal());
}
public boolean shortCircuit(EvalState state, Value arg1, Value result) throws HyracksDataException {
MutableBoolean arg1_bool = objectPool.boolPool.get();
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;
}
@Override
public boolean privateEvaluate(EvalState state, Value result, ExprTreeHolder tree) throws HyracksDataException {
int sig;
Value val1 = objectPool.valuePool.get();
Value val2 = objectPool.valuePool.get();
Value val3 = objectPool.valuePool.get();
ExprTreeHolder t1 = objectPool.mutableExprPool.get();
ExprTreeHolder t2 = objectPool.mutableExprPool.get();
ExprTreeHolder t3 = objectPool.mutableExprPool.get();
boolean valid1 = false, valid2 = false, valid3 = false;
AMutableInt32 opKind = objectPool.int32Pool.get();
ExprTreeHolder child1 = objectPool.mutableExprPool.get();
ExprTreeHolder child2 = objectPool.mutableExprPool.get();
ExprTreeHolder child3 = objectPool.mutableExprPool.get();
getComponents(opKind, child1, child2, child3);
// Evaluate all valid children
tree = objectPool.mutableExprPool.get();
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(), val1, val2, val3, valid1, valid2, valid3, result, state,
objectPool);
// 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())) {
// strict unary operators: unary -, unary +, !, ~, ()
if (opKind.getIntegerValue() == OpKind_UNARY_MINUS_OP || opKind.getIntegerValue() == OpKind_UNARY_PLUS_OP
|| opKind.getIntegerValue() == OpKind_LOGICAL_NOT_OP
|| opKind.getIntegerValue() == OpKind_BITWISE_NOT_OP
|| opKind.getIntegerValue() == 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(), t1, objectPool));
}
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(), t1, t2, objectPool));
return (true);
}
}
} else {
// non-strict operators
if (opKind.getIntegerValue() == OpKind_IS_OP || opKind.getIntegerValue() == OpKind_ISNT_OP) {
// the operation is *always* significant for IS and ISNT
tree.setInnerTree(createOperation(opKind.getIntegerValue(), t1, t2, objectPool));
return (true);
}
// other non-strict binary operators
if (opKind.getIntegerValue() == OpKind_LOGICAL_AND_OP || opKind.getIntegerValue() == 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(), t1, t2, objectPool));
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() == OpKind_TERNARY_OP) {
Value tmpVal = objectPool.valuePool.get();
tmpVal.setUndefinedValue();
tree.setInnerTree(Literal.createLiteral(tmpVal, objectPool));
// "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");
}
@Override
public boolean privateFlatten(EvalState state, Value val, ExprTreeHolder tree, AMutableInt32 opPtr)
throws HyracksDataException {
AMutableInt32 childOp1 = objectPool.int32Pool.get();
childOp1.setValue(OpKind_NO_OP);
AMutableInt32 childOp2 = objectPool.int32Pool.get();
childOp2.setValue(OpKind_NO_OP);
ExprTreeHolder fChild1 = objectPool.mutableExprPool.get();
ExprTreeHolder fChild2 = objectPool.mutableExprPool.get();
Value val1 = objectPool.valuePool.get();
Value val2 = objectPool.valuePool.get();
Value val3 = objectPool.valuePool.get();
AMutableInt32 newOp = objectPool.int32Pool.get();
newOp.setValue(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, objectPool);
tree.setInnerTree(null);
return true;
} else if (fChild1.getInnerTree() != null && fChild2.getInnerTree() != null) {
tree.setInnerTree(Operation.createOperation(op, fChild1, fChild2, objectPool));
return true;
} else if (fChild1.getInnerTree() != null) {
tree.setInnerTree(Operation.createOperation(op, fChild1, val2, objectPool));
return true;
} else if (fChild2.getInnerTree() != null) {
tree.setInnerTree(Operation.createOperation(op, val1, fChild2, objectPool));
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.getInnerTree() != null && !child1.publicFlatten(state, val1, fChild1, childOp1))
|| (child2.getInnerTree() != 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() != OpKind_NO_OP) {
tree.setInnerTree(Operation.createOperation(newOp.getIntegerValue(), val, tree, objectPool));
if (tree.getInnerTree() == null) {
return false;
}
return true;
} else if (opPtr != null) {
opPtr.setValue(newOp.getIntegerValue());
}
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 = objectPool.operationPool.get();
Value dummy = objectPool.valuePool.get(); // 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(), tree1.getInnerTree() == null ? val1 : dummy,
tree2.getInnerTree() == null ? val2 : dummy, dummy, true, true, false, val, objectPool);
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(), val1, val2, dummy, true, true, false, val, objectPool);
tree.setInnerTree(null);
op.setValue(OpKind_NO_OP);
return true;
} else if (tree1.getInnerTree() == null
&& (tree2.getInnerTree() != null && op2.getIntegerValue() == OpKind_NO_OP)) {
// leftson is a value, rightson is a tree
tree.setInnerTree(tree2.getInnerTree());
val.setValue(val1);
return true;
} else if (tree2.getInnerTree() == null
&& (tree1.getInnerTree() != null && op1.getIntegerValue() == OpKind_NO_OP)) {
// rightson is a value, leftson is a tree
tree.setInnerTree(tree1.getInnerTree());
val.setValue(val2);
return true;
} else if ((tree1.getInnerTree() != null && op1.getIntegerValue() == OpKind_NO_OP)
&& (tree2.getInnerTree() != null && op2.getIntegerValue() == OpKind_NO_OP)) {
// left and rightsons are trees only
if (null != (newOp = createOperation(op.getIntegerValue(), tree1, tree2, objectPool))) {
return false;
}
tree.setInnerTree(newOp);
op.setValue(OpKind_NO_OP);
return true;
}
// cannot collapse values due to dissimilar ops
if ((op1.getIntegerValue() != OpKind_NO_OP || op2.getIntegerValue() != 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 = objectPool.mutableExprPool.get();
ExprTreeHolder newOp2 = objectPool.mutableExprPool.get();
if (op1.getIntegerValue() != OpKind_NO_OP) {
newOp1.setInnerTree(Operation.createOperation(op1.getIntegerValue(), val1, tree1, objectPool));
} else if (tree1.getInnerTree() != null) {
newOp1.setInnerTree(tree1.getInnerTree());
} else {
newOp1.setInnerTree(Literal.createLiteral(val1, objectPool));
}
if (op2.getIntegerValue() != OpKind_NO_OP) {
newOp2.setInnerTree(Operation.createOperation(op2.getIntegerValue(), val2, tree2, objectPool));
} else if (tree2.getInnerTree() != null) {
newOp2.setInnerTree(tree2);
} else {
newOp2.setInnerTree(Literal.createLiteral(val2, objectPool));
}
if (newOp1.getInnerTree() == null || newOp2.getInnerTree() == null) {
tree.setInnerTree(null);
op.setValue(OpKind_NO_OP);
return false;
}
newOp = createOperation(op.getIntegerValue(), newOp1, newOp2, objectPool);
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(), tree1, tree2, objectPool);
if (newOp == null) {
return false;
}
privateDoOperation(op.getIntegerValue(), val1, val2, dummy, true, true, false, val, objectPool);
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(), val1, val2, dummy, true, true, false, val, objectPool);
tree.setInnerTree(tree1);
return true;
} else {
// rightson makes a tree contribution
Operation local_newOp = createOperation(op.getIntegerValue(), tree1, tree2, objectPool);
if (local_newOp == null) {
tree.setInnerTree(null);
op.setValue(OpKind_NO_OP);
return false;
}
val.setValue(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(), val1, val2, dummy, true, true, false, val, objectPool);
tree.setInnerTree(tree2);
return true;
} else {
// leftson makes a tree contribution
Operation local_newOp = createOperation(op.getIntegerValue(), tree1, tree2, objectPool);
if (local_newOp == null) {
tree.setInnerTree(null);
op.setValue(OpKind_NO_OP);
return false;
}
tree.setInnerTree(local_newOp); // NAC BUG FIX
val.setValue(val2);
return true;
}
}
throw new HyracksDataException("Should not reach here");
}
public static int doComparison(int op, Value v1, Value v2, Value result, ClassAdObjectPool objectPool)
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, objectPool);
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, objectPool);
return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal());
case INTEGER_VALUE:
compareIntegers(op, v1, v2, result, objectPool);
return (SigValues.SIG_CHLD1.ordinal() | SigValues.SIG_CHLD2.ordinal());
case REAL_VALUE:
compareReals(op, v1, v2, result, objectPool);
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, objectPool);
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, objectPool);
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, objectPool);
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, ClassAdObjectPool objectPool)
throws HyracksDataException {
AMutableInt64 i1 = objectPool.int64Pool.get();
AMutableInt64 i2 = objectPool.int64Pool.get();
ClassAdTime t1 = objectPool.classAdTimePool.get();
AMutableDouble r1 = objectPool.doublePool.get();
MutableBoolean b1 = objectPool.boolPool.get();
// 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.setValue(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, objectPool)) {
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, objectPool));
}
case ABSOLUTE_TIME_VALUE:
case RELATIVE_TIME_VALUE: {
return (doTimeArithmetic(op, v1, v2, result, objectPool));
}
default:
// should not get here
throw new HyracksDataException("Should not get here");
}
}
public static int doLogical(int op, Value v1, Value v2, Value result, ClassAdObjectPool objectPool)
throws HyracksDataException {
MutableBoolean b1 = objectPool.boolPool.get();
MutableBoolean b2 = objectPool.boolPool.get();
// 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.setValue(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.setValue(v2);
} else if (vt2 != ValueType.BOOLEAN_VALUE) {
result.setValue(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.setValue(v2);
} else if (vt2 != ValueType.BOOLEAN_VALUE) {
result.setValue(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, ClassAdObjectPool objectPool)
throws HyracksDataException {
AMutableInt64 i1 = objectPool.int64Pool.get();
AMutableInt64 i2 = objectPool.int64Pool.get();
// 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, ClassAdObjectPool objectPool)
throws HyracksDataException {
AMutableDouble r1 = objectPool.doublePool.get();
AMutableDouble r2 = objectPool.doublePool.get();
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, ClassAdObjectPool objectPool) {
ClassAdTime asecs1 = objectPool.classAdTimePool.get();
ClassAdTime asecs2 = objectPool.classAdTimePool.get();
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 = objectPool.int64Pool.get();
ClassAdTime msecs = objectPool.classAdTimePool.get();
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 = objectPool.doublePool.get();
AMutableDouble msecs = objectPool.doublePool.get();
v1.isRelativeTimeValue(asecs1);
v2.isRealValue(num);
if (op == OpKind_MULTIPLICATION_OP) {
msecs.setValue(asecs1.getRelativeTime() * num.getDoubleValue());
} else {
msecs.setValue(asecs1.getRelativeTime() * num.getDoubleValue());
}
ClassAdTime time = objectPool.classAdTimePool.get();
time.setRelativeTime(1000L * ((long) msecs.getDoubleValue()));
result.setRelativeTimeValue(time);
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 = objectPool.int64Pool.get();
v1.isIntegerValue(num);
v2.isRelativeTimeValue(asecs1);
ClassAdTime time = objectPool.classAdTimePool.get();
time.setRelativeTime(num.getLongValue() * asecs1.getRelativeTime());
result.setRelativeTimeValue(time);
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 = objectPool.doublePool.get();
v1.isRelativeTimeValue(asecs1);
v2.isRealValue(num);
ClassAdTime time = objectPool.classAdTimePool.get();
time.setRelativeTime((long) (asecs1.getRelativeTime() * num.getDoubleValue()));
result.setRelativeTimeValue(time);
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, ClassAdObjectPool objectPool) {
AMutableCharArrayString s1 = objectPool.strPool.get();
AMutableCharArrayString s2 = objectPool.strPool.get();
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, ClassAdObjectPool objectPool)
throws HyracksDataException {
ClassAdTime asecs1 = objectPool.classAdTimePool.get();
ClassAdTime asecs2 = objectPool.classAdTimePool.get();
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, ClassAdObjectPool objectPool)
throws HyracksDataException {
ClassAdTime rsecs1 = objectPool.classAdTimePool.get();
ClassAdTime rsecs2 = objectPool.classAdTimePool.get();
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, ClassAdObjectPool objectPool)
throws HyracksDataException {
MutableBoolean b1 = objectPool.boolPool.get();
MutableBoolean b2 = objectPool.boolPool.get();
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, ClassAdObjectPool objectPool)
throws HyracksDataException {
AMutableInt64 i1 = objectPool.int64Pool.get();
AMutableInt64 i2 = objectPool.int64Pool.get();
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, ClassAdObjectPool objectPool)
throws HyracksDataException {
AMutableDouble r1 = objectPool.doublePool.get();
AMutableDouble r2 = objectPool.doublePool.get();
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, ClassAdObjectPool objectPool) {
AMutableInt64 i = objectPool.int64Pool.get();
AMutableDouble r = objectPool.doublePool.get();
MutableBoolean b = objectPool.boolPool.get();
// 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(i.getLongValue());
} else if (v1.isRealValue(r) && v2.isIntegerValue(i)) {
v2.setRealValue(i.getLongValue());
}
return ValueType.REAL_VALUE;
}
public Operation(int op, ExprTreeHolder e1, ExprTreeHolder e2, ExprTreeHolder e3, ClassAdObjectPool objectPool)
throws HyracksDataException {
super(objectPool);
this.opKind = op;
this.child1 = new ExprTreeHolder(objectPool);
this.child2 = new ExprTreeHolder(objectPool);
this.child3 = new ExprTreeHolder(objectPool);
child1.copyFrom(e1);
child2.copyFrom(e2);
child3.copyFrom(e3);
}
public static Operation createOperation(int op, ExprTree e1, ExprTree e2, ExprTree e3, ClassAdObjectPool objectPool)
throws HyracksDataException {
Operation opnode = objectPool.operationPool.get();
opnode.opKind = op;
opnode.child1.copyFrom(e1);
opnode.child2.copyFrom(e2);
opnode.child3.copyFrom(e3);
return opnode;
}
public static void createOperation(int op, ExprTree e1, ExprTree e2, ExprTree e3, Operation opnode)
throws HyracksDataException {
opnode.opKind = op;
opnode.child1.copyFrom(e1);
opnode.child2.copyFrom(e2);
opnode.child3.copyFrom(e3);
}
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, ClassAdObjectPool objectPool)
throws HyracksDataException {
if (tree.getInnerTree() == null) {
return null;
}
Literal lit = Literal.createLiteral(val, objectPool);
if (lit == null) {
return null;
}
Operation newOp = createOperation(op, lit, tree, objectPool);
return newOp;
}
public static Operation createOperation(int op, ExprTreeHolder tree, Value val, ClassAdObjectPool objectPool)
throws HyracksDataException {
if (tree.getInnerTree() == null) {
return null;
}
Literal lit = Literal.createLiteral(val, objectPool);
if (lit == null) {
return null;
}
Operation newOp = createOperation(op, lit, tree, objectPool);
return newOp;
}
public boolean flattenSpecials(EvalState state, Value val, ExprTreeHolder tree) throws HyracksDataException {
ExprTreeHolder fChild1 = objectPool.mutableExprPool.get();
ExprTreeHolder fChild2 = objectPool.mutableExprPool.get();
ExprTreeHolder fChild3 = objectPool.mutableExprPool.get();
Value eval1 = objectPool.valuePool.get();
Value eval2 = objectPool.valuePool.get();
Value eval3 = objectPool.valuePool.get();
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, objectPool));
return (tree.getInnerTree() != null);
} else {
privateDoOperation(opKind, eval1, null, null, true, false, false, val, objectPool);
tree.setInnerTree(null);
eval1.setUndefinedValue();
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 = objectPool.boolPool.get();
// if the selector is not boolean-equivalent, propagate error
if (!eval1.isBooleanValueEquiv(b)) {
val.setErrorValue();
eval1.setUndefinedValue();
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, objectPool));
}
if (fChild3.getInnerTree() == null) {
fChild3.setInnerTree(Literal.createLiteral(eval3, objectPool));
}
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, objectPool));
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, objectPool);
tree.setInnerTree(null);
return true;
}
// otherwise convert Flattened values into literals
if (fChild1.getInnerTree() == null) {
fChild1.setInnerTree(Literal.createLiteral(eval1, objectPool));
}
if (fChild2.getInnerTree() == null) {
fChild2.setInnerTree(Literal.createLiteral(eval2, objectPool));
}
if (fChild1.getInnerTree() == null || fChild2.getInnerTree() == null) {
tree.setInnerTree(null);
return false;
}
tree.setInnerTree(Operation.createOperation(opKind, fChild1, fChild2, objectPool));
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;
child1.reset();
child2.reset();
child3.reset();
}
}