use of org.apache.phoenix.parse.ArithmeticParseNode in project phoenix by apache.
the class ExpressionCompiler method visitLeave.
private Expression visitLeave(ArithmeticParseNode node, List<Expression> children, ArithmeticExpressionBinder binder, ArithmeticExpressionFactory factory) throws SQLException {
boolean isNull = false;
for (Expression child : children) {
boolean isChildLiteral = (child instanceof LiteralExpression);
isNull |= isChildLiteral && ((LiteralExpression) child).getValue() == null;
}
Expression expression = factory.create(node, children);
for (int i = 0; i < node.getChildren().size(); i++) {
ParseNode childNode = node.getChildren().get(i);
if (childNode instanceof BindParseNode) {
context.getBindManager().addParamMetaData((BindParseNode) childNode, binder == null ? expression : binder.getBindMetaData(i, children, expression));
}
}
ImmutableBytesWritable ptr = context.getTempPtr();
// If all children are literals, just evaluate now
if (ExpressionUtil.isConstant(expression)) {
return ExpressionUtil.getConstantExpression(expression, ptr);
} else if (isNull) {
return LiteralExpression.newConstant(null, expression.getDataType(), expression.getDeterminism());
}
// Otherwise create and return the expression
return wrapGroupByExpression(expression);
}
use of org.apache.phoenix.parse.ArithmeticParseNode in project phoenix by apache.
the class ExpressionCompiler method visitLeave.
@Override
public Expression visitLeave(SubtractParseNode node, List<Expression> children) throws SQLException {
return visitLeave(node, children, new ArithmeticExpressionBinder() {
@Override
public PDatum getBindMetaData(int i, List<Expression> children, final Expression expression) {
final PDataType type;
// we know that the first parameter must be a date type too.
if (i == 0 && (type = children.get(1).getDataType()) != null && type.isCoercibleTo(PDate.INSTANCE)) {
return new PDatum() {
@Override
public boolean isNullable() {
return expression.isNullable();
}
@Override
public PDataType getDataType() {
return type;
}
@Override
public Integer getMaxLength() {
return expression.getMaxLength();
}
@Override
public Integer getScale() {
return expression.getScale();
}
@Override
public SortOrder getSortOrder() {
return expression.getSortOrder();
}
};
} else if (expression.getDataType() != null && expression.getDataType().isCoercibleTo(PDate.INSTANCE)) {
return new // Same as with addition
PDatum() {
@Override
public boolean isNullable() {
return expression.isNullable();
}
@Override
public PDataType getDataType() {
return PDecimal.INSTANCE;
}
@Override
public Integer getMaxLength() {
return expression.getMaxLength();
}
@Override
public Integer getScale() {
return expression.getScale();
}
@Override
public SortOrder getSortOrder() {
return expression.getSortOrder();
}
};
}
// Otherwise just go with what was calculated for the expression
return expression;
}
}, new ArithmeticExpressionFactory() {
@Override
public Expression create(ArithmeticParseNode node, List<Expression> children) throws SQLException {
int i = 0;
PDataType theType = null;
Expression e1 = children.get(0);
Expression e2 = children.get(1);
Determinism determinism = e1.getDeterminism().combine(e2.getDeterminism());
PDataType type1 = e1.getDataType();
PDataType type2 = e2.getDataType();
// TODO: simplify this special case for DATE conversion
/**
* For date1-date2, we want to coerce to a LONG because this
* cannot be compared against another date. It has essentially
* become a number. For date1-5, we want to preserve the DATE
* type because this can still be compared against another date
* and cannot be multiplied or divided. Any other time occurs is
* an error. For example, 5-date1 is an error. The nulls occur if
* we have bind variables.
*/
boolean isType1Date = type1 != null && type1 != PTimestamp.INSTANCE && type1 != PUnsignedTimestamp.INSTANCE && type1.isCoercibleTo(PDate.INSTANCE);
boolean isType2Date = type2 != null && type2 != PTimestamp.INSTANCE && type2 != PUnsignedTimestamp.INSTANCE && type2.isCoercibleTo(PDate.INSTANCE);
if (isType1Date || isType2Date) {
if (isType1Date && isType2Date) {
i = 2;
theType = PDecimal.INSTANCE;
} else if (isType1Date && type2 != null && type2.isCoercibleTo(PDecimal.INSTANCE)) {
i = 2;
theType = PDate.INSTANCE;
} else if (type1 == null || type2 == null) {
/*
* FIXME: Could be either a Date or BigDecimal, but we
* don't know if we're comparing to a date or a number
* which would be disambiguate it.
*/
i = 2;
theType = null;
}
} else if (type1 == PTimestamp.INSTANCE || type2 == PTimestamp.INSTANCE) {
i = 2;
theType = PTimestamp.INSTANCE;
} else if (type1 == PUnsignedTimestamp.INSTANCE || type2 == PUnsignedTimestamp.INSTANCE) {
i = 2;
theType = PUnsignedTimestamp.INSTANCE;
}
for (; i < children.size(); i++) {
// This logic finds the common type to which all child types are coercible
// without losing precision.
Expression e = children.get(i);
determinism = determinism.combine(e.getDeterminism());
PDataType type = e.getDataType();
if (type == null) {
continue;
} else if (type.isCoercibleTo(PLong.INSTANCE)) {
if (theType == null) {
theType = PLong.INSTANCE;
}
} else if (type == PDecimal.INSTANCE) {
// unless we're doing date arithmetic.
if (theType == null || !theType.isCoercibleTo(PDate.INSTANCE)) {
theType = PDecimal.INSTANCE;
}
} else if (type.isCoercibleTo(PDouble.INSTANCE)) {
// unless we're doing date arithmetic or we've found another child of type DECIMAL
if (theType == null || (theType != PDecimal.INSTANCE && !theType.isCoercibleTo(PDate.INSTANCE))) {
theType = PDouble.INSTANCE;
}
} else {
throw TypeMismatchException.newException(type, node.toString());
}
}
if (theType == PDecimal.INSTANCE) {
return new DecimalSubtractExpression(children);
} else if (theType == PLong.INSTANCE) {
return new LongSubtractExpression(children);
} else if (theType == PDouble.INSTANCE) {
return new DoubleSubtractExpression(children);
} else if (theType == null) {
return LiteralExpression.newConstant(null, theType, determinism);
} else if (theType == PTimestamp.INSTANCE || theType == PUnsignedTimestamp.INSTANCE) {
return new TimestampSubtractExpression(children);
} else if (theType.isCoercibleTo(PDate.INSTANCE)) {
return new DateSubtractExpression(children);
} else {
throw TypeMismatchException.newException(theType, node.toString());
}
}
});
}
Aggregations