This is an automated email from the ASF dual-hosted git repository.

shenghang pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/seatunnel.git


The following commit(s) were added to refs/heads/dev by this push:
     new 2720c11bbe [Fix][Transform] Fix ClassCastException in SQL Transform 
with TRIM(Expression) (#10031)
2720c11bbe is described below

commit 2720c11bbea8d8b8a5b30c1f88f2b8690d1201a3
Author: corgy-w <[email protected]>
AuthorDate: Mon Nov 10 22:54:18 2025 +0800

    [Fix][Transform] Fix ClassCastException in SQL Transform with 
TRIM(Expression) (#10031)
---
 .../transform/sql/zeta/ZetaSQLFunction.java        |   6 +-
 .../seatunnel/transform/sql/SQLTransformTest.java  | 303 +++++++++++++++++++++
 2 files changed, 306 insertions(+), 3 deletions(-)

diff --git 
a/seatunnel-transforms-v2/src/main/java/org/apache/seatunnel/transform/sql/zeta/ZetaSQLFunction.java
 
b/seatunnel-transforms-v2/src/main/java/org/apache/seatunnel/transform/sql/zeta/ZetaSQLFunction.java
index 79e5c3b1ec..4adadaf60f 100644
--- 
a/seatunnel-transforms-v2/src/main/java/org/apache/seatunnel/transform/sql/zeta/ZetaSQLFunction.java
+++ 
b/seatunnel-transforms-v2/src/main/java/org/apache/seatunnel/transform/sql/zeta/ZetaSQLFunction.java
@@ -244,10 +244,10 @@ public class ZetaSQLFunction {
 
         if (expression instanceof TrimFunction) {
             TrimFunction function = (TrimFunction) expression;
-            Column column = (Column) function.getExpression();
+            Expression innerExpression = function.getExpression();
             List<Object> functionArgs = new ArrayList<>();
-            if (column != null) {
-                functionArgs.add(computeForValue(column, inputFields));
+            if (innerExpression != null) {
+                functionArgs.add(computeForValue(innerExpression, 
inputFields));
                 if (function.getFromExpression() != null) {
                     functionArgs.add(((StringValue) 
function.getFromExpression()).getValue());
                 }
diff --git 
a/seatunnel-transforms-v2/src/test/java/org/apache/seatunnel/transform/sql/SQLTransformTest.java
 
b/seatunnel-transforms-v2/src/test/java/org/apache/seatunnel/transform/sql/SQLTransformTest.java
index bafebc01b5..97f771326d 100644
--- 
a/seatunnel-transforms-v2/src/test/java/org/apache/seatunnel/transform/sql/SQLTransformTest.java
+++ 
b/seatunnel-transforms-v2/src/test/java/org/apache/seatunnel/transform/sql/SQLTransformTest.java
@@ -760,4 +760,307 @@ public class SQLTransformTest {
                     }
                 });
     }
+
+    @Test
+    public void testTrimWithCastExpression() {
+        // Test TRIM(CAST(id AS VARCHAR)) - fix for ClassCastException bug
+        String tableName = "test";
+        String[] fields = new String[] {"id", "name"};
+        CatalogTable table =
+                CatalogTableUtil.getCatalogTable(
+                        tableName,
+                        new SeaTunnelRowType(
+                                fields,
+                                new SeaTunnelDataType[] {
+                                    BasicType.INT_TYPE, BasicType.STRING_TYPE
+                                }));
+
+        ReadonlyConfig config =
+                ReadonlyConfig.fromMap(
+                        Collections.singletonMap(
+                                "query",
+                                "select id, TRIM(CAST(id AS VARCHAR)) as 
id_str, name from dual"));
+
+        SQLTransform sqlTransform = new SQLTransform(config, table);
+        List<SeaTunnelRow> result =
+                sqlTransform.transformRow(new SeaTunnelRow(new Object[] {123, 
"test"}));
+
+        Assertions.assertNotNull(result);
+        Assertions.assertEquals(1, result.size());
+        Assertions.assertEquals(123, result.get(0).getField(0));
+        Assertions.assertEquals("123", result.get(0).getField(1));
+        Assertions.assertEquals("test", result.get(0).getField(2));
+    }
+
+    @Test
+    public void testTrimWithMultipleCastExpressions() {
+        // Test multiple TRIM(CAST(...)) in one query
+        String tableName = "test";
+        String[] fields = new String[] {"int_val", "long_val", "double_val"};
+        CatalogTable table =
+                CatalogTableUtil.getCatalogTable(
+                        tableName,
+                        new SeaTunnelRowType(
+                                fields,
+                                new SeaTunnelDataType[] {
+                                    BasicType.INT_TYPE, BasicType.LONG_TYPE, 
BasicType.DOUBLE_TYPE
+                                }));
+
+        ReadonlyConfig config =
+                ReadonlyConfig.fromMap(
+                        Collections.singletonMap(
+                                "query",
+                                "select "
+                                        + "TRIM(CAST(int_val AS VARCHAR)) as 
int_str, "
+                                        + "TRIM(CAST(long_val AS VARCHAR)) as 
long_str, "
+                                        + "TRIM(CAST(double_val AS VARCHAR)) 
as double_str "
+                                        + "from dual"));
+
+        SQLTransform sqlTransform = new SQLTransform(config, table);
+        List<SeaTunnelRow> result =
+                sqlTransform.transformRow(new SeaTunnelRow(new Object[] {123, 
456L, 789.12}));
+
+        Assertions.assertNotNull(result);
+        Assertions.assertEquals(1, result.size());
+        Assertions.assertEquals("123", result.get(0).getField(0));
+        Assertions.assertEquals("456", result.get(0).getField(1));
+        Assertions.assertEquals("789.12", result.get(0).getField(2));
+    }
+
+    @Test
+    public void testTrimWithNestedFunctions() {
+        // Test TRIM with nested CAST and other functions
+        String tableName = "test";
+        String[] fields = new String[] {"id", "name"};
+        CatalogTable table =
+                CatalogTableUtil.getCatalogTable(
+                        tableName,
+                        new SeaTunnelRowType(
+                                fields,
+                                new SeaTunnelDataType[] {
+                                    BasicType.INT_TYPE, BasicType.STRING_TYPE
+                                }));
+
+        ReadonlyConfig config =
+                ReadonlyConfig.fromMap(
+                        Collections.singletonMap(
+                                "query",
+                                "select id, UPPER(TRIM(CAST(id AS VARCHAR))) 
as id_upper from dual"));
+
+        SQLTransform sqlTransform = new SQLTransform(config, table);
+        List<SeaTunnelRow> result =
+                sqlTransform.transformRow(new SeaTunnelRow(new Object[] {123, 
"test"}));
+
+        Assertions.assertNotNull(result);
+        Assertions.assertEquals(1, result.size());
+        Assertions.assertEquals(123, result.get(0).getField(0));
+        Assertions.assertEquals("123", result.get(0).getField(1));
+    }
+
+    @Test
+    public void testTrimWithCastInWhereClause() {
+        // Test TRIM(CAST(...)) in WHERE clause
+        String tableName = "test";
+        String[] fields = new String[] {"id", "name"};
+        CatalogTable table =
+                CatalogTableUtil.getCatalogTable(
+                        tableName,
+                        new SeaTunnelRowType(
+                                fields,
+                                new SeaTunnelDataType[] {
+                                    BasicType.INT_TYPE, BasicType.STRING_TYPE
+                                }));
+
+        ReadonlyConfig config =
+                ReadonlyConfig.fromMap(
+                        Collections.singletonMap(
+                                "query",
+                                "select id, name from dual where TRIM(CAST(id 
AS VARCHAR)) = '123'"));
+
+        SQLTransform sqlTransform = new SQLTransform(config, table);
+
+        // Should match
+        List<SeaTunnelRow> result =
+                sqlTransform.transformRow(new SeaTunnelRow(new Object[] {123, 
"test"}));
+        Assertions.assertNotNull(result);
+        Assertions.assertEquals(1, result.size());
+        Assertions.assertEquals(123, result.get(0).getField(0));
+        Assertions.assertEquals("test", result.get(0).getField(1));
+
+        // Should not match
+        result = sqlTransform.transformRow(new SeaTunnelRow(new Object[] {456, 
"test2"}));
+        Assertions.assertNull(result);
+    }
+
+    @Test
+    public void testTrimWithCastNull() {
+        // Test TRIM(CAST(NULL AS VARCHAR))
+        String tableName = "test";
+        String[] fields = new String[] {"id", "name"};
+        CatalogTable table =
+                CatalogTableUtil.getCatalogTable(
+                        tableName,
+                        new SeaTunnelRowType(
+                                fields,
+                                new SeaTunnelDataType[] {
+                                    BasicType.INT_TYPE, BasicType.STRING_TYPE
+                                }));
+
+        ReadonlyConfig config =
+                ReadonlyConfig.fromMap(
+                        Collections.singletonMap(
+                                "query",
+                                "select id, TRIM(CAST(id AS VARCHAR)) as 
id_str from dual"));
+
+        SQLTransform sqlTransform = new SQLTransform(config, table);
+        List<SeaTunnelRow> result =
+                sqlTransform.transformRow(new SeaTunnelRow(new Object[] {null, 
"test"}));
+
+        Assertions.assertNotNull(result);
+        Assertions.assertEquals(1, result.size());
+        Assertions.assertNull(result.get(0).getField(0));
+        Assertions.assertNull(result.get(0).getField(1)); // TRIM(CAST(NULL)) 
should be NULL
+    }
+
+    @Test
+    public void testTrimWithConcatFunction() {
+        // Test TRIM(CONCAT(...)) - function inside TRIM
+        String tableName = "test";
+        String[] fields = new String[] {"first_name", "last_name"};
+        CatalogTable table =
+                CatalogTableUtil.getCatalogTable(
+                        tableName,
+                        new SeaTunnelRowType(
+                                fields,
+                                new SeaTunnelDataType[] {
+                                    BasicType.STRING_TYPE, 
BasicType.STRING_TYPE
+                                }));
+
+        ReadonlyConfig config =
+                ReadonlyConfig.fromMap(
+                        Collections.singletonMap(
+                                "query",
+                                "select TRIM(CONCAT(first_name, ' ', 
last_name)) as full_name from dual"));
+
+        SQLTransform sqlTransform = new SQLTransform(config, table);
+        List<SeaTunnelRow> result =
+                sqlTransform.transformRow(new SeaTunnelRow(new Object[] 
{"John", "Doe"}));
+
+        Assertions.assertNotNull(result);
+        Assertions.assertEquals(1, result.size());
+        Assertions.assertEquals("John Doe", result.get(0).getField(0));
+    }
+
+    @Test
+    public void testTrimWithSubstringFunction() {
+        // Test TRIM(SUBSTRING(...)) - another function inside TRIM
+        String tableName = "test";
+        String[] fields = new String[] {"text"};
+        CatalogTable table =
+                CatalogTableUtil.getCatalogTable(
+                        tableName,
+                        new SeaTunnelRowType(
+                                fields, new SeaTunnelDataType[] 
{BasicType.STRING_TYPE}));
+
+        ReadonlyConfig config =
+                ReadonlyConfig.fromMap(
+                        Collections.singletonMap(
+                                "query",
+                                "select TRIM(SUBSTRING(text, 1, 5)) as trimmed 
from dual"));
+
+        SQLTransform sqlTransform = new SQLTransform(config, table);
+        List<SeaTunnelRow> result =
+                sqlTransform.transformRow(new SeaTunnelRow(new Object[] {"  
Hello World  "}));
+
+        Assertions.assertNotNull(result);
+        Assertions.assertEquals(1, result.size());
+        Assertions.assertEquals("Hel", result.get(0).getField(0));
+    }
+
+    @Test
+    public void testTrimWithReplaceFunction() {
+        // Test TRIM(REPLACE(...)) - yet another function inside TRIM
+        String tableName = "test";
+        String[] fields = new String[] {"text"};
+        CatalogTable table =
+                CatalogTableUtil.getCatalogTable(
+                        tableName,
+                        new SeaTunnelRowType(
+                                fields, new SeaTunnelDataType[] 
{BasicType.STRING_TYPE}));
+
+        ReadonlyConfig config =
+                ReadonlyConfig.fromMap(
+                        Collections.singletonMap(
+                                "query",
+                                "select TRIM(REPLACE(text, 'old', 'new')) as 
replaced from dual"));
+
+        SQLTransform sqlTransform = new SQLTransform(config, table);
+        List<SeaTunnelRow> result =
+                sqlTransform.transformRow(new SeaTunnelRow(new Object[] {" old 
text "}));
+
+        Assertions.assertNotNull(result);
+        Assertions.assertEquals(1, result.size());
+        Assertions.assertEquals("new text", result.get(0).getField(0));
+    }
+
+    @Test
+    public void testTrimWithArithmeticExpression() {
+        // Test TRIM with arithmetic expression (id + 100)
+        String tableName = "test";
+        String[] fields = new String[] {"id", "name"};
+        CatalogTable table =
+                CatalogTableUtil.getCatalogTable(
+                        tableName,
+                        new SeaTunnelRowType(
+                                fields,
+                                new SeaTunnelDataType[] {
+                                    BasicType.INT_TYPE, BasicType.STRING_TYPE
+                                }));
+
+        ReadonlyConfig config =
+                ReadonlyConfig.fromMap(
+                        Collections.singletonMap(
+                                "query",
+                                "select TRIM(CAST(id + 100 AS VARCHAR)) as 
result from dual"));
+
+        SQLTransform sqlTransform = new SQLTransform(config, table);
+        List<SeaTunnelRow> result =
+                sqlTransform.transformRow(new SeaTunnelRow(new Object[] {23, 
"test"}));
+
+        Assertions.assertNotNull(result);
+        Assertions.assertEquals(1, result.size());
+        Assertions.assertEquals("123", result.get(0).getField(0));
+    }
+
+    @Test
+    public void testTrimWithCoalesceFunction() {
+        // Test TRIM(COALESCE(...)) - system function inside TRIM
+        String tableName = "test";
+        String[] fields = new String[] {"name", "default_name"};
+        CatalogTable table =
+                CatalogTableUtil.getCatalogTable(
+                        tableName,
+                        new SeaTunnelRowType(
+                                fields,
+                                new SeaTunnelDataType[] {
+                                    BasicType.STRING_TYPE, 
BasicType.STRING_TYPE
+                                }));
+
+        ReadonlyConfig config =
+                ReadonlyConfig.fromMap(
+                        Collections.singletonMap(
+                                "query",
+                                "select TRIM(COALESCE(name, default_name)) as 
result from dual"));
+
+        SQLTransform sqlTransform = new SQLTransform(config, table);
+
+        // Test with non-null name
+        List<SeaTunnelRow> result =
+                sqlTransform.transformRow(new SeaTunnelRow(new Object[] {" 
John ", "Default"}));
+        Assertions.assertEquals("John", result.get(0).getField(0));
+
+        // Test with null name
+        result = sqlTransform.transformRow(new SeaTunnelRow(new Object[] 
{null, " Default "}));
+        Assertions.assertEquals("Default", result.get(0).getField(0));
+    }
 }

Reply via email to