Skip to content
This repository was archived by the owner on Dec 28, 2025. It is now read-only.

Commit 46f7cc0

Browse files
yzeng1618zengyi
andauthored
[Fix][Transform-V2] Fix datetime/numeric/string function edge cases and update tests (apache#10168)
Co-authored-by: zengyi <zengyi@chinatelecom.cn>
1 parent f951b0a commit 46f7cc0

File tree

10 files changed

+116
-15
lines changed

10 files changed

+116
-15
lines changed

docs/en/concept/incompatible-changes.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ You need to check this document before you upgrade to related version.
1313

1414
### Transform Changes
1515

16+
- Adjusted SQL Transform date & time functions:
17+
- `DATEDIFF(<start>, <end>, 'MONTH')` now returns the total number of months between the two dates across years (for example, from `2023-01-01` to `2024-03-01` returns `14` instead of `15`).
18+
- `WEEK(<datetime>)` now returns the ISO week number directly (previous behavior added an extra `+1` to the ISO week value).
19+
1620
### Engine Behavior Changes
1721

18-
### Dependency Upgrades
22+
### Dependency Upgrades

seatunnel-e2e/seatunnel-transforms-v2-e2e/seatunnel-transforms-v2-e2e-part-2/src/test/resources/sql_transform/func_datetime.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ sink {
380380
field_name = "c4_10"
381381
field_type = "int"
382382
field_value = [
383-
{equals_to = 15}
383+
{equals_to = 14}
384384
]
385385
},
386386
{

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ public static Long datediff(List<Object> args) {
186186
break;
187187
case "MONTH":
188188
if (date1 != null && date2 != null) {
189-
return (long) Period.between(date1, date2).getMonths();
189+
return Period.between(date1, date2).toTotalMonths();
190190
}
191191
break;
192192
case "WEEK":
@@ -500,6 +500,7 @@ public static Integer extract(List<Object> args) {
500500
}
501501
break;
502502
case "DOW":
503+
case "DAYOFWEEK":
503504
if (datetime instanceof LocalDate) {
504505
return ((LocalDate) datetime).getDayOfWeek().getValue() % 7;
505506
}
@@ -550,8 +551,6 @@ public static Integer extract(List<Object> args) {
550551
return (year > 0) ? (year - 1) / 1000 + 1 : year / 1000;
551552
}
552553
break;
553-
case "DAYOFWEEK":
554-
return dayOfWeek(args);
555554
default:
556555
throw new TransformException(
557556
CommonErrorCodeDeprecated.UNSUPPORTED_OPERATION,
@@ -688,7 +687,7 @@ public static Integer week(List<Object> args) {
688687
}
689688
LocalDate localDate = convertToLocalDate(datetime);
690689
WeekFields weekFields = WeekFields.ISO;
691-
return localDate.get(weekFields.weekOfYear()) + 1;
690+
return localDate.get(weekFields.weekOfYear());
692691
}
693692

694693
public static Integer year(List<Object> args) {

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ private static Number round(Number v1, Number v2, RoundingMode roundingMode) {
208208
c:
209209
switch (t.toUpperCase()) {
210210
case "INTEGER":
211-
case "SHOT":
211+
case "SHORT":
212212
case "LONG":
213213
{
214214
if (scale < 0) {
@@ -262,10 +262,10 @@ private static Number round(Number v1, Number v2, RoundingMode roundingMode) {
262262
}
263263

264264
private static Number convertTo(String valueType, Number column) {
265-
switch (valueType) {
265+
switch (valueType.toUpperCase()) {
266266
case "INTEGER":
267267
return column.intValue();
268-
case "SHOT":
268+
case "SHORT":
269269
return column.shortValue();
270270
case "LONG":
271271
return column.longValue();
@@ -403,10 +403,10 @@ public static Number round(List<Object> args) {
403403
return round(v1, v2, RoundingMode.HALF_UP);
404404
}
405405

406-
public static int sign(List<Object> args) {
406+
public static Integer sign(List<Object> args) {
407407
Number v1 = (Number) args.get(0);
408408
if (v1 == null) {
409-
return 0;
409+
return null;
410410
}
411411
if (v1 instanceof Integer) {
412412
return Integer.signum((Integer) v1);

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public class StringFunction {
5050

5151
public static Integer ascii(List<Object> args) {
5252
String arg = (String) args.get(0);
53-
if (arg == null) {
53+
if (arg == null || arg.isEmpty()) {
5454
return null;
5555
} else {
5656
return (int) arg.charAt(0);
@@ -231,6 +231,9 @@ public static String left(List<Object> args) {
231231
return null;
232232
}
233233
int count = ((Number) args.get(1)).intValue();
234+
if (count < 0) {
235+
return "";
236+
}
234237
if (count > arg.length()) {
235238
count = arg.length();
236239
}
@@ -243,6 +246,9 @@ public static String right(List<Object> args) {
243246
return null;
244247
}
245248
int count = ((Number) args.get(1)).intValue();
249+
if (count < 0) {
250+
return "";
251+
}
246252
int length = arg.length();
247253
if (count > length) {
248254
count = length;

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,6 @@ public static Object castAs(List<Object> args) {
107107
if (v1 == null) {
108108
return null;
109109
}
110-
if (v1.equals(v2)) {
111-
return null;
112-
}
113110
switch (v2) {
114111
case "VARCHAR":
115112
case "STRING":

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,16 @@
2424
import org.apache.seatunnel.api.table.type.SeaTunnelRowType;
2525
import org.apache.seatunnel.transform.sql.SQLEngine;
2626
import org.apache.seatunnel.transform.sql.SQLEngineFactory;
27+
import org.apache.seatunnel.transform.sql.zeta.functions.DateTimeFunction;
2728

2829
import org.junit.jupiter.api.Assertions;
2930
import org.junit.jupiter.api.Test;
3031

32+
import java.time.LocalDate;
3133
import java.time.LocalDateTime;
3234
import java.time.ZoneId;
3335
import java.util.ArrayList;
36+
import java.util.Arrays;
3437

3538
public class DateTimeFunctionTest {
3639

@@ -176,4 +179,14 @@ public void testFromUnixtimeFunctionWithIntegerInput() {
176179
// Both Integer and Long inputs should produce the same result
177180
Assertions.assertEquals(fieldInt.toString(), fieldLong.toString());
178181
}
182+
183+
@Test
184+
public void testDateDiffMonthAcrossYearUsesTotalMonths() {
185+
LocalDate start = LocalDate.of(2023, 1, 1);
186+
LocalDate end = LocalDate.of(2024, 3, 1);
187+
188+
Long months = DateTimeFunction.datediff(Arrays.asList(start, end, "MONTH"));
189+
190+
Assertions.assertEquals(14L, months);
191+
}
179192
}

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.junit.jupiter.api.Test;
3131

3232
import java.math.BigDecimal;
33+
import java.util.Arrays;
3334
import java.util.Collections;
3435

3536
public class NumericFunctionTest {
@@ -78,4 +79,18 @@ public void testTrimScale() {
7879
Assertions.assertEquals("0", NumericFunction.trimScale(Collections.singletonList(0)));
7980
Assertions.assertNull(NumericFunction.trimScale(Collections.singletonList((Object) null)));
8081
}
82+
83+
@Test
84+
public void testRoundShortNegativeScale() {
85+
short shortValue = 123;
86+
87+
Number result = NumericFunction.round(Arrays.asList(shortValue, -1));
88+
89+
Assertions.assertEquals(120, result.intValue());
90+
}
91+
92+
@Test
93+
public void testSignNullReturnsNull() {
94+
Assertions.assertNull(NumericFunction.sign(Collections.singletonList(null)));
95+
}
8196
}

seatunnel-transforms-v2/src/test/java/org/apache/seatunnel/transform/sql/zeta/functions/StringFunctionTest.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,4 +121,28 @@ public void testSubstringWithTemporal() {
121121
// Should extract time part from formatted string "15:30:45"
122122
Assertions.assertEquals("15:30", StringFunction.substring(args));
123123
}
124+
125+
@Test
126+
public void testAsciiNullAndEmptyReturnNull() {
127+
List<Object> args = new ArrayList<>();
128+
args.add(null);
129+
Assertions.assertNull(StringFunction.ascii(args));
130+
131+
args.clear();
132+
args.add("");
133+
Assertions.assertNull(StringFunction.ascii(args));
134+
}
135+
136+
@Test
137+
public void testLeftAndRightNegativeCountReturnEmpty() {
138+
List<Object> args = new ArrayList<>();
139+
args.add("abc");
140+
args.add(-1);
141+
Assertions.assertEquals("", StringFunction.left(args));
142+
143+
args.clear();
144+
args.add("abc");
145+
args.add(-2);
146+
Assertions.assertEquals("", StringFunction.right(args));
147+
}
124148
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.seatunnel.transform.sql.zeta.functions;
19+
20+
import org.apache.seatunnel.api.table.type.BasicType;
21+
import org.apache.seatunnel.api.table.type.SeaTunnelDataType;
22+
23+
import org.junit.jupiter.api.Assertions;
24+
import org.junit.jupiter.api.Test;
25+
26+
import java.util.Arrays;
27+
28+
public class SystemFunctionTest {
29+
30+
@Test
31+
public void testCastAsDoesNotReturnNullWhenValueEqualsTypeName() {
32+
Object result = SystemFunction.castAs(Arrays.asList("VARCHAR", "VARCHAR"));
33+
Assertions.assertEquals("VARCHAR", result);
34+
}
35+
36+
@Test
37+
public void testCoalesceRespectsTargetType() {
38+
SeaTunnelDataType<?> targetType = BasicType.INT_TYPE;
39+
Object result = SystemFunction.coalesce(Arrays.asList(null, "123"), targetType);
40+
41+
Assertions.assertEquals(123, result);
42+
}
43+
}

0 commit comments

Comments
 (0)