Skip to content

Commit b2fed4e

Browse files
committed
[Feature][Transform] support boolean type for sql transform
1 parent 5f55e31 commit b2fed4e

File tree

6 files changed

+182
-5
lines changed

6 files changed

+182
-5
lines changed

docs/en/transform-v2/sql-functions.md

+11-3
Original file line numberDiff line numberDiff line change
@@ -917,11 +917,17 @@ CALL FROM_UNIXTIME(1672502400, 'yyyy-MM-dd HH:mm:ss','UTC+6')
917917

918918
Converts a value to another data type.
919919

920-
Supported data types: STRING | VARCHAR, INT | INTEGER, LONG | BIGINT, BYTE, FLOAT, DOUBLE, DECIMAL(p,s), TIMESTAMP, DATE, TIME, BYTES
920+
Supported data types: STRING | VARCHAR, INT | INTEGER, LONG | BIGINT, BYTE, FLOAT, DOUBLE, DECIMAL(p,s), TIMESTAMP, DATE, TIME, BYTES, BOOLEAN
921921

922922
Example:
923+
* CONVERT(NAME AS INT)
924+
* CAST(FLAG AS BOOLEAN)
923925

924-
CONVERT(NAME AS INT)
926+
NOTE:
927+
Converts a value to a BOOLEAN data type according to the following rules:
928+
1. If the value can be interpreted as a boolean string (`'true'` or `'false'`), it returns the corresponding boolean value.
929+
2. If the value can be interpreted as a numeric value (`1` or `0`), it returns `true` for `1` and `false` for `0`.
930+
3. If the value cannot be interpreted according to the above rules, it throws a `TransformException`.
925931

926932
### TRY_CAST
927933

@@ -1016,7 +1022,9 @@ It is used to determine whether the condition is valid and return different valu
10161022

10171023
Example:
10181024

1019-
case when c_string in ('c_string') then 1 else 0 end
1025+
case when c_string in ('c_string') then 1 else 0 end
1026+
1027+
case when c_string in ('c_string') then true else false end
10201028

10211029
### UUID
10221030

docs/zh/transform-v2/sql-functions.md

+11-1
Original file line numberDiff line numberDiff line change
@@ -914,7 +914,15 @@ CALL FROM_UNIXTIME(1672502400, 'yyyy-MM-dd HH:mm:ss','UTC+6')
914914

915915
示例:
916916

917-
CONVERT(NAME AS INT)
917+
CAST(NAME AS INT)
918+
919+
CAST(FLAG AS BOOLEAN)
920+
921+
注意:将值转换为布尔数据类型时,遵循以下规则:
922+
923+
1. 如果值可以被解释为布尔字符串('true' 或 'false'),则返回相应的布尔值。
924+
2. 如果值可以被解释为数值(1 或 0),则对于 1 返回 true,对于 0 返回 false。
925+
3. 如果值无法根据以上规则进行解释,则抛出 TransformException 异常。
918926

919927
### TRY_CAST
920928

@@ -1007,6 +1015,8 @@ from
10071015

10081016
case when c_string in ('c_string') then 1 else 0 end
10091017

1018+
case when c_string in ('c_string') then true else false end
1019+
10101020
### UUID
10111021

10121022
```UUID()```

seatunnel-transforms-v2/src/main/java/org/apache/seatunnel/transform/sql/zeta/ZetaSQLFunction.java

+5
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,11 @@ public Object computeForValue(Expression expression, Object[] inputFields) {
270270
columnName = columnName.substring(1, columnName.length() - 1);
271271
index = inputRowType.indexOf(columnName, false);
272272
}
273+
if (index == -1
274+
&& ("true".equalsIgnoreCase(columnName)
275+
|| "false".equalsIgnoreCase(columnName))) {
276+
return Boolean.parseBoolean(columnName);
277+
}
273278

