This is an automated email from the ASF dual-hosted git repository.
philo-he pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gluten.git
The following commit(s) were added to refs/heads/main by this push:
new 21ee05ee4c [GLUTEN-13454][FLINK] Add support for CURRENT_DATE and
CURRENT_TIME (#13455)
21ee05ee4c is described below
commit 21ee05ee4ca53b58c5292e1dc80f6446c8eabc7a
Author: wud <[email protected]>
AuthorDate: Fri Nov 6 02:58:44 2026 +0800
[GLUTEN-13454][FLINK] Add support for CURRENT_DATE and CURRENT_TIME (#13455)
---
.github/workflows/flink.yml | 2 +-
gluten-flink/docs/Flink.md | 6 +-
.../apache/gluten/rexnode/RexNodeConverter.java | 5 ++
.../rexnode/functions/RexCallConverterFactory.java | 6 ++
.../table/runtime/config/VeloxQueryConfig.java | 11 ++--
.../apache/gluten/util/LogicalTypeConverter.java | 5 ++
.../gluten/rexnode/RexNodeConverterTest.java | 20 ++++++
.../stream/common/GlutenStreamingTestBase.java | 11 +++-
.../stream/custom/CurrentDateFunctionsTest.java | 50 +++++++++++++++
.../stream/custom/CurrentTimeFunctionsTest.java | 74 ++++++++++++++++++++++
gluten-flink/velox4j-ref.txt | 1 +
11 files changed, 184 insertions(+), 7 deletions(-)
diff --git a/.github/workflows/flink.yml b/.github/workflows/flink.yml
index 1ebcc2e4b6..87df3910a0 100644
--- a/.github/workflows/flink.yml
+++ b/.github/workflows/flink.yml
@@ -91,7 +91,7 @@ jobs:
export folly_SOURCE=BUNDLED
git clone -b gluten-20260829 https://github.com/bigo-sg/velox4j.git
cd velox4j
- git reset --hard cfe63ea5f7838a0221a268ce58d6d223c594bddc
+ git reset --hard $(cat
$GITHUB_WORKSPACE/gluten-flink/velox4j-ref.txt)
git apply $GITHUB_WORKSPACE/gluten-flink/patches/fix-velox4j.patch
$GITHUB_WORKSPACE/build/mvn clean install -DskipTests -Dgpg.skip
-Dspotless.skip=true
cd ..
diff --git a/gluten-flink/docs/Flink.md b/gluten-flink/docs/Flink.md
index cd7b5b4e1d..e11e6e41a1 100644
--- a/gluten-flink/docs/Flink.md
+++ b/gluten-flink/docs/Flink.md
@@ -39,6 +39,10 @@ export PATH=$JAVA_HOME/bin:$PATH
**Get Velox4j**
+The velox4j commit is maintained in the single file
`gluten-flink/velox4j-ref.txt`;
+edit that file to update the pin — the CI workflow and this guide both read the
+commit from there.
+
Gluten for Flink depends on [Velox4j](https://github.com/velox4j/velox4j) to
call velox. This is an experimental feature.
You need to get the Velox4j code, and compile it first.
@@ -48,7 +52,7 @@ As some features have not been committed to upstream, you
have to use the follow
## fetch velox4j code
git clone -b gluten-20260829 https://github.com/bigo-sg/velox4j.git
cd velox4j
-git reset --hard cc8b56d74baa3863ae0fb8387f5745652370fa7d
+git reset --hard $(cat $GLUTEN_FLINK_HOME/velox4j-ref.txt)
mvn clean install -DskipTests -Dgpg.skip -Dspotless.skip=true
```
**Get gluten**
diff --git
a/gluten-flink/planner/src/main/java/org/apache/gluten/rexnode/RexNodeConverter.java
b/gluten-flink/planner/src/main/java/org/apache/gluten/rexnode/RexNodeConverter.java
index 38228b104d..9e79797be3 100644
---
a/gluten-flink/planner/src/main/java/org/apache/gluten/rexnode/RexNodeConverter.java
+++
b/gluten-flink/planner/src/main/java/org/apache/gluten/rexnode/RexNodeConverter.java
@@ -119,6 +119,7 @@ public class RexNodeConverter {
case DATE:
case INTERVAL_SECOND:
case SYMBOL:
+ case TIME:
case TIMESTAMP:
return new VarCharValue(null);
default:
@@ -174,6 +175,10 @@ public class RexNodeConverter {
long epochMillis = literal.getValueAs(Long.class);
return TimestampValue.create(
Math.floorDiv(epochMillis, 1000L), Math.floorMod(epochMillis,
1000L) * 1_000_000L);
+ case TIME:
+ // Calcite stores TIME literals as the millisecond-of-day Integer —
+ // the same encoding the velox side uses for TIME.
+ return new IntegerValue(literal.getValueAs(Integer.class));
default:
throw new RuntimeException(
"Unsupported rex node type: " +
literal.getType().getSqlTypeName());
diff --git
a/gluten-flink/planner/src/main/java/org/apache/gluten/rexnode/functions/RexCallConverterFactory.java
b/gluten-flink/planner/src/main/java/org/apache/gluten/rexnode/functions/RexCallConverterFactory.java
index 4f0547a144..b148fb4877 100644
---
a/gluten-flink/planner/src/main/java/org/apache/gluten/rexnode/functions/RexCallConverterFactory.java
+++
b/gluten-flink/planner/src/main/java/org/apache/gluten/rexnode/functions/RexCallConverterFactory.java
@@ -119,6 +119,12 @@ public class RexCallConverterFactory {
// substring returns an empty string. Start semantics (0 counts as 1,
// negative counts from the end) already match Flink.
Map.entry("SUBSTRING", Arrays.asList(() -> new
SubstringRexCallConverter())),
+ // Offload targets implemented in velox's flinksql namespace;
+ // the names arrive upper-cased from the operator table.
+ Map.entry(
+ "CURRENT_DATE", Arrays.asList(() -> new
DefaultRexCallConverter("current_date"))),
+ Map.entry(
+ "CURRENT_TIME", Arrays.asList(() -> new
DefaultRexCallConverter("current_time"))),
Map.entry("IFNULL", Arrays.asList(() -> new
ScalarOnlyRexCallConverter("ifnull"))),
// TRIM is normalized by Calcite to (flag, seek, str); the converter
// maps the flag to ltrim/rtrim/trim and reorders to (str, seek).
diff --git
a/gluten-flink/runtime/src/main/java/org/apache/gluten/table/runtime/config/VeloxQueryConfig.java
b/gluten-flink/runtime/src/main/java/org/apache/gluten/table/runtime/config/VeloxQueryConfig.java
index a1026cfe49..e66f77f366 100644
---
a/gluten-flink/runtime/src/main/java/org/apache/gluten/table/runtime/config/VeloxQueryConfig.java
+++
b/gluten-flink/runtime/src/main/java/org/apache/gluten/table/runtime/config/VeloxQueryConfig.java
@@ -25,6 +25,7 @@ import org.apache.flink.table.api.config.TableConfigOptions;
import java.util.HashMap;
import java.util.Map;
+import java.util.TimeZone;
public class VeloxQueryConfig {
@@ -42,10 +43,12 @@ public class VeloxQueryConfig {
Map<String, String> configMap = new HashMap<>();
configMap.put(keyVeloxAdjustTimestampToSessionTimeZone, "true");
String localTimeZone = config.get(TableConfigOptions.LOCAL_TIME_ZONE);
- // As flink's default timezone value is `default`, it is not a valid
timezone id, so we should
- // convert it to `UTC` timezone.
- if
(TableConfigOptions.LOCAL_TIME_ZONE.defaultValue().equals(localTimeZone)) {
- configMap.put(keyVeloxSessionTimezone, "UTC");
+ // Flink's `default` value means the JVM default timezone, not UTC; velox
+ // must resolve it the same way so CURRENT_DATE/CURRENT_TIME (and every
+ // session-timezone-sensitive function) match native Flink.
+ if (localTimeZone == null
+ ||
TableConfigOptions.LOCAL_TIME_ZONE.defaultValue().equals(localTimeZone)) {
+ configMap.put(keyVeloxSessionTimezone, TimeZone.getDefault().getID());
} else {
configMap.put(keyVeloxSessionTimezone, localTimeZone);
}
diff --git
a/gluten-flink/runtime/src/main/java/org/apache/gluten/util/LogicalTypeConverter.java
b/gluten-flink/runtime/src/main/java/org/apache/gluten/util/LogicalTypeConverter.java
index 8d684fab52..c5cdc1c84d 100644
---
a/gluten-flink/runtime/src/main/java/org/apache/gluten/util/LogicalTypeConverter.java
+++
b/gluten-flink/runtime/src/main/java/org/apache/gluten/util/LogicalTypeConverter.java
@@ -32,6 +32,7 @@ import org.apache.flink.table.types.logical.LogicalType;
import org.apache.flink.table.types.logical.MapType;
import org.apache.flink.table.types.logical.RowType;
import org.apache.flink.table.types.logical.SymbolType;
+import org.apache.flink.table.types.logical.TimeType;
import org.apache.flink.table.types.logical.TimestampType;
import org.apache.flink.table.types.logical.TinyIntType;
import org.apache.flink.table.types.logical.VarCharType;
@@ -117,6 +118,10 @@ public class LogicalTypeConverter {
Map.entry(
TinyIntType.class,
logicalType -> new
io.github.zhztheplayer.velox4j.type.TinyIntType()),
+ // Flink RowData represents TIME as INT (millisecond-of-day), the
+ // same encoding the flinksql time functions use.
+ Map.entry(
+ TimeType.class, logicalType -> new
io.github.zhztheplayer.velox4j.type.IntegerType()),
Map.entry(
SymbolType.class,
logicalType -> new
io.github.zhztheplayer.velox4j.type.VarCharType()));
diff --git
a/gluten-flink/ut/src/test/java/org/apache/gluten/rexnode/RexNodeConverterTest.java
b/gluten-flink/ut/src/test/java/org/apache/gluten/rexnode/RexNodeConverterTest.java
index 2acde24b38..8809a15311 100644
---
a/gluten-flink/ut/src/test/java/org/apache/gluten/rexnode/RexNodeConverterTest.java
+++
b/gluten-flink/ut/src/test/java/org/apache/gluten/rexnode/RexNodeConverterTest.java
@@ -16,6 +16,7 @@
*/
package org.apache.gluten.rexnode;
+import io.github.zhztheplayer.velox4j.variant.IntegerValue;
import io.github.zhztheplayer.velox4j.variant.VarCharValue;
import io.github.zhztheplayer.velox4j.variant.Variant;
@@ -30,6 +31,7 @@ import org.apache.calcite.rex.RexLiteral;
import org.apache.calcite.sql.SqlIntervalQualifier;
import org.apache.calcite.sql.parser.SqlParserPos;
import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.util.TimeString;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
@@ -58,6 +60,24 @@ public class RexNodeConverterTest {
assertThat(((VarCharValue) variant).getValue()).isEqualTo("apple");
}
+ @Test
+ public void testTimeLiteralConvertsToMillisOfDay() {
+ RexLiteral literal = rexBuilder.makeTimeLiteral(new TimeString(12, 34,
56), 0);
+ Variant variant = RexNodeConverter.toVariant(literal);
+ assertThat(variant).isInstanceOf(IntegerValue.class);
+ assertThat(((IntegerValue) variant).getValue())
+ .isEqualTo(12 * 3_600_000 + 34 * 60_000 + 56_000);
+ }
+
+ @Test
+ public void testTimeNullLiteralConvertsToNullCarrier() {
+ RexLiteral literal =
+ (RexLiteral)
rexBuilder.makeNullLiteral(typeFactory.createSqlType(SqlTypeName.TIME));
+ Variant variant = RexNodeConverter.toVariant(literal);
+ assertThat(variant).isInstanceOf(VarCharValue.class);
+ assertThat(((VarCharValue) variant).getValue()).isNull();
+ }
+
@Test
public void testCharLiteralExtractsRawValue() {
RexLiteral literal =
diff --git
a/gluten-flink/ut/src/test/java/org/apache/gluten/table/runtime/stream/common/GlutenStreamingTestBase.java
b/gluten-flink/ut/src/test/java/org/apache/gluten/table/runtime/stream/common/GlutenStreamingTestBase.java
index 393a0064d5..c88ea73509 100644
---
a/gluten-flink/ut/src/test/java/org/apache/gluten/table/runtime/stream/common/GlutenStreamingTestBase.java
+++
b/gluten-flink/ut/src/test/java/org/apache/gluten/table/runtime/stream/common/GlutenStreamingTestBase.java
@@ -131,6 +131,15 @@ public class GlutenStreamingTestBase extends
StreamingTestBase {
}
protected void runAndCheck(String query, List<String> expected) {
+ assertThat(runQuery(query)).isEqualTo(expected);
+ }
+
+ /**
+ * Runs a query through the embedded gluten stack and returns the print rows
— each line is one
+ * changelog row, e.g. "+I[value]". Callers that need tolerance-based checks
on time-varying
+ * expressions compare the returned rows themselves instead of using {@link
#runAndCheck}.
+ */
+ protected List<String> runQuery(String query) {
String printResultDirPath = System.getProperty("user.dir") + "/log/";
new File(printResultDirPath).mkdirs();
String printResultFilePath = printResultDirPath + "taskmanager.out";
@@ -191,7 +200,7 @@ public class GlutenStreamingTestBase extends
StreamingTestBase {
result.add(line);
}
}
- assertThat(result).isEqualTo(expected);
+ return result;
} catch (Exception e) {
throw new FlinkRuntimeException(e);
} finally {
diff --git
a/gluten-flink/ut/src/test/java/org/apache/gluten/table/runtime/stream/custom/CurrentDateFunctionsTest.java
b/gluten-flink/ut/src/test/java/org/apache/gluten/table/runtime/stream/custom/CurrentDateFunctionsTest.java
new file mode 100644
index 0000000000..947ba00ddc
--- /dev/null
+++
b/gluten-flink/ut/src/test/java/org/apache/gluten/table/runtime/stream/custom/CurrentDateFunctionsTest.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.gluten.table.runtime.stream.custom;
+
+import org.apache.gluten.table.runtime.stream.common.GlutenStreamingTestBase;
+
+import org.apache.flink.types.Row;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.time.LocalDate;
+import java.util.Arrays;
+import java.util.List;
+
+class CurrentDateFunctionsTest extends GlutenStreamingTestBase {
+
+ @Override
+ @BeforeEach
+ public void before() throws Exception {
+ super.before();
+ }
+
+ @Test
+ void testCurrentDateIsToday() {
+ List<Row> rows = Arrays.asList(Row.of(1), Row.of(2), Row.of(3));
+ createSimpleBoundedValuesTable("tblCD", "x int", rows);
+ String query = "select x, CAST(CURRENT_DATE AS DATE) from tblCD";
+ // The velox print sink renders DATE as epoch days; assert it equals today.
+ long expected = LocalDate.now().toEpochDay();
+ runAndCheck(
+ query,
+ Arrays.asList(
+ "+I[1, " + expected + "]", "+I[2, " + expected + "]", "+I[3, " +
expected + "]"));
+ }
+}
diff --git
a/gluten-flink/ut/src/test/java/org/apache/gluten/table/runtime/stream/custom/CurrentTimeFunctionsTest.java
b/gluten-flink/ut/src/test/java/org/apache/gluten/table/runtime/stream/custom/CurrentTimeFunctionsTest.java
new file mode 100644
index 0000000000..5a9cb39925
--- /dev/null
+++
b/gluten-flink/ut/src/test/java/org/apache/gluten/table/runtime/stream/custom/CurrentTimeFunctionsTest.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.gluten.table.runtime.stream.custom;
+
+import org.apache.gluten.table.runtime.stream.common.GlutenStreamingTestBase;
+
+import org.apache.flink.types.Row;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.time.LocalTime;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class CurrentTimeFunctionsTest extends GlutenStreamingTestBase {
+
+ @Override
+ @BeforeEach
+ public void before() throws Exception {
+ super.before();
+ }
+
+ @Test
+ void testCurrentTimeIsMillisOfDay() {
+ List<Row> rows = Arrays.asList(Row.of(1), Row.of(2), Row.of(3));
+ createSimpleBoundedValuesTable("tblCT", "x int", rows);
+ String query = "select x, CAST(CURRENT_TIME AS TIME) from tblCT";
+ // The velox print sink renders TIME as the underlying INT millis-of-day;
+ // each row must be close to the local wall clock.
+ List<String> result = runQuery(query);
+ assertThat(result).hasSize(3);
+ int nowMillis = (int) (LocalTime.now().toNanoOfDay() / 1_000_000);
+ for (int i = 0; i < result.size(); i++) {
+ String prefix = "+I[" + (i + 1) + ", ";
+ assertThat(result.get(i)).startsWith(prefix).endsWith("]");
+ int millis =
+ Integer.parseInt(result.get(i).substring(prefix.length(),
result.get(i).length() - 1));
+ assertThat(millis).isBetween(0, 86_400_000 - 1);
+ long delta = Math.abs(millis - nowMillis);
+ delta = Math.min(delta, 86_400_000L - delta); // midnight wraparound
+ assertThat(delta).isLessThanOrEqualTo(60_000L);
+ }
+ }
+
+ @Test
+ void testCurrentTimeComparisons() {
+ List<Row> rows = Arrays.asList(Row.of(1), Row.of(2));
+ createSimpleBoundedValuesTable("tblCT2", "x int", rows);
+ // TIME literals become INT millis-of-day constants. Inclusive bounds
+ // covering the entire day: always true at any run time, so the test
+ // cannot flip near midnight (strict bounds did).
+ String query =
+ "select x, CURRENT_TIME >= TIME '00:00:00', CURRENT_TIME <= TIME
'23:59:59.999'"
+ + " from tblCT2";
+ runAndCheck(query, Arrays.asList("+I[1, true, true]", "+I[2, true,
true]"));
+ }
+}
diff --git a/gluten-flink/velox4j-ref.txt b/gluten-flink/velox4j-ref.txt
new file mode 100644
index 0000000000..e443ac0dec
--- /dev/null
+++ b/gluten-flink/velox4j-ref.txt
@@ -0,0 +1 @@
+cfe63ea5f7838a0221a268ce58d6d223c594bddc
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]