Search in sources :

Example 6 with ExprEval

use of org.apache.druid.math.expr.ExprEval in project druid by druid-io.

the class IPv4AddressParseExprMacroTest method eval.

private Object eval(Expr arg) {
    Expr expr = apply(Collections.singletonList(arg));
    ExprEval eval = expr.eval(InputBindings.nilBindings());
    return eval.value();
}
Also used : ExprEval(org.apache.druid.math.expr.ExprEval) Expr(org.apache.druid.math.expr.Expr)

Example 7 with ExprEval

use of org.apache.druid.math.expr.ExprEval in project druid by druid-io.

the class DruidRexExecutor method reduce.

@Override
public void reduce(final RexBuilder rexBuilder, final List<RexNode> constExps, final List<RexNode> reducedValues) {
    for (RexNode constExp : constExps) {
        final DruidExpression druidExpression = Expressions.toDruidExpression(plannerContext, EMPTY_ROW_SIGNATURE, constExp);
        if (druidExpression == null) {
            reducedValues.add(constExp);
        } else {
            final SqlTypeName sqlTypeName = constExp.getType().getSqlTypeName();
            final Expr expr = Parser.parse(druidExpression.getExpression(), plannerContext.getExprMacroTable());
            final ExprEval exprResult = expr.eval(InputBindings.forFunction(name -> {
                // Sanity check. Bindings should not be used for a constant expression.
                throw new UnsupportedOperationException();
            }));
            final RexNode literal;
            if (sqlTypeName == SqlTypeName.BOOLEAN) {
                literal = rexBuilder.makeLiteral(exprResult.asBoolean(), constExp.getType(), true);
            } else if (sqlTypeName == SqlTypeName.DATE) {
                // ExprEval.isNumericNull checks whether the parsed primitive value is null or not.
                if (!constExp.getType().isNullable() && exprResult.isNumericNull()) {
                    throw new UnsupportedSQLQueryException("Illegal DATE constant: %s", constExp);
                }
                literal = rexBuilder.makeDateLiteral(Calcites.jodaToCalciteDateString(DateTimes.utc(exprResult.asLong()), plannerContext.getTimeZone()));
            } else if (sqlTypeName == SqlTypeName.TIMESTAMP) {
                // ExprEval.isNumericNull checks whether the parsed primitive value is null or not.
                if (!constExp.getType().isNullable() && exprResult.isNumericNull()) {
                    throw new UnsupportedSQLQueryException("Illegal TIMESTAMP constant: %s", constExp);
                }
                literal = rexBuilder.makeTimestampLiteral(Calcites.jodaToCalciteTimestampString(DateTimes.utc(exprResult.asLong()), plannerContext.getTimeZone()), RelDataType.PRECISION_NOT_SPECIFIED);
            } else if (SqlTypeName.NUMERIC_TYPES.contains(sqlTypeName)) {
                final BigDecimal bigDecimal;
                if (exprResult.isNumericNull()) {
                    literal = rexBuilder.makeNullLiteral(constExp.getType());
                } else {
                    if (exprResult.type().is(ExprType.LONG)) {
                        bigDecimal = BigDecimal.valueOf(exprResult.asLong());
                    } else {
                        // if exprResult evaluates to Nan or infinity, this will throw a NumberFormatException.
                        // If you find yourself in such a position, consider casting the literal to a BIGINT so that
                        // the query can execute.
                        double exprResultDouble = exprResult.asDouble();
                        if (Double.isNaN(exprResultDouble) || Double.isInfinite(exprResultDouble)) {
                            String expression = druidExpression.getExpression();
                            throw new UnsupportedSQLQueryException("'%s' evaluates to '%s' that is not supported in SQL. You can either cast the expression as bigint ('cast(%s as bigint)') or char ('cast(%s as char)') or change the expression itself", expression, Double.toString(exprResultDouble), expression, expression);
                        }
                        bigDecimal = BigDecimal.valueOf(exprResult.asDouble());
                    }
                    literal = rexBuilder.makeLiteral(bigDecimal, constExp.getType(), true);
                }
            } else if (sqlTypeName == SqlTypeName.ARRAY) {
                assert exprResult.isArray();
                if (SqlTypeName.NUMERIC_TYPES.contains(constExp.getType().getComponentType().getSqlTypeName())) {
                    if (exprResult.type().getElementType().is(ExprType.LONG)) {
                        List<BigDecimal> resultAsBigDecimalList = Arrays.stream(exprResult.asLongArray()).map(BigDecimal::valueOf).collect(Collectors.toList());
                        literal = rexBuilder.makeLiteral(resultAsBigDecimalList, constExp.getType(), true);
                    } else {
                        List<BigDecimal> resultAsBigDecimalList = Arrays.stream(exprResult.asDoubleArray()).map(doubleVal -> {
                            if (Double.isNaN(doubleVal) || Double.isInfinite(doubleVal)) {
                                String expression = druidExpression.getExpression();
                                throw new UnsupportedSQLQueryException("'%s' contains an element that evaluates to '%s' which is not supported in SQL. You can either cast the element in the array to bigint or char or change the expression itself", expression, Double.toString(doubleVal));
                            }
                            return BigDecimal.valueOf(doubleVal);
                        }).collect(Collectors.toList());
                        literal = rexBuilder.makeLiteral(resultAsBigDecimalList, constExp.getType(), true);
                    }
                } else {
                    literal = rexBuilder.makeLiteral(Arrays.asList(exprResult.asArray()), constExp.getType(), true);
                }
            } else if (sqlTypeName == SqlTypeName.OTHER && constExp.getType() instanceof RowSignatures.ComplexSqlType) {
                // complex constant is not reducible, so just leave it as an expression
                literal = constExp;
            } else {
                if (exprResult.isArray()) {
                    // just leave array expressions on multi-value strings alone, we're going to push them down into a virtual
                    // column selector anyway
                    literal = constExp;
                } else {
                    literal = rexBuilder.makeLiteral(exprResult.value(), constExp.getType(), true);
                }
            }
            reducedValues.add(literal);
        }
    }
}
Also used : RelDataType(org.apache.calcite.rel.type.RelDataType) DateTimes(org.apache.druid.java.util.common.DateTimes) InputBindings(org.apache.druid.math.expr.InputBindings) Arrays(java.util.Arrays) SqlTypeName(org.apache.calcite.sql.type.SqlTypeName) RexBuilder(org.apache.calcite.rex.RexBuilder) Parser(org.apache.druid.math.expr.Parser) ExprType(org.apache.druid.math.expr.ExprType) RowSignatures(org.apache.druid.sql.calcite.table.RowSignatures) Collectors(java.util.stream.Collectors) ExprEval(org.apache.druid.math.expr.ExprEval) DruidExpression(org.apache.druid.sql.calcite.expression.DruidExpression) BigDecimal(java.math.BigDecimal) List(java.util.List) RexNode(org.apache.calcite.rex.RexNode) RowSignature(org.apache.druid.segment.column.RowSignature) Expr(org.apache.druid.math.expr.Expr) RexExecutor(org.apache.calcite.rex.RexExecutor) Expressions(org.apache.druid.sql.calcite.expression.Expressions) ExprEval(org.apache.druid.math.expr.ExprEval) DruidExpression(org.apache.druid.sql.calcite.expression.DruidExpression) SqlTypeName(org.apache.calcite.sql.type.SqlTypeName) Expr(org.apache.druid.math.expr.Expr) BigDecimal(java.math.BigDecimal) RexNode(org.apache.calcite.rex.RexNode)

Example 8 with ExprEval

use of org.apache.druid.math.expr.ExprEval in project druid by druid-io.

the class IPv4AddressMatchExprMacro method apply.

@Override
public Expr apply(final List<Expr> args) {
    if (args.size() != 2) {
        throw new IAE(ExprUtils.createErrMsg(name(), "must have 2 arguments"));
    }
    SubnetUtils.SubnetInfo subnetInfo = getSubnetInfo(args);
    Expr arg = args.get(0);
    class IPv4AddressMatchExpr extends ExprMacroTable.BaseScalarUnivariateMacroFunctionExpr {

        private final SubnetUtils.SubnetInfo subnetInfo;

        private IPv4AddressMatchExpr(Expr arg, SubnetUtils.SubnetInfo subnetInfo) {
            super(FN_NAME, arg);
            this.subnetInfo = subnetInfo;
        }

        @Nonnull
        @Override
        public ExprEval eval(final ObjectBinding bindings) {
            ExprEval eval = arg.eval(bindings);
            boolean match;
            switch(eval.type().getType()) {
                case STRING:
                    match = isStringMatch(eval.asString());
                    break;
                case LONG:
                    match = !eval.isNumericNull() && isLongMatch(eval.asLong());
                    break;
                default:
                    match = false;
            }
            return ExprEval.ofLongBoolean(match);
        }

        private boolean isStringMatch(String stringValue) {
            return IPv4AddressExprUtils.isValidAddress(stringValue) && subnetInfo.isInRange(stringValue);
        }

        private boolean isLongMatch(long longValue) {
            return !IPv4AddressExprUtils.overflowsUnsignedInt(longValue) && subnetInfo.isInRange((int) longValue);
        }

        @Override
        public Expr visit(Shuttle shuttle) {
            return shuttle.visit(apply(shuttle.visitAll(args)));
        }

        @Nullable
        @Override
        public ExpressionType getOutputType(InputBindingInspector inspector) {
            return ExpressionType.LONG;
        }

        @Override
        public String stringify() {
            return StringUtils.format("%s(%s, %s)", FN_NAME, arg.stringify(), args.get(ARG_SUBNET).stringify());
        }
    }
    return new IPv4AddressMatchExpr(arg, subnetInfo);
}
Also used : SubnetUtils(org.apache.commons.net.util.SubnetUtils) IAE(org.apache.druid.java.util.common.IAE) ExprEval(org.apache.druid.math.expr.ExprEval) Expr(org.apache.druid.math.expr.Expr)

Example 9 with ExprEval

use of org.apache.druid.math.expr.ExprEval in project druid by druid-io.

the class BloomFilterExpressionsTest method testAddLong.

@Test
public void testAddLong() {
    Expr expr = Parser.parse("bloom_filter_add(1234, bloomy)", macroTable);
    ExprEval eval = expr.eval(inputBindings);
    Assert.assertEquals(BloomFilterExpressions.BLOOM_FILTER_TYPE, eval.type());
    Assert.assertTrue(eval.value() instanceof BloomKFilter);
    Assert.assertTrue(((BloomKFilter) eval.value()).testLong(SOME_LONG));
    expr = Parser.parse("bloom_filter_add(long, bloomy)", macroTable);
    eval = expr.eval(inputBindings);
    Assert.assertEquals(BloomFilterExpressions.BLOOM_FILTER_TYPE, eval.type());
    Assert.assertTrue(eval.value() instanceof BloomKFilter);
    Assert.assertTrue(((BloomKFilter) eval.value()).testLong(SOME_LONG));
}
Also used : ExprEval(org.apache.druid.math.expr.ExprEval) Expr(org.apache.druid.math.expr.Expr) BloomKFilter(org.apache.druid.query.filter.BloomKFilter) InitializedNullHandlingTest(org.apache.druid.testing.InitializedNullHandlingTest) Test(org.junit.Test)

Example 10 with ExprEval

use of org.apache.druid.math.expr.ExprEval in project druid by druid-io.

the class BloomFilterExpressionsTest method testCreate.

@Test
public void testCreate() {
    Expr expr = Parser.parse("bloom_filter(100)", macroTable);
    ExprEval eval = expr.eval(inputBindings);
    Assert.assertEquals(BloomFilterExpressions.BLOOM_FILTER_TYPE, eval.type());
    Assert.assertTrue(eval.value() instanceof BloomKFilter);
    Assert.assertEquals(1024, ((BloomKFilter) eval.value()).getBitSize());
}
Also used : ExprEval(org.apache.druid.math.expr.ExprEval) Expr(org.apache.druid.math.expr.Expr) BloomKFilter(org.apache.druid.query.filter.BloomKFilter) InitializedNullHandlingTest(org.apache.druid.testing.InitializedNullHandlingTest) Test(org.junit.Test)

Aggregations

ExprEval (org.apache.druid.math.expr.ExprEval)19 Expr (org.apache.druid.math.expr.Expr)17 InitializedNullHandlingTest (org.apache.druid.testing.InitializedNullHandlingTest)11 Test (org.junit.Test)11 HyperLogLogCollector (org.apache.druid.hll.HyperLogLogCollector)4 BloomKFilter (org.apache.druid.query.filter.BloomKFilter)4 IAE (org.apache.druid.java.util.common.IAE)2 BigDecimal (java.math.BigDecimal)1 Arrays (java.util.Arrays)1 List (java.util.List)1 Collectors (java.util.stream.Collectors)1 RelDataType (org.apache.calcite.rel.type.RelDataType)1 RexBuilder (org.apache.calcite.rex.RexBuilder)1 RexExecutor (org.apache.calcite.rex.RexExecutor)1 RexNode (org.apache.calcite.rex.RexNode)1 SqlTypeName (org.apache.calcite.sql.type.SqlTypeName)1 SubnetUtils (org.apache.commons.net.util.SubnetUtils)1 DateTimes (org.apache.druid.java.util.common.DateTimes)1 ExprType (org.apache.druid.math.expr.ExprType)1 InputBindings (org.apache.druid.math.expr.InputBindings)1