274279
if (index != -1) {
275280
return inputFields[index];

seatunnel-transforms-v2/src/main/java/org/apache/seatunnel/transform/sql/zeta/ZetaSQLType.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ public class ZetaSQLType {
8181
public static final String DATETIME = "DATETIME";
8282
public static final String DATE = "DATE";
8383
public static final String TIME = "TIME";
84+
public static final String BOOLEAN = "BOOLEAN";
8485

8586
private final SeaTunnelRowType inputRowType;
8687

@@ -121,7 +122,11 @@ public SeaTunnelDataType<?> getExpressionType(Expression expression) {
121122
columnName = columnName.substring(1, columnName.length() - 1);
122123
index = inputRowType.indexOf(columnName, false);
123124
}
124-
125+
if (index == -1
126+
&& ("true".equalsIgnoreCase(columnName)
127+
|| "false".equalsIgnoreCase(columnName))) {
128+
return BasicType.BOOLEAN_TYPE;
129+
}
125130
if (index != -1) {
126131
return inputRowType.getFieldType(index);
127132
} else {
@@ -352,6 +357,8 @@ private SeaTunnelDataType<?> getCastType(CastExpression castExpression) {
352357
return LocalTimeType.LOCAL_DATE_TYPE;
353358
case TIME:
354359
return LocalTimeType.LOCAL_TIME_TYPE;
360+
case BOOLEAN:
361+
return BasicType.BOOLEAN_TYPE;
355362
default:
356363
throw new TransformException(
357364
CommonErrorCodeDeprecated.UNSUPPORTED_OPERATION,

seatunnel-transforms-v2/src/main/java/org/apache/seatunnel/transform/sql/zeta/functions/SystemFunction.java

+21
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import java.time.LocalTime;
3434
import java.time.ZoneId;
3535
import java.util.ArrayList;
36+
import java.util.Arrays;
3637
import java.util.List;
3738

3839
public class SystemFunction {
@@ -177,6 +178,26 @@ public static Object castAs(List<Object> args) {
177178
BigDecimal bigDecimal = new BigDecimal(v1.toString());
178179
Integer scale = (Integer) args.get(3);
179180
return bigDecimal.setScale(scale, RoundingMode.CEILING);
181+
case "BOOLEAN":
182+
if (v1 instanceof Number) {
183+
if (Arrays.asList(1, 0).contains(((Number) v1).intValue())) {
184+
return ((Number) v1).intValue() == 1;
185+
} else {
186+
throw new TransformException(
187+
CommonErrorCodeDeprecated.UNSUPPORTED_OPERATION,
188+
String.format("Unsupported CAST AS Boolean: %s", v1));
189+
}
190+
} else if (v1 instanceof String) {
191+
if (Arrays.asList("TRUE", "FALSE").contains(v1.toString().toUpperCase())) {
192+
return Boolean.parseBoolean(v1.toString());
193+
} else {
194+
throw new TransformException(
195+
CommonErrorCodeDeprecated.UNSUPPORTED_OPERATION,
196+
String.format("Unsupported CAST AS Boolean: %s", v1));
197+
}
198+
} else if (v1 instanceof Boolean) {
199+
return v1;
200+
}
180201
}
181202
throw new TransformException(
182203
CommonErrorCodeDeprecated.UNSUPPORTED_OPERATION,

seatunnel-transforms-v2/src/test/java/org/apache/seatunnel/transform/sql/SQLTransformTest.java

+126
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.apache.seatunnel.api.table.type.SeaTunnelDataType;
3030
import org.apache.seatunnel.api.table.type.SeaTunnelRow;
3131
import org.apache.seatunnel.api.table.type.SeaTunnelRowType;
32+
import org.apache.seatunnel.transform.exception.TransformException;
3233

3334
import org.junit.jupiter.api.Assertions;
3435
import org.junit.jupiter.api.Test;
@@ -315,4 +316,129 @@ public void tesCaseWhenClausesWithBooleanField() {
315316
Assertions.assertEquals(false, result.get(0).getField(1));
316317
Assertions.assertEquals(2, result.get(0).getField(2));
317318
}
319+
320+
@Test
321+
public void tesCaseWhenBooleanClausesWithField() {
322+
String tableName = "test";
323+
String[] fields = new String[] {"id", "int", "string"};
324+
CatalogTable table =
325+
CatalogTableUtil.getCatalogTable(
326+
tableName,
327+
new SeaTunnelRowType(
328+
fields,
329+
new SeaTunnelDataType[] {
330+
BasicType.INT_TYPE, BasicType.INT_TYPE, BasicType.STRING_TYPE
331+
}));
332+
ReadonlyConfig config =
333+
ReadonlyConfig.fromMap(
334+
Collections.singletonMap(
335+
"query",
336+
"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"));
337+
SQLTransform sqlTransform = new SQLTransform(config, table);
338+
List<SeaTunnelRow> result =
339+
sqlTransform.transformRow(new SeaTunnelRow(new Object[] {1, 1, "true"}));
340+
341+
Assertions.assertEquals(1, result.get(0).getField(0));
342+
Assertions.assertEquals(1, result.get(0).getField(1));
343+
Assertions.assertEquals(true, result.get(0).getField(2));
344+
Assertions.assertEquals("true", result.get(0).getField(3));
345+
Assertions.assertEquals(true, result.get(0).getField(4));
346+
347+
result = sqlTransform.transformRow(new SeaTunnelRow(new Object[] {1, 0, "false"}));
348+
Assertions.assertEquals(1, result.get(0).getField(0));
349+
Assertions.assertEquals(0, result.get(0).getField(1));
350+
Assertions.assertEquals(false, result.get(0).getField(2));
351+
Assertions.assertEquals("false", result.get(0).getField(3));
352+
Assertions.assertEquals(false, result.get(0).getField(4));
353+
}
354+
355+
@Test
356+
public void tesCastBooleanClausesWithField() {
357+
String tableName = "test";
358+
String[] fields = new String[] {"id", "int", "string"};
359+
CatalogTable table =
360+
CatalogTableUtil.getCatalogTable(
361+
tableName,
362+
new SeaTunnelRowType(
363+
fields,
364+
new SeaTunnelDataType[] {
365+
BasicType.INT_TYPE, BasicType.INT_TYPE, BasicType.STRING_TYPE
366+
}));
367+
ReadonlyConfig config =
368+
ReadonlyConfig.fromMap(
369+
Collections.singletonMap(
370+
"query",
371+
"select `id`, `int`, cast(`int` as boolean) as bool_1 , `string`, cast(`string` as boolean) as bool_2 from dual"));
372+
SQLTransform sqlTransform = new SQLTransform(config, table);
373+
List<SeaTunnelRow> result =
374+
sqlTransform.transformRow(
375+
new SeaTunnelRow(new Object[] {Integer.valueOf(1), 1, "true"}));
376+
377+
Assertions.assertEquals(1, result.get(0).getField(0));
378+
Assertions.assertEquals(1, result.get(0).getField(1));
379+
Assertions.assertEquals(true, result.get(0).getField(2));
380+
Assertions.assertEquals("true", result.get(0).getField(3));
381+
Assertions.assertEquals(true, result.get(0).getField(4));
382+
383+
result =
384+
sqlTransform.transformRow(
385+
new SeaTunnelRow(new Object[] {Integer.valueOf(1), 0, "false"}));
386+
Assertions.assertEquals(1, result.get(0).getField(0));
387+
Assertions.assertEquals(0, result.get(0).getField(1));
388+
Assertions.assertEquals(false, result.get(0).getField(2));
389+
Assertions.assertEquals("false", result.get(0).getField(3));
390+
Assertions.assertEquals(false, result.get(0).getField(4));
391+
392+
Assertions.assertThrows(
393+
TransformException.class,
394+
() -> {
395+
try {
396+
sqlTransform.transformRow(
397+
new SeaTunnelRow(new Object[] {Integer.valueOf(1), 3, "false"}));
398+
} catch (Exception e) {
399+
Assertions.assertEquals(
400+
"ErrorCode:[COMMON-05], ErrorDescription:[Unsupported operation] - Unsupported CAST AS Boolean: 3",
401+
e.getMessage());
402+
throw e;
403+
}
404+
});
405+
406+
Assertions.assertThrows(
407+
TransformException.class,
408+
() -> {
409+
try {
410+
sqlTransform.transformRow(
411+
new SeaTunnelRow(new Object[] {Integer.valueOf(1), 0, "false333"}));
412+
} catch (Exception e) {
413+
Assertions.assertEquals(
414+
"ErrorCode:[COMMON-05], ErrorDescription:[Unsupported operation] - Unsupported CAST AS Boolean: false333",
415+
e.getMessage());
416+
throw e;
417+
}
418+
});
419+
}
420+
421+
@Test
422+
public void tesBooleanField() {
423+
String tableName = "test";
424+
String[] fields = new String[] {"id", "int", "string"};
425+
CatalogTable table =
426+
CatalogTableUtil.getCatalogTable(
427+
tableName,
428+
new SeaTunnelRowType(
429+
fields,
430+
new SeaTunnelDataType[] {
431+
BasicType.INT_TYPE, BasicType.INT_TYPE, BasicType.STRING_TYPE
432+
}));
433+
ReadonlyConfig config =
434+
ReadonlyConfig.fromMap(
435+
Collections.singletonMap(
436+
"query", "select `id`, true as bool_1, false as bool_2 from dual"));
437+
SQLTransform sqlTransform = new SQLTransform(config, table);
438+
List<SeaTunnelRow> result =
439+
sqlTransform.transformRow(new SeaTunnelRow(new Object[] {1, 1, "true"}));
440+
Assertions.assertEquals(1, result.get(0).getField(0));
441+
Assertions.assertEquals(true, result.get(0).getField(1));
442+
Assertions.assertEquals(false, result.get(0).getField(2));
443+
}
318444
}

0 commit comments

Comments
 (0)