use of org.apache.druid.sql.calcite.expression.DruidExpression in project druid by druid-io.
the class TimeShiftOperatorConversion method toDruidExpression.
@Override
public DruidExpression toDruidExpression(final PlannerContext plannerContext, final RowSignature rowSignature, final RexNode rexNode) {
final RexCall call = (RexCall) rexNode;
final DruidExpression timeExpression = Expressions.toDruidExpression(plannerContext, rowSignature, call.getOperands().get(0));
final DruidExpression periodExpression = Expressions.toDruidExpression(plannerContext, rowSignature, call.getOperands().get(1));
final DruidExpression stepExpression = Expressions.toDruidExpression(plannerContext, rowSignature, call.getOperands().get(2));
if (timeExpression == null || periodExpression == null || stepExpression == null) {
return null;
}
final DateTimeZone timeZone = OperatorConversions.getOperandWithDefault(call.getOperands(), 3, operand -> DateTimes.inferTzFromString(RexLiteral.stringValue(operand)), plannerContext.getTimeZone());
return DruidExpression.ofFunctionCall(Calcites.getColumnTypeForRelDataType(rexNode.getType()), "timestamp_shift", ImmutableList.of(timeExpression, periodExpression, stepExpression, DruidExpression.ofStringLiteral(timeZone.getID())));
}
use of org.apache.druid.sql.calcite.expression.DruidExpression in project druid by druid-io.
the class ArrayContainsOperatorConversion method toDruidFilter.
@Nullable
@Override
public DimFilter toDruidFilter(final PlannerContext plannerContext, RowSignature rowSignature, @Nullable VirtualColumnRegistry virtualColumnRegistry, final RexNode rexNode) {
final List<RexNode> operands = ((RexCall) rexNode).getOperands();
final List<DruidExpression> druidExpressions = Expressions.toDruidExpressions(plannerContext, rowSignature, operands);
if (druidExpressions == null) {
return null;
}
// Converts array_contains() function into an AND of Selector filters if possible.
final DruidExpression leftExpr = druidExpressions.get(0);
final DruidExpression rightExpr = druidExpressions.get(1);
if (leftExpr.isSimpleExtraction()) {
Expr expr = Parser.parse(rightExpr.getExpression(), plannerContext.getExprMacroTable());
// different package.
if (expr.isLiteral()) {
// Evaluate the expression to get out the array elements.
// We can safely pass a noop ObjectBinding if the expression is literal.
ExprEval<?> exprEval = expr.eval(InputBindings.nilBindings());
String[] arrayElements = exprEval.asStringArray();
if (arrayElements == null || arrayElements.length == 0) {
// to create an empty array with no argument, we just return null.
return null;
} else if (arrayElements.length == 1) {
return newSelectorDimFilter(leftExpr.getSimpleExtraction(), arrayElements[0]);
} else {
final List<DimFilter> selectFilters = Arrays.stream(arrayElements).map(val -> newSelectorDimFilter(leftExpr.getSimpleExtraction(), val)).collect(Collectors.toList());
return new AndDimFilter(selectFilters);
}
}
}
return toExpressionFilter(plannerContext, getDruidFunctionName(), druidExpressions);
}
use of org.apache.druid.sql.calcite.expression.DruidExpression in project druid by druid-io.
the class ArrayOverlapOperatorConversion method toDruidFilter.
@Nullable
@Override
public DimFilter toDruidFilter(final PlannerContext plannerContext, RowSignature rowSignature, @Nullable VirtualColumnRegistry virtualColumnRegistry, final RexNode rexNode) {
final List<RexNode> operands = ((RexCall) rexNode).getOperands();
final List<DruidExpression> druidExpressions = Expressions.toDruidExpressions(plannerContext, rowSignature, operands);
if (druidExpressions == null) {
return null;
}
// Converts array_overlaps() function into an OR of Selector filters if possible.
final boolean leftSimpleExtractionExpr = druidExpressions.get(0).isSimpleExtraction();
final boolean rightSimpleExtractionExpr = druidExpressions.get(1).isSimpleExtraction();
final DruidExpression simpleExtractionExpr;
final DruidExpression complexExpr;
if (leftSimpleExtractionExpr ^ rightSimpleExtractionExpr) {
if (leftSimpleExtractionExpr) {
simpleExtractionExpr = druidExpressions.get(0);
complexExpr = druidExpressions.get(1);
} else {
simpleExtractionExpr = druidExpressions.get(1);
complexExpr = druidExpressions.get(0);
}
} else {
return toExpressionFilter(plannerContext, getDruidFunctionName(), druidExpressions);
}
Expr expr = Parser.parse(complexExpr.getExpression(), plannerContext.getExprMacroTable());
if (expr.isLiteral()) {
// Evaluate the expression to take out the array elements.
// We can safely pass null if the expression is literal.
ExprEval<?> exprEval = expr.eval(InputBindings.nilBindings());
String[] arrayElements = exprEval.asStringArray();
if (arrayElements == null || arrayElements.length == 0) {
// to create an empty array with no argument, we just return null.
return null;
} else if (arrayElements.length == 1) {
return newSelectorDimFilter(simpleExtractionExpr.getSimpleExtraction(), arrayElements[0]);
} else {
return new InDimFilter(simpleExtractionExpr.getSimpleExtraction().getColumn(), Sets.newHashSet(arrayElements), simpleExtractionExpr.getSimpleExtraction().getExtractionFn(), null);
}
}
return toExpressionFilter(plannerContext, getDruidFunctionName(), druidExpressions);
}
use of org.apache.druid.sql.calcite.expression.DruidExpression in project druid by druid-io.
the class RegexpExtractOperatorConversion method toDruidExpression.
@Override
public DruidExpression toDruidExpression(final PlannerContext plannerContext, final RowSignature rowSignature, final RexNode rexNode) {
return OperatorConversions.convertDirectCallWithExtraction(plannerContext, rowSignature, rexNode, StringUtils.toLowerCase(calciteOperator().getName()), inputExpressions -> {
final DruidExpression arg = inputExpressions.get(0);
final Expr patternExpr = inputExpressions.get(1).parse(plannerContext.getExprMacroTable());
final Expr indexExpr = inputExpressions.size() > 2 ? inputExpressions.get(2).parse(plannerContext.getExprMacroTable()) : null;
if (arg.isSimpleExtraction() && patternExpr.isLiteral() && (indexExpr == null || indexExpr.isLiteral())) {
final String pattern = (String) patternExpr.getLiteralValue();
return arg.getSimpleExtraction().cascade(new RegexDimExtractionFn(// non-SQL-compliant null handling mode).
StringUtils.nullToEmptyNonDruidDataString(pattern), indexExpr == null ? DEFAULT_INDEX : ((Number) indexExpr.getLiteralValue()).intValue(), true, null));
} else {
return null;
}
});
}
use of org.apache.druid.sql.calcite.expression.DruidExpression in project druid by druid-io.
the class TDigestSketchQuantileSqlAggregator method toDruidAggregation.
@Nullable
@Override
public Aggregation toDruidAggregation(final PlannerContext plannerContext, final RowSignature rowSignature, final VirtualColumnRegistry virtualColumnRegistry, final RexBuilder rexBuilder, final String name, final AggregateCall aggregateCall, final Project project, final List<Aggregation> existingAggregations, final boolean finalizeAggregations) {
// This is expected to be a tdigest sketch
final DruidExpression input = Aggregations.toDruidExpressionForNumericAggregator(plannerContext, rowSignature, Expressions.fromFieldAccess(rowSignature, project, aggregateCall.getArgList().get(0)));
if (input == null) {
return null;
}
final AggregatorFactory aggregatorFactory;
final String sketchName = StringUtils.format("%s:agg", name);
// this is expected to be quantile fraction
final RexNode quantileArg = Expressions.fromFieldAccess(rowSignature, project, aggregateCall.getArgList().get(1));
if (!quantileArg.isA(SqlKind.LITERAL)) {
// Quantile must be a literal in order to plan.
return null;
}
final double quantile = ((Number) RexLiteral.value(quantileArg)).floatValue();
Integer compression = TDigestSketchAggregatorFactory.DEFAULT_COMPRESSION;
if (aggregateCall.getArgList().size() > 2) {
final RexNode compressionArg = Expressions.fromFieldAccess(rowSignature, project, aggregateCall.getArgList().get(2));
compression = ((Number) RexLiteral.value(compressionArg)).intValue();
}
// Look for existing matching aggregatorFactory.
for (final Aggregation existing : existingAggregations) {
for (AggregatorFactory factory : existing.getAggregatorFactories()) {
if (factory instanceof TDigestSketchAggregatorFactory) {
final boolean matches = TDigestSketchUtils.matchingAggregatorFactoryExists(virtualColumnRegistry, input, compression, (TDigestSketchAggregatorFactory) factory);
if (matches) {
// Found existing one. Use this.
return Aggregation.create(ImmutableList.of(), new TDigestSketchToQuantilePostAggregator(name, new FieldAccessPostAggregator(factory.getName(), factory.getName()), quantile));
}
}
}
}
// No existing match found. Create a new one.
if (input.isDirectColumnAccess()) {
aggregatorFactory = new TDigestSketchAggregatorFactory(sketchName, input.getDirectColumn(), compression);
} else {
String virtualColumnName = virtualColumnRegistry.getOrCreateVirtualColumnForExpression(input, ColumnType.FLOAT);
aggregatorFactory = new TDigestSketchAggregatorFactory(sketchName, virtualColumnName, compression);
}
return Aggregation.create(ImmutableList.of(aggregatorFactory), new TDigestSketchToQuantilePostAggregator(name, new FieldAccessPostAggregator(sketchName, sketchName), quantile));
}
Aggregations