This is an automated email from the ASF dual-hosted git repository. jhyde pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/calcite.git
commit f7ad9093f40b813a5ee287ba71c1fe1c234a60c5 Author: zstan <[email protected]> AuthorDate: Thu May 11 16:26:41 2023 +0300 [CALCITE-5699] Negated posix regex expressions throw NullPointerException when applied to NULL values Close apache/calcite#3197 --- .../java/org/apache/calcite/test/BabelTest.java | 18 ++++++++ babel/src/test/resources/sql/postgresql.iq | 51 ++++++++++++++++++++++ .../calcite/adapter/enumerable/RexImpTable.java | 10 +++-- 3 files changed, 76 insertions(+), 3 deletions(-) diff --git a/babel/src/test/java/org/apache/calcite/test/BabelTest.java b/babel/src/test/java/org/apache/calcite/test/BabelTest.java index afe05ed2ba..8bed1b28c4 100644 --- a/babel/src/test/java/org/apache/calcite/test/BabelTest.java +++ b/babel/src/test/java/org/apache/calcite/test/BabelTest.java @@ -109,6 +109,24 @@ class BabelTest { } } + @Test void testPosixRegex() { + final SqlValidatorFixture f = Fixtures.forValidator() + .withParserConfig(p -> p.withParserFactory(SqlBabelParserImpl.FACTORY)); + f.withSql("select null !~ 'ab[cd]'").ok(); + f.withSql("select 'abcd' !~ null").ok(); + f.withSql("select null !~ null").ok(); + f.withSql("select null !~* 'ab[cd]'").ok(); + f.withSql("select 'abcd' !~* null").ok(); + f.withSql("select null !~* null").ok(); + f.withSql("select null ~* null").ok(); + f.withSql("select 'abcd' ~* null").ok(); + f.withSql("select null ~* 'ab[cd]'").ok(); + f.withSql("select null ~ null").ok(); + f.withSql("select 'abcd' ~ null").ok(); + f.withSql("select null ~ 'ab[cd]'").ok(); + f.withSql("select 'abcd' !~* 'ab[CD]'").ok(); + } + /** Tests that you can run tests via {@link Fixtures}. */ @Test void testFixtures() { final SqlValidatorFixture v = Fixtures.forValidator(); diff --git a/babel/src/test/resources/sql/postgresql.iq b/babel/src/test/resources/sql/postgresql.iq index b69f8b0fe1..4cc2661154 100644 --- a/babel/src/test/resources/sql/postgresql.iq +++ b/babel/src/test/resources/sql/postgresql.iq @@ -62,3 +62,54 @@ select to_char(timestamp '2022-06-03 12:15:48.678', 'YYYY-MM-DD HH24:MI:SS.MS TZ EXPR$0 2022-06-03 12:15:48.678 !ok + +# ----------------------------------------------------------------------------- +# Posix regex + +# [CALCITE-5699] NPE in Posix regex +SELECT null !~ 'ab[cd]' AS x; +X +null +!ok + +SELECT 'abcd' !~ null AS x; +X +null +!ok + +SELECT null !~ null AS x; +X +null +!ok + +SELECT null !~* 'ab[cd]' AS x; +X +null +!ok + +SELECT 'abcd' !~* null AS x; +X +null +!ok + +SELECT null !~* null AS x; +X +null +!ok + +SELECT 'abe' !~ 'ab[cd]' AS x; +X +true +!ok + +SELECT 'abd' !~ 'ab[cd]' AS x; +X +false +!ok + +SELECT 'abd' ~ 'ab[cd]' AS x; +X +true +!ok + +# End postgresql.iq diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java index 0d5090a93a..6bc1dd18e7 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java @@ -3216,7 +3216,7 @@ public class RexImpTable { private final AbstractRexCallImplementor implementor; private NotImplementor(AbstractRexCallImplementor implementor) { - super("not", null, false); + super("not", implementor.getNullPolicy(), false); this.implementor = implementor; } @@ -3489,9 +3489,13 @@ public class RexImpTable { return variableName; } + @Nullable NullPolicy getNullPolicy() { + return nullPolicy; + } + /** Figures out conditional expression according to NullPolicy. */ Expression getCondition(final List<Expression> argIsNullList) { - if (argIsNullList.size() == 0 + if (argIsNullList.isEmpty() || nullPolicy == null || nullPolicy == NullPolicy.NONE) { return FALSE_EXPR; @@ -3618,7 +3622,7 @@ public class RexImpTable { .map(AbstractRexCallImplementor::unboxExpression) .collect(Collectors.toList()); } - if (nullPolicy == NullPolicy.ARG0 && argValueList.size() > 0) { + if (nullPolicy == NullPolicy.ARG0 && !argValueList.isEmpty()) { final Expression unboxArg0 = unboxExpression(unboxValueList.get(0)); unboxValueList.set(0, unboxArg0); }
