diff --git a/core/src/main/java/org/opensearch/sql/ast/tree/Rex.java b/core/src/main/java/org/opensearch/sql/ast/tree/Rex.java index c3b1d975ac1..4b0e2188617 100644 --- a/core/src/main/java/org/opensearch/sql/ast/tree/Rex.java +++ b/core/src/main/java/org/opensearch/sql/ast/tree/Rex.java @@ -79,7 +79,7 @@ public Rex attach(UnresolvedPlan child) { @Override public List getChild() { - return ImmutableList.of(child); + return this.child == null ? ImmutableList.of() : ImmutableList.of(this.child); } @Override diff --git a/integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalcitePPLAppendcolIT.java b/integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalcitePPLAppendcolIT.java index 877c10947b8..c6fc62fae74 100644 --- a/integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalcitePPLAppendcolIT.java +++ b/integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalcitePPLAppendcolIT.java @@ -81,4 +81,18 @@ public void testAppendColOverride() throws IOException { rows("F", "DE", 101, null), rows("F", "FL", 310, null)); } + + /** Verifies that rex can be used as the first command of an appendcol subsearch. */ + @Test + public void testAppendColWithRexInSubsearch() throws IOException { + JSONObject actual = + executeQuery( + String.format( + "source=%s | stats count() as cnt by gender" + + " | appendcol [ rex field=email '^(?[^@]+)@.*' | fields user ]" + + " | head 2", + TEST_INDEX_ACCOUNT)); + verifySchema( + actual, schema("gender", "string"), schema("cnt", "bigint"), schema("user", "string")); + } } diff --git a/ppl/src/test/java/org/opensearch/sql/ppl/calcite/CalcitePPLRexTest.java b/ppl/src/test/java/org/opensearch/sql/ppl/calcite/CalcitePPLRexTest.java index 619cb26b64a..2275f9352de 100644 --- a/ppl/src/test/java/org/opensearch/sql/ppl/calcite/CalcitePPLRexTest.java +++ b/ppl/src/test/java/org/opensearch/sql/ppl/calcite/CalcitePPLRexTest.java @@ -306,4 +306,14 @@ public void testRexWithMaxMatchAndOffsetField() { + "FROM `scott`.`EMP`"; verifyPPLToSparkSQL(root, expectedSparkSql); } + + /** Verifies that rex plans correctly when it appears as the first command of a subsearch. */ + @Test + public void testRexInsideSubsearch() { + String ppl = + "source=EMP | stats count() as base_c by JOB" + + " | appendcol [ rex field=ENAME '^(?[A-Z])' | fields ENAME, first ]"; + RelNode root = getRelNode(ppl); + org.junit.Assert.assertNotNull(root); + } }