Skip to content

Scalar CASE function only supports up to 15 WHEN THEN clauses #14126

@yashmayya

Description

@yashmayya
  • Currently, the CASE scalar function only supports up to 15 WHEN THEN clauses, and this restriction exists because there is a separate implementation for scalar CASE with 3 arguments, 4 arguments, and so on.
  • See Support up to 15 boolean expressions for casewhen scalar function #11566 for instance, which increased the number of supported clauses from 5 to 15.
  • The equivalent transform function, however, has no such restriction on the number of supported clauses -
    @Override
    public void init(List<TransformFunction> arguments, Map<String, ColumnContext> columnContextMap,
    boolean nullHandlingEnabled) {
    super.init(arguments, columnContextMap, nullHandlingEnabled);
    // Check that there are more than 2 arguments
    // Else statement can be omitted.
    if (arguments.size() < 2) {
    throw new IllegalArgumentException("At least two arguments are required for CASE-WHEN function");
    }
    int numWhenStatements = arguments.size() / 2;
    _whenStatements = new ArrayList<>(numWhenStatements);
    _thenStatements = new ArrayList<>(numWhenStatements);
    // Alternating WHEN and THEN clause, last one ELSE
    for (int i = 0; i < numWhenStatements; i++) {
    _whenStatements.add(arguments.get(i * 2));
    _thenStatements.add(arguments.get(i * 2 + 1));
    }
    if (arguments.size() % 2 != 0 && !isNullLiteral(arguments.get(arguments.size() - 1))) {
    _elseStatement = arguments.get(arguments.size() - 1);
    }
    _resultMetadata = new TransformResultMetadata(calculateResultType(), true, false);
    _computeThenStatements = new boolean[numWhenStatements];
    }
  • This leads to very confusing user experiences, since most users won't be aware about Pinot internal implementation details like transform functions vs scalar functions and which situations use which type of function. So, certain queries with > 15 when then clauses in a case function will fail with an error like IllegalArgumentException: Unsupported function: CASE with argument types: ... / IllegalArgumentException: Unsupported function: CASE with ... arguments whereas some other queries with > 15 when then clauses in a case function will succeed.
  • For instance, in the multi-stage query engine, a projection in a leaf stage will use the transform function variant, whereas a projection in an intermediate stage will use the scalar function variant. We need to support an arbitrary number of WHEN THEN clauses in the scalar CASE function as well.
  • Example of a query that currently fails in the multi-stage query engine (since intermediate stages can only use scalar functions, not transform functions):
SELECT CASE 
    WHEN val BETWEEN 1 AND 5 THEN 0
    WHEN val BETWEEN 5 AND 10 THEN 1
    ...
    ...
    WHEN val BETWEEN 95 AND 100 THEN 19
    ELSE 20 END
FROM (SELECT val FROM mytable ORDER BY val LIMIT 100);
  • Example of a query that currently fails in the single-stage query engine (since post-aggregation internally uses scalar functions):
SELECT CASE 
    WHEN SUM(val) BETWEEN 1 AND 5 THEN 0
    WHEN SUM(val) BETWEEN 5 AND 10 THEN 1
    ...
    ...
    WHEN SUM(val) BETWEEN 95 AND 100 THEN 19
    ELSE 20 END
FROM mytable;

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions