Search in sources :

Example 6 with SqlAggFunction

use of org.apache.calcite.sql.SqlAggFunction in project calcite by apache.

the class RelJsonReader method toAggCall.

private AggregateCall toAggCall(Map<String, Object> jsonAggCall) {
    final String aggName = (String) jsonAggCall.get("agg");
    final SqlAggFunction aggregation = relJson.toAggregation(aggName, jsonAggCall);
    final Boolean distinct = (Boolean) jsonAggCall.get("distinct");
    @SuppressWarnings("unchecked") final List<Integer> operands = (List<Integer>) jsonAggCall.get("operands");
    final Integer filterOperand = (Integer) jsonAggCall.get("filter");
    final RelDataType type = relJson.toType(cluster.getTypeFactory(), jsonAggCall.get("type"));
    return AggregateCall.create(aggregation, distinct, false, operands, filterOperand == null ? -1 : filterOperand, type, null);
}
Also used : AbstractList(java.util.AbstractList) ArrayList(java.util.ArrayList) ImmutableList(com.google.common.collect.ImmutableList) List(java.util.List) RelDataType(org.apache.calcite.rel.type.RelDataType) SqlAggFunction(org.apache.calcite.sql.SqlAggFunction)

Example 7 with SqlAggFunction

use of org.apache.calcite.sql.SqlAggFunction in project calcite by apache.

the class Aggregate method typeMatchesInferred.

/**
 * Returns whether the inferred type of an {@link AggregateCall} matches the
 * type it was given when it was created.
 *
 * @param aggCall Aggregate call
 * @param litmus What to do if an error is detected (types do not match)
 * @return Whether the inferred and declared types match
 */
private boolean typeMatchesInferred(final AggregateCall aggCall, final Litmus litmus) {
    SqlAggFunction aggFunction = aggCall.getAggregation();
    AggCallBinding callBinding = aggCall.createBinding(this);
    RelDataType type = aggFunction.inferReturnType(callBinding);
    RelDataType expectedType = aggCall.type;
    return RelOptUtil.eq("aggCall type", expectedType, "inferred type", type, litmus);
}
Also used : RelDataType(org.apache.calcite.rel.type.RelDataType) SqlAggFunction(org.apache.calcite.sql.SqlAggFunction)

Example 8 with SqlAggFunction

use of org.apache.calcite.sql.SqlAggFunction in project calcite by apache.

the class SqlOperatorBaseTest method testArgumentBounds.

/**
 * Test that calls all operators with all possible argument types, and for
 * each type, with a set of tricky values.
 */
