Search in sources :

Example 11 with PinotException

use of com.facebook.presto.pinot.PinotException in project presto by prestodb.

the class PinotQueryGeneratorContext method toPqlQuery.

/**
 * Convert the current context to a PQL
 */
public PinotQueryGenerator.GeneratedPinotQuery toPqlQuery(PinotConfig pinotConfig, ConnectorSession session) {
    int nonAggregateShortQueryLimit = PinotSessionProperties.getNonAggregateLimitForBrokerQueries(session);
    boolean isQueryShort = hasAggregation() || limit.orElse(Integer.MAX_VALUE) < nonAggregateShortQueryLimit;
    boolean forBroker = !PinotSessionProperties.isForbidBrokerQueries(session) && isQueryShort;
    if (!pinotConfig.isAllowMultipleAggregations() && aggregations > 1 && hasGroupBy()) {
        throw new PinotException(PINOT_QUERY_GENERATOR_FAILURE, Optional.empty(), "Multiple aggregates in the presence of group by is forbidden");
    }
    if (hasLimit() && aggregations > 1 && hasGroupBy()) {
        throw new PinotException(PINOT_QUERY_GENERATOR_FAILURE, Optional.empty(), "Multiple aggregates in the presence of group by and limit is forbidden");
    }
    String expressions = outputs.stream().filter(// remove the group by columns from the query as Pinot barfs if the group by column is an expression
    o -> !groupByColumns.contains(o)).map(o -> updateSelection(selections.get(o).getDefinition(), session)).collect(Collectors.joining(", "));
    if (expressions.isEmpty()) {
        throw new PinotException(PINOT_QUERY_GENERATOR_FAILURE, Optional.empty(), "Empty PQL expressions: " + toString());
    }
    String tableName = from.orElseThrow(() -> new PinotException(PINOT_QUERY_GENERATOR_FAILURE, Optional.empty(), "Table name not encountered yet"));
    // Rules for limit:
    // - If its a selection query:
    // + given limit or configured limit
    // - Else if has group by:
    // + ensure that only one aggregation
    // + default limit or configured top limit
    // - Fail if limit is invalid
    String limitKeyWord = "";
    int queryLimit = -1;
    if (!hasAggregation()) {
        if (!limit.isPresent() && forBroker) {
            throw new PinotException(PINOT_QUERY_GENERATOR_FAILURE, Optional.empty(), "Broker non aggregate queries have to have a limit");
        } else {
            queryLimit = limit.orElse(PinotSessionProperties.getLimitLargerForSegment(session));
        }
        limitKeyWord = "LIMIT";
    } else if (hasGroupBy()) {
        limitKeyWord = "TOP";
        if (limit.isPresent()) {
            if (aggregations > 1) {
                throw new PinotException(PINOT_QUERY_GENERATOR_FAILURE, Optional.of(generatePinotQueryHelper(forBroker, expressions, tableName, "")), "Pinot has weird semantics with group by and multiple aggregation functions and limits");
            } else {
                queryLimit = limit.getAsInt();
            }
        } else {
            queryLimit = PinotSessionProperties.getTopNLarge(session);
        }
    }
    String limitClause = "";
    if (!limitKeyWord.isEmpty()) {
        limitClause = " " + limitKeyWord + " " + queryLimit;
    }
    String query = generatePinotQueryHelper(forBroker, expressions, tableName, limitClause);
    LinkedHashMap<VariableReferenceExpression, PinotColumnHandle> assignments = getAssignments(false);
    List<Integer> indices = getIndicesMappingFromPinotSchemaToPrestoSchema(query, assignments);
    return new PinotQueryGenerator.GeneratedPinotQuery(tableName, query, PinotQueryGenerator.PinotQueryFormat.PQL, indices, groupByColumns.size(), filter.isPresent(), isQueryShort);
}
Also used : PinotPushdownUtils.checkSupported(com.facebook.presto.pinot.PinotPushdownUtils.checkSupported) PinotException(com.facebook.presto.pinot.PinotException) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) VariableReferenceExpression(com.facebook.presto.spi.relation.VariableReferenceExpression) HashMap(java.util.HashMap) PINOT_DISTINCT_COUNT_FUNCTION_NAME(com.facebook.presto.pinot.PinotPushdownUtils.PINOT_DISTINCT_COUNT_FUNCTION_NAME) OptionalInt(java.util.OptionalInt) HashSet(java.util.HashSet) LinkedHashMap(java.util.LinkedHashMap) ImmutableList(com.google.common.collect.ImmutableList) Locale(java.util.Locale) Map(java.util.Map) Objects.requireNonNull(java.util.Objects.requireNonNull) StrictMath.toIntExact(java.lang.StrictMath.toIntExact) LinkedHashSet(java.util.LinkedHashSet) PinotColumnHandle(com.facebook.presto.pinot.PinotColumnHandle) ImmutableSet(com.google.common.collect.ImmutableSet) Iterator(java.util.Iterator) SortOrder(com.facebook.presto.common.block.SortOrder) Set(java.util.Set) Collectors(java.util.stream.Collectors) PinotSessionProperties(com.facebook.presto.pinot.PinotSessionProperties) String.format(java.lang.String.format) ConnectorSession(com.facebook.presto.spi.ConnectorSession) List(java.util.List) PinotConfig(com.facebook.presto.pinot.PinotConfig) PINOT_QUERY_GENERATOR_FAILURE(com.facebook.presto.pinot.PinotErrorCode.PINOT_QUERY_GENERATOR_FAILURE) PINOT_UNSUPPORTED_EXPRESSION(com.facebook.presto.pinot.PinotErrorCode.PINOT_UNSUPPORTED_EXPRESSION) Optional(java.util.Optional) Joiner(com.google.common.base.Joiner) MoreObjects.toStringHelper(com.google.common.base.MoreObjects.toStringHelper) PinotException(com.facebook.presto.pinot.PinotException) PinotColumnHandle(com.facebook.presto.pinot.PinotColumnHandle) VariableReferenceExpression(com.facebook.presto.spi.relation.VariableReferenceExpression)

Example 12 with PinotException

use of com.facebook.presto.pinot.PinotException in project presto by prestodb.

the class PinotQueryGeneratorContext method getIndicesMappingFromPinotSchemaToPrestoSchema.

private List<Integer> getIndicesMappingFromPinotSchemaToPrestoSchema(String query, Map<VariableReferenceExpression, PinotColumnHandle> assignments) {
    LinkedHashMap<VariableReferenceExpression, Selection> expressionsInPinotOrder = new LinkedHashMap<>();
    for (VariableReferenceExpression groupByColumn : groupByColumns) {
        Selection groupByColumnDefinition = selections.get(groupByColumn);
        if (groupByColumnDefinition == null) {
            throw new IllegalStateException(format("Group By column (%s) definition not found in input selections: %s", groupByColumn, Joiner.on(",").withKeyValueSeparator(":").join(selections)));
        }
        expressionsInPinotOrder.put(groupByColumn, groupByColumnDefinition);
    }
    for (VariableReferenceExpression outputColumn : outputs) {
        Selection outputColumnDefinition = selections.get(outputColumn);
        if (outputColumnDefinition == null) {
            throw new IllegalStateException(format("Output column (%s) definition not found in input selections: %s", outputColumn, Joiner.on(",").withKeyValueSeparator(":").join(selections)));
        }
        expressionsInPinotOrder.put(outputColumn, outputColumnDefinition);
    }
    if (useSqlSyntax) {
        checkSupported(assignments.size() <= expressionsInPinotOrder.keySet().stream().filter(key -> !hiddenColumnSet.contains(key)).count(), "Expected returned expressions %s is a superset of selections %s", Joiner.on(",").withKeyValueSeparator(":").join(expressionsInPinotOrder), Joiner.on(",").withKeyValueSeparator("=").join(assignments));
    } else {
        checkSupported(assignments.size() == expressionsInPinotOrder.keySet().stream().filter(key -> !hiddenColumnSet.contains(key)).count(), "Expected returned expressions %s to match selections %s", Joiner.on(",").withKeyValueSeparator(":").join(expressionsInPinotOrder), Joiner.on(",").withKeyValueSeparator("=").join(assignments));
    }
    Map<VariableReferenceExpression, Integer> assignmentToIndex = new HashMap<>();
    Iterator<Map.Entry<VariableReferenceExpression, PinotColumnHandle>> assignmentsIterator = assignments.entrySet().iterator();
    for (int i = 0; i < assignments.size(); i++) {
        VariableReferenceExpression key = assignmentsIterator.next().getKey();
        Integer previous = assignmentToIndex.put(key, i);
        if (previous != null) {
            throw new PinotException(PINOT_UNSUPPORTED_EXPRESSION, Optional.of(query), format("Expected Pinot column handle %s to occur only once, but we have: %s", key, Joiner.on(",").withKeyValueSeparator("=").join(assignments)));
        }
    }
    ImmutableList.Builder<Integer> outputIndices = ImmutableList.builder();
    for (Map.Entry<VariableReferenceExpression, Selection> expression : expressionsInPinotOrder.entrySet()) {
        Integer index;
        if (hiddenColumnSet.contains(expression.getKey())) {
            // negative output index means to skip this value returned by pinot at query time
            index = -1;
        } else {
            index = assignmentToIndex.get(expression.getKey());
        }
        if (index == null) {
            if (useSqlSyntax) {
                // negative output index means to skip this value returned by pinot at query time
                index = -1;
            } else {
                throw new PinotException(PINOT_UNSUPPORTED_EXPRESSION, Optional.of(query), format("Expected to find a Pinot column handle for the expression %s, but we have %s", expression, Joiner.on(",").withKeyValueSeparator(":").join(assignmentToIndex)));
            }
        }
        outputIndices.add(index);
    }
    return outputIndices.build();
}
Also used : PinotPushdownUtils.checkSupported(com.facebook.presto.pinot.PinotPushdownUtils.checkSupported) PinotException(com.facebook.presto.pinot.PinotException) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) VariableReferenceExpression(com.facebook.presto.spi.relation.VariableReferenceExpression) HashMap(java.util.HashMap) PINOT_DISTINCT_COUNT_FUNCTION_NAME(com.facebook.presto.pinot.PinotPushdownUtils.PINOT_DISTINCT_COUNT_FUNCTION_NAME) OptionalInt(java.util.OptionalInt) HashSet(java.util.HashSet) LinkedHashMap(java.util.LinkedHashMap) ImmutableList(com.google.common.collect.ImmutableList) Locale(java.util.Locale) Map(java.util.Map) Objects.requireNonNull(java.util.Objects.requireNonNull) StrictMath.toIntExact(java.lang.StrictMath.toIntExact) LinkedHashSet(java.util.LinkedHashSet) PinotColumnHandle(com.facebook.presto.pinot.PinotColumnHandle) ImmutableSet(com.google.common.collect.ImmutableSet) Iterator(java.util.Iterator) SortOrder(com.facebook.presto.common.block.SortOrder) Set(java.util.Set) Collectors(java.util.stream.Collectors) PinotSessionProperties(com.facebook.presto.pinot.PinotSessionProperties) String.format(java.lang.String.format) ConnectorSession(com.facebook.presto.spi.ConnectorSession) List(java.util.List) PinotConfig(com.facebook.presto.pinot.PinotConfig) PINOT_QUERY_GENERATOR_FAILURE(com.facebook.presto.pinot.PinotErrorCode.PINOT_QUERY_GENERATOR_FAILURE) PINOT_UNSUPPORTED_EXPRESSION(com.facebook.presto.pinot.PinotErrorCode.PINOT_UNSUPPORTED_EXPRESSION) Optional(java.util.Optional) Joiner(com.google.common.base.Joiner) MoreObjects.toStringHelper(com.google.common.base.MoreObjects.toStringHelper) PinotException(com.facebook.presto.pinot.PinotException) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) ImmutableList(com.google.common.collect.ImmutableList) LinkedHashMap(java.util.LinkedHashMap) VariableReferenceExpression(com.facebook.presto.spi.relation.VariableReferenceExpression) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map)

Example 13 with PinotException

use of com.facebook.presto.pinot.PinotException in project presto by prestodb.

the class PinotAggregationProjectConverter method handleFunction.

private PinotExpression handleFunction(CallExpression function, Map<VariableReferenceExpression, PinotQueryGeneratorContext.Selection> context) {
    String functionName = function.getDisplayName().toLowerCase(ENGLISH);
    switch(functionName) {
        case "date_trunc":
            boolean useDateTruncation = PinotSessionProperties.isUseDateTruncation(session);
            return useDateTruncation ? handleDateTruncationViaDateTruncation(function, context) : handleDateTruncationViaDateTimeConvert(function, context);
        case "array_max":
        case "array_min":
            String pinotArrayFunctionName = PRESTO_TO_PINOT_ARRAY_AGGREGATIONS.get(functionName);
            requireNonNull(pinotArrayFunctionName, "Converted Pinot array function is null for - " + functionName);
            return derived(String.format("%s(%s)", pinotArrayFunctionName, function.getArguments().get(0).accept(this, context).getDefinition()));
        // this arrayVariableHint to help determine which array function it is.
        case "reduce":
            if (arrayVariableHint != null) {
                String arrayFunctionName = getArrayFunctionName(arrayVariableHint);
                if (arrayFunctionName != null) {
                    String inputColumn = function.getArguments().get(0).accept(this, context).getDefinition();
                    return derived(String.format("%s(%s)", arrayFunctionName, inputColumn));
                }
            }
        default:
            throw new PinotException(PINOT_UNSUPPORTED_EXPRESSION, Optional.empty(), format("function %s not supported yet", function.getDisplayName()));
    }
}
Also used : PinotException(com.facebook.presto.pinot.PinotException) PinotPushdownUtils.getLiteralAsString(com.facebook.presto.pinot.PinotPushdownUtils.getLiteralAsString)

Example 14 with PinotException

use of com.facebook.presto.pinot.PinotException in project presto by prestodb.

the class PinotAggregationProjectConverter method handleDateTruncationViaDateTruncation.

private PinotExpression handleDateTruncationViaDateTruncation(CallExpression function, Map<VariableReferenceExpression, PinotQueryGeneratorContext.Selection> context) {
    RowExpression timeInputParameter = function.getArguments().get(1);
    String inputColumn;
    String inputTimeZone;
    String inputFormat;
    CallExpression timeConversion = getExpressionAsFunction(timeInputParameter, timeInputParameter);
    switch(timeConversion.getDisplayName().toLowerCase(ENGLISH)) {
        case FROM_UNIXTIME:
            inputColumn = timeConversion.getArguments().get(0).accept(this, context).getDefinition();
            inputTimeZone = timeConversion.getArguments().size() > 1 ? getStringFromConstant(timeConversion.getArguments().get(1)) : DateTimeZone.UTC.getID();
            inputFormat = "seconds";
            break;
        default:
            throw new PinotException(PINOT_UNSUPPORTED_EXPRESSION, Optional.empty(), "not supported: " + timeConversion.getDisplayName());
    }
    RowExpression intervalParameter = function.getArguments().get(0);
    if (!(intervalParameter instanceof ConstantExpression)) {
        throw new PinotException(PINOT_UNSUPPORTED_EXPRESSION, Optional.empty(), "interval unit in date_trunc is not supported: " + intervalParameter);
    }
    return derived("dateTrunc(" + inputColumn + "," + inputFormat + ", " + inputTimeZone + ", " + getStringFromConstant(intervalParameter) + ")");
}
Also used : PinotException(com.facebook.presto.pinot.PinotException) ConstantExpression(com.facebook.presto.spi.relation.ConstantExpression) RowExpression(com.facebook.presto.spi.relation.RowExpression) PinotPushdownUtils.getLiteralAsString(com.facebook.presto.pinot.PinotPushdownUtils.getLiteralAsString) CallExpression(com.facebook.presto.spi.relation.CallExpression)

Example 15 with PinotException

use of com.facebook.presto.pinot.PinotException in project presto by prestodb.

the class PinotAggregationProjectConverter method handleDateTruncationViaDateTimeConvert.

private PinotExpression handleDateTruncationViaDateTimeConvert(CallExpression function, Map<VariableReferenceExpression, PinotQueryGeneratorContext.Selection> context) {
    // Convert SQL standard function `DATE_TRUNC(INTERVAL, DATE/TIMESTAMP COLUMN)` to
    // Pinot's equivalent function `dateTimeConvert(columnName, inputFormat, outputFormat, outputGranularity)`
    // Pinot doesn't have a DATE/TIMESTAMP type. That means the input column (second argument) has been converted from numeric type to DATE/TIMESTAMP using one of the
    // conversion functions in SQL. First step is find the function and find its input column units (seconds, secondsSinceEpoch etc.)
    RowExpression timeInputParameter = function.getArguments().get(1);
    String inputColumn;
    String inputFormat;
    CallExpression timeConversion = getExpressionAsFunction(timeInputParameter, timeInputParameter);
    switch(timeConversion.getDisplayName().toLowerCase(ENGLISH)) {
        case FROM_UNIXTIME:
            inputColumn = timeConversion.getArguments().get(0).accept(this, context).getDefinition();
            inputFormat = "'1:SECONDS:EPOCH'";
            break;
        default:
            throw new PinotException(PINOT_UNSUPPORTED_EXPRESSION, Optional.empty(), "not supported: " + timeConversion.getDisplayName());
    }
    String outputFormat = "'1:MILLISECONDS:EPOCH'";
    String outputGranularity;
    RowExpression intervalParameter = function.getArguments().get(0);
    if (!(intervalParameter instanceof ConstantExpression)) {
        throw new PinotException(PINOT_UNSUPPORTED_EXPRESSION, Optional.empty(), "interval unit in date_trunc is not supported: " + intervalParameter);
    }
    String value = getStringFromConstant(intervalParameter);
    switch(value) {
        case "second":
            outputGranularity = "'1:SECONDS'";
            break;
        case "minute":
            outputGranularity = "'1:MINUTES'";
            break;
        case "hour":
            outputGranularity = "'1:HOURS'";
            break;
        case "day":
            outputGranularity = "'1:DAYS'";
            break;
        case "week":
            outputGranularity = "'1:WEEKS'";
            break;
        case "month":
            outputGranularity = "'1:MONTHS'";
            break;
        case "quarter":
            outputGranularity = "'1:QUARTERS'";
            break;
        case "year":
            outputGranularity = "'1:YEARS'";
            break;
        default:
            throw new PinotException(PINOT_UNSUPPORTED_EXPRESSION, Optional.empty(), "interval in date_trunc is not supported: " + value);
    }
    return derived("dateTimeConvert(" + inputColumn + ", " + inputFormat + ", " + outputFormat + ", " + outputGranularity + ")");
}
Also used : PinotException(com.facebook.presto.pinot.PinotException) ConstantExpression(com.facebook.presto.spi.relation.ConstantExpression) RowExpression(com.facebook.presto.spi.relation.RowExpression) PinotPushdownUtils.getLiteralAsString(com.facebook.presto.pinot.PinotPushdownUtils.getLiteralAsString) CallExpression(com.facebook.presto.spi.relation.CallExpression)

Aggregations

PinotException (com.facebook.presto.pinot.PinotException)17 RowExpression (com.facebook.presto.spi.relation.RowExpression)10 OperatorType (com.facebook.presto.common.function.OperatorType)5 PinotPushdownUtils.getLiteralAsString (com.facebook.presto.pinot.PinotPushdownUtils.getLiteralAsString)5 Type (com.facebook.presto.common.type.Type)4 ConstantExpression (com.facebook.presto.spi.relation.ConstantExpression)4 VariableReferenceExpression (com.facebook.presto.spi.relation.VariableReferenceExpression)4 SortOrder (com.facebook.presto.common.block.SortOrder)3 BigintType (com.facebook.presto.common.type.BigintType)3 DateType (com.facebook.presto.common.type.DateType)3 IntegerType (com.facebook.presto.common.type.IntegerType)3 PinotColumnHandle (com.facebook.presto.pinot.PinotColumnHandle)3 PinotConfig (com.facebook.presto.pinot.PinotConfig)3 PINOT_QUERY_GENERATOR_FAILURE (com.facebook.presto.pinot.PinotErrorCode.PINOT_QUERY_GENERATOR_FAILURE)3 PINOT_UNSUPPORTED_EXPRESSION (com.facebook.presto.pinot.PinotErrorCode.PINOT_UNSUPPORTED_EXPRESSION)3 PINOT_DISTINCT_COUNT_FUNCTION_NAME (com.facebook.presto.pinot.PinotPushdownUtils.PINOT_DISTINCT_COUNT_FUNCTION_NAME)3 PinotPushdownUtils.checkSupported (com.facebook.presto.pinot.PinotPushdownUtils.checkSupported)3 PinotSessionProperties (com.facebook.presto.pinot.PinotSessionProperties)3 ConnectorSession (com.facebook.presto.spi.ConnectorSession)3 CallExpression (com.facebook.presto.spi.relation.CallExpression)3