}
public static Expression create(CompareOp op, List<Expression> children, ImmutableBytesWritable ptr) throws SQLException {
Expression lhsExpr = children.get(0);
Expression rhsExpr = children.get(1);
PDataType lhsExprDataType = lhsExpr.getDataType();
PDataType rhsExprDataType = rhsExpr.getDataType();
if (lhsExpr instanceof RowValueConstructorExpression || rhsExpr instanceof RowValueConstructorExpression) {
if (op == CompareOp.EQUAL || op == CompareOp.NOT_EQUAL) {
List<Expression> andNodes = Lists.<Expression>newArrayListWithExpectedSize(Math.max(lhsExpr.getChildren().size(), rhsExpr.getChildren().size()));
rewriteRVCAsEqualityExpression(lhsExpr, rhsExpr, andNodes, ptr);
Expression expr = AndExpression.create(andNodes);
if (op == CompareOp.NOT_EQUAL) {
expr = NotExpression.create(expr, ptr);
}
return expr;
}
rhsExpr = RowValueConstructorExpression.coerce(lhsExpr, rhsExpr, op);
// Always wrap both sides in row value constructor, so we don't have to consider comparing
// a non rvc with a rvc.
if ( ! ( lhsExpr instanceof RowValueConstructorExpression ) ) {
lhsExpr = new RowValueConstructorExpression(Collections.singletonList(lhsExpr), lhsExpr.isStateless());
}
children = Arrays.asList(lhsExpr, rhsExpr);
} else if(lhsExprDataType != null && rhsExprDataType != null && !lhsExprDataType.isComparableTo(rhsExprDataType)) {
throw TypeMismatchException.newException(lhsExprDataType, rhsExprDataType, toString(op, children));
}
boolean isDeterministic = lhsExpr.isDeterministic() || rhsExpr.isDeterministic();
Object lhsValue = null;
// Can't use lhsNode.isConstant(), because we have cases in which we don't know
// in advance if a function evaluates to null (namely when bind variables are used)
// TODO: use lhsExpr.isStateless instead
if (lhsExpr instanceof LiteralExpression) {
lhsValue = ((LiteralExpression)lhsExpr).getValue();
if (lhsValue == null) {
return LiteralExpression.newConstant(false, PDataType.BOOLEAN, lhsExpr.isDeterministic());
}
}
Object rhsValue = null;
// TODO: use lhsExpr.isStateless instead
if (rhsExpr instanceof LiteralExpression) {
rhsValue = ((LiteralExpression)rhsExpr).getValue();
if (rhsValue == null) {
return LiteralExpression.newConstant(false, PDataType.BOOLEAN, rhsExpr.isDeterministic());
}
}
if (lhsValue != null && rhsValue != null) {
return LiteralExpression.newConstant(ByteUtil.compare(op,lhsExprDataType.compareTo(lhsValue, rhsValue, rhsExprDataType)), isDeterministic);
}
// Coerce constant to match type of lhs so that we don't need to
// convert at filter time. Since we normalize the select statement
// to put constants on the LHS, we don't need to check the RHS.
if (rhsValue != null) {
// Comparing an unsigned int/long against a negative int/long would be an example. We just need to take
// into account the comparison operator.
if (rhsExprDataType != lhsExprDataType
|| rhsExpr.getSortOrder() != lhsExpr.getSortOrder()
|| (rhsExprDataType.isFixedWidth() && rhsExpr.getMaxLength() != null && lhsExprDataType.isFixedWidth() && lhsExpr.getMaxLength() != null && rhsExpr.getMaxLength() < lhsExpr.getMaxLength())) {
// TODO: if lengths are unequal and fixed width?
if (rhsExprDataType.isCoercibleTo(lhsExprDataType, rhsValue)) { // will convert 2.0 -> 2
children = Arrays.asList(children.get(0), LiteralExpression.newConstant(rhsValue, lhsExprDataType,
lhsExpr.getMaxLength(), null, lhsExpr.getSortOrder(), isDeterministic));
} else if (op == CompareOp.EQUAL) {
return LiteralExpression.newConstant(false, PDataType.BOOLEAN, true);
} else if (op == CompareOp.NOT_EQUAL) {