@Test
public void testArgumentBounds() {
    if (!CalciteAssert.ENABLE_SLOW) {
        return;
    }
    final SqlValidatorImpl validator = (SqlValidatorImpl) tester.getValidator();
    final SqlValidatorScope scope = validator.getEmptyScope();
    final RelDataTypeFactory typeFactory = validator.getTypeFactory();
    final Builder builder = new Builder(typeFactory);
    builder.add0(SqlTypeName.BOOLEAN, true, false);
    builder.add0(SqlTypeName.TINYINT, 0, 1, -3, Byte.MAX_VALUE, Byte.MIN_VALUE);
    builder.add0(SqlTypeName.SMALLINT, 0, 1, -4, Short.MAX_VALUE, Short.MIN_VALUE);
    builder.add0(SqlTypeName.INTEGER, 0, 1, -2, Integer.MIN_VALUE, Integer.MAX_VALUE);
    builder.add0(SqlTypeName.BIGINT, 0, 1, -5, Integer.MAX_VALUE, Long.MAX_VALUE, Long.MIN_VALUE);
    builder.add1(SqlTypeName.VARCHAR, 11, "", " ", "hello world");
    builder.add1(SqlTypeName.CHAR, 5, "", "e", "hello");
    builder.add0(SqlTypeName.TIMESTAMP, 0L, DateTimeUtils.MILLIS_PER_DAY);
    for (SqlOperator op : SqlStdOperatorTable.instance().getOperatorList()) {
        switch(op.getKind()) {
            // can't handle the flag argument
            case TRIM:
            case EXISTS:
                continue;
        }
        switch(op.getSyntax()) {
            case SPECIAL:
                continue;
        }
        final SqlOperandTypeChecker typeChecker = op.getOperandTypeChecker();
        if (typeChecker == null) {
            continue;
        }
        final SqlOperandCountRange range = typeChecker.getOperandCountRange();
        for (int n = range.getMin(), max = range.getMax(); n <= max; n++) {
            final List<List<ValueType>> argValues = Collections.nCopies(n, builder.values);
            for (final List<ValueType> args : Linq4j.product(argValues)) {
                SqlNodeList nodeList = new SqlNodeList(SqlParserPos.ZERO);
                int nullCount = 0;
                for (ValueType arg : args) {
                    if (arg.value == null) {
                        ++nullCount;
                    }
                    nodeList.add(arg.node);
                }
                final SqlCall call = op.createCall(nodeList);
                final SqlCallBinding binding = new SqlCallBinding(validator, scope, call);
                if (!typeChecker.checkOperandTypes(binding, false)) {
                    continue;
                }
                final SqlPrettyWriter writer = new SqlPrettyWriter(CalciteSqlDialect.DEFAULT);
                op.unparse(writer, call, 0, 0);
                final String s = writer.toSqlString().toString();
                if (s.startsWith("OVERLAY(") || s.contains(" / 0") || s.matches("MOD\\(.*, 0\\)")) {
                    continue;
                }
                final Strong.Policy policy = Strong.policy(op.kind);
                try {
                    if (nullCount > 0 && policy == Strong.Policy.ANY) {
                        tester.checkNull(s);
                    } else {
                        final String query;
                        if (op instanceof SqlAggFunction) {
                            if (op.requiresOrder()) {
                                query = "SELECT " + s + " OVER () FROM (VALUES (1))";
                            } else {
                                query = "SELECT " + s + " FROM (VALUES (1))";
                            }
                        } else {
                            query = SqlTesterImpl.buildQuery(s);
                        }
                        tester.check(query, SqlTests.ANY_TYPE_CHECKER, SqlTests.ANY_PARAMETER_CHECKER, SqlTests.ANY_RESULT_CHECKER);
                    }
                } catch (Error e) {
                    System.out.println(s + ": " + e.getMessage());
                    throw e;
                } catch (Exception e) {
                    System.out.println("Failed: " + s + ": " + e.getMessage());
                }
            }
        }
    }
}
Also used : SqlValidatorScope(org.apache.calcite.sql.validate.SqlValidatorScope) SqlOperator(org.apache.calcite.sql.SqlOperator) SqlCall(org.apache.calcite.sql.SqlCall) TimestampString(org.apache.calcite.util.TimestampString) SqlString(org.apache.calcite.sql.util.SqlString) SqlAggFunction(org.apache.calcite.sql.SqlAggFunction) Strong(org.apache.calcite.plan.Strong) SQLException(java.sql.SQLException) SqlOperandCountRange(org.apache.calcite.sql.SqlOperandCountRange) SqlValidatorImpl(org.apache.calcite.sql.validate.SqlValidatorImpl) RelDataTypeFactory(org.apache.calcite.rel.type.RelDataTypeFactory) SqlCallBinding(org.apache.calcite.sql.SqlCallBinding) SqlPrettyWriter(org.apache.calcite.sql.pretty.SqlPrettyWriter) SqlNodeList(org.apache.calcite.sql.SqlNodeList) SqlOperandTypeChecker(org.apache.calcite.sql.type.SqlOperandTypeChecker) List(java.util.List) ArrayList(java.util.ArrayList) SqlNodeList(org.apache.calcite.sql.SqlNodeList) SqlLimitsTest(org.apache.calcite.test.SqlLimitsTest) Test(org.junit.Test)

Example 9 with SqlAggFunction

use of org.apache.calcite.sql.SqlAggFunction in project calcite by apache.

the class EnumerableWindow method declareAndResetState.

private void declareAndResetState(final JavaTypeFactory typeFactory, BlockBuilder builder, final Result result, int windowIdx, List<AggImpState> aggs, PhysType outputPhysType, List<Expression> outputRow) {
    for (final AggImpState agg : aggs) {
        agg.context = new WinAggContext() {

            public SqlAggFunction aggregation() {
                return agg.call.getAggregation();
            }

            public RelDataType returnRelType() {
                return agg.call.type;
            }

            public Type returnType() {
                return EnumUtils.javaClass(typeFactory, returnRelType());
            }

            public List<? extends Type> parameterTypes() {
                return EnumUtils.fieldTypes(typeFactory, parameterRelTypes());
            }

            public List<? extends RelDataType> parameterRelTypes() {
                return EnumUtils.fieldRowTypes(result.physType.getRowType(), constants, agg.call.getArgList());
            }

            public List<ImmutableBitSet> groupSets() {
                throw new UnsupportedOperationException();
            }

            public List<Integer> keyOrdinals() {
                throw new UnsupportedOperationException();
            }

            public List<? extends RelDataType> keyRelTypes() {
                throw new UnsupportedOperationException();
            }

            public List<? extends Type> keyTypes() {
                throw new UnsupportedOperationException();
            }
        };
        String aggName = "a" + agg.aggIdx;
        if (CalcitePrepareImpl.DEBUG) {
            aggName = Util.toJavaId(agg.call.getAggregation().getName(), 0).substring("ID$0$".length()) + aggName;
        }
        List<Type> state = agg.implementor.getStateType(agg.context);
        final List<Expression> decls = new ArrayList<Expression>(state.size());
        for (int i = 0; i < state.size(); i++) {
            Type type = state.get(i);
            ParameterExpression pe = Expressions.parameter(type, builder.newName(aggName + "s" + i + "w" + windowIdx));
            builder.add(Expressions.declare(0, pe, null));
            decls.add(pe);
        }
        agg.state = decls;
        Type aggHolderType = agg.context.returnType();
        Type aggStorageType = outputPhysType.getJavaFieldType(outputRow.size());
        if (Primitive.is(aggHolderType) && !Primitive.is(aggStorageType)) {
            aggHolderType = Primitive.box(aggHolderType);
        }
        ParameterExpression aggRes = Expressions.parameter(0, aggHolderType, builder.newName(aggName + "w" + windowIdx));
        builder.add(Expressions.declare(0, aggRes, Expressions.constant(Primitive.is(aggRes.getType()) ? Primitive.of(aggRes.getType()).defaultValue : null, aggRes.getType())));
        agg.result = aggRes;
        outputRow.add(aggRes);
        agg.implementor.implementReset(agg.context, new WinAggResetContextImpl(builder, agg.state, null, null, null, null, null, null));
    }
}
Also used : WinAggResetContextImpl(org.apache.calcite.adapter.enumerable.impl.WinAggResetContextImpl) ArrayList(java.util.ArrayList) RelDataType(org.apache.calcite.rel.type.RelDataType) SqlAggFunction(org.apache.calcite.sql.SqlAggFunction) RelDataType(org.apache.calcite.rel.type.RelDataType) Type(java.lang.reflect.Type) BinaryExpression(org.apache.calcite.linq4j.tree.BinaryExpression) Expression(org.apache.calcite.linq4j.tree.Expression) ParameterExpression(org.apache.calcite.linq4j.tree.ParameterExpression) ParameterExpression(org.apache.calcite.linq4j.tree.ParameterExpression) ArrayList(java.util.ArrayList) ImmutableList(com.google.common.collect.ImmutableList) List(java.util.List)

Example 10 with SqlAggFunction

use of org.apache.calcite.sql.SqlAggFunction in project calcite by apache.

the class AggregateJoinTransposeRule method onMatch.

public void onMatch(RelOptRuleCall call) {
    final Aggregate aggregate = call.rel(0);
    final Join join = call.rel(1);
    final RexBuilder rexBuilder = aggregate.getCluster().getRexBuilder();
    final RelBuilder relBuilder = call.builder();
    // If any aggregate call has a filter, bail out
    for (AggregateCall aggregateCall : aggregate.getAggCallList()) {
        if (aggregateCall.getAggregation().unwrap(SqlSplittableAggFunction.class) == null) {
            return;
        }
        if (aggregateCall.filterArg >= 0) {
            return;
        }
    }
    // aggregate operator
    if (join.getJoinType() != JoinRelType.INNER) {
        return;
    }
    if (!allowFunctions && !aggregate.getAggCallList().isEmpty()) {
        return;
    }
    // Do the columns used by the join appear in the output of the aggregate?
    final ImmutableBitSet aggregateColumns = aggregate.getGroupSet();
    final RelMetadataQuery mq = call.getMetadataQuery();
    final ImmutableBitSet keyColumns = keyColumns(aggregateColumns, mq.getPulledUpPredicates(join).pulledUpPredicates);
    final ImmutableBitSet joinColumns = RelOptUtil.InputFinder.bits(join.getCondition());
    final boolean allColumnsInAggregate = keyColumns.contains(joinColumns);
    final ImmutableBitSet belowAggregateColumns = aggregateColumns.union(joinColumns);
    // Split join condition
    final List<Integer> leftKeys = Lists.newArrayList();
    final List<Integer> rightKeys = Lists.newArrayList();
    final List<Boolean> filterNulls = Lists.newArrayList();
    RexNode nonEquiConj = RelOptUtil.splitJoinCondition(join.getLeft(), join.getRight(), join.getCondition(), leftKeys, rightKeys, filterNulls);
    // If it contains non-equi join conditions, we bail out
    if (!nonEquiConj.isAlwaysTrue()) {
        return;
    }
    // Push each aggregate function down to each side that contains all of its
    // arguments. Note that COUNT(*), because it has no arguments, can go to
    // both sides.
    final Map<Integer, Integer> map = new HashMap<>();
    final List<Side> sides = new ArrayList<>();
    int uniqueCount = 0;
    int offset = 0;
    int belowOffset = 0;
    for (int s = 0; s < 2; s++) {
        final Side side = new Side();
        final RelNode joinInput = join.getInput(s);
        int fieldCount = joinInput.getRowType().getFieldCount();
        final ImmutableBitSet fieldSet = ImmutableBitSet.range(offset, offset + fieldCount);
        final ImmutableBitSet belowAggregateKeyNotShifted = belowAggregateColumns.intersect(fieldSet);
        for (Ord<Integer> c : Ord.zip(belowAggregateKeyNotShifted)) {
            map.put(c.e, belowOffset + c.i);
        }
        final Mappings.TargetMapping mapping = s == 0 ? Mappings.createIdentity(fieldCount) : Mappings.createShiftMapping(fieldCount + offset, 0, offset, fieldCount);
        final ImmutableBitSet belowAggregateKey = belowAggregateKeyNotShifted.shift(-offset);
        final boolean unique;
        if (!allowFunctions) {
            assert aggregate.getAggCallList().isEmpty();
            // If there are no functions, it doesn't matter as much whether we
            // aggregate the inputs before the join, because there will not be
            // any functions experiencing a cartesian product effect.
            // 
            // But finding out whether the input is already unique requires a call
            // to areColumnsUnique that currently (until [CALCITE-1048] "Make
            // metadata more robust" is fixed) places a heavy load on
            // the metadata system.
            // 
            // So we choose to imagine the the input is already unique, which is
            // untrue but harmless.
            // 
            Util.discard(Bug.CALCITE_1048_FIXED);
            unique = true;
        } else {
            final Boolean unique0 = mq.areColumnsUnique(joinInput, belowAggregateKey);
            unique = unique0 != null && unique0;
        }
        if (unique) {
            ++uniqueCount;
            side.aggregate = false;
            relBuilder.push(joinInput);
            final List<RexNode> projects = new ArrayList<>();
            for (Integer i : belowAggregateKey) {
                projects.add(relBuilder.field(i));
            }
            for (Ord<AggregateCall> aggCall : Ord.zip(aggregate.getAggCallList())) {
                final SqlAggFunction aggregation = aggCall.e.getAggregation();
                final SqlSplittableAggFunction splitter = Preconditions.checkNotNull(aggregation.unwrap(SqlSplittableAggFunction.class));
                if (!aggCall.e.getArgList().isEmpty() && fieldSet.contains(ImmutableBitSet.of(aggCall.e.getArgList()))) {
                    final RexNode singleton = splitter.singleton(rexBuilder, joinInput.getRowType(), aggCall.e.transform(mapping));
                    if (singleton instanceof RexInputRef) {
                        side.split.put(aggCall.i, ((RexInputRef) singleton).getIndex());
                    } else {
                        projects.add(singleton);
                        side.split.put(aggCall.i, projects.size() - 1);
                    }
                }
            }
            relBuilder.project(projects);
            side.newInput = relBuilder.build();
        } else {
            side.aggregate = true;
            List<AggregateCall> belowAggCalls = new ArrayList<>();
            final SqlSplittableAggFunction.Registry<AggregateCall> belowAggCallRegistry = registry(belowAggCalls);
            final int oldGroupKeyCount = aggregate.getGroupCount();
            final int newGroupKeyCount = belowAggregateKey.cardinality();
            for (Ord<AggregateCall> aggCall : Ord.zip(aggregate.getAggCallList())) {
                final SqlAggFunction aggregation = aggCall.e.getAggregation();
                final SqlSplittableAggFunction splitter = Preconditions.checkNotNull(aggregation.unwrap(SqlSplittableAggFunction.class));
                final AggregateCall call1;
                if (fieldSet.contains(ImmutableBitSet.of(aggCall.e.getArgList()))) {
                    final AggregateCall splitCall = splitter.split(aggCall.e, mapping);
                    call1 = splitCall.adaptTo(joinInput, splitCall.getArgList(), splitCall.filterArg, oldGroupKeyCount, newGroupKeyCount);
                } else {
                    call1 = splitter.other(rexBuilder.getTypeFactory(), aggCall.e);
                }
                if (call1 != null) {
                    side.split.put(aggCall.i, belowAggregateKey.cardinality() + belowAggCallRegistry.register(call1));
                }
            }
            side.newInput = relBuilder.push(joinInput).aggregate(relBuilder.groupKey(belowAggregateKey, null), belowAggCalls).build();
        }
        offset += fieldCount;
        belowOffset += side.newInput.getRowType().getFieldCount();
        sides.add(side);
    }
    if (uniqueCount == 2) {
        // invocation of this rule; if we continue we might loop forever.
        return;
    }
    // Update condition
    final Mapping mapping = (Mapping) Mappings.target(new Function<Integer, Integer>() {

        public Integer apply(Integer a0) {
            return map.get(a0);
        }
    }, join.getRowType().getFieldCount(), belowOffset);
    final RexNode newCondition = RexUtil.apply(mapping, join.getCondition());
    // Create new join
    relBuilder.push(sides.get(0).newInput).push(sides.get(1).newInput).join(join.getJoinType(), newCondition);
    // Aggregate above to sum up the sub-totals
    final List<AggregateCall> newAggCalls = new ArrayList<>();
    final int groupIndicatorCount = aggregate.getGroupCount() + aggregate.getIndicatorCount();
    final int newLeftWidth = sides.get(0).newInput.getRowType().getFieldCount();
    final List<RexNode> projects = new ArrayList<>(rexBuilder.identityProjects(relBuilder.peek().getRowType()));
    for (Ord<AggregateCall> aggCall : Ord.zip(aggregate.getAggCallList())) {
        final SqlAggFunction aggregation = aggCall.e.getAggregation();
        final SqlSplittableAggFunction splitter = Preconditions.checkNotNull(aggregation.unwrap(SqlSplittableAggFunction.class));
        final Integer leftSubTotal = sides.get(0).split.get(aggCall.i);
        final Integer rightSubTotal = sides.get(1).split.get(aggCall.i);
        newAggCalls.add(splitter.topSplit(rexBuilder, registry(projects), groupIndicatorCount, relBuilder.peek().getRowType(), aggCall.e, leftSubTotal == null ? -1 : leftSubTotal, rightSubTotal == null ? -1 : rightSubTotal + newLeftWidth));
    }
    relBuilder.project(projects);
    boolean aggConvertedToProjects = false;
    if (allColumnsInAggregate) {
        // let's see if we can convert aggregate into projects
        List<RexNode> projects2 = new ArrayList<>();
        for (int key : Mappings.apply(mapping, aggregate.getGroupSet())) {
            projects2.add(relBuilder.field(key));
        }
        for (AggregateCall newAggCall : newAggCalls) {
            final SqlSplittableAggFunction splitter = newAggCall.getAggregation().unwrap(SqlSplittableAggFunction.class);
            if (splitter != null) {
                final RelDataType rowType = relBuilder.peek().getRowType();
                projects2.add(splitter.singleton(rexBuilder, rowType, newAggCall));
            }
        }
        if (projects2.size() == aggregate.getGroupSet().cardinality() + newAggCalls.size()) {
            // We successfully converted agg calls into projects.
            relBuilder.project(projects2);
            aggConvertedToProjects = true;
        }
    }
    if (!aggConvertedToProjects) {
        relBuilder.aggregate(relBuilder.groupKey(Mappings.apply(mapping, aggregate.getGroupSet()), Mappings.apply2(mapping, aggregate.getGroupSets())), newAggCalls);
    }
    call.transformTo(relBuilder.build());
}
Also used : RelMetadataQuery(org.apache.calcite.rel.metadata.RelMetadataQuery) ImmutableBitSet(org.apache.calcite.util.ImmutableBitSet) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) Mapping(org.apache.calcite.util.mapping.Mapping) RelDataType(org.apache.calcite.rel.type.RelDataType) Function(com.google.common.base.Function) SqlSplittableAggFunction(org.apache.calcite.sql.SqlSplittableAggFunction) SqlAggFunction(org.apache.calcite.sql.SqlAggFunction) RexBuilder(org.apache.calcite.rex.RexBuilder) SqlSplittableAggFunction(org.apache.calcite.sql.SqlSplittableAggFunction) RelBuilder(org.apache.calcite.tools.RelBuilder) Join(org.apache.calcite.rel.core.Join) LogicalJoin(org.apache.calcite.rel.logical.LogicalJoin) SqlAggFunction(org.apache.calcite.sql.SqlAggFunction) AggregateCall(org.apache.calcite.rel.core.AggregateCall) RelNode(org.apache.calcite.rel.RelNode) Mappings(org.apache.calcite.util.mapping.Mappings) RexInputRef(org.apache.calcite.rex.RexInputRef) Aggregate(org.apache.calcite.rel.core.Aggregate) LogicalAggregate(org.apache.calcite.rel.logical.LogicalAggregate) RexNode(org.apache.calcite.rex.RexNode)

Aggregations

SqlAggFunction (org.apache.calcite.sql.SqlAggFunction)43 RelDataType (org.apache.calcite.rel.type.RelDataType)30 ArrayList (java.util.ArrayList)22 RexNode (org.apache.calcite.rex.RexNode)22 AggregateCall (org.apache.calcite.rel.core.AggregateCall)17 RexBuilder (org.apache.calcite.rex.RexBuilder)13 List (java.util.List)11 RelNode (org.apache.calcite.rel.RelNode)11 RelDataTypeFactory (org.apache.calcite.rel.type.RelDataTypeFactory)9 ImmutableBitSet (org.apache.calcite.util.ImmutableBitSet)8 ImmutableList (com.google.common.collect.ImmutableList)7 HashMap (java.util.HashMap)7 Aggregate (org.apache.calcite.rel.core.Aggregate)7 RelBuilder (org.apache.calcite.tools.RelBuilder)7 SqlOperator (org.apache.calcite.sql.SqlOperator)6 Type (java.lang.reflect.Type)5 RelMetadataQuery (org.apache.calcite.rel.metadata.RelMetadataQuery)5 RexInputRef (org.apache.calcite.rex.RexInputRef)5 Mappings (org.apache.calcite.util.mapping.Mappings)5 Join (org.apache.calcite.rel.core.Join)4