Search in sources :

Example 6 with SqlCountAggFunction

use of org.apache.calcite.sql.fun.SqlCountAggFunction in project flink by apache.

the class FlinkAggregateExpandDistinctAggregatesRule method convertSingletonDistinct.

/**
	 * Converts an aggregate with one distinct aggregate and one or more
	 * non-distinct aggregates to multi-phase aggregates (see reference example
	 * below).
	 *
	 * @param relBuilder Contains the input relational expression
	 * @param aggregate  Original aggregate
	 * @param argLists   Arguments and filters to the distinct aggregate function
	 *
	 */
private RelBuilder convertSingletonDistinct(RelBuilder relBuilder, Aggregate aggregate, Set<Pair<List<Integer>, Integer>> argLists) {
    // For example,
    //	SELECT deptno, COUNT(*), SUM(bonus), MIN(DISTINCT sal)
    //	FROM emp
    //	GROUP BY deptno
    //
    // becomes
    //
    //	SELECT deptno, SUM(cnt), SUM(bonus), MIN(sal)
    //	FROM (
    //		  SELECT deptno, COUNT(*) as cnt, SUM(bonus), sal
    //		  FROM EMP
    //		  GROUP BY deptno, sal)			// Aggregate B
    //	GROUP BY deptno						// Aggregate A
    relBuilder.push(aggregate.getInput());
    final List<Pair<RexNode, String>> projects = new ArrayList<>();
    final Map<Integer, Integer> sourceOf = new HashMap<>();
    SortedSet<Integer> newGroupSet = new TreeSet<>();
    final List<RelDataTypeField> childFields = relBuilder.peek().getRowType().getFieldList();
    final boolean hasGroupBy = aggregate.getGroupSet().size() > 0;
    SortedSet<Integer> groupSet = new TreeSet<>(aggregate.getGroupSet().asList());
    // Add the distinct aggregate column(s) to the group-by columns,
    // if not already a part of the group-by
    newGroupSet.addAll(aggregate.getGroupSet().asList());
    for (Pair<List<Integer>, Integer> argList : argLists) {
        newGroupSet.addAll(argList.getKey());
    }
    // transformation.
    for (int arg : newGroupSet) {
        sourceOf.put(arg, projects.size());
        projects.add(RexInputRef.of2(arg, childFields));
    }
    // Generate the intermediate aggregate B
    final List<AggregateCall> aggCalls = aggregate.getAggCallList();
    final List<AggregateCall> newAggCalls = new ArrayList<>();
    final List<Integer> fakeArgs = new ArrayList<>();
    final Map<AggregateCall, Integer> callArgMap = new HashMap<>();
    // e.g. if real arguments are 0, 1, 3. Then the fake arguments will be 2, 4
    for (final AggregateCall aggCall : aggCalls) {
        if (!aggCall.isDistinct()) {
            for (int arg : aggCall.getArgList()) {
                if (!groupSet.contains(arg)) {
                    sourceOf.put(arg, projects.size());
                }
            }
        }
    }
    int fakeArg0 = 0;
    for (final AggregateCall aggCall : aggCalls) {
        // We will deal with non-distinct aggregates below
        if (!aggCall.isDistinct()) {
            boolean isGroupKeyUsedInAgg = false;
            for (int arg : aggCall.getArgList()) {
                if (groupSet.contains(arg)) {
                    isGroupKeyUsedInAgg = true;
                    break;
                }
            }
            if (aggCall.getArgList().size() == 0 || isGroupKeyUsedInAgg) {
                while (sourceOf.get(fakeArg0) != null) {
                    ++fakeArg0;
                }
                fakeArgs.add(fakeArg0);
                ++fakeArg0;
            }
        }
    }
    for (final AggregateCall aggCall : aggCalls) {
        if (!aggCall.isDistinct()) {
            for (int arg : aggCall.getArgList()) {
                if (!groupSet.contains(arg)) {
                    sourceOf.remove(arg);
                }
            }
        }
    }
    // Compute the remapped arguments using fake arguments for non-distinct
    // aggregates with no arguments e.g. count(*).
    int fakeArgIdx = 0;
    for (final AggregateCall aggCall : aggCalls) {
        // as-is all the non-distinct aggregates
        if (!aggCall.isDistinct()) {
            final AggregateCall newCall = AggregateCall.create(aggCall.getAggregation(), false, aggCall.getArgList(), -1, ImmutableBitSet.of(newGroupSet).cardinality(), relBuilder.peek(), null, aggCall.name);
            newAggCalls.add(newCall);
            if (newCall.getArgList().size() == 0) {
                int fakeArg = fakeArgs.get(fakeArgIdx);
                callArgMap.put(newCall, fakeArg);
                sourceOf.put(fakeArg, projects.size());
                projects.add(Pair.of((RexNode) new RexInputRef(fakeArg, newCall.getType()), newCall.getName()));
                ++fakeArgIdx;
            } else {
                for (int arg : newCall.getArgList()) {
                    if (groupSet.contains(arg)) {
                        int fakeArg = fakeArgs.get(fakeArgIdx);
                        callArgMap.put(newCall, fakeArg);
                        sourceOf.put(fakeArg, projects.size());
                        projects.add(Pair.of((RexNode) new RexInputRef(fakeArg, newCall.getType()), newCall.getName()));
                        ++fakeArgIdx;
                    } else {
                        sourceOf.put(arg, projects.size());
                        projects.add(Pair.of((RexNode) new RexInputRef(arg, newCall.getType()), newCall.getName()));
                    }
                }
            }
        }
    }
    // Generate the aggregate B (see the reference example above)
    relBuilder.push(aggregate.copy(aggregate.getTraitSet(), relBuilder.build(), false, ImmutableBitSet.of(newGroupSet), null, newAggCalls));
    // Convert the existing aggregate to aggregate A (see the reference example above)
    final List<AggregateCall> newTopAggCalls = Lists.newArrayList(aggregate.getAggCallList());
    // Use the remapped arguments for the (non)distinct aggregate calls
    for (int i = 0; i < newTopAggCalls.size(); i++) {
        // Re-map arguments.
        final AggregateCall aggCall = newTopAggCalls.get(i);
        final int argCount = aggCall.getArgList().size();
        final List<Integer> newArgs = new ArrayList<>(argCount);
        final AggregateCall newCall;
        for (int j = 0; j < argCount; j++) {
            final Integer arg = aggCall.getArgList().get(j);
            if (callArgMap.containsKey(aggCall)) {
                newArgs.add(sourceOf.get(callArgMap.get(aggCall)));
            } else {
                newArgs.add(sourceOf.get(arg));
            }
        }
        if (aggCall.isDistinct()) {
            newCall = AggregateCall.create(aggCall.getAggregation(), false, newArgs, -1, aggregate.getGroupSet().cardinality(), relBuilder.peek(), aggCall.getType(), aggCall.name);
        } else {
            // aggregate A must be SUM. For other aggregates, it remains the same.
            if (aggCall.getAggregation() instanceof SqlCountAggFunction) {
                if (aggCall.getArgList().size() == 0) {
                    newArgs.add(sourceOf.get(callArgMap.get(aggCall)));
                }
                if (hasGroupBy) {
                    SqlSumAggFunction sumAgg = new SqlSumAggFunction(null);
                    newCall = AggregateCall.create(sumAgg, false, newArgs, -1, aggregate.getGroupSet().cardinality(), relBuilder.peek(), aggCall.getType(), aggCall.getName());
                } else {
                    SqlSumEmptyIsZeroAggFunction sumAgg = new SqlSumEmptyIsZeroAggFunction();
                    newCall = AggregateCall.create(sumAgg, false, newArgs, -1, aggregate.getGroupSet().cardinality(), relBuilder.peek(), aggCall.getType(), aggCall.getName());
                }
            } else {
                newCall = AggregateCall.create(aggCall.getAggregation(), false, newArgs, -1, aggregate.getGroupSet().cardinality(), relBuilder.peek(), aggCall.getType(), aggCall.name);
            }
        }
        newTopAggCalls.set(i, newCall);
    }
    // Populate the group-by keys with the remapped arguments for aggregate A
    newGroupSet.clear();
    for (int arg : aggregate.getGroupSet()) {
        newGroupSet.add(sourceOf.get(arg));
    }
    relBuilder.push(aggregate.copy(aggregate.getTraitSet(), relBuilder.build(), aggregate.indicator, ImmutableBitSet.of(newGroupSet), null, newTopAggCalls));
    return relBuilder;
}
Also used : HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) SqlCountAggFunction(org.apache.calcite.sql.fun.SqlCountAggFunction) AggregateCall(org.apache.calcite.rel.core.AggregateCall) SqlSumEmptyIsZeroAggFunction(org.apache.calcite.sql.fun.SqlSumEmptyIsZeroAggFunction) RelDataTypeField(org.apache.calcite.rel.type.RelDataTypeField) TreeSet(java.util.TreeSet) SqlSumAggFunction(org.apache.calcite.sql.fun.SqlSumAggFunction) RexInputRef(org.apache.calcite.rex.RexInputRef) ArrayList(java.util.ArrayList) ImmutableList(com.google.common.collect.ImmutableList) ImmutableIntList(org.apache.calcite.util.ImmutableIntList) List(java.util.List) Pair(org.apache.calcite.util.Pair) RexNode(org.apache.calcite.rex.RexNode)

