prestodb/presto · error · PinotException

PINOT_UNSUPPORTED_EXPRESSION

PINOT_UNSUPPORTED_EXPRESSION

Error message

'%s' is not supported in filter

What it means

PinotFilterExpressionConverter.handleLogicalBinary translates logical operators in WHERE clauses to Pinot filter syntax. Only operators in LOGICAL_BINARY_OPS_FILTER (AND/OR family) are pushable; any other logical binary operator reaching this method is rejected with ''%s' is not supported in filter'.

Source

Thrown at presto-pinot-toolkit/src/main/java/com/facebook/presto/pinot/query/PinotFilterExpressionConverter.java:109

    }

    private PinotExpression handleIsNull(
            SpecialFormExpression specialForm,
            boolean isWhitelist,
            Function<VariableReferenceExpression, Selection> context)
    {
        return derived(format("(%s %s)",
                specialForm.getArguments().get(0).accept(this, context).getDefinition(),
                isWhitelist ? "IS NULL" : "IS NOT NULL"));
    }

    private PinotExpression handleLogicalBinary(
            String operator,
            CallExpression call,
            Function<VariableReferenceExpression, Selection> context)
    {
        if (!LOGICAL_BINARY_OPS_FILTER.contains(operator)) {
            throw new PinotException(PINOT_UNSUPPORTED_EXPRESSION, Optional.empty(), format("'%s' is not supported in filter", operator));
        }
        List<RowExpression> arguments = call.getArguments();
        if (arguments.size() == 2) {
            // Check if call compares a date/time column with a date/time constant. Otherwise just treat it like a regular binary operator.
            return handleDateOrTimestampBinaryExpression(operator, arguments, context).orElseGet(
                    () -> derived(format(
                            "(%s %s %s)",
                            arguments.get(0).accept(this, context).getDefinition(),
                            operator,
                            arguments.get(1).accept(this, context).getDefinition())));
        }
        throw new PinotException(PINOT_UNSUPPORTED_EXPRESSION, Optional.empty(), format("Unknown logical binary: '%s'", call));
    }

    private Optional<PinotExpression> handleDateOrTimestampBinaryExpression(String operator, List<RowExpression> arguments, Function<VariableReferenceExpression, Selection> context)
    {
        Optional<String> left = handleTimeValueCast(context, arguments.get(1), arguments.get(0));
        Optional<String> right = handleTimeValueCast(context, arguments.get(0), arguments.get(1));

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Rewrite the predicate using AND/OR/NOT: XOR(a, b) becomes (a AND NOT b) OR (NOT a AND b)
  2. Split the query so unsupported boolean logic is applied outside the Pinot-pushed filter (outer query over a subquery)
  3. Inspect LOGICAL_BINARY_OPS_FILTER in your connector version and restrict queries to those operators
  4. Upgrade the connector if newer versions added the operator to the filter allowlist

Example fix

// before
SELECT * FROM t WHERE a XOR b;
// after
SELECT * FROM t WHERE (a AND NOT b) OR (NOT a AND b);
Defensive patterns

Strategy: validation

Validate before calling

// Check WHERE-clause logical operators against the connector allowlist
private static final Set<String> FILTER_LOGICAL_OPS = Set.of("AND", "OR");
if (!FILTER_LOGICAL_OPS.contains(op.toUpperCase(Locale.ROOT))) {
    throw new IllegalArgumentException(
        "Logical operator not pushable to Pinot filter: " + op);
}

Type guard

private static boolean isFilterPushableLogical(String operator) {
    return operator != null
        && Set.of("AND", "OR").contains(operator.toUpperCase(Locale.ROOT));
}

Try / catch

try {
    PinotExpression filter = filterConverter.visitCall(call, context);
} catch (PinotException ex) {
    if (ex.getMessage() != null && ex.getMessage().endsWith("is not supported in filter")) {
        // keep this predicate for Presto-side filtering
    } else throw ex;
}

Prevention

When it happens

Trigger: A CallExpression in a filter (WHERE/HAVING) resolves to a logical binary function not in LOGICAL_BINARY_OPS_FILTER — e.g. XOR, or a non-standard logical function the planner represents as a call with operator name outside the allowlist.

Common situations: Queries using XOR or exotic boolean operators in WHERE clauses, new Presto versions introducing different function names for logical ops, and third-party SQL generators emitting logical operators the connector allowlist does not cover.

Related errors


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/259cdf39ace91436. Report an issue: GitHub.