JingsongLi commented on code in PR #8395:
URL: https://github.com/apache/paimon/pull/8395#discussion_r3519380929
##########
paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/PredicateConverter.java:
##########
@@ -194,10 +194,56 @@ public Predicate visit(CallExpression call) {
FieldReferenceExpression fieldRefExpr =
extractFieldReference(children.get(0)).orElseThrow(UnsupportedExpression::new);
return builder.equal(builder.indexOf(fieldRefExpr.getName()),
Boolean.FALSE);
+ } else if (func == BuiltInFunctionDefinitions.NOT) {
+ // NOT predicate - negate the inner predicate
+ Predicate innerPredicate = children.get(0).accept(this);
+ return
innerPredicate.negate().orElseThrow(UnsupportedExpression::new);
Review Comment:
`NOT` cannot be delegated blindly to `Predicate.negate()` for predicates
that were encoded with two-valued comparison predicates. For example, `IS_TRUE`
is represented as `equal(field, TRUE)`, so `NOT (field IS TRUE)` becomes
`NotEqual(field, TRUE)`. Paimon comparisons return false for NULL inputs, but
SQL `NOT (field IS TRUE)` is equivalent to `field IS NOT TRUE` and must keep
NULL rows. The same applies to `NOT (field IS FALSE)`. Please special-case
these boolean IS predicates (or leave those NOT forms unsupported) and add
NULL-row tests for `NOT(IS_TRUE)`/`NOT(IS_FALSE)`.
##########
paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/PredicateConverter.java:
##########
@@ -291,6 +337,87 @@ private boolean supportsPredicate(LogicalType type) {
}
}
+ /**
+ * Converts a SQL SIMILAR TO pattern to an equivalent SQL LIKE pattern so
that it can be
+ * evaluated by {@link PredicateBuilder#like}.
+ *
+ * <p>The conversion handles only the subset of SIMILAR TO syntax that
maps directly to SQL
+ * LIKE:
+ *
+ * <ul>
+ * <li>{@code %} (any-string wildcard) is preserved as-is.
+ * <li>{@code _} (single-character wildcard) is preserved as-is.
+ * <li>Escape sequences: {@code escape + '_'} and {@code escape + '%'}
become their literal
+ * equivalents, emitted as {@code \ + char} so that the downstream
{@link Like} function
+ * (which uses {@code \} as its default escape) treats them as
literals. {@code escape +
+ * escape} becomes a literal escape character.
+ * </ul>
+ *
+ * <p>SIMILAR TO-only features (character classes {@code [...]},
alternation {@code |},
+ * quantifiers {@code *}, {@code +}, {@code ?}, {@code {m,n}}, and
grouping {@code ()}) are not
+ * supported and will cause an {@link UnsupportedExpression} to be thrown.
+ *
+ * @param sqlPattern the SIMILAR TO pattern string
+ * @param escape the escape character string (single char), or {@code
null} for no escaping
+ * @return an equivalent SQL LIKE pattern (using {@code \} as the escape
character)
+ * @throws UnsupportedExpression if the pattern uses SIMILAR TO-only
features
+ */
+ private String convertSimilarToLike(String sqlPattern, String escape) {
+ if (sqlPattern == null || sqlPattern.isEmpty()) {
+ return sqlPattern;
+ }
+
+ // Sentinel 0 means no escape character is defined.
+ char escapeChar = (escape != null && !escape.isEmpty()) ?
escape.charAt(0) : 0;
+ // The output LIKE pattern will always use '\' as its escape char,
because that is what
+ // Like.sqlToRegexLike uses by default.
+ final char outputEscape = '\\';
+
+ StringBuilder like = new StringBuilder();
+
+ for (int i = 0; i < sqlPattern.length(); i++) {
+ char c = sqlPattern.charAt(i);
+
+ if (escapeChar != 0 && c == escapeChar) {
+ // Escape sequence
+ if (i + 1 >= sqlPattern.length()) {
+ throw new UnsupportedExpression();
+ }
+ char next = sqlPattern.charAt(i + 1);
+ if (next == '_' || next == '%') {
+ // Escaped wildcard -> literal in the LIKE output.
+ // Emit as outputEscape + wildcard so Like treats it as a
literal.
+ like.append(outputEscape).append(next);
+ } else if (next == escapeChar) {
+ // Escaped escape char -> emit as a literal character.
+ // If the escape char itself is special to LIKE (% or _),
escape it; otherwise
+ // emit it as-is since Like only special-cases % and _.
+ like.append(escapeChar);
Review Comment:
When the SIMILAR escape character is itself `%` or `_`, this branch emits
the escaped escape character as a bare LIKE wildcard. For example, `col SIMILAR
TO 'a%%b' ESCAPE '%'` should match literal `a%b`, but this returns `a%b`, which
`Like` treats as `a` + wildcard + `b` and will also keep rows like `axb`.
Please emit `outputEscape + escapeChar` when `escapeChar` is `%` or `_`, and
add tests with `%`/`_` as the escape character.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]