Example 7 with SqlCountAggFunction

use of org.apache.calcite.sql.fun.SqlCountAggFunction in project drill by axbaretto.

the class DrillReduceAggregatesRule method reduceSum.

private RexNode reduceSum(Aggregate oldAggRel, AggregateCall oldCall, List<AggregateCall> newCalls, Map<AggregateCall, RexNode> aggCallMapping) {
    final PlannerSettings plannerSettings = (PlannerSettings) oldAggRel.getCluster().getPlanner().getContext();
    final boolean isInferenceEnabled = plannerSettings.isTypeInferenceEnabled();
    final int nGroups = oldAggRel.getGroupCount();
    RelDataTypeFactory typeFactory = oldAggRel.getCluster().getTypeFactory();
    RexBuilder rexBuilder = oldAggRel.getCluster().getRexBuilder();
    int arg = oldCall.getArgList().get(0);
    RelDataType argType = getFieldType(oldAggRel.getInput(), arg);
    final RelDataType sumType;
    final SqlAggFunction sumZeroAgg;
    if (isInferenceEnabled) {
        sumType = oldCall.getType();
    } else {
        sumType = typeFactory.createTypeWithNullability(oldCall.getType(), argType.isNullable());
    }
    sumZeroAgg = new DrillCalciteSqlAggFunctionWrapper(new SqlSumEmptyIsZeroAggFunction(), sumType);
    AggregateCall sumZeroCall = AggregateCall.create(sumZeroAgg, oldCall.isDistinct(), oldCall.isApproximate(), oldCall.getArgList(), -1, sumType, null);
    final SqlCountAggFunction countAgg = (SqlCountAggFunction) SqlStdOperatorTable.COUNT;
    final RelDataType countType = countAgg.getReturnType(typeFactory);
    AggregateCall countCall = AggregateCall.create(countAgg, oldCall.isDistinct(), oldCall.isApproximate(), oldCall.getArgList(), -1, countType, null);
    // NOTE:  these references are with respect to the output
    // of newAggRel
    RexNode sumZeroRef = rexBuilder.addAggCall(sumZeroCall, nGroups, oldAggRel.indicator, newCalls, aggCallMapping, ImmutableList.of(argType));
    if (!oldCall.getType().isNullable()) {
        // null). Therefore we translate to SUM0(x).
        return sumZeroRef;
    }
    RexNode countRef = rexBuilder.addAggCall(countCall, nGroups, oldAggRel.indicator, newCalls, aggCallMapping, ImmutableList.of(argType));
    return rexBuilder.makeCall(SqlStdOperatorTable.CASE, rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, countRef, rexBuilder.makeExactLiteral(BigDecimal.ZERO)), rexBuilder.constantNull(), sumZeroRef);
}
Also used : SqlSumEmptyIsZeroAggFunction(org.apache.calcite.sql.fun.SqlSumEmptyIsZeroAggFunction) AggregateCall(org.apache.calcite.rel.core.AggregateCall) PlannerSettings(org.apache.drill.exec.planner.physical.PlannerSettings) RelDataTypeFactory(org.apache.calcite.rel.type.RelDataTypeFactory) RexBuilder(org.apache.calcite.rex.RexBuilder) RelDataType(org.apache.calcite.rel.type.RelDataType) SqlAggFunction(org.apache.calcite.sql.SqlAggFunction) SqlCountAggFunction(org.apache.calcite.sql.fun.SqlCountAggFunction) DrillCalciteSqlAggFunctionWrapper(org.apache.drill.exec.planner.sql.DrillCalciteSqlAggFunctionWrapper) RexNode(org.apache.calcite.rex.RexNode)

Example 8 with SqlCountAggFunction

use of org.apache.calcite.sql.fun.SqlCountAggFunction in project drill by axbaretto.

the class UnsupportedOperatorsVisitor method visit.

@Override
public SqlNode visit(SqlCall sqlCall) {
    // Inspect the window functions
    if (sqlCall instanceof SqlSelect) {
        SqlSelect sqlSelect = (SqlSelect) sqlCall;
        checkGrouping((sqlSelect));
        checkRollupCubeGrpSets(sqlSelect);
        for (SqlNode nodeInSelectList : sqlSelect.getSelectList()) {
            // enter the first operand of AS operator
            if (nodeInSelectList.getKind() == SqlKind.AS && (((SqlCall) nodeInSelectList).getOperandList().get(0).getKind() == SqlKind.OVER)) {
                nodeInSelectList = ((SqlCall) nodeInSelectList).getOperandList().get(0);
            }
            if (nodeInSelectList.getKind() == SqlKind.OVER) {
                // Throw exceptions if window functions are disabled
                if (!context.getOptions().getOption(ExecConstants.ENABLE_WINDOW_FUNCTIONS).bool_val) {
                    unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, "Window functions are disabled\n" + "See Apache Drill JIRA: DRILL-2559");
                    throw new UnsupportedOperationException();
                }
                // DRILL-3182, DRILL-3195
                SqlCall over = (SqlCall) nodeInSelectList;
                if (over.getOperandList().get(0) instanceof SqlCall) {
                    SqlCall function = (SqlCall) over.getOperandList().get(0);
                    // Window function with DISTINCT qualifier is temporarily disabled
                    if (function.getFunctionQuantifier() != null && function.getFunctionQuantifier().getValue() == SqlSelectKeyword.DISTINCT) {
                        unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, "DISTINCT for window aggregate functions is not currently supported\n" + "See Apache Drill JIRA: DRILL-3182");
                        throw new UnsupportedOperationException();
                    }
                    // DRILL-3596: we only allow (<column-name>) or (<column-name>, 1)
                    final String functionName = function.getOperator().getName().toUpperCase();
                    if ("LEAD".equals(functionName) || "LAG".equals(functionName)) {
                        boolean supported = true;
                        if (function.operandCount() > 2) {
                            // we don't support more than 2 arguments
                            supported = false;
                        } else if (function.operandCount() == 2) {
                            SqlNode operand = function.operand(1);
                            if (operand instanceof SqlNumericLiteral) {
                                SqlNumericLiteral offsetLiteral = (SqlNumericLiteral) operand;
                                try {
                                    if (offsetLiteral.intValue(true) != 1) {
                                        // we don't support offset != 1
                                        supported = false;
                                    }
                                } catch (AssertionError e) {
                                    // we only support offset as an integer
                                    supported = false;
                                }
                            } else {
                                // we only support offset as a numeric literal
                                supported = false;
                            }
                        }
                        if (!supported) {
                            unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, "Function " + functionName + " only supports (<value expression>) or (<value expression>, 1)\n" + "See Apache DRILL JIRA: DRILL-3596");
                            throw new UnsupportedOperationException();
                        }
                    }
                }
            }
        }
    }
    // (i.e., BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
    if (sqlCall instanceof SqlWindow) {
        SqlWindow window = (SqlWindow) sqlCall;
        SqlNode lowerBound = window.getLowerBound();
        SqlNode upperBound = window.getUpperBound();
        // If no frame is specified
        // it is a default frame
        boolean isSupported = (lowerBound == null && upperBound == null);
        // RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
        if (window.getOrderList().size() != 0 && !window.isRows() && SqlWindow.isUnboundedPreceding(lowerBound) && (upperBound == null || SqlWindow.isCurrentRow(upperBound) || SqlWindow.isUnboundedFollowing(upperBound))) {
            isSupported = true;
        }
        // is supported with and without the ORDER BY clause
        if (window.isRows() && SqlWindow.isUnboundedPreceding(lowerBound) && (upperBound == null || SqlWindow.isCurrentRow(upperBound))) {
            isSupported = true;
        }
        // is supported with and without an ORDER BY clause
        if (!window.isRows() && SqlWindow.isCurrentRow(lowerBound) && SqlWindow.isCurrentRow(upperBound)) {
            isSupported = true;
        }
        // ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
        if (window.getOrderList().size() == 0 && SqlWindow.isUnboundedPreceding(lowerBound) && SqlWindow.isUnboundedFollowing(upperBound)) {
            isSupported = true;
        }
        if (!isSupported) {
            unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, "This type of window frame is currently not supported \n" + "See Apache Drill JIRA: DRILL-3188");
            throw new UnsupportedOperationException();
        }
        // DRILL-3189: Disable DISALLOW PARTIAL
        if (!window.isAllowPartial()) {
            unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, "Disallowing partial windows is currently not supported \n" + "See Apache Drill JIRA: DRILL-3189");
            throw new UnsupportedOperationException();
        }
    }
    // Disable unsupported Intersect, Except
    if (sqlCall.getKind() == SqlKind.INTERSECT || sqlCall.getKind() == SqlKind.EXCEPT) {
        unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.RELATIONAL, sqlCall.getOperator().getName() + " is not supported\n" + "See Apache Drill JIRA: DRILL-1921");
        throw new UnsupportedOperationException();
    }
    // Disable unsupported JOINs
    if (sqlCall.getKind() == SqlKind.JOIN) {
        SqlJoin join = (SqlJoin) sqlCall;
        // Block Natural Join
        if (join.isNatural()) {
            unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.RELATIONAL, "NATURAL JOIN is not supported\n" + "See Apache Drill JIRA: DRILL-1986");
            throw new UnsupportedOperationException();
        }
        // Block Cross Join
        if (join.getJoinType() == JoinType.CROSS) {
            unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.RELATIONAL, "CROSS JOIN is not supported\n" + "See Apache Drill JIRA: DRILL-1921");
            throw new UnsupportedOperationException();
        }
    }
    // Disable Function
    for (String strOperator : disabledOperators) {
        if (sqlCall.getOperator().isName(strOperator)) {
            unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, sqlCall.getOperator().getName() + " is not supported\n" + "See Apache Drill JIRA: DRILL-2115");
            throw new UnsupportedOperationException();
        }
    }
    // Disable complex functions incorrect placement
    if (sqlCall instanceof SqlSelect) {
        SqlSelect sqlSelect = (SqlSelect) sqlCall;
        for (SqlNode nodeInSelectList : sqlSelect.getSelectList()) {
            if (checkDirExplorers(nodeInSelectList)) {
                unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, "Directory explorers " + dirExplorers + " functions are not supported in Select List\n" + "See Apache Drill JIRA: DRILL-3944");
                throw new UnsupportedOperationException();
            }
        }
        if (sqlSelect.hasWhere()) {
            if (checkDirExplorers(sqlSelect.getWhere()) && !context.getPlannerSettings().isConstantFoldingEnabled()) {
                unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, "Directory explorers " + dirExplorers + " functions can not be used " + "when " + PlannerSettings.CONSTANT_FOLDING.getOptionName() + " option is set to false\n" + "See Apache Drill JIRA: DRILL-3944");
                throw new UnsupportedOperationException();
            }
        }
        if (sqlSelect.hasOrderBy()) {
            for (SqlNode sqlNode : sqlSelect.getOrderList()) {
                if (containsFlatten(sqlNode)) {
                    unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, "Flatten function is not supported in Order By\n" + "See Apache Drill JIRA: DRILL-2181");
                    throw new UnsupportedOperationException();
                } else if (checkDirExplorers(sqlNode)) {
                    unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, "Directory explorers " + dirExplorers + " functions are not supported in Order By\n" + "See Apache Drill JIRA: DRILL-3944");
                    throw new UnsupportedOperationException();
                }
            }
        }
        if (sqlSelect.getGroup() != null) {
            for (SqlNode sqlNode : sqlSelect.getGroup()) {
                if (containsFlatten(sqlNode)) {
                    unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, "Flatten function is not supported in Group By\n" + "See Apache Drill JIRA: DRILL-2181");
                    throw new UnsupportedOperationException();
                } else if (checkDirExplorers(sqlNode)) {
                    unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, "Directory explorers " + dirExplorers + " functions are not supported in Group By\n" + "See Apache Drill JIRA: DRILL-3944");
                    throw new UnsupportedOperationException();
                }
            }
        }
        if (sqlSelect.isDistinct()) {
            for (SqlNode column : sqlSelect.getSelectList()) {
                if (column.getKind() == SqlKind.AS) {
                    if (containsFlatten(((SqlCall) column).getOperandList().get(0))) {
                        unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, "Flatten function is not supported in Distinct\n" + "See Apache Drill JIRA: DRILL-2181");
                        throw new UnsupportedOperationException();
                    }
                } else {
                    if (containsFlatten(column)) {
                        unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, "Flatten function is not supported in Distinct\n" + "See Apache Drill JIRA: DRILL-2181");
                        throw new UnsupportedOperationException();
                    }
                }
            }
        }
    }
    if (DrillCalciteWrapperUtility.extractSqlOperatorFromWrapper(sqlCall.getOperator()) instanceof SqlCountAggFunction) {
        for (SqlNode sqlNode : sqlCall.getOperandList()) {
            if (containsFlatten(sqlNode)) {
                unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, "Flatten function in aggregate functions is not supported\n" + "See Apache Drill JIRA: DRILL-2181");
                throw new UnsupportedOperationException();
            }
        }
    }
    return sqlCall.getOperator().acceptCall(this, sqlCall);
}
Also used : SqlSelect(org.apache.calcite.sql.SqlSelect) SqlCall(org.apache.calcite.sql.SqlCall) SqlJoin(org.apache.calcite.sql.SqlJoin) SqlWindow(org.apache.calcite.sql.SqlWindow) SqlNumericLiteral(org.apache.calcite.sql.SqlNumericLiteral) SqlCountAggFunction(org.apache.calcite.sql.fun.SqlCountAggFunction) SqlNode(org.apache.calcite.sql.SqlNode)

Example 9 with SqlCountAggFunction

use of org.apache.calcite.sql.fun.SqlCountAggFunction in project drill by apache.

the class UnsupportedOperatorsVisitor method visit.

@Override
public SqlNode visit(SqlCall sqlCall) {
    // Inspect the window functions
    if (sqlCall instanceof SqlSelect) {
        SqlSelect sqlSelect = (SqlSelect) sqlCall;
        checkGrouping((sqlSelect));
        checkRollupCubeGrpSets(sqlSelect);
        for (SqlNode nodeInSelectList : sqlSelect.getSelectList()) {
            // enter the first operand of AS operator
            if (nodeInSelectList.getKind() == SqlKind.AS && (((SqlCall) nodeInSelectList).getOperandList().get(0).getKind() == SqlKind.OVER)) {
                nodeInSelectList = ((SqlCall) nodeInSelectList).getOperandList().get(0);
            }
            if (nodeInSelectList.getKind() == SqlKind.OVER) {
                // Throw exceptions if window functions are disabled
                if (!context.getOptions().getOption(ExecConstants.ENABLE_WINDOW_FUNCTIONS).bool_val) {
                    unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, "Window functions are disabled\n" + "See Apache Drill JIRA: DRILL-2559");
                    throw new UnsupportedOperationException();
                }
                // DRILL-3182, DRILL-3195
                SqlCall over = (SqlCall) nodeInSelectList;
                if (over.getOperandList().get(0) instanceof SqlCall) {
                    SqlCall function = (SqlCall) over.getOperandList().get(0);
                    // Window function with DISTINCT qualifier is temporarily disabled
                    if (function.getFunctionQuantifier() != null && function.getFunctionQuantifier().getValue() == SqlSelectKeyword.DISTINCT) {
                        unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, "DISTINCT for window aggregate functions is not currently supported\n" + "See Apache Drill JIRA: DRILL-3182");
                        throw new UnsupportedOperationException();
                    }
                    // DRILL-3596: we only allow (<column-name>) or (<column-name>, 1)
                    final String functionName = function.getOperator().getName().toUpperCase();
                    if ("LEAD".equals(functionName) || "LAG".equals(functionName)) {
                        boolean supported = true;
                        if (function.operandCount() > 2) {
                            // we don't support more than 2 arguments
                            supported = false;
                        } else if (function.operandCount() == 2) {
                            SqlNode operand = function.operand(1);
                            if (operand instanceof SqlNumericLiteral) {
                                SqlNumericLiteral offsetLiteral = (SqlNumericLiteral) operand;
                                try {
                                    if (offsetLiteral.intValue(true) != 1) {
                                        // we don't support offset != 1
                                        supported = false;
                                    }
                                } catch (AssertionError e) {
                                    // we only support offset as an integer
                                    supported = false;
                                }
                            } else {
                                // we only support offset as a numeric literal
                                supported = false;
                            }
                        }
                        if (!supported) {
                            unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, "Function " + functionName + " only supports (<value expression>) or (<value expression>, 1)\n" + "See Apache DRILL JIRA: DRILL-3596");
                            throw new UnsupportedOperationException();
                        }
                    }
                }
            }
        }
    }
    // (i.e., BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
    if (sqlCall instanceof SqlWindow) {
        SqlWindow window = (SqlWindow) sqlCall;
        SqlNode lowerBound = window.getLowerBound();
        SqlNode upperBound = window.getUpperBound();
        // If no frame is specified
        // it is a default frame
        boolean isSupported = (lowerBound == null && upperBound == null);
        // RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
        if (window.getOrderList().size() != 0 && !window.isRows() && SqlWindow.isUnboundedPreceding(lowerBound) && (upperBound == null || SqlWindow.isCurrentRow(upperBound) || SqlWindow.isUnboundedFollowing(upperBound))) {
            isSupported = true;
        }
        // is supported with and without the ORDER BY clause
        if (window.isRows() && SqlWindow.isUnboundedPreceding(lowerBound) && (upperBound == null || SqlWindow.isCurrentRow(upperBound))) {
            isSupported = true;
        }
        // is supported with and without an ORDER BY clause
        if (!window.isRows() && SqlWindow.isCurrentRow(lowerBound) && SqlWindow.isCurrentRow(upperBound)) {
            isSupported = true;
        }
        // ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
        if (window.getOrderList().size() == 0 && SqlWindow.isUnboundedPreceding(lowerBound) && SqlWindow.isUnboundedFollowing(upperBound)) {
            isSupported = true;
        }
        if (!isSupported) {
            unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, "This type of window frame is currently not supported \n" + "See Apache Drill JIRA: DRILL-3188");
            throw new UnsupportedOperationException();
        }
        // DRILL-3189: Disable DISALLOW PARTIAL
        if (!window.isAllowPartial()) {
            unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, "Disallowing partial windows is currently not supported \n" + "See Apache Drill JIRA: DRILL-3189");
            throw new UnsupportedOperationException();
        }
    }
    // Disable unsupported Intersect, Except
    if (sqlCall.getKind() == SqlKind.INTERSECT || sqlCall.getKind() == SqlKind.EXCEPT) {
        unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.RELATIONAL, sqlCall.getOperator().getName() + " is not supported\n" + "See Apache Drill JIRA: DRILL-1921");
        throw new UnsupportedOperationException();
    }
    // Disable unsupported JOINs
    if (sqlCall.getKind() == SqlKind.JOIN) {
        SqlJoin join = (SqlJoin) sqlCall;
        // Block Natural Join
        if (join.isNatural()) {
            unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.RELATIONAL, "NATURAL JOIN is not supported\n" + "See Apache Drill JIRA: DRILL-1986");
            throw new UnsupportedOperationException();
        }
    }
    // Disable UNNEST if the configuration disable it
    if (sqlCall.getKind() == SqlKind.UNNEST) {
        if (!context.getPlannerSettings().isUnnestLateralEnabled()) {
            unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.RELATIONAL, "Unnest is not enabled per configuration");
            throw new UnsupportedOperationException();
        }
    }
    // Disable Function
    for (String strOperator : disabledOperators) {
        if (sqlCall.getOperator().isName(strOperator, true)) {
            // true is passed to preserve previous behavior
            unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, sqlCall.getOperator().getName() + " is not supported\n" + "See Apache Drill JIRA: DRILL-2115");
            throw new UnsupportedOperationException();
        }
    }
    // Disable complex functions incorrect placement
    if (sqlCall instanceof SqlSelect) {
        SqlSelect sqlSelect = (SqlSelect) sqlCall;
        for (SqlNode nodeInSelectList : sqlSelect.getSelectList()) {
            if (checkDirExplorers(nodeInSelectList)) {
                unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, "Directory explorers " + dirExplorers + " functions are not supported in Select List\n" + "See Apache Drill JIRA: DRILL-3944");
                throw new UnsupportedOperationException();
            }
        }
        if (sqlSelect.hasWhere()) {
            if (checkDirExplorers(sqlSelect.getWhere()) && !context.getPlannerSettings().isConstantFoldingEnabled()) {
                unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, "Directory explorers " + dirExplorers + " functions can not be used " + "when " + PlannerSettings.CONSTANT_FOLDING.getOptionName() + " option is set to false\n" + "See Apache Drill JIRA: DRILL-3944");
                throw new UnsupportedOperationException();
            }
        }
        if (sqlSelect.hasOrderBy()) {
            for (SqlNode sqlNode : sqlSelect.getOrderList()) {
                if (containsFlatten(sqlNode)) {
                    unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, "Flatten function is not supported in Order By\n" + "See Apache Drill JIRA: DRILL-2181");
                    throw new UnsupportedOperationException();
                } else if (checkDirExplorers(sqlNode)) {
                    unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, "Directory explorers " + dirExplorers + " functions are not supported in Order By\n" + "See Apache Drill JIRA: DRILL-3944");
                    throw new UnsupportedOperationException();
                }
            }
        }
        if (sqlSelect.getGroup() != null) {
            for (SqlNode sqlNode : sqlSelect.getGroup()) {
                if (containsFlatten(sqlNode)) {
                    unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, "Flatten function is not supported in Group By\n" + "See Apache Drill JIRA: DRILL-2181");
                    throw new UnsupportedOperationException();
                } else if (checkDirExplorers(sqlNode)) {
                    unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, "Directory explorers " + dirExplorers + " functions are not supported in Group By\n" + "See Apache Drill JIRA: DRILL-3944");
                    throw new UnsupportedOperationException();
                }
            }
        }
        if (sqlSelect.isDistinct()) {
            for (SqlNode column : sqlSelect.getSelectList()) {
                if (column.getKind() == SqlKind.AS) {
                    if (containsFlatten(((SqlCall) column).getOperandList().get(0))) {
                        unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, "Flatten function is not supported in Distinct\n" + "See Apache Drill JIRA: DRILL-2181");
                        throw new UnsupportedOperationException();
                    }
                } else {
                    if (containsFlatten(column)) {
                        unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, "Flatten function is not supported in Distinct\n" + "See Apache Drill JIRA: DRILL-2181");
                        throw new UnsupportedOperationException();
                    }
                }
            }
        }
    }
    if (DrillCalciteWrapperUtility.extractSqlOperatorFromWrapper(sqlCall.getOperator()) instanceof SqlCountAggFunction) {
        for (SqlNode sqlNode : sqlCall.getOperandList()) {
            if (containsFlatten(sqlNode)) {
                unsupportedOperatorCollector.setException(SqlUnsupportedException.ExceptionType.FUNCTION, "Flatten function in aggregate functions is not supported\n" + "See Apache Drill JIRA: DRILL-2181");
                throw new UnsupportedOperationException();
            }
        }
    }
    return sqlCall.getOperator().acceptCall(this, sqlCall);
}
Also used : SqlSelect(org.apache.calcite.sql.SqlSelect) SqlCall(org.apache.calcite.sql.SqlCall) SqlJoin(org.apache.calcite.sql.SqlJoin) SqlWindow(org.apache.calcite.sql.SqlWindow) SqlNumericLiteral(org.apache.calcite.sql.SqlNumericLiteral) SqlCountAggFunction(org.apache.calcite.sql.fun.SqlCountAggFunction) SqlNode(org.apache.calcite.sql.SqlNode)

Example 10 with SqlCountAggFunction

use of org.apache.calcite.sql.fun.SqlCountAggFunction in project drill by apache.

the class DrillReduceAggregatesRule method reduceAvg.

private RexNode reduceAvg(Aggregate oldAggRel, AggregateCall oldCall, List<AggregateCall> newCalls, Map<AggregateCall, RexNode> aggCallMapping) {
    final PlannerSettings plannerSettings = (PlannerSettings) oldAggRel.getCluster().getPlanner().getContext();
    final boolean isInferenceEnabled = plannerSettings.isTypeInferenceEnabled();
    final int nGroups = oldAggRel.getGroupCount();
    RelDataTypeFactory typeFactory = oldAggRel.getCluster().getTypeFactory();
    RexBuilder rexBuilder = oldAggRel.getCluster().getRexBuilder();
    int iAvgInput = oldCall.getArgList().get(0);
    RelDataType avgInputType = getFieldType(oldAggRel.getInput(), iAvgInput);
    RelDataType sumType = TypeInferenceUtils.getDrillSqlReturnTypeInference(SqlKind.SUM.name(), ImmutableList.of()).inferReturnType(oldCall.createBinding(oldAggRel));
    sumType = typeFactory.createTypeWithNullability(sumType, sumType.isNullable() || nGroups == 0);
    SqlAggFunction sumAgg = new DrillCalciteSqlAggFunctionWrapper(new SqlSumEmptyIsZeroAggFunction(), sumType);
    AggregateCall sumCall = AggregateCall.create(sumAgg, oldCall.isDistinct(), oldCall.isApproximate(), oldCall.getArgList(), -1, sumType, null);
    final SqlCountAggFunction countAgg = (SqlCountAggFunction) SqlStdOperatorTable.COUNT;
    final RelDataType countType = countAgg.getReturnType(typeFactory);
    AggregateCall countCall = AggregateCall.create(countAgg, oldCall.isDistinct(), oldCall.isApproximate(), oldCall.getArgList(), -1, countType, null);
    RexNode tmpsumRef = rexBuilder.addAggCall(sumCall, nGroups, newCalls, aggCallMapping, ImmutableList.of(avgInputType));
    RexNode tmpcountRef = rexBuilder.addAggCall(countCall, nGroups, newCalls, aggCallMapping, ImmutableList.of(avgInputType));
    RexNode n = rexBuilder.makeCall(SqlStdOperatorTable.CASE, rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, tmpcountRef, rexBuilder.makeExactLiteral(BigDecimal.ZERO)), rexBuilder.constantNull(), tmpsumRef);
    // NOTE:  these references are with respect to the output
    // of newAggRel
    /*
    RexNode numeratorRef =
        rexBuilder.makeCall(CastHighOp,
          rexBuilder.addAggCall(
              sumCall,
              nGroups,
              newCalls,
              aggCallMapping,
              ImmutableList.of(avgInputType))
        );
    */
    RexNode numeratorRef = rexBuilder.makeCall(CastHighOp, n);
    RexNode denominatorRef = rexBuilder.addAggCall(countCall, nGroups, newCalls, aggCallMapping, ImmutableList.of(avgInputType));
    if (isInferenceEnabled) {
        return rexBuilder.makeCall(new DrillSqlOperator("divide", 2, true, oldCall.getType(), false), numeratorRef, denominatorRef);
    } else {
        final RexNode divideRef = rexBuilder.makeCall(SqlStdOperatorTable.DIVIDE, numeratorRef, denominatorRef);
        return rexBuilder.makeCast(typeFactory.createSqlType(SqlTypeName.ANY), divideRef);
    }
}
Also used : PlannerSettings(org.apache.drill.exec.planner.physical.PlannerSettings) RelDataType(org.apache.calcite.rel.type.RelDataType) SqlAggFunction(org.apache.calcite.sql.SqlAggFunction) SqlCountAggFunction(org.apache.calcite.sql.fun.SqlCountAggFunction) DrillCalciteSqlAggFunctionWrapper(org.apache.drill.exec.planner.sql.DrillCalciteSqlAggFunctionWrapper) DrillSqlOperator(org.apache.drill.exec.planner.sql.DrillSqlOperator) SqlSumEmptyIsZeroAggFunction(org.apache.calcite.sql.fun.SqlSumEmptyIsZeroAggFunction) AggregateCall(org.apache.calcite.rel.core.AggregateCall) RelDataTypeFactory(org.apache.calcite.rel.type.RelDataTypeFactory) RexBuilder(org.apache.calcite.rex.RexBuilder) RexNode(org.apache.calcite.rex.RexNode)

Aggregations

SqlCountAggFunction (org.apache.calcite.sql.fun.SqlCountAggFunction)10 AggregateCall (org.apache.calcite.rel.core.AggregateCall)8 RexNode (org.apache.calcite.rex.RexNode)7 RelDataType (org.apache.calcite.rel.type.RelDataType)6 RelDataTypeFactory (org.apache.calcite.rel.type.RelDataTypeFactory)6 RexBuilder (org.apache.calcite.rex.RexBuilder)6 PlannerSettings (org.apache.drill.exec.planner.physical.PlannerSettings)6 DrillCalciteSqlAggFunctionWrapper (org.apache.drill.exec.planner.sql.DrillCalciteSqlAggFunctionWrapper)6 SqlSumEmptyIsZeroAggFunction (org.apache.calcite.sql.fun.SqlSumEmptyIsZeroAggFunction)5 SqlAggFunction (org.apache.calcite.sql.SqlAggFunction)4 SqlSumAggFunction (org.apache.calcite.sql.fun.SqlSumAggFunction)4 DrillSqlOperator (org.apache.drill.exec.planner.sql.DrillSqlOperator)4 ImmutableList (com.google.common.collect.ImmutableList)2 BigDecimal (java.math.BigDecimal)2 ArrayList (java.util.ArrayList)2 List (java.util.List)2 RelDataTypeField (org.apache.calcite.rel.type.RelDataTypeField)2 RexInputRef (org.apache.calcite.rex.RexInputRef)2 RexLiteral (org.apache.calcite.rex.RexLiteral)2 SqlCall (org.apache.calcite.sql.SqlCall)2