Search in sources :

Example 6 with PinotException

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

the class PinotAggregationProjectConverter method visitCall.

@Override
public PinotExpression visitCall(CallExpression call, Map<VariableReferenceExpression, PinotQueryGeneratorContext.Selection> context) {
    Optional<PinotExpression> basicCallHandlingResult = basicCallHandling(call, context);
    if (basicCallHandlingResult.isPresent()) {
        return basicCallHandlingResult.get();
    }
    FunctionMetadata functionMetadata = functionMetadataManager.getFunctionMetadata(call.getFunctionHandle());
    Optional<OperatorType> operatorTypeOptional = functionMetadata.getOperatorType();
    if (operatorTypeOptional.isPresent()) {
        OperatorType operatorType = operatorTypeOptional.get();
        if (operatorType.isArithmeticOperator()) {
            return handleArithmeticExpression(call, operatorType, context);
        }
        if (operatorType.isComparisonOperator()) {
            throw new PinotException(PINOT_UNSUPPORTED_EXPRESSION, Optional.empty(), "Comparison operator not supported: " + call);
        }
    }
    return handleFunction(call, context);
}
Also used : FunctionMetadata(com.facebook.presto.spi.function.FunctionMetadata) PinotException(com.facebook.presto.pinot.PinotException) OperatorType(com.facebook.presto.common.function.OperatorType)

Example 7 with PinotException

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

the class PinotFilterExpressionConverter method handleTimeValueCast.

private Optional<String> handleTimeValueCast(Function<VariableReferenceExpression, Selection> context, RowExpression timeFieldExpression, RowExpression timeValueExpression) {
    // Handle the binary comparison logic of <DATE/TIMESTAMP field> <binary op> <DATE/TIMESTAMP literal>.
    // Pinot stores time as:
    // - `DATE`: Stored as `INT`/`LONG` `daysSinceEpoch` value
    // - `TIMESTAMP`: Stored as `LONG` `millisSinceEpoch` value.
    // In order to push down this predicate, we need to convert the literal to the type of Pinot time field.
    // Below code compares the time type of both side:
    // - if same, then directly push down.
    // - if not same, then convert the literal time type to the field time type.
    // - if not compatible time types, returns Optional.empty(), indicates no change has been made in this cast.
    // Take an example of comparing a `DATE` field to a `TIMESTAMP` literal:
    // - Sample predicate: `WHERE eventDate < current_time`.
    // - Input type is the `eventDate` field data type, which is `DATE`.
    // - Expect type is the right side `literal type`, which means right side is `TIMESTAMP`.
    // The code below converts `current_time` from `millisSinceEpoch` value to `daysSinceEpoch` value, which is
    // comparable to values in `eventDate` column.
    Type inputType;
    Type expectedType;
    if (!isDateTimeConstantType(timeFieldExpression.getType()) || !isDateTimeConstantType(timeValueExpression.getType())) {
        return Optional.empty();
    }
    String timeValueString = timeValueExpression.accept(this, context).getDefinition();
    if (timeFieldExpression instanceof CallExpression) {
        // Handles cases like: `cast(eventDate as TIMESTAMP) <  DATE '2014-01-31'`
        // For cast function,
        // - inputType is the argument type,
        // - expectedType is the cast function return type.
        CallExpression callExpression = (CallExpression) timeFieldExpression;
        if (!standardFunctionResolution.isCastFunction(callExpression.getFunctionHandle())) {
            return Optional.empty();
        }
        if (callExpression.getArguments().size() != 1) {
            return Optional.empty();
        }
        inputType = callExpression.getArguments().get(0).getType();
        expectedType = callExpression.getType();
    } else if (timeFieldExpression instanceof VariableReferenceExpression) {
        // For VariableReferenceExpression,
        // Handles queries like: `eventDate <  TIMESTAMP '2014-01-31 00:00:00 UTC'`
        // - inputType is timeFieldExpression type,
        // - expectedType is the timeValueExpression type.
        inputType = timeFieldExpression.getType();
        expectedType = timeValueExpression.getType();
    } else if (timeFieldExpression instanceof ConstantExpression) {
        // timeFieldExpression is a ConstantExpression, directly return.
        return Optional.of(timeValueString);
    } else {
        return Optional.empty();
    }
    if (inputType == DateType.DATE && (expectedType == TimestampType.TIMESTAMP || expectedType == TimestampWithTimeZoneType.TIMESTAMP_WITH_TIME_ZONE)) {
        // time field is `DATE`, try to convert time value from `TIMESTAMP` to `DATE`
        try {
            return Optional.of(Long.toString(TimeUnit.MILLISECONDS.toDays(Long.parseLong(timeValueString))));
        } catch (NumberFormatException e) {
            throw new PinotException(PINOT_UNSUPPORTED_EXPRESSION, Optional.empty(), format("Unable to parse timestamp string: '%s'", timeValueString), e);
        }
    }
    if ((inputType == TimestampType.TIMESTAMP || inputType == TimestampWithTimeZoneType.TIMESTAMP_WITH_TIME_ZONE) && expectedType == DateType.DATE) {
        // time field is `TIMESTAMP`, try to convert time value from `DATE` to `TIMESTAMP`
        try {
            return Optional.of(Long.toString(TimeUnit.DAYS.toMillis(Long.parseLong(timeValueString))));
        } catch (NumberFormatException e) {
            throw new PinotException(PINOT_UNSUPPORTED_EXPRESSION, Optional.empty(), format("Unable to parse date string: '%s'", timeValueString), e);
        }
    }
    // Vacuous cast from variable to same type: cast(eventDate, DAYS). Already handled by handleCast.
    return Optional.of(timeValueString);
}
Also used : PinotException(com.facebook.presto.pinot.PinotException) IntegerType(com.facebook.presto.common.type.IntegerType) Type(com.facebook.presto.common.type.Type) BigintType(com.facebook.presto.common.type.BigintType) VarcharType(com.facebook.presto.common.type.VarcharType) OperatorType(com.facebook.presto.common.function.OperatorType) TimestampWithTimeZoneType(com.facebook.presto.common.type.TimestampWithTimeZoneType) DateType(com.facebook.presto.common.type.DateType) TimestampType(com.facebook.presto.common.type.TimestampType) VariableReferenceExpression(com.facebook.presto.spi.relation.VariableReferenceExpression) ConstantExpression(com.facebook.presto.spi.relation.ConstantExpression) PinotPushdownUtils.getLiteralAsString(com.facebook.presto.pinot.PinotPushdownUtils.getLiteralAsString) CallExpression(com.facebook.presto.spi.relation.CallExpression)

Example 8 with PinotException

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

the class PinotFilterExpressionConverter method handleContains.

private PinotExpression handleContains(CallExpression contains, Function<VariableReferenceExpression, Selection> context) {
    if (contains.getArguments().size() != 2) {
        throw new PinotException(PINOT_UNSUPPORTED_EXPRESSION, Optional.empty(), format("Contains operator not supported: %s", contains));
    }
    RowExpression left = contains.getArguments().get(0);
    RowExpression right = contains.getArguments().get(1);
    if (!(right instanceof ConstantExpression)) {
        throw new PinotException(PINOT_UNSUPPORTED_EXPRESSION, Optional.empty(), format("Contains operator can not push down non-literal value: %s", right));
    }
    return derived(format("(%s = %s)", left.accept(this, context).getDefinition(), right.accept(this, context).getDefinition()));
}
Also used : PinotException(com.facebook.presto.pinot.PinotException) ConstantExpression(com.facebook.presto.spi.relation.ConstantExpression) RowExpression(com.facebook.presto.spi.relation.RowExpression)

Example 9 with PinotException

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

the class PinotFilterExpressionConverter method visitCall.

@Override
public PinotExpression visitCall(CallExpression call, Function<VariableReferenceExpression, Selection> context) {
    FunctionHandle functionHandle = call.getFunctionHandle();
    if (standardFunctionResolution.isNotFunction(functionHandle)) {
        return handleNot(call, context);
    }
    if (standardFunctionResolution.isCastFunction(functionHandle)) {
        return handleCast(call, context);
    }
    if (standardFunctionResolution.isBetweenFunction(functionHandle)) {
        return handleBetween(call, context);
    }
    FunctionMetadata functionMetadata = functionMetadataManager.getFunctionMetadata(call.getFunctionHandle());
    Optional<OperatorType> operatorTypeOptional = functionMetadata.getOperatorType();
    if (operatorTypeOptional.isPresent()) {
        OperatorType operatorType = operatorTypeOptional.get();
        if (operatorType.isArithmeticOperator()) {
            throw new PinotException(PINOT_UNSUPPORTED_EXPRESSION, Optional.empty(), "Arithmetic expressions are not supported in filter: " + call);
        }
        if (operatorType.isComparisonOperator()) {
            return handleLogicalBinary(operatorType.getOperator(), call, context);
        }
    }
    if ("contains".equals(functionMetadata.getName().getObjectName())) {
        return handleContains(call, context);
    }
    // Otherwise TypeManager.canCoerce(...) will return false and directly fail this query.
    if (functionMetadata.getName().getObjectName().equalsIgnoreCase("$literal$timestamp") || functionMetadata.getName().getObjectName().equalsIgnoreCase("$literal$date")) {
        return handleDateAndTimestampMagicLiteralFunction(call, context);
    }
    throw new PinotException(PINOT_UNSUPPORTED_EXPRESSION, Optional.empty(), format("function %s not supported in filter", call));
}
Also used : FunctionMetadata(com.facebook.presto.spi.function.FunctionMetadata) PinotException(com.facebook.presto.pinot.PinotException) FunctionHandle(com.facebook.presto.spi.function.FunctionHandle) OperatorType(com.facebook.presto.common.function.OperatorType)

Example 10 with PinotException

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

the class PinotQueryGeneratorContext method toSqlQuery.

/**
 * Convert the current context to a Pinot SQL
 */
public PinotQueryGenerator.GeneratedPinotQuery toSqlQuery(PinotConfig pinotConfig, ConnectorSession session) {
    int nonAggregateShortQueryLimit = PinotSessionProperties.getNonAggregateLimitForBrokerQueries(session);
    boolean isQueryShort = (hasAggregation() || hasGroupBy()) || limit.orElse(Integer.MAX_VALUE) < nonAggregateShortQueryLimit;
    boolean forBroker = !PinotSessionProperties.isForbidBrokerQueries(session) && isQueryShort;
    String groupByExpressions = groupByColumns.stream().map(x -> selections.get(x).getDefinition()).collect(Collectors.joining(", "));
    String selectExpressions = outputs.stream().filter(o -> !groupByColumns.contains(o)).map(o -> updateSelection(selections.get(o).getDefinition(), session)).collect(Collectors.joining(", "));
    String expressions = (groupByExpressions.isEmpty()) ? selectExpressions : (selectExpressions.isEmpty()) ? groupByExpressions : groupByExpressions + ", " + selectExpressions;
    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:
    // + default limit or configured top limit
    // - Aggregation only query limit is ignored.
    // - Fail if limit is invalid
    int queryLimit = -1;
    if (!hasAggregation() && !hasGroupBy()) {
        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));
        }
    } else if (hasGroupBy()) {
        if (limit.isPresent()) {
            queryLimit = limit.getAsInt();
        } else {
            queryLimit = PinotSessionProperties.getTopNLarge(session);
        }
    }
    String limitClause = "";
    if (queryLimit > 0) {
        limitClause = " LIMIT " + queryLimit;
    }
    String query = generatePinotQueryHelper(forBroker, expressions, tableName, limitClause);
    LinkedHashMap<VariableReferenceExpression, PinotColumnHandle> assignments = getAssignments(true);
    List<Integer> indices = getIndicesMappingFromPinotSchemaToPrestoSchema(query, assignments);
    return new PinotQueryGenerator.GeneratedPinotQuery(tableName, query, PinotQueryGenerator.PinotQueryFormat.SQL, 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)

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