Skip to content

[flink] Support negated predicates in PredicateConverter - #9427

Open
Stephen0421 wants to merge 1 commit into
apache:masterfrom
Stephen0421:flink-predicate-converter-more-predicates
Open

[flink] Support negated predicates in PredicateConverter#9427
Stephen0421 wants to merge 1 commit into
apache:masterfrom
Stephen0421:flink-predicate-converter-more-predicates

Conversation

@Stephen0421

@Stephen0421 Stephen0421 commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Purpose

This PR extends PredicateConverter to support negated predicates while preserving SQL three-valued logic.

The main changes include:

  • Add expression-level NOT conversion with double-negation elimination.
  • Apply De Morgan's law to negated AND and OR expressions.
  • Map negated comparisons to their opposite operators.
  • Support NOT IN through PredicateBuilder.notIn.
  • Support NOT BETWEEN through the structured negation of Between.
  • Support negated IS NULL and IS NOT NULL.
  • Support IS NOT TRUE, IS NOT FALSE, and their unary negations with correct NULL semantics.
  • Keep unsupported negations, such as prefix NOT LIKE, as Flink residual filters.

The conversion failure contract remains unchanged: expressions that cannot be converted safely are not consumed by the source and remain for Flink evaluation.

Tests

  • Added unit tests for:

    • IN and NOT IN, including NULL literals and large-IN predicates.
    • NOT BETWEEN predicate structure.
    • Negation of all comparison operators with literals on either side.
    • Nested AND / OR negation and double NOT.
    • IS TRUE, IS FALSE, IS NOT TRUE, and IS NOT FALSE over TRUE, FALSE, and NULL.
    • Unsupported NOT LIKE conversion.
    • Accepted predicates and remaining source filters.
  • Added a nullable SQL integration test covering NOT BETWEEN, NOT IN, and boolean truth predicates.

  • Verified with Flink 1 and Flink 2:

    • PredicateConverterTest and FlinkTableSourceTest: 65 tests passed for each profile.
    • ReadWriteTableITCase#testNullablePredicateThreeValuedLogic: passed for each profile.

@Stephen0421 Stephen0421 reopened this Aug 27, 2026
return negated
? visitBiFunction(children, builder::equal, builder::equal)
: visitBiFunction(children, builder::notEqual, builder::notEqual);
} else if (func == BuiltInFunctionDefinitions.GREATER_THAN) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Preserve Flink NaN semantics for negated comparisons

For FLOAT and DOUBLE, this rewrite is not equivalent to the original expression. Flink numeric comparisons use Java operators, so NOT (NaN > 1.0) evaluates to true, while the Paimon LessOrEqual predicate orders values through Double.compare and rejects NaN. Because this predicate is pushed down before the remaining Flink filter runs, the row is discarded and the query returns incomplete results.

Please keep negated floating-point comparisons unsupported/residual, or construct NaN-aware equivalents for every comparison direction and add row/source tests containing NaN.

}
return builder.in(builder.indexOf(fieldRefExpr.getName()), literals);
return negated
? builder.notIn(field.index, literals)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Short-circuit NOT IN lists containing NULL

Under SQL WHERE semantics, v NOT IN (1, NULL, 3) can never be true. Passing the NULL literal to builder.notIn is also unsafe for file-index evaluation: the BSI reader can unbox a null mapped value, and the range-bitmap reader can pass null to its comparator, causing the query to fail when either index is enabled. Before this change, the unsupported expression stayed as a Flink residual filter.

Please return an always-false predicate when a negated IN list contains NULL, or reject the conversion so it remains residual. An index-enabled regression test would cover both paths.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants