use of io.druid.math.expr.ExprType in project druid by druid-io.
the class Expressions method toMathExpression.
/**
* Translate a row-expression to a Druid math expression. One day, when possible, this could be folded into
* {@link #toRowExtraction(DruidOperatorTable, PlannerContext, List, RexNode)}.
*
* @param rowOrder order of fields in the Druid rows to be extracted from
* @param expression expression meant to be applied on top of the rows
*
* @return expression referring to fields in rowOrder, or null if not possible
*/
public static String toMathExpression(final List<String> rowOrder, final RexNode expression) {
final SqlKind kind = expression.getKind();
final SqlTypeName sqlTypeName = expression.getType().getSqlTypeName();
if (kind == SqlKind.INPUT_REF) {
// Translate field references.
final RexInputRef ref = (RexInputRef) expression;
final String columnName = rowOrder.get(ref.getIndex());
if (columnName == null) {
throw new ISE("WTF?! Expression referred to nonexistent index[%d]", ref.getIndex());
}
return String.format("\"%s\"", escape(columnName));
} else if (kind == SqlKind.CAST || kind == SqlKind.REINTERPRET) {
// Translate casts.
final RexNode operand = ((RexCall) expression).getOperands().get(0);
final String operandExpression = toMathExpression(rowOrder, operand);
if (operandExpression == null) {
return null;
}
final ExprType fromType = MATH_TYPES.get(operand.getType().getSqlTypeName());
final ExprType toType = MATH_TYPES.get(sqlTypeName);
if (fromType != toType) {
return String.format("CAST(%s, '%s')", operandExpression, toType.toString());
} else {
return operandExpression;
}
} else if (kind == SqlKind.TIMES || kind == SqlKind.DIVIDE || kind == SqlKind.PLUS || kind == SqlKind.MINUS) {
// Translate simple arithmetic.
final List<RexNode> operands = ((RexCall) expression).getOperands();
final String lhsExpression = toMathExpression(rowOrder, operands.get(0));
final String rhsExpression = toMathExpression(rowOrder, operands.get(1));
if (lhsExpression == null || rhsExpression == null) {
return null;
}
final String op = ImmutableMap.of(SqlKind.TIMES, "*", SqlKind.DIVIDE, "/", SqlKind.PLUS, "+", SqlKind.MINUS, "-").get(kind);
return String.format("(%s %s %s)", lhsExpression, op, rhsExpression);
} else if (kind == SqlKind.OTHER_FUNCTION) {
final String calciteFunction = ((RexCall) expression).getOperator().getName();
final String druidFunction = MATH_FUNCTIONS.get(calciteFunction);
final List<String> functionArgs = Lists.newArrayList();
for (final RexNode operand : ((RexCall) expression).getOperands()) {
final String operandExpression = toMathExpression(rowOrder, operand);
if (operandExpression == null) {
return null;
}
functionArgs.add(operandExpression);
}
if ("MOD".equals(calciteFunction)) {
// Special handling for MOD, which is a function in Calcite but a binary operator in Druid.
Preconditions.checkState(functionArgs.size() == 2, "WTF?! Expected 2 args for MOD.");
return String.format("(%s %s %s)", functionArgs.get(0), "%", functionArgs.get(1));
}
if (druidFunction == null) {
return null;
}
return String.format("%s(%s)", druidFunction, Joiner.on(", ").join(functionArgs));
} else if (kind == SqlKind.LITERAL) {
// Translate literal.
if (SqlTypeName.NUMERIC_TYPES.contains(sqlTypeName)) {
// Include literal numbers as-is.
return String.valueOf(RexLiteral.value(expression));
} else if (SqlTypeName.STRING_TYPES.contains(sqlTypeName)) {
// Quote literal strings.
return "\'" + escape(RexLiteral.stringValue(expression)) + "\'";
} else {
// Can't translate other literals.
return null;
}
} else {
// Can't translate other kinds of expressions.
return null;
}
}
Aggregations