From 95c98a4f04a593cbd78ff6f97ba003e8e2ad769c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=AE=B5=E6=99=93=E9=9B=84?= Date: Wed, 4 Mar 2026 23:22:00 +0800 Subject: [PATCH 1/7] feat(task-sql): support SQL from resource file Made-with: Cursor --- .../task/api/parameters/SqlParameters.java | 47 ++++++++++++++++++- .../api/parameters/SqlParametersTest.java | 5 ++ .../plugin/task/sql/SqlTask.java | 33 +++++++++++++ 3 files changed, 83 insertions(+), 2 deletions(-) diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/parameters/SqlParameters.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/parameters/SqlParameters.java index 8864943bac43..9dc311a11fc9 100644 --- a/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/parameters/SqlParameters.java +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/parameters/SqlParameters.java @@ -58,6 +58,18 @@ public class SqlParameters extends AbstractParameters { */ private String sql; + /** + * sql source + * SCRIPT: inline sql text + * FILE: sql from resource center file + */ + private String sqlSource; + + /** + * sql resource file path in resource center + */ + private String sqlResource; + /** * sql type * 0 query @@ -139,6 +151,22 @@ public void setSql(String sql) { this.sql = sql; } + public String getSqlSource() { + return sqlSource; + } + + public void setSqlSource(String sqlSource) { + this.sqlSource = sqlSource; + } + + public String getSqlResource() { + return sqlResource; + } + + public void setSqlResource(String sqlResource) { + this.sqlResource = sqlResource; + } + public int getSqlType() { return sqlType; } @@ -213,12 +241,25 @@ public void setGroupId(int groupId) { @Override public boolean checkParameters() { - return datasource != 0 && StringUtils.isNotEmpty(type) && StringUtils.isNotEmpty(sql); + if (datasource == 0 || StringUtils.isEmpty(type)) { + return false; + } + // support both inline sql and sql from resource file + if (StringUtils.isNotEmpty(sql)) { + return true; + } + return StringUtils.isNotEmpty(sqlResource); } @Override public List getResourceFilesList() { - return new ArrayList<>(); + List resourceFiles = new ArrayList<>(); + if (StringUtils.isNotEmpty(sqlResource)) { + ResourceInfo resourceInfo = new ResourceInfo(); + resourceInfo.setResourceName(sqlResource); + resourceFiles.add(resourceInfo); + } + return resourceFiles; } public void dealOutParam(String result) { @@ -272,6 +313,8 @@ public String toString() { + "type='" + type + '\'' + ", datasource=" + datasource + ", sql='" + sql + '\'' + + ", sqlSource='" + sqlSource + '\'' + + ", sqlResource='" + sqlResource + '\'' + ", sqlType=" + sqlType + ", sendEmail=" + sendEmail + ", displayRows=" + displayRows diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/test/java/org/apache/dolphinscheduler/plugin/task/api/parameters/SqlParametersTest.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/test/java/org/apache/dolphinscheduler/plugin/task/api/parameters/SqlParametersTest.java index 8f1ee7656000..c141612f96c0 100644 --- a/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/test/java/org/apache/dolphinscheduler/plugin/task/api/parameters/SqlParametersTest.java +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/test/java/org/apache/dolphinscheduler/plugin/task/api/parameters/SqlParametersTest.java @@ -87,5 +87,10 @@ public void testSqlParameters() { sqlParameters.setLocalParams(properties); sqlParameters.dealOutParam(sqlResult); Assertions.assertNotNull(sqlParameters.getVarPool().get(0)); + + // resource files list should contain sqlResource when it is set + sqlParameters.setSql(null); + sqlParameters.setSqlResource("/sql/demo.sql"); + Assertions.assertFalse(CollectionUtils.isEmpty(sqlParameters.getResourceFilesList())); } } diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-sql/src/main/java/org/apache/dolphinscheduler/plugin/task/sql/SqlTask.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-sql/src/main/java/org/apache/dolphinscheduler/plugin/task/sql/SqlTask.java index 33b85e1a66b8..76087736cf8b 100644 --- a/dolphinscheduler-task-plugin/dolphinscheduler-task-sql/src/main/java/org/apache/dolphinscheduler/plugin/task/sql/SqlTask.java +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-sql/src/main/java/org/apache/dolphinscheduler/plugin/task/sql/SqlTask.java @@ -36,11 +36,17 @@ import org.apache.dolphinscheduler.plugin.task.api.parameters.AbstractParameters; import org.apache.dolphinscheduler.plugin.task.api.parameters.SqlParameters; import org.apache.dolphinscheduler.plugin.task.api.utils.ParameterUtils; +import org.apache.dolphinscheduler.plugin.task.api.resource.ResourceContext; import org.apache.dolphinscheduler.spi.datasource.BaseConnectionParam; import org.apache.dolphinscheduler.spi.enums.DbType; import org.apache.commons.lang3.StringUtils; +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -128,6 +134,8 @@ public void handle(TaskCallBack taskCallBack) throws TaskException { sqlParameters.getLimit()); try { + ensureSqlContent(); + // get datasource baseConnectionParam = (BaseConnectionParam) DataSourceUtils.buildConnectionParams(dbType, sqlTaskExecutionContext.getConnectionParams()); @@ -402,6 +410,31 @@ private void printReplacedSql(String content, String formatSql, String rgex, Map .append(")"); } } + + private void ensureSqlContent() { + if (StringUtils.isNotEmpty(sqlParameters.getSql())) { + return; + } + if (StringUtils.isEmpty(sqlParameters.getSqlResource())) { + return; + } + String resourcePathInStorage = sqlParameters.getSqlResource(); + try { + ResourceContext resourceContext = taskExecutionContext.getResourceContext(); + ResourceContext.ResourceItem resourceItem = + resourceContext.getResourceItem(resourcePathInStorage); + String localPath = resourceItem.getResourceAbsolutePathInLocal(); + log.info("Load sql content from resource file: {}", resourcePathInStorage); + String sqlContent = new String( + Files.readAllBytes(Paths.get(localPath)), + StandardCharsets.UTF_8); + sqlParameters.setSql(sqlContent); + } catch (IOException e) { + log.error("Read sql content from resource file {} error", resourcePathInStorage, e); + throw new TaskException(String.format("Read sql content from resource file %s error", resourcePathInStorage), + e); + } + } log.info("Sql Params are {}", logPrint); } From 5495a68bc57988b3c4e56fcb6eb42b51c03b2d4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=AE=B5=E6=99=93=E9=9B=84?= Date: Wed, 4 Mar 2026 23:24:36 +0800 Subject: [PATCH 2/7] feat(ui): support resource SQL option for task-sql Made-with: Cursor --- .../src/locales/en_US/project.ts | 4 +++ .../src/locales/zh_CN/project.ts | 4 +++ .../task/components/node/fields/use-sql.ts | 36 +++++++++++++++++++ .../task/components/node/tasks/use-sql.ts | 2 ++ 4 files changed, 46 insertions(+) diff --git a/dolphinscheduler-ui/src/locales/en_US/project.ts b/dolphinscheduler-ui/src/locales/en_US/project.ts index 2553f0df62c6..6cc335331757 100644 --- a/dolphinscheduler-ui/src/locales/en_US/project.ts +++ b/dolphinscheduler-ui/src/locales/en_US/project.ts @@ -549,10 +549,14 @@ export default { sql_type_query: 'Query', sql_type_non_query: 'Non Query', sql_statement: 'SQL Statement', + sql_source: 'SQL Source', + sql_source_script: 'Script', + sql_source_file: 'Resource file', pre_sql_statement: 'Pre SQL Statement', post_sql_statement: 'Post SQL Statement', sql_input_placeholder: 'Please enter non-query sql.', sql_empty_tips: 'The sql can not be empty.', + sql_resource_file: 'SQL Resource File', procedure_method: 'SQL Statement', procedure_method_tips: 'Please enter the procedure script', procedure_method_snippet: diff --git a/dolphinscheduler-ui/src/locales/zh_CN/project.ts b/dolphinscheduler-ui/src/locales/zh_CN/project.ts index 94407159131e..139948359222 100644 --- a/dolphinscheduler-ui/src/locales/zh_CN/project.ts +++ b/dolphinscheduler-ui/src/locales/zh_CN/project.ts @@ -532,10 +532,14 @@ export default { sql_type_query: '查询', sql_type_non_query: '非查询', sql_statement: 'SQL语句', + sql_source: 'SQL来源', + sql_source_script: '脚本', + sql_source_file: '资源文件', pre_sql_statement: '前置SQL语句', post_sql_statement: '后置SQL语句', sql_input_placeholder: '请输入非查询SQL语句', sql_empty_tips: '语句不能为空', + sql_resource_file: 'SQL资源文件', procedure_method: 'SQL语句', procedure_method_tips: '请输入存储脚本', procedure_method_snippet: diff --git a/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-sql.ts b/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-sql.ts index 0044fa9cf8a2..b31a7f80371c 100644 --- a/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-sql.ts +++ b/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-sql.ts @@ -22,6 +22,9 @@ import type { IJsonItem } from '../types' export function useSql(model: { [field: string]: any }): IJsonItem[] { const { t } = useI18n() const hiveSpan = computed(() => (model.type === 'HIVE' ? 24 : 0)) + const showScriptEditor = computed( + () => model.sqlSource === 'SCRIPT' || !model.sqlSource + ) return [ { @@ -34,10 +37,27 @@ export function useSql(model: { [field: string]: any }): IJsonItem[] { }, span: hiveSpan }, + { + type: 'radio', + field: 'sqlSource', + name: t('project.node.sql_source'), + options: [ + { + label: t('project.node.sql_source_script'), + value: 'SCRIPT' + }, + { + label: t('project.node.sql_source_file'), + value: 'FILE' + } + ], + span: 24 + }, { type: 'editor', field: 'sql', name: t('project.node.sql_statement'), + if: showScriptEditor, validate: { trigger: ['input', 'trigger'], required: true, @@ -47,6 +67,22 @@ export function useSql(model: { [field: string]: any }): IJsonItem[] { language: 'sql' } }, + { + type: 'tree-select', + field: 'sqlResource', + name: t('project.node.sql_resource_file'), + span: 24, + if: () => model.sqlSource === 'FILE', + props: { + placeholder: t('project.node.resources_tips'), + keyField: 'fullName', + labelField: 'name', + disabledField: 'disable' + }, + slots: { + // 这里占位,真正的资源数据从全局资源 store 中获取,保持与 use-resources 一致行为 + } + }, ...useCustomParams({ model, field: 'localParams', diff --git a/dolphinscheduler-ui/src/views/projects/task/components/node/tasks/use-sql.ts b/dolphinscheduler-ui/src/views/projects/task/components/node/tasks/use-sql.ts index e967c2f09b5c..371ae737fa7d 100644 --- a/dolphinscheduler-ui/src/views/projects/task/components/node/tasks/use-sql.ts +++ b/dolphinscheduler-ui/src/views/projects/task/components/node/tasks/use-sql.ts @@ -47,6 +47,8 @@ export function useSql({ type: 'MYSQL', displayRows: 10, sql: '', + sqlSource: 'SCRIPT', + sqlResource: '', sqlType: '0', preStatements: [], postStatements: [], From b53fc03828606422786c9b791d9ff176ee5e90b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=AE=B5=E6=99=93=E9=9B=84?= Date: Wed, 4 Mar 2026 23:29:18 +0800 Subject: [PATCH 3/7] feat(task-sql): improve placeholder replacement for SQL title Made-with: Cursor --- .../plugin/task/sql/SqlTask.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-sql/src/main/java/org/apache/dolphinscheduler/plugin/task/sql/SqlTask.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-sql/src/main/java/org/apache/dolphinscheduler/plugin/task/sql/SqlTask.java index 76087736cf8b..5d6a9fc6de2c 100644 --- a/dolphinscheduler-task-plugin/dolphinscheduler-task-sql/src/main/java/org/apache/dolphinscheduler/plugin/task/sql/SqlTask.java +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-sql/src/main/java/org/apache/dolphinscheduler/plugin/task/sql/SqlTask.java @@ -42,7 +42,6 @@ import org.apache.commons.lang3.StringUtils; -import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -54,6 +53,7 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -435,8 +435,6 @@ private void ensureSqlContent() { e); } } - log.info("Sql Params are {}", logPrint); - } /** * ready to execute SQL and parameter entity Map @@ -453,19 +451,22 @@ private SqlBinds getSqlAndSqlParamsMap(String sql) { Map paramsMap = taskExecutionContext.getPrepareParamsMap(); - // spell SQL according to the final user-defined variable - if (paramsMap == null) { - sqlBuilder.append(sql); - return new SqlBinds(sqlBuilder.toString(), sqlParamsMap); - } + Map placeholderParamsMap = paramsMap == null + ? Collections.emptyMap() + : ParameterUtils.convert(paramsMap); if (StringUtils.isNotEmpty(sqlParameters.getTitle())) { - String title = ParameterUtils.convertParameterPlaceholders(sqlParameters.getTitle(), - ParameterUtils.convert(paramsMap)); + String title = ParameterUtils.convertParameterPlaceholders(sqlParameters.getTitle(), placeholderParamsMap); log.info("SQL title : {}", title); sqlParameters.setTitle(title); } + // spell SQL according to the final user-defined variable + if (paramsMap == null) { + sqlBuilder.append(sql); + return new SqlBinds(sqlBuilder.toString(), sqlParamsMap); + } + // special characters need to be escaped, ${} needs to be escaped setSqlParamsMap(sql, sqlParamsMap, paramsMap, taskExecutionContext.getTaskInstanceId()); // Replace the original value in sql !{...} ,Does not participate in precompilation From efc9fdf9bca12145ea32b430978c82911c7017bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=AE=B5=E6=99=93=E9=9B=84?= Date: Wed, 4 Mar 2026 23:31:31 +0800 Subject: [PATCH 4/7] test(task-sql): verify loading SQL from resource file Made-with: Cursor --- .../plugin/task/sql/SqlTaskTest.java | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-sql/src/test/java/org/apache/dolphinscheduler/plugin/task/sql/SqlTaskTest.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-sql/src/test/java/org/apache/dolphinscheduler/plugin/task/sql/SqlTaskTest.java index 3832d653a527..a588ba9f5cd3 100644 --- a/dolphinscheduler-task-plugin/dolphinscheduler-task-sql/src/test/java/org/apache/dolphinscheduler/plugin/task/sql/SqlTaskTest.java +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-sql/src/test/java/org/apache/dolphinscheduler/plugin/task/sql/SqlTaskTest.java @@ -17,6 +17,75 @@ package org.apache.dolphinscheduler.plugin.task.sql; +import org.apache.dolphinscheduler.common.utils.JSONUtils; +import org.apache.dolphinscheduler.plugin.task.api.TaskExecutionContext; +import org.apache.dolphinscheduler.plugin.task.api.parameters.SqlParameters; +import org.apache.dolphinscheduler.plugin.task.api.resource.ResourceContext; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; + +class SqlTaskTest { + + @Test + void testSqlLoadedFromResourceFileWhenSqlIsEmpty(@TempDir Path tempDir) throws Exception { + Path sqlFile = tempDir.resolve("test.sql"); + String sqlContent = "SELECT 1"; + Files.write(sqlFile, sqlContent.getBytes(StandardCharsets.UTF_8)); + + SqlParameters sqlParameters = new SqlParameters(); + sqlParameters.setType("MYSQL"); + sqlParameters.setDatasource(1); + sqlParameters.setSql(null); + sqlParameters.setSqlResource("/sql/test.sql"); + + TaskExecutionContext taskExecutionContext = new TaskExecutionContext(); + taskExecutionContext.setTaskParams(JSONUtils.toJsonString(sqlParameters)); + taskExecutionContext.setScheduleTime(System.currentTimeMillis()); + + ResourceContext resourceContext = new ResourceContext(); + resourceContext.addResourceItem(ResourceContext.ResourceItem.builder() + .resourceAbsolutePathInStorage(sqlParameters.getSqlResource()) + .resourceAbsolutePathInLocal(sqlFile.toString()) + .build()); + taskExecutionContext.setResourceContext(resourceContext); + + SqlTask sqlTask = new SqlTask(taskExecutionContext); + + Method ensureSqlContent = SqlTask.class.getDeclaredMethod("ensureSqlContent"); + ensureSqlContent.setAccessible(true); + ensureSqlContent.invoke(sqlTask); + + SqlParameters loadedParameters = (SqlParameters) sqlTask.getParameters(); + Assertions.assertEquals(sqlContent, loadedParameters.getSql()); + } +} + +/* + * 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.dolphinscheduler.plugin.task.sql; + import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; From 599ed1f49102825dc34da470402f33a54935a977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=AE=B5=E6=99=93=E9=9B=84?= Date: Thu, 5 Mar 2026 17:17:06 +0800 Subject: [PATCH 5/7] fix(task-sql): address review comments from PR #18020 - Use SqlSourceType enum instead of String for sqlSource field - Fix SqlTaskTest.java: merge new test into existing class, remove duplicate license/class block - Remove Chinese comment from frontend use-sql.ts slots - Fix missing closing brace in SqlTask.printReplacedSql method Made-with: Cursor --- .../plugin/task/api/enums/SqlSourceType.java | 26 ++++ .../task/api/parameters/SqlParameters.java | 9 +- .../plugin/task/sql/SqlTask.java | 1 + .../plugin/task/sql/SqlTaskTest.java | 132 +++++++----------- .../task/components/node/fields/use-sql.ts | 4 +- 5 files changed, 81 insertions(+), 91 deletions(-) create mode 100644 dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/enums/SqlSourceType.java diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/enums/SqlSourceType.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/enums/SqlSourceType.java new file mode 100644 index 000000000000..3c812049bbcf --- /dev/null +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/enums/SqlSourceType.java @@ -0,0 +1,26 @@ +/* + * 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.dolphinscheduler.plugin.task.api.enums; + +public enum SqlSourceType { + /** + * SCRIPT: inline sql text + * FILE: sql from resource center file + */ + SCRIPT, FILE +} diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/parameters/SqlParameters.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/parameters/SqlParameters.java index 9dc311a11fc9..42817f538647 100644 --- a/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/parameters/SqlParameters.java +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/parameters/SqlParameters.java @@ -21,6 +21,7 @@ import org.apache.dolphinscheduler.plugin.task.api.SQLTaskExecutionContext; import org.apache.dolphinscheduler.plugin.task.api.enums.DataType; import org.apache.dolphinscheduler.plugin.task.api.enums.ResourceType; +import org.apache.dolphinscheduler.plugin.task.api.enums.SqlSourceType; import org.apache.dolphinscheduler.plugin.task.api.model.Property; import org.apache.dolphinscheduler.plugin.task.api.model.ResourceInfo; import org.apache.dolphinscheduler.plugin.task.api.parameters.resource.DataSourceParameters; @@ -60,10 +61,8 @@ public class SqlParameters extends AbstractParameters { /** * sql source - * SCRIPT: inline sql text - * FILE: sql from resource center file */ - private String sqlSource; + private SqlSourceType sqlSource; /** * sql resource file path in resource center @@ -151,11 +150,11 @@ public void setSql(String sql) { this.sql = sql; } - public String getSqlSource() { + public SqlSourceType getSqlSource() { return sqlSource; } - public void setSqlSource(String sqlSource) { + public void setSqlSource(SqlSourceType sqlSource) { this.sqlSource = sqlSource; } diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-sql/src/main/java/org/apache/dolphinscheduler/plugin/task/sql/SqlTask.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-sql/src/main/java/org/apache/dolphinscheduler/plugin/task/sql/SqlTask.java index 5d6a9fc6de2c..9c3b0c3475ab 100644 --- a/dolphinscheduler-task-plugin/dolphinscheduler-task-sql/src/main/java/org/apache/dolphinscheduler/plugin/task/sql/SqlTask.java +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-sql/src/main/java/org/apache/dolphinscheduler/plugin/task/sql/SqlTask.java @@ -410,6 +410,7 @@ private void printReplacedSql(String content, String formatSql, String rgex, Map .append(")"); } } + } private void ensureSqlContent() { if (StringUtils.isNotEmpty(sqlParameters.getSql())) { diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-sql/src/test/java/org/apache/dolphinscheduler/plugin/task/sql/SqlTaskTest.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-sql/src/test/java/org/apache/dolphinscheduler/plugin/task/sql/SqlTaskTest.java index a588ba9f5cd3..587019267653 100644 --- a/dolphinscheduler-task-plugin/dolphinscheduler-task-sql/src/test/java/org/apache/dolphinscheduler/plugin/task/sql/SqlTaskTest.java +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-sql/src/test/java/org/apache/dolphinscheduler/plugin/task/sql/SqlTaskTest.java @@ -17,75 +17,6 @@ package org.apache.dolphinscheduler.plugin.task.sql; -import org.apache.dolphinscheduler.common.utils.JSONUtils; -import org.apache.dolphinscheduler.plugin.task.api.TaskExecutionContext; -import org.apache.dolphinscheduler.plugin.task.api.parameters.SqlParameters; -import org.apache.dolphinscheduler.plugin.task.api.resource.ResourceContext; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -import java.lang.reflect.Method; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; - -class SqlTaskTest { - - @Test - void testSqlLoadedFromResourceFileWhenSqlIsEmpty(@TempDir Path tempDir) throws Exception { - Path sqlFile = tempDir.resolve("test.sql"); - String sqlContent = "SELECT 1"; - Files.write(sqlFile, sqlContent.getBytes(StandardCharsets.UTF_8)); - - SqlParameters sqlParameters = new SqlParameters(); - sqlParameters.setType("MYSQL"); - sqlParameters.setDatasource(1); - sqlParameters.setSql(null); - sqlParameters.setSqlResource("/sql/test.sql"); - - TaskExecutionContext taskExecutionContext = new TaskExecutionContext(); - taskExecutionContext.setTaskParams(JSONUtils.toJsonString(sqlParameters)); - taskExecutionContext.setScheduleTime(System.currentTimeMillis()); - - ResourceContext resourceContext = new ResourceContext(); - resourceContext.addResourceItem(ResourceContext.ResourceItem.builder() - .resourceAbsolutePathInStorage(sqlParameters.getSqlResource()) - .resourceAbsolutePathInLocal(sqlFile.toString()) - .build()); - taskExecutionContext.setResourceContext(resourceContext); - - SqlTask sqlTask = new SqlTask(taskExecutionContext); - - Method ensureSqlContent = SqlTask.class.getDeclaredMethod("ensureSqlContent"); - ensureSqlContent.setAccessible(true); - ensureSqlContent.invoke(sqlTask); - - SqlParameters loadedParameters = (SqlParameters) sqlTask.getParameters(); - Assertions.assertEquals(sqlContent, loadedParameters.getSql()); - } -} - -/* - * 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.dolphinscheduler.plugin.task.sql; - import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -100,11 +31,15 @@ void testSqlLoadedFromResourceFileWhenSqlIsEmpty(@TempDir Path tempDir) throws E import org.apache.dolphinscheduler.plugin.task.api.parameters.SqlParameters; import org.apache.dolphinscheduler.plugin.task.api.parameters.resource.DataSourceParameters; import org.apache.dolphinscheduler.plugin.task.api.parameters.resource.ResourceParametersHelper; +import org.apache.dolphinscheduler.plugin.task.api.resource.ResourceContext; import org.apache.dolphinscheduler.plugin.task.api.utils.ParameterUtils; import org.apache.dolphinscheduler.spi.enums.DbType; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.util.HashMap; @@ -113,6 +48,7 @@ void testSqlLoadedFromResourceFileWhenSqlIsEmpty(@TempDir Path tempDir) throws E import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -138,6 +74,47 @@ void setup() { sqlTask = new SqlTask(ctx); } + @Test + void testSqlLoadedFromResourceFileWhenSqlIsEmpty(@TempDir Path tempDir) throws Exception { + Path sqlFile = tempDir.resolve("test.sql"); + String sqlContent = "SELECT 1"; + Files.write(sqlFile, sqlContent.getBytes(StandardCharsets.UTF_8)); + + SqlParameters sqlParameters = new SqlParameters(); + sqlParameters.setType("MYSQL"); + sqlParameters.setDatasource(1); + sqlParameters.setSql(null); + sqlParameters.setSqlResource("/sql/test.sql"); + + DataSourceParameters dataSourceParameters = new DataSourceParameters(); + dataSourceParameters.setType(DbType.MYSQL); + dataSourceParameters.setResourceType(ResourceType.DATASOURCE.name()); + + ResourceParametersHelper resourceParametersHelper = new ResourceParametersHelper(); + resourceParametersHelper.put(ResourceType.DATASOURCE, 1, dataSourceParameters); + + TaskExecutionContext taskExecutionContext = new TaskExecutionContext(); + taskExecutionContext.setTaskParams(JSONUtils.toJsonString(sqlParameters)); + taskExecutionContext.setScheduleTime(System.currentTimeMillis()); + taskExecutionContext.setResourceParametersHelper(resourceParametersHelper); + + ResourceContext resourceContext = new ResourceContext(); + resourceContext.addResourceItem(ResourceContext.ResourceItem.builder() + .resourceAbsolutePathInStorage(sqlParameters.getSqlResource()) + .resourceAbsolutePathInLocal(sqlFile.toString()) + .build()); + taskExecutionContext.setResourceContext(resourceContext); + + SqlTask task = new SqlTask(taskExecutionContext); + + Method ensureSqlContent = SqlTask.class.getDeclaredMethod("ensureSqlContent"); + ensureSqlContent.setAccessible(true); + ensureSqlContent.invoke(task); + + SqlParameters loadedParameters = (SqlParameters) task.getParameters(); + Assertions.assertEquals(sqlContent, loadedParameters.getSql()); + } + @Test void testReplacingSqlWithoutParams() { String querySql = "select 1"; @@ -279,7 +256,6 @@ void testVarPoolSetting() { @Test void testGenerateEmptyRow_WithNonNullResultSet_ReturnsEmptyValuesForAllColumns() throws Exception { - // Arrange ResultSet mockResultSet = mock(ResultSet.class); ResultSetMetaData mockMetaData = mock(ResultSetMetaData.class); @@ -291,10 +267,8 @@ void testGenerateEmptyRow_WithNonNullResultSet_ReturnsEmptyValuesForAllColumns() Method method = SqlTask.class.getDeclaredMethod("generateEmptyRow", ResultSet.class); method.setAccessible(true); - // Act ArrayNode result = (ArrayNode) method.invoke(sqlTask, mockResultSet); - // Assert Assertions.assertNotNull(result); Assertions.assertEquals(1, result.size()); @@ -305,14 +279,11 @@ void testGenerateEmptyRow_WithNonNullResultSet_ReturnsEmptyValuesForAllColumns() @Test void testGenerateEmptyRow_WithNullResultSet_ReturnsErrorObject() throws Exception { - // Arrange Method method = SqlTask.class.getDeclaredMethod("generateEmptyRow", ResultSet.class); method.setAccessible(true); - // Act ArrayNode result = (ArrayNode) method.invoke(sqlTask, (ResultSet) null); - // Assert Assertions.assertNotNull(result); Assertions.assertEquals(1, result.size()); @@ -329,7 +300,7 @@ void testGenerateEmptyRow_WithDuplicateColumns_DeduplicatesLabels() throws Excep when(mockResultSet.getMetaData()).thenReturn(mockMetaData); when(mockMetaData.getColumnCount()).thenReturn(3); when(mockMetaData.getColumnLabel(1)).thenReturn("id"); - when(mockMetaData.getColumnLabel(2)).thenReturn("id"); // duplicate + when(mockMetaData.getColumnLabel(2)).thenReturn("id"); when(mockMetaData.getColumnLabel(3)).thenReturn("name"); Method method = SqlTask.class.getDeclaredMethod("generateEmptyRow", ResultSet.class); @@ -350,7 +321,6 @@ void testResultProcess_NullResultSet_ReturnsEmptyResult() throws Exception { Method resultProcessMethod = SqlTask.class.getDeclaredMethod("resultProcess", ResultSet.class); resultProcessMethod.setAccessible(true); - // Mock a null ResultSet String result = (String) resultProcessMethod.invoke(sqlTask, (ResultSet) null); Assertions.assertNotNull(result); @@ -359,7 +329,6 @@ void testResultProcess_NullResultSet_ReturnsEmptyResult() throws Exception { @Test void testResultProcess_EmptyResultSet_ReturnsEmptyResult() throws Exception { - // Mock a non-null ResultSet that contains no data rows ResultSet mockResultSet = mock(ResultSet.class); ResultSetMetaData mockMetaData = mock(ResultSetMetaData.class); @@ -367,7 +336,7 @@ void testResultProcess_EmptyResultSet_ReturnsEmptyResult() throws Exception { when(mockMetaData.getColumnCount()).thenReturn(2); when(mockMetaData.getColumnLabel(1)).thenReturn("id"); when(mockMetaData.getColumnLabel(2)).thenReturn("name"); - when(mockResultSet.next()).thenReturn(false); // no rows available + when(mockResultSet.next()).thenReturn(false); Method resultProcessMethod = SqlTask.class.getDeclaredMethod("resultProcess", ResultSet.class); resultProcessMethod.setAccessible(true); @@ -375,7 +344,6 @@ void testResultProcess_EmptyResultSet_ReturnsEmptyResult() throws Exception { String result = (String) resultProcessMethod.invoke(sqlTask, mockResultSet); Assertions.assertNotNull(result); - // Verify the result contains empty string values for all columns and is a valid JSON array Assertions.assertTrue(result.contains("\"id\":\"\"")); Assertions.assertTrue(result.contains("\"name\":\"\"")); Assertions.assertTrue(result.startsWith("[{")); @@ -390,17 +358,15 @@ void testResultProcess_DuplicateColumnLabels_ThrowsTaskException() throws Except when(mockRs.getMetaData()).thenReturn(mockMd); when(mockMd.getColumnCount()).thenReturn(2); when(mockMd.getColumnLabel(1)).thenReturn("id"); - when(mockMd.getColumnLabel(2)).thenReturn("id"); // duplicate column name + when(mockMd.getColumnLabel(2)).thenReturn("id"); Method method = SqlTask.class.getDeclaredMethod("resultProcess", ResultSet.class); method.setAccessible(true); - // Assert that InvocationTargetException is thrown InvocationTargetException thrown = Assertions.assertThrows( InvocationTargetException.class, () -> method.invoke(sqlTask, mockRs)); - // Check the actual cause Throwable cause = thrown.getCause(); Assertions.assertNotNull(cause); Assertions.assertInstanceOf(TaskException.class, cause, diff --git a/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-sql.ts b/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-sql.ts index b31a7f80371c..1de39efec114 100644 --- a/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-sql.ts +++ b/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-sql.ts @@ -79,9 +79,7 @@ export function useSql(model: { [field: string]: any }): IJsonItem[] { labelField: 'name', disabledField: 'disable' }, - slots: { - // 这里占位,真正的资源数据从全局资源 store 中获取,保持与 use-resources 一致行为 - } + slots: {} }, ...useCustomParams({ model, From 872dc5bac7fe58ac4f373f41ec64c1281e960e99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=AE=B5=E6=99=93=E9=9B=84?= Date: Sat, 7 Mar 2026 23:07:58 +0800 Subject: [PATCH 6/7] style(task-sql): remove redundant comment per review NIT Made-with: Cursor --- .../plugin/task/api/parameters/SqlParameters.java | 1 - 1 file changed, 1 deletion(-) diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/parameters/SqlParameters.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/parameters/SqlParameters.java index 42817f538647..c614bfc15e8c 100644 --- a/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/parameters/SqlParameters.java +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/parameters/SqlParameters.java @@ -243,7 +243,6 @@ public boolean checkParameters() { if (datasource == 0 || StringUtils.isEmpty(type)) { return false; } - // support both inline sql and sql from resource file if (StringUtils.isNotEmpty(sql)) { return true; } From 4c329d4ceec244b2b654178143d5b355b97d72b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=AE=B5=E6=99=93=E9=9B=84?= Date: Thu, 12 Mar 2026 20:20:26 +0800 Subject: [PATCH 7/7] fix(task-sql): restore Sql Params debug log in printReplacedSql per review Made-with: Cursor --- .../org/apache/dolphinscheduler/plugin/task/sql/SqlTask.java | 1 + 1 file changed, 1 insertion(+) diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-sql/src/main/java/org/apache/dolphinscheduler/plugin/task/sql/SqlTask.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-sql/src/main/java/org/apache/dolphinscheduler/plugin/task/sql/SqlTask.java index 9c3b0c3475ab..dd976821db40 100644 --- a/dolphinscheduler-task-plugin/dolphinscheduler-task-sql/src/main/java/org/apache/dolphinscheduler/plugin/task/sql/SqlTask.java +++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-sql/src/main/java/org/apache/dolphinscheduler/plugin/task/sql/SqlTask.java @@ -410,6 +410,7 @@ private void printReplacedSql(String content, String formatSql, String rgex, Map .append(")"); } } + log.info("Sql Params are {}", logPrint); } private void ensureSqlContent() {