This is an automated email from the ASF dual-hosted git repository.
nzw921rx 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 d01059082a [Improve][Transform-V2] Add fast path for plain column
projections in Zeta SQL engine (#12528)
d01059082a is described below
commit d01059082a91045512cc8c654f9e45272d4baaac
Author: Jast <[email protected]>
AuthorDate: Fri Oct 23 00:46:51 2026 +0800
[Improve][Transform-V2] Add fast path for plain column projections in Zeta
SQL engine (#12528)
Co-authored-by: jast <[email protected]>
Co-authored-by: Claude Code <[email protected]>
Co-authored-by: multica-agent <[email protected]>
---
.../transform/sql/zeta/ZetaSQLEngine.java | 58 ++++++++++++++++++++++
.../transform/sql/zeta/ZetaSQLEngineTest.java | 35 +++++++++++++
2 files changed, 93 insertions(+)
diff --git
a/seatunnel-transforms-v2/src/main/java/org/apache/seatunnel/transform/sql/zeta/ZetaSQLEngine.java
b/seatunnel-transforms-v2/src/main/java/org/apache/seatunnel/transform/sql/zeta/ZetaSQLEngine.java
index c998582665..fcf39de014 100644
---
a/seatunnel-transforms-v2/src/main/java/org/apache/seatunnel/transform/sql/zeta/ZetaSQLEngine.java
+++
b/seatunnel-transforms-v2/src/main/java/org/apache/seatunnel/transform/sql/zeta/ZetaSQLEngine.java
@@ -75,6 +75,12 @@ public class ZetaSQLEngine implements SQLEngine {
private Integer allColumnsCount = null;
private boolean udfOpened;
+ /**
+ * Field indexes for the common {@code SELECT source_column AS
target_column} projection.
+ * Keeping this plan avoids evaluating a full SQL expression tree for
every row.
+ */
+ @Nullable private int[] directProjectionIndexes;
+
public ZetaSQLEngine() {}
@Override
@@ -148,6 +154,7 @@ public class ZetaSQLEngine implements SQLEngine {
// validate SQL statement
validateSQL(statement);
this.selectBody = (PlainSelect) ((Select)
statement).getSelectBody();
+ prepareDirectProjection();
} catch (JSQLParserException e) {
throw new TransformException(
CommonErrorCodeDeprecated.UNSUPPORTED_OPERATION,
@@ -155,6 +162,43 @@ public class ZetaSQLEngine implements SQLEngine {
}
}
+ /**
+ * Enables the fast path only for plain column projections. Any expression
that needs the
+ * original evaluator, such as literals, nested fields, functions, or
wildcards, leaves this
+ * disabled.
+ */
+ private void prepareDirectProjection() {
+ directProjectionIndexes = null;
+ if (selectBody.getWhere() != null
+ || selectBody.getHaving() != null
+ || selectBody.getDistinct() != null) {
+ return;
+ }
+
+ List<SelectItem<?>> selectItems = selectBody.getSelectItems();
+ int[] projectionIndexes = new int[selectItems.size()];
+ for (int i = 0; i < selectItems.size(); i++) {
+ Expression expression = selectItems.get(i).getExpression();
+ if (!(expression instanceof Column)) {
+ return;
+ }
+
+ String columnName = ((Column) expression).getColumnName();
+ int index = inputRowType.indexOf(columnName, false);
+ if (index == -1
+ && columnName.startsWith(ESCAPE_IDENTIFIER)
+ && columnName.endsWith(ESCAPE_IDENTIFIER)) {
+ columnName = columnName.substring(1, columnName.length() - 1);
+ index = inputRowType.indexOf(columnName, false);
+ }
+ if (index == -1) {
+ return;
+ }
+ projectionIndexes[i] = index;
+ }
+ directProjectionIndexes = projectionIndexes;
+ }
+
private void validateSQL(Statement statement) {
try {
if (!(statement instanceof Select)) {
@@ -320,6 +364,20 @@ public class ZetaSQLEngine implements SQLEngine {
}
private Object[] project(Object[] inputFields) {
+ if (directProjectionIndexes != null) {
+ Object[] fields = new Object[directProjectionIndexes.length];
+ List<SelectItem<?>> selectItems = selectBody.getSelectItems();
+ for (int i = 0; i < directProjectionIndexes.length; i++) {
+ try {
+ fields[i] = inputFields[directProjectionIndexes[i]];
+ } catch (Exception e) {
+ throw TransformCommonError.sqlExpressionError(
+ selectItems.get(i).getExpression().toString(), e);
+ }
+ }
+ return fields;
+ }
+
List<SelectItem<?>> selectItems = selectBody.getSelectItems();
int columnsSize = countColumnsSize(selectItems);
diff --git
a/seatunnel-transforms-v2/src/test/java/org/apache/seatunnel/transform/sql/zeta/ZetaSQLEngineTest.java
b/seatunnel-transforms-v2/src/test/java/org/apache/seatunnel/transform/sql/zeta/ZetaSQLEngineTest.java
index ce531acbf5..d508d2d1b6 100644
---
a/seatunnel-transforms-v2/src/test/java/org/apache/seatunnel/transform/sql/zeta/ZetaSQLEngineTest.java
+++
b/seatunnel-transforms-v2/src/test/java/org/apache/seatunnel/transform/sql/zeta/ZetaSQLEngineTest.java
@@ -152,6 +152,41 @@ public class ZetaSQLEngineTest {
Assertions.assertEquals(1, failedUdf.getCloseCount());
}
+ @Test
+ public void testDirectColumnProjection() {
+ SeaTunnelRowType rowType = simpleRowType();
+ ZetaSQLEngine engine = new ZetaSQLEngine();
+ engine.init("test", "test", rowType, "select id as id2, name as name2
from test");
+
+ SeaTunnelRowType outType = engine.typeMapping(new ArrayList<>());
+ Assertions.assertArrayEquals(new String[] {"id2", "name2"},
outType.getFieldNames());
+
+ List<SeaTunnelRow> outRows =
+ engine.transformBySQL(new SeaTunnelRow(new Object[] {1,
"Alice", 20}), outType);
+
+ Assertions.assertNotNull(outRows);
+ Assertions.assertEquals(1, outRows.size());
+ Assertions.assertArrayEquals(new Object[] {1, "Alice"},
outRows.get(0).getFields());
+ engine.close();
+ }
+
+ @Test
+ public void testDirectColumnProjectionReordersAndQuotesColumns() {
+ SeaTunnelRowType rowType = simpleRowType();
+ ZetaSQLEngine engine = new ZetaSQLEngine();
+ engine.init("test", "test", rowType, "select `name`, id from test");
+
+ SeaTunnelRowType outType = engine.typeMapping(new ArrayList<>());
+
+ List<SeaTunnelRow> outRows =
+ engine.transformBySQL(new SeaTunnelRow(new Object[] {1,
"Alice", 20}), outType);
+
+ Assertions.assertNotNull(outRows);
+ Assertions.assertEquals(1, outRows.size());
+ Assertions.assertArrayEquals(new Object[] {"Alice", 1},
outRows.get(0).getFields());
+ engine.close();
+ }
+
private static final class TestableZetaSQLEngine extends ZetaSQLEngine {
private final List<ZetaUDF> testUdfs;