use of org.apache.calcite.rex.RexLiteral in project drill by apache.
the class MongoPluginImplementor method implement.
@Override
public void implement(PluginSortRel sort) throws IOException {
runAggregate = true;
visitChild(sort.getInput());
if (!sort.collation.getFieldCollations().isEmpty()) {
BsonDocument sortKeys = new BsonDocument();
List<RelDataTypeField> fields = sort.getRowType().getFieldList();
for (RelFieldCollation fieldCollation : sort.collation.getFieldCollations()) {
String name = fields.get(fieldCollation.getFieldIndex()).getName();
sortKeys.put(name, new BsonInt32(direction(fieldCollation)));
}
operations.add(Aggregates.sort(sortKeys).toBsonDocument());
}
if (sort.offset != null) {
operations.add(Aggregates.skip(rexLiteralIntValue((RexLiteral) sort.offset)).toBsonDocument());
}
if (sort.fetch != null) {
operations.add(Aggregates.limit(rexLiteralIntValue((RexLiteral) sort.fetch)).toBsonDocument());
}
}
use of org.apache.calcite.rex.RexLiteral in project drill by apache.
the class RexToMongoTranslator method visitCall.
@Override
public BsonValue visitCall(RexCall call) {
String name = isItem(call);
if (name != null) {
return new BsonString("'$" + name + "'");
}
List<BsonValue> strings = call.operands.stream().map(operand -> operand.accept(this)).collect(Collectors.toList());
if (call.getKind() == SqlKind.CAST) {
return strings.get(0);
}
String stdOperator = MONGO_OPERATORS.get(call.getOperator());
if (stdOperator != null) {
return new BsonDocument(stdOperator, new BsonArray(strings));
}
if (call.getOperator() == SqlStdOperatorTable.ITEM) {
RexNode op1 = call.operands.get(1);
if (op1 instanceof RexLiteral) {
if (op1.getType().getSqlTypeName() == SqlTypeName.INTEGER) {
return new BsonDocument("$arrayElemAt", new BsonArray(Arrays.asList(strings.get(0), new BsonInt32(((RexLiteral) op1).getValueAs(Integer.class)))));
} else if (op1.getType().getSqlTypeName() == SqlTypeName.CHAR) {
return new BsonString(strings.get(0).asString().getValue() + "." + ((RexLiteral) op1).getValueAs(String.class));
}
}
}
if (call.getOperator() == SqlStdOperatorTable.CASE) {
// case(a, b, c) -> $cond:[a, b, c]
// case(a, b, c, d) -> $cond:[a, b, $cond:[c, d, null]]
// case(a, b, c, d, e) -> $cond:[a, b, $cond:[c, d, e]]
BsonDocument result = new BsonDocument();
BsonArray args = new BsonArray();
result.put("$cond", args);
for (int i = 0; i < strings.size(); i += 2) {
args.add(strings.get(i));
args.add(strings.get(i + 1));
if (i == strings.size() - 3) {
args.add(strings.get(i + 2));
break;
}
if (i == strings.size() - 2) {
args.add(BsonNull.VALUE);
break;
}
BsonArray innerArgs = new BsonArray();
BsonDocument innerDocument = new BsonDocument();
innerDocument.put("$cond", innerArgs);
args.add(innerDocument);
args = innerArgs;
}
return result;
}
throw new IllegalArgumentException("Translation of " + call + " is not supported by MongoProject");
}
use of org.apache.calcite.rex.RexLiteral in project drill by apache.
the class DrillReduceAggregatesRule method reduceStddev.
private RexNode reduceStddev(Aggregate oldAggRel, AggregateCall oldCall, boolean biased, boolean sqrt, List<AggregateCall> newCalls, Map<AggregateCall, RexNode> aggCallMapping, List<RexNode> inputExprs) {
// stddev_pop(x) ==>
// power(
// (sum(x * x) - sum(x) * sum(x) / count(x))
// / count(x),
// .5)
//
// stddev_samp(x) ==>
// power(
// (sum(x * x) - sum(x) * sum(x) / count(x))
// / nullif(count(x) - 1, 0),
// .5)
final PlannerSettings plannerSettings = (PlannerSettings) oldAggRel.getCluster().getPlanner().getContext();
final boolean isInferenceEnabled = plannerSettings.isTypeInferenceEnabled();
final int nGroups = oldAggRel.getGroupCount();
RelDataTypeFactory typeFactory = oldAggRel.getCluster().getTypeFactory();
final RexBuilder rexBuilder = oldAggRel.getCluster().getRexBuilder();
assert oldCall.getArgList().size() == 1 : oldCall.getArgList();
final int argOrdinal = oldCall.getArgList().get(0);
final RelDataType argType = getFieldType(oldAggRel.getInput(), argOrdinal);
// final RexNode argRef = inputExprs.get(argOrdinal);
RexNode argRef = rexBuilder.makeCall(CastHighOp, inputExprs.get(argOrdinal));
inputExprs.set(argOrdinal, argRef);
final RexNode argSquared = rexBuilder.makeCall(SqlStdOperatorTable.MULTIPLY, argRef, argRef);
final int argSquaredOrdinal = lookupOrAdd(inputExprs, argSquared);
RelDataType sumType = TypeInferenceUtils.getDrillSqlReturnTypeInference(SqlKind.SUM.name(), ImmutableList.of()).inferReturnType(oldCall.createBinding(oldAggRel));
sumType = typeFactory.createTypeWithNullability(sumType, true);
final AggregateCall sumArgSquaredAggCall = AggregateCall.create(new DrillCalciteSqlAggFunctionWrapper(new SqlSumAggFunction(sumType), sumType), oldCall.isDistinct(), oldCall.isApproximate(), ImmutableIntList.of(argSquaredOrdinal), -1, sumType, null);
final RexNode sumArgSquared = rexBuilder.addAggCall(sumArgSquaredAggCall, nGroups, newCalls, aggCallMapping, ImmutableList.of(argType));
final AggregateCall sumArgAggCall = AggregateCall.create(new DrillCalciteSqlAggFunctionWrapper(new SqlSumAggFunction(sumType), sumType), oldCall.isDistinct(), oldCall.isApproximate(), ImmutableIntList.of(argOrdinal), -1, sumType, null);
final RexNode sumArg = rexBuilder.addAggCall(sumArgAggCall, nGroups, newCalls, aggCallMapping, ImmutableList.of(argType));
final RexNode sumSquaredArg = rexBuilder.makeCall(SqlStdOperatorTable.MULTIPLY, sumArg, sumArg);
final SqlCountAggFunction countAgg = (SqlCountAggFunction) SqlStdOperatorTable.COUNT;
final RelDataType countType = countAgg.getReturnType(typeFactory);
final AggregateCall countArgAggCall = AggregateCall.create(countAgg, oldCall.isDistinct(), oldCall.isApproximate(), oldCall.getArgList(), -1, countType, null);
final RexNode countArg = rexBuilder.addAggCall(countArgAggCall, nGroups, newCalls, aggCallMapping, ImmutableList.of(argType));
final RexNode avgSumSquaredArg = rexBuilder.makeCall(SqlStdOperatorTable.DIVIDE, sumSquaredArg, countArg);
final RexNode diff = rexBuilder.makeCall(SqlStdOperatorTable.MINUS, sumArgSquared, avgSumSquaredArg);
final RexNode denominator;
if (biased) {
denominator = countArg;
} else {
final RexLiteral one = rexBuilder.makeExactLiteral(BigDecimal.ONE);
final RexNode nul = rexBuilder.makeNullLiteral(countArg.getType());
final RexNode countMinusOne = rexBuilder.makeCall(SqlStdOperatorTable.MINUS, countArg, one);
final RexNode countEqOne = rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, countArg, one);
denominator = rexBuilder.makeCall(SqlStdOperatorTable.CASE, countEqOne, nul, countMinusOne);
}
final SqlOperator divide;
if (isInferenceEnabled) {
divide = new DrillSqlOperator("divide", 2, true, oldCall.getType(), false);
} else {
divide = SqlStdOperatorTable.DIVIDE;
}
final RexNode div = rexBuilder.makeCall(divide, diff, denominator);
RexNode result = div;
if (sqrt) {
final RexNode half = rexBuilder.makeExactLiteral(new BigDecimal("0.5"));
result = rexBuilder.makeCall(SqlStdOperatorTable.POWER, div, half);
}
if (isInferenceEnabled) {
return result;
} else {
/*
* Currently calcite's strategy to infer the return type of aggregate functions
* is wrong because it uses the first known argument to determine output type. For
* instance if we are performing stddev on an integer column then it interprets the
* output type to be integer which is incorrect as it should be double. So based on
* this if we add cast after rewriting the aggregate we add an additional cast which
* would cause wrong results. So we simply add a cast to ANY.
*/
return rexBuilder.makeCast(typeFactory.createSqlType(SqlTypeName.ANY), result);
}
}
use of org.apache.calcite.rex.RexLiteral in project drill by apache.
the class FieldsReWriterUtil method getFieldNameFromItemStarField.
/**
* Checks if operator call is using item star field.
* Will return field name if true. null otherwise.
*
* @param rexCall operator call
* @param fieldNames list of field names
* @return field name, null otherwise
*/
public static String getFieldNameFromItemStarField(RexCall rexCall, List<String> fieldNames) {
if (!SqlStdOperatorTable.ITEM.equals(rexCall.getOperator())) {
return null;
}
if (rexCall.getOperands().size() != 2) {
return null;
}
if (!(rexCall.getOperands().get(0) instanceof RexInputRef && rexCall.getOperands().get(1) instanceof RexLiteral)) {
return null;
}
// get parent field reference from the first operand (ITEM($0, 'col_name' -> $0)
// and check if it corresponds to the dynamic star
RexInputRef rexInputRef = (RexInputRef) rexCall.getOperands().get(0);
String parentFieldName = fieldNames.get(rexInputRef.getIndex());
if (!SchemaPath.DYNAMIC_STAR.equals(parentFieldName)) {
return null;
}
// get field name from the second operand (ITEM($0, 'col_name') -> col_name)
RexLiteral rexLiteral = (RexLiteral) rexCall.getOperands().get(1);
if (SqlTypeName.CHAR.equals(rexLiteral.getType().getSqlTypeName())) {
return RexLiteral.stringValue(rexLiteral);
}
return null;
}
use of org.apache.calcite.rex.RexLiteral in project drill by apache.
the class MapRDBStatistics method convertLikeToRange.
/*
* Helper function to perform additional pre-processing for LIKE predicates
*/
private RexNode convertLikeToRange(RexCall condition, RexBuilder builder) {
Preconditions.checkArgument(condition.getOperator().getKind() == SqlKind.LIKE, "Unable to convertLikeToRange: argument is not a LIKE condition!");
HBaseRegexParser parser = null;
RexNode arg = null;
RexLiteral pattern = null, escape = null;
String patternStr = null, escapeStr = null;
if (condition.getOperands().size() == 2) {
// No escape character specified
for (RexNode op : condition.getOperands()) {
if (op.getKind() == SqlKind.LITERAL) {
pattern = (RexLiteral) op;
} else {
arg = op;
}
}
// Get the PATTERN strings from the corresponding RexLiteral
if (pattern.getTypeName() == SqlTypeName.DECIMAL || pattern.getTypeName() == SqlTypeName.INTEGER) {
patternStr = pattern.getValue().toString();
} else if (pattern.getTypeName() == SqlTypeName.CHAR) {
patternStr = pattern.getValue2().toString();
}
if (patternStr != null) {
parser = new HBaseRegexParser(patternStr);
}
} else if (condition.getOperands().size() == 3) {
// Escape character specified
for (RexNode op : condition.getOperands()) {
if (op.getKind() == SqlKind.LITERAL) {
// Assume first literal specifies PATTERN and the second literal specifies the ESCAPE char
if (pattern == null) {
pattern = (RexLiteral) op;
} else {
escape = (RexLiteral) op;
}
} else {
arg = op;
}
}
// Get the PATTERN and ESCAPE strings from the corresponding RexLiteral
if (pattern.getTypeName() == SqlTypeName.DECIMAL || pattern.getTypeName() == SqlTypeName.INTEGER) {
patternStr = pattern.getValue().toString();
} else if (pattern.getTypeName() == SqlTypeName.CHAR) {
patternStr = pattern.getValue2().toString();
}
if (escape.getTypeName() == SqlTypeName.DECIMAL || escape.getTypeName() == SqlTypeName.INTEGER) {
escapeStr = escape.getValue().toString();
} else if (escape.getTypeName() == SqlTypeName.CHAR) {
escapeStr = escape.getValue2().toString();
}
if (patternStr != null && escapeStr != null) {
parser = new HBaseRegexParser(patternStr, escapeStr.toCharArray()[0]);
}
}
if (parser != null) {
parser.parse();
String prefix = parser.getPrefixString();
/*
* If there is a literal prefix, convert it into an EQUALITY or RANGE predicate
*/
if (prefix != null) {
if (prefix.equals(parser.getLikeString())) {
// No WILDCARD present. This turns the LIKE predicate to EQUALITY predicate
if (arg != null) {
return builder.makeCall(SqlStdOperatorTable.EQUALS, arg, pattern);
}
} else {
// WILDCARD present. This turns the LIKE predicate to RANGE predicate
byte[] startKey = HConstants.EMPTY_START_ROW;
byte[] stopKey = HConstants.EMPTY_END_ROW;
startKey = prefix.getBytes(Charsets.UTF_8);
stopKey = startKey.clone();
boolean isMaxVal = true;
for (int i = stopKey.length - 1; i >= 0; --i) {
int nextByteValue = (0xff & stopKey[i]) + 1;
if (nextByteValue < 0xff) {
stopKey[i] = (byte) nextByteValue;
isMaxVal = false;
break;
} else {
stopKey[i] = 0;
}
}
if (isMaxVal) {
stopKey = HConstants.EMPTY_END_ROW;
}
try {
// TODO: This maybe a potential bug since we assume UTF-8 encoding. However, we follow the
// current DB implementation. See HBaseFilterBuilder.createHBaseScanSpec "like" CASE statement
RexLiteral startKeyLiteral = builder.makeLiteral(new String(startKey, Charsets.UTF_8.toString()));
RexLiteral stopKeyLiteral = builder.makeLiteral(new String(stopKey, Charsets.UTF_8.toString()));
if (arg != null) {
RexNode startPred = builder.makeCall(SqlStdOperatorTable.GREATER_THAN_OR_EQUAL, arg, startKeyLiteral);
RexNode stopPred = builder.makeCall(SqlStdOperatorTable.LESS_THAN, arg, stopKeyLiteral);
return builder.makeCall(SqlStdOperatorTable.AND, startPred, stopPred);
}
} catch (UnsupportedEncodingException ex) {
// Encoding not supported - Do nothing!
logger.debug("Statistics: convertLikeToRange: Unsupported Encoding Exception -> {}", ex.getMessage());
}
}
}
}
// Could not convert - return condition as-is.
return condition;
}
Aggregations