apache/flink · error · RuntimeException
Invalid binary comparison.
Error message
Invalid binary comparison.
What it means
OrcFilters.literalOnRight inspects a binary comparison CallExpression to decide which side is the literal. It accepts (a) a single child that is a field reference (unary like NOT/IS_NULL), (b) literal-left/ref-right, or (c) ref-left/literal-right. Anything else — two literals, two references, or unsupported child types — throws RuntimeException('Invalid binary comparison').
Source
Thrown at flink-formats/flink-orc/src/main/java/org/apache/flink/orc/OrcFilters.java:318
private static String getColumnName(CallExpression comp) {
if (literalOnRight(comp)) {
return ((FieldReferenceExpression) comp.getChildren().get(0)).getName();
} else {
return ((FieldReferenceExpression) comp.getChildren().get(1)).getName();
}
}
private static boolean literalOnRight(CallExpression comp) {
if (comp.getChildren().size() == 1
&& comp.getChildren().get(0) instanceof FieldReferenceExpression) {
return true;
} else if (isLit(comp.getChildren().get(0)) && isRef(comp.getChildren().get(1))) {
return false;
} else if (isRef(comp.getChildren().get(0)) && isLit(comp.getChildren().get(1))) {
return true;
} else {
throw new RuntimeException("Invalid binary comparison.");
}
}
private static PredicateLeaf.Type getLiteralType(CallExpression comp) {
if (literalOnRight(comp)) {
return toOrcType(
((ValueLiteralExpression) comp.getChildren().get(1)).getOutputDataType());
} else {
return toOrcType(
((ValueLiteralExpression) comp.getChildren().get(0)).getOutputDataType());
}
}
private static Object toOrcObject(PredicateLeaf.Type litType, Object literalObj) {
switch (litType) {
case DATE:
if (literalObj instanceof LocalDate) {
LocalDate localDate = (LocalDate) literalObj;View on GitHub (pinned to 2f3c205e92)
Solutions
- Push down only comparisons of a column against a literal; keep column-to-column predicates in Flink (do not pass them to OrcFilters).
- When using the legacy OrcTableSource API, pre-simplify/normalize expressions before handing them to the filter builder.
- Prefer the modern ORC filesystem connector (flink-orc with the FLIP-27 file source) whose predicate pushdown handles richer shapes.
Example fix
// before
Expression pred = $("a").isEqual($("b")); // column vs column
orcTableSource.getSchema().project().filters(pred);
// after
Expression pred = $("a").isEqual(lit(42)); // column vs literal
// column-to-column predicate stays in Flink, not pushed to ORC Defensive patterns
Strategy: type-guard
Validate before calling
// Only push down ref-vs-literal comparisons
boolean pushable(CallExpression c) {
List<Expression> ch = c.getChildren();
if (ch.size() == 1) return ch.get(0) instanceof FieldReferenceExpression;
if (ch.size() != 2) return false;
return (ch.get(0) instanceof FieldReferenceExpression && ch.get(1) instanceof ValueLiteralExpression)
|| (ch.get(0) instanceof ValueLiteralExpression && ch.get(1) instanceof FieldReferenceExpression);
} Type guard
static boolean isValidBinaryComparison(CallExpression c) {
return c.getChildren().size() == 1
? c.getChildren().get(0) instanceof FieldReferenceExpression
: (isRef(c.getChildren().get(0)) && isLit(c.getChildren().get(1)))
|| (isLit(c.getChildren().get(0)) && isRef(c.getChildren().get(1)));
} Prevention
- Keep column-to-column predicates out of ORC pushdown lists.
- Prefer the modern ORC filesystem connector over legacy OrcTableSource filter plumbing.
When it happens
Trigger: Calling OrcFilters or the ORC table predicate pushdown path with a comparison expression whose children are not exactly one FieldReferenceExpression and one ValueLiteralExpression (e.g. two columns compared, two constants, or resolved expressions of another type).
Common situations: Queries like SELECT * FROM t WHERE a = b (column-to-column) reaching the legacy OrcTableSource/OrcFilters API; older planner versions producing expressions the filter converter does not recognize; direct programmatic use of OrcFilters with unnormalized expressions.
Related errors
- A predicate on a LONG column requires an integer literal, i.
- A predicate on a FLOAT column requires a floating literal, i
- A predicate on a STRING column requires a floating literal,
- A predicate on a BOOLEAN column requires a Boolean literal.
- Interrupted
AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14).
Data as JSON: /api/errors/59ab5366cb72f98f.
Report an issue: GitHub.