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

wanghailin 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 6897367424 [Feature][Transform] support boolean type for sql transform 
(#9136)
6897367424 is described below

commit 689736742434000451a07b8d5afaf7c66e3c1277
Author: zhangdonghao <[email protected]>
AuthorDate: Mon Apr 21 20:49:43 2025 +0800

    [Feature][Transform] support boolean type for sql transform (#9136)
---
 docs/en/transform-v2/sql-functions.md              |  14 ++-
 docs/zh/transform-v2/sql-functions.md              |  12 +-
 .../transform/sql/zeta/ZetaSQLFunction.java        |   5 +
 .../seatunnel/transform/sql/zeta/ZetaSQLType.java  |   9 +-
 .../sql/zeta/functions/SystemFunction.java         |  21 ++++
 .../seatunnel/transform/sql/SQLTransformTest.java  | 126 +++++++++++++++++++++
 6 files changed, 182 insertions(+), 5 deletions(-)

diff --git a/docs/en/transform-v2/sql-functions.md 
b/docs/en/transform-v2/sql-functions.md
index 6a2209cb12..f5928e1b94 100644
--- a/docs/en/transform-v2/sql-functions.md
+++ b/docs/en/transform-v2/sql-functions.md
@@ -911,11 +911,17 @@ CALL FROM_UNIXTIME(1672502400, 'yyyy-MM-dd 
HH:mm:ss','UTC+6')
 
 Converts a value to another data type.
 
-Supported data types: STRING | VARCHAR, INT | INTEGER, LONG | BIGINT, BYTE, 
FLOAT, DOUBLE, DECIMAL(p,s), TIMESTAMP, DATE, TIME, BYTES
+Supported data types: STRING | VARCHAR, INT | INTEGER, LONG | BIGINT, BYTE, 
FLOAT, DOUBLE, DECIMAL(p,s), TIMESTAMP, DATE, TIME, BYTES, BOOLEAN
 
 Example:
+* CAST(NAME AS INT)
+* CAST(FLAG AS BOOLEAN)
 
-CONVERT(NAME AS INT)
+NOTE:
+Converts a value to a BOOLEAN data type according to the following rules:
+1. If the value can be interpreted as a boolean string (`'true'` or 
`'false'`), it returns the corresponding boolean value.
+2. If the value can be interpreted as a numeric value (`1` or `0`), it returns 
`true` for `1` and `false` for `0`.
+3. If the value cannot be interpreted according to the above rules, it throws 
a `TransformException`.
 
 ### TRY_CAST
 
@@ -1010,7 +1016,9 @@ It is used to determine whether the condition is valid 
and return different valu
 
 Example:
 
-case when c_string in ('c_string') then 1 else 0 end
+case when c_string in ('c_string') then 1 else 0 end 
+
+case when c_string in ('c_string') then true else false end
 
 ### UUID
 
diff --git a/docs/zh/transform-v2/sql-functions.md 
b/docs/zh/transform-v2/sql-functions.md
index 8140c05646..dbc3cb94e5 100644
--- a/docs/zh/transform-v2/sql-functions.md
+++ b/docs/zh/transform-v2/sql-functions.md
@@ -908,7 +908,15 @@ CALL FROM_UNIXTIME(1672502400, 'yyyy-MM-dd 
HH:mm:ss','UTC+6')
 
 示例:
 
-CONVERT(NAME AS INT)
+CAST(NAME AS INT)
+
+CAST(FLAG AS BOOLEAN)
+
+注意:将值转换为布尔数据类型时,遵循以下规则:
+
+1.  如果值可以被解释为布尔字符串('true' 或 'false'),则返回相应的布尔值。
+2.  如果值可以被解释为数值(1 或 0),则对于 1 返回 true,对于 0 返回 false。
+3.  如果值无法根据以上规则进行解释,则抛出 TransformException 异常。
 
 ### TRY_CAST
 
@@ -1001,6 +1009,8 @@ from
 
 case when c_string in ('c_string') then 1 else 0 end
 
+case when c_string in ('c_string') then true else false end
+
 ### UUID
 
 ```UUID()```
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 4787ada1a4..22074758bf 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
@@ -270,6 +270,11 @@ public class ZetaSQLFunction {
                 columnName = columnName.substring(1, columnName.length() - 1);
                 index = inputRowType.indexOf(columnName, false);
             }
+            if (index == -1
+                    && ("true".equalsIgnoreCase(columnName)
+                            || "false".equalsIgnoreCase(columnName))) {
+                return Boolean.parseBoolean(columnName);
+            }
 
             if (index != -1) {
                 return inputFields[index];
diff --git 
a/seatunnel-transforms-v2/src/main/java/org/apache/seatunnel/transform/sql/zeta/ZetaSQLType.java
 
b/seatunnel-transforms-v2/src/main/java/org/apache/seatunnel/transform/sql/zeta/ZetaSQLType.java
index 5d5a26bf40..6c402247d1 100644
--- 
a/seatunnel-transforms-v2/src/main/java/org/apache/seatunnel/transform/sql/zeta/ZetaSQLType.java
+++ 
b/seatunnel-transforms-v2/src/main/java/org/apache/seatunnel/transform/sql/zeta/ZetaSQLType.java
@@ -81,6 +81,7 @@ public class ZetaSQLType {
     public static final String DATETIME = "DATETIME";
     public static final String DATE = "DATE";
     public static final String TIME = "TIME";
+    public static final String BOOLEAN = "BOOLEAN";
 
     private final SeaTunnelRowType inputRowType;
 
@@ -121,7 +122,11 @@ public class ZetaSQLType {
                 columnName = columnName.substring(1, columnName.length() - 1);
                 index = inputRowType.indexOf(columnName, false);
             }
-
+            if (index == -1
+                    && ("true".equalsIgnoreCase(columnName)
+                            || "false".equalsIgnoreCase(columnName))) {
+                return BasicType.BOOLEAN_TYPE;
+            }
             if (index != -1) {
                 return inputRowType.getFieldType(index);
             } else {
@@ -352,6 +357,8 @@ public class ZetaSQLType {
                 return LocalTimeType.LOCAL_DATE_TYPE;
             case TIME:
                 return LocalTimeType.LOCAL_TIME_TYPE;
+            case BOOLEAN:
+                return BasicType.BOOLEAN_TYPE;
             default:
                 throw new TransformException(
                         CommonErrorCodeDeprecated.UNSUPPORTED_OPERATION,
diff --git 
a/seatunnel-transforms-v2/src/main/java/org/apache/seatunnel/transform/sql/zeta/functions/SystemFunction.java
 
b/seatunnel-transforms-v2/src/main/java/org/apache/seatunnel/transform/sql/zeta/functions/SystemFunction.java
index abd6c35c9a..579d91ce17 100644
--- 
a/seatunnel-transforms-v2/src/main/java/org/apache/seatunnel/transform/sql/zeta/functions/SystemFunction.java
+++ 
b/seatunnel-transforms-v2/src/main/java/org/apache/seatunnel/transform/sql/zeta/functions/SystemFunction.java
@@ -33,6 +33,7 @@ import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.time.ZoneId;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 public class SystemFunction {
@@ -177,6 +178,26 @@ public class SystemFunction {
                 BigDecimal bigDecimal = new BigDecimal(v1.toString());
                 Integer scale = (Integer) args.get(3);
                 return bigDecimal.setScale(scale, RoundingMode.CEILING);
+            case "BOOLEAN":
+                if (v1 instanceof Number) {
+                    if (Arrays.asList(1, 0).contains(((Number) 
v1).intValue())) {
+                        return ((Number) v1).intValue() == 1;
+                    } else {
+                        throw new TransformException(
+                                
CommonErrorCodeDeprecated.UNSUPPORTED_OPERATION,
+                                String.format("Unsupported CAST AS Boolean: 
%s", v1));
+                    }
+                } else if (v1 instanceof String) {
+                    if (Arrays.asList("TRUE", 
"FALSE").contains(v1.toString().toUpperCase())) {
+                        return Boolean.parseBoolean(v1.toString());
+                    } else {
+                        throw new TransformException(
+                                
CommonErrorCodeDeprecated.UNSUPPORTED_OPERATION,
+                                String.format("Unsupported CAST AS Boolean: 
%s", v1));
+                    }
+                } else if (v1 instanceof Boolean) {
+                    return v1;
+                }
         }
         throw new TransformException(
                 CommonErrorCodeDeprecated.UNSUPPORTED_OPERATION,
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 2bf47c36c2..afd6fde0ed 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
@@ -29,6 +29,7 @@ import org.apache.seatunnel.api.table.type.MapType;
 import org.apache.seatunnel.api.table.type.SeaTunnelDataType;
 import org.apache.seatunnel.api.table.type.SeaTunnelRow;
 import org.apache.seatunnel.api.table.type.SeaTunnelRowType;
+import org.apache.seatunnel.transform.exception.TransformException;
 
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
@@ -315,4 +316,129 @@ public class SQLTransformTest {
         Assertions.assertEquals(false, result.get(0).getField(1));
         Assertions.assertEquals(2, result.get(0).getField(2));
     }
+
+    @Test
+    public void tesCaseWhenBooleanClausesWithField() {
+        String tableName = "test";
+        String[] fields = new String[] {"id", "int", "string"};
+        CatalogTable table =
+                CatalogTableUtil.getCatalogTable(
+                        tableName,
+                        new SeaTunnelRowType(
+                                fields,
+                                new SeaTunnelDataType[] {
+                                    BasicType.INT_TYPE, BasicType.INT_TYPE, 
BasicType.STRING_TYPE
+                                }));
+        ReadonlyConfig config =
+                ReadonlyConfig.fromMap(
+                        Collections.singletonMap(
+                                "query",
+                                "select `id`, `int`, (case when `int` = 1 then 
true else false end) as bool_1 , `string`, (case when `string` = 'true' then 
true else false end) as bool_2 from dual"));
+        SQLTransform sqlTransform = new SQLTransform(config, table);
+        List<SeaTunnelRow> result =
+                sqlTransform.transformRow(new SeaTunnelRow(new Object[] {1, 1, 
"true"}));
+
+        Assertions.assertEquals(1, result.get(0).getField(0));
+        Assertions.assertEquals(1, result.get(0).getField(1));
+        Assertions.assertEquals(true, result.get(0).getField(2));
+        Assertions.assertEquals("true", result.get(0).getField(3));
+        Assertions.assertEquals(true, result.get(0).getField(4));
+
+        result = sqlTransform.transformRow(new SeaTunnelRow(new Object[] {1, 
0, "false"}));
+        Assertions.assertEquals(1, result.get(0).getField(0));
+        Assertions.assertEquals(0, result.get(0).getField(1));
+        Assertions.assertEquals(false, result.get(0).getField(2));
+        Assertions.assertEquals("false", result.get(0).getField(3));
+        Assertions.assertEquals(false, result.get(0).getField(4));
+    }
+
+    @Test
+    public void tesCastBooleanClausesWithField() {
+        String tableName = "test";
+        String[] fields = new String[] {"id", "int", "string"};
+        CatalogTable table =
+                CatalogTableUtil.getCatalogTable(
+                        tableName,
+                        new SeaTunnelRowType(
+                                fields,
+                                new SeaTunnelDataType[] {
+                                    BasicType.INT_TYPE, BasicType.INT_TYPE, 
BasicType.STRING_TYPE
+                                }));
+        ReadonlyConfig config =
+                ReadonlyConfig.fromMap(
+                        Collections.singletonMap(
+                                "query",
+                                "select `id`, `int`, cast(`int` as boolean) as 
bool_1 , `string`, cast(`string` as boolean) as bool_2 from dual"));
+        SQLTransform sqlTransform = new SQLTransform(config, table);
+        List<SeaTunnelRow> result =
+                sqlTransform.transformRow(
+                        new SeaTunnelRow(new Object[] {Integer.valueOf(1), 1, 
"true"}));
+
+        Assertions.assertEquals(1, result.get(0).getField(0));
+        Assertions.assertEquals(1, result.get(0).getField(1));
+        Assertions.assertEquals(true, result.get(0).getField(2));
+        Assertions.assertEquals("true", result.get(0).getField(3));
+        Assertions.assertEquals(true, result.get(0).getField(4));
+
+        result =
+                sqlTransform.transformRow(
+                        new SeaTunnelRow(new Object[] {Integer.valueOf(1), 0, 
"false"}));
+        Assertions.assertEquals(1, result.get(0).getField(0));
+        Assertions.assertEquals(0, result.get(0).getField(1));
+        Assertions.assertEquals(false, result.get(0).getField(2));
+        Assertions.assertEquals("false", result.get(0).getField(3));
+        Assertions.assertEquals(false, result.get(0).getField(4));
+
+        Assertions.assertThrows(
+                TransformException.class,
+                () -> {
+                    try {
+                        sqlTransform.transformRow(
+                                new SeaTunnelRow(new Object[] 
{Integer.valueOf(1), 3, "false"}));
+                    } catch (Exception e) {
+                        Assertions.assertEquals(
+                                "ErrorCode:[COMMON-05], 
ErrorDescription:[Unsupported operation] - Unsupported CAST AS Boolean: 3",
+                                e.getMessage());
+                        throw e;
+                    }
+                });
+
+        Assertions.assertThrows(
+                TransformException.class,
+                () -> {
+                    try {
+                        sqlTransform.transformRow(
+                                new SeaTunnelRow(new Object[] 
{Integer.valueOf(1), 0, "false333"}));
+                    } catch (Exception e) {
+                        Assertions.assertEquals(
+                                "ErrorCode:[COMMON-05], 
ErrorDescription:[Unsupported operation] - Unsupported CAST AS Boolean: 
false333",
+                                e.getMessage());
+                        throw e;
+                    }
+                });
+    }
+
+    @Test
+    public void tesBooleanField() {
+        String tableName = "test";
+        String[] fields = new String[] {"id", "int", "string"};
+        CatalogTable table =
+                CatalogTableUtil.getCatalogTable(
+                        tableName,
+                        new SeaTunnelRowType(
+                                fields,
+                                new SeaTunnelDataType[] {
+                                    BasicType.INT_TYPE, BasicType.INT_TYPE, 
BasicType.STRING_TYPE
+                                }));
+        ReadonlyConfig config =
+                ReadonlyConfig.fromMap(
+                        Collections.singletonMap(
+                                "query", "select `id`, true as bool_1, false 
as bool_2 from dual"));
+        SQLTransform sqlTransform = new SQLTransform(config, table);
+        List<SeaTunnelRow> result =
+                sqlTransform.transformRow(new SeaTunnelRow(new Object[] {1, 1, 
"true"}));
+        Assertions.assertEquals(1, result.get(0).getField(0));
+        Assertions.assertEquals(true, result.get(0).getField(1));
+        Assertions.assertEquals(false, result.get(0).getField(2));
+    }
 }

Reply via email to