diff --git a/dolphinscheduler-api/src/main/resources/task-type-config.yaml b/dolphinscheduler-api/src/main/resources/task-type-config.yaml
index e95d4190fc60..9475e93420cf 100644
--- a/dolphinscheduler-api/src/main/resources/task-type-config.yaml
+++ b/dolphinscheduler-api/src/main/resources/task-type-config.yaml
@@ -23,6 +23,7 @@ task:
- 'PROCEDURE'
- 'SQL'
- 'SPARK'
+ - 'FLINK_SGW'
- 'FLINK'
- 'GRPC'
- 'HTTP'
diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-all/pom.xml b/dolphinscheduler-task-plugin/dolphinscheduler-task-all/pom.xml
index f3e6f8855568..b4a97a851b7a 100644
--- a/dolphinscheduler-task-plugin/dolphinscheduler-task-all/pom.xml
+++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-all/pom.xml
@@ -222,6 +222,12 @@
dolphinscheduler-task-aliyunserverlessspark
${project.version}
+
+
+ org.apache.dolphinscheduler
+ dolphinscheduler-task-flink-sqlgateway
+ ${project.version}
+
diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-flink-sqlgateway/pom.xml b/dolphinscheduler-task-plugin/dolphinscheduler-task-flink-sqlgateway/pom.xml
new file mode 100644
index 000000000000..c360b78209a6
--- /dev/null
+++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-flink-sqlgateway/pom.xml
@@ -0,0 +1,75 @@
+
+
+
+ 4.0.0
+
+
+ org.apache.dolphinscheduler
+ dolphinscheduler-task-plugin
+ dev-SNAPSHOT
+
+
+ dolphinscheduler-task-flink-sqlgateway
+ jar
+
+
+ task.flink.sqlgateway
+ 2.2.0
+
+
+
+
+ org.apache.dolphinscheduler
+ dolphinscheduler-task-api
+ ${project.version}
+ provided
+
+
+
+ org.apache.dolphinscheduler
+ dolphinscheduler-common
+ ${project.version}
+ provided
+
+
+
+
+ org.apache.flink
+ flink-sql-jdbc-driver
+ ${flink-sql-jdbc-driver.version}
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+
+
+
+ shade
+
+ package
+
+
+
+
+
+
diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-flink-sqlgateway/src/main/java/org/apache/dolphinscheduler/plugin/task/flinksqlgateway/FlinkSqlGatewayParameters.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-flink-sqlgateway/src/main/java/org/apache/dolphinscheduler/plugin/task/flinksqlgateway/FlinkSqlGatewayParameters.java
new file mode 100644
index 000000000000..831934de8ead
--- /dev/null
+++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-flink-sqlgateway/src/main/java/org/apache/dolphinscheduler/plugin/task/flinksqlgateway/FlinkSqlGatewayParameters.java
@@ -0,0 +1,202 @@
+/*
+ * 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.flinksqlgateway;
+
+import org.apache.dolphinscheduler.plugin.task.api.enums.SqlSourceType;
+import org.apache.dolphinscheduler.plugin.task.api.model.ResourceInfo;
+import org.apache.dolphinscheduler.plugin.task.api.parameters.AbstractParameters;
+
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+public class FlinkSqlGatewayParameters extends AbstractParameters {
+
+ /**
+ * example: jdbc:flink://host:port
+ */
+ private String flinkJdbcUrl;
+
+ /**
+ * optional: username/password or other jdbc properties
+ */
+ private Map jdbcProperties;
+
+ /**
+ * init script source: SCRIPT = inline sql text, FILE = sql from resource center file
+ */
+ private SqlSourceType initScriptType = SqlSourceType.FILE;
+
+ /**
+ * optional init sql script (when initScriptType=SCRIPT), or read-only display (when FILE)
+ */
+ private String initScript;
+
+ /**
+ * resource list for init script file (when initScriptType=FILE), size 1
+ */
+ private List initScriptResourceList;
+
+ /**
+ * main script source: SCRIPT = inline sql text, FILE = sql from resource center file
+ */
+ private SqlSourceType rawScriptType = SqlSourceType.FILE;
+
+ /**
+ * main sql script (when rawScriptType=SCRIPT), or read-only display content (when rawScriptType=FILE)
+ */
+ private String rawScript;
+
+ /**
+ * resource list for main script file (when rawScriptType=FILE), size 1
+ */
+ private List resourceList;
+
+ /**
+ * default: ;
+ */
+ private String statementSeparator = ";";
+
+ /**
+ * print query result rows count in log, default 0 means do not print rows
+ */
+ private int maxPrintRows = 0;
+
+ public Properties toJdbcProperties() {
+ Properties props = new Properties();
+ if (jdbcProperties != null) {
+ jdbcProperties.forEach((k, v) -> {
+ if (k != null && v != null) {
+ props.put(k, v);
+ }
+ });
+ }
+ return props;
+ }
+
+ @Override
+ public boolean checkParameters() {
+ if (StringUtils.isBlank(flinkJdbcUrl)) {
+ return false;
+ }
+ if (initScriptType == SqlSourceType.FILE
+ && (CollectionUtils.isEmpty(initScriptResourceList) || initScriptResourceList.size() < 1)) {
+ return false;
+ }
+ if (rawScriptType == SqlSourceType.FILE) {
+ return CollectionUtils.isNotEmpty(resourceList) && resourceList.size() >= 1;
+ }
+ return rawScriptType == SqlSourceType.SCRIPT && StringUtils.isNotBlank(rawScript);
+ }
+
+ @Override
+ public List getResourceFilesList() {
+ List list = new ArrayList<>();
+ if (initScriptType == SqlSourceType.FILE && CollectionUtils.isNotEmpty(initScriptResourceList)) {
+ list.addAll(initScriptResourceList);
+ }
+ if (rawScriptType == SqlSourceType.FILE && CollectionUtils.isNotEmpty(resourceList)) {
+ list.addAll(resourceList);
+ }
+ return list;
+ }
+
+ public String getFlinkJdbcUrl() {
+ return flinkJdbcUrl;
+ }
+
+ public void setFlinkJdbcUrl(String flinkJdbcUrl) {
+ this.flinkJdbcUrl = flinkJdbcUrl;
+ }
+
+ public Map getJdbcProperties() {
+ return jdbcProperties;
+ }
+
+ public void setJdbcProperties(Map jdbcProperties) {
+ this.jdbcProperties = jdbcProperties;
+ }
+
+ public SqlSourceType getInitScriptType() {
+ return initScriptType;
+ }
+
+ public void setInitScriptType(SqlSourceType initScriptType) {
+ this.initScriptType = initScriptType;
+ }
+
+ public String getInitScript() {
+ return initScript;
+ }
+
+ public void setInitScript(String initScript) {
+ this.initScript = initScript;
+ }
+
+ public List getInitScriptResourceList() {
+ return initScriptResourceList;
+ }
+
+ public void setInitScriptResourceList(List initScriptResourceList) {
+ this.initScriptResourceList = initScriptResourceList;
+ }
+
+ public SqlSourceType getRawScriptType() {
+ return rawScriptType;
+ }
+
+ public void setRawScriptType(SqlSourceType rawScriptType) {
+ this.rawScriptType = rawScriptType;
+ }
+
+ public String getRawScript() {
+ return rawScript;
+ }
+
+ public void setRawScript(String rawScript) {
+ this.rawScript = rawScript;
+ }
+
+ public List getResourceList() {
+ return resourceList;
+ }
+
+ public void setResourceList(List resourceList) {
+ this.resourceList = resourceList;
+ }
+
+ public String getStatementSeparator() {
+ return statementSeparator;
+ }
+
+ public void setStatementSeparator(String statementSeparator) {
+ this.statementSeparator = statementSeparator;
+ }
+
+ public int getMaxPrintRows() {
+ return maxPrintRows;
+ }
+
+ public void setMaxPrintRows(int maxPrintRows) {
+ this.maxPrintRows = maxPrintRows;
+ }
+}
diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-flink-sqlgateway/src/main/java/org/apache/dolphinscheduler/plugin/task/flinksqlgateway/FlinkSqlGatewayTask.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-flink-sqlgateway/src/main/java/org/apache/dolphinscheduler/plugin/task/flinksqlgateway/FlinkSqlGatewayTask.java
new file mode 100644
index 000000000000..a1c531852cdf
--- /dev/null
+++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-flink-sqlgateway/src/main/java/org/apache/dolphinscheduler/plugin/task/flinksqlgateway/FlinkSqlGatewayTask.java
@@ -0,0 +1,221 @@
+/*
+ * 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.flinksqlgateway;
+
+import org.apache.dolphinscheduler.common.utils.JSONUtils;
+import org.apache.dolphinscheduler.plugin.task.api.AbstractTask;
+import org.apache.dolphinscheduler.plugin.task.api.TaskCallBack;
+import org.apache.dolphinscheduler.plugin.task.api.TaskConstants;
+import org.apache.dolphinscheduler.plugin.task.api.TaskException;
+import org.apache.dolphinscheduler.plugin.task.api.TaskExecutionContext;
+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.AbstractParameters;
+import org.apache.dolphinscheduler.plugin.task.api.resource.ResourceContext;
+import org.apache.dolphinscheduler.plugin.task.api.utils.ParameterUtils;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class FlinkSqlGatewayTask extends AbstractTask {
+
+ private final TaskExecutionContext taskExecutionContext;
+ private FlinkSqlGatewayParameters parameters;
+
+ private volatile Connection connection;
+ private volatile Statement statement;
+
+ public FlinkSqlGatewayTask(TaskExecutionContext taskExecutionContext) {
+ super(taskExecutionContext);
+ this.taskExecutionContext = taskExecutionContext;
+ }
+
+ @Override
+ public void init() {
+ parameters =
+ JSONUtils.parseObject(taskExecutionContext.getTaskParams(), FlinkSqlGatewayParameters.class);
+
+ log.info("Initialize flink sqlgateway task params {}", JSONUtils.toPrettyJsonString(parameters));
+
+ if (parameters == null || !parameters.checkParameters()) {
+ throw new TaskException("flink sqlgateway task params is not valid");
+ }
+ }
+
+ @Override
+ public AbstractParameters getParameters() {
+ return parameters;
+ }
+
+ @Override
+ public void handle(TaskCallBack taskCallBack) throws TaskException {
+ try {
+ String jdbcUrl = resolveFlinkJdbcUrl();
+ Properties props = parameters.toJdbcProperties();
+ log.info("Connecting flink sql gateway with jdbcUrl: {}", jdbcUrl);
+ connection = DriverManager.getConnection(jdbcUrl, props);
+ statement = connection.createStatement();
+
+ executeScriptIfPresent(resolveScriptContent(parameters.getInitScriptType(),
+ parameters.getInitScript(), parameters.getInitScriptResourceList()), "init");
+ executeScriptIfPresent(resolveScriptContent(parameters.getRawScriptType(),
+ parameters.getRawScript(), parameters.getResourceList()), "main");
+
+ setExitStatusCode(TaskConstants.EXIT_CODE_SUCCESS);
+ } catch (Exception e) {
+ if (exitStatusCode == TaskConstants.EXIT_CODE_KILL) {
+ log.info("flink sqlgateway task has been killed");
+ return;
+ }
+ setExitStatusCode(TaskConstants.EXIT_CODE_FAILURE);
+ throw new TaskException("Execute flink sqlgateway task failed", e);
+ } finally {
+ closeQuietly(statement);
+ closeQuietly(connection);
+ }
+ }
+
+ @Override
+ public void cancel() throws TaskException {
+ exitStatusCode = TaskConstants.EXIT_CODE_KILL;
+ try {
+ if (statement != null) {
+ statement.cancel();
+ }
+ } catch (Exception e) {
+ throw new TaskException("Cancel flink sqlgateway task failed", e);
+ } finally {
+ closeQuietly(statement);
+ closeQuietly(connection);
+ }
+ }
+
+ private String resolvePlaceholderParams(String content) {
+ Map paramsMap = taskExecutionContext.getPrepareParamsMap();
+ Map stringParams = ParameterUtils.convert(paramsMap);
+ return ParameterUtils.convertParameterPlaceholders(content, stringParams);
+ }
+
+ private String resolveFlinkJdbcUrl() {
+ return resolvePlaceholderParams(parameters.getFlinkJdbcUrl());
+ }
+
+ private String resolveScriptContent(SqlSourceType scriptType, String inlineScript,
+ List resourceList) throws Exception {
+ if (scriptType == SqlSourceType.FILE && resourceList != null && !resourceList.isEmpty()) {
+ String resourceName = resourceList.get(0).getResourceName();
+ ResourceContext resourceContext = taskExecutionContext.getResourceContext();
+ String localPath = resourceContext.getResourceItem(resourceName).getResourceAbsolutePathInLocal();
+ String content = FileUtils.readFileToString(new File(localPath), StandardCharsets.UTF_8);
+ log.info("Load {} sql script from resource file: {}, {} chars", scriptType, localPath, content.length());
+ return resolvePlaceholderParams(content);
+ }
+ if (scriptType == SqlSourceType.SCRIPT && StringUtils.isNotBlank(inlineScript)) {
+ return resolvePlaceholderParams(inlineScript);
+ }
+ return inlineScript;
+ }
+
+ private void executeScriptIfPresent(String script, String tag) throws Exception {
+ if (StringUtils.isBlank(script)) {
+ return;
+ }
+ List sqlList = splitSql(script, parameters.getStatementSeparator());
+ for (int i = 0; i < sqlList.size(); i++) {
+ String sql = sqlList.get(i);
+ String trimmed = stripLeadingCommentsAndBlanks(sql == null ? "" : sql);
+ if (trimmed.isEmpty()) {
+ continue;
+ }
+
+ log.info("[{}] execute #{} sql: {}", tag, i + 1, trimmed);
+
+ boolean hasResultSet = statement.execute(trimmed);
+ if (hasResultSet) {
+ try (ResultSet rs = statement.getResultSet()) {
+ int row = 0;
+ int maxPrint = Math.max(parameters.getMaxPrintRows(), 0);
+ while (rs != null && rs.next() && row < maxPrint) {
+ row++;
+ // avoid log explosion, print row index only
+ log.info("[{}] query result row {}", tag, row);
+ }
+ if (maxPrint > 0) {
+ log.info("[{}] query printed rows: {}", tag, row);
+ }
+ }
+ } else {
+ int updateCount = statement.getUpdateCount();
+ log.info("[{}] updateCount={}", tag, updateCount);
+ }
+ }
+ }
+
+ static List splitSql(String script, String separator) {
+ String sep = StringUtils.isBlank(separator) ? ";" : separator;
+ return Arrays.stream(script.split(Pattern.quote(sep)))
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Strip leading line comments (-- ...) and blank lines so that Flink parser
+ * receives only the actual statement (e.g. SET pipeline.name='...').
+ */
+ static String stripLeadingCommentsAndBlanks(String sql) {
+ if (sql == null) {
+ return "";
+ }
+ String[] lines = sql.split("\n");
+ for (int i = 0; i < lines.length; i++) {
+ String trimmed = lines[i].trim();
+ if (!trimmed.isEmpty() && !trimmed.startsWith("--")) {
+ return String.join("\n", Arrays.copyOfRange(lines, i, lines.length)).trim();
+ }
+ }
+ // all lines are comments or blank, nothing to execute
+ return "";
+ }
+
+ private static void closeQuietly(AutoCloseable c) {
+ if (c == null) {
+ return;
+ }
+ try {
+ c.close();
+ } catch (Exception ignored) {
+ // ignored
+ }
+ }
+}
diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-flink-sqlgateway/src/main/java/org/apache/dolphinscheduler/plugin/task/flinksqlgateway/FlinkSqlGatewayTaskChannel.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-flink-sqlgateway/src/main/java/org/apache/dolphinscheduler/plugin/task/flinksqlgateway/FlinkSqlGatewayTaskChannel.java
new file mode 100644
index 000000000000..bb22609fe4cc
--- /dev/null
+++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-flink-sqlgateway/src/main/java/org/apache/dolphinscheduler/plugin/task/flinksqlgateway/FlinkSqlGatewayTaskChannel.java
@@ -0,0 +1,36 @@
+/*
+ * 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.flinksqlgateway;
+
+import org.apache.dolphinscheduler.common.utils.JSONUtils;
+import org.apache.dolphinscheduler.plugin.task.api.TaskChannel;
+import org.apache.dolphinscheduler.plugin.task.api.TaskExecutionContext;
+import org.apache.dolphinscheduler.plugin.task.api.parameters.AbstractParameters;
+
+public class FlinkSqlGatewayTaskChannel implements TaskChannel {
+
+ @Override
+ public FlinkSqlGatewayTask createTask(TaskExecutionContext taskRequest) {
+ return new FlinkSqlGatewayTask(taskRequest);
+ }
+
+ @Override
+ public AbstractParameters parseParameters(String taskParams) {
+ return JSONUtils.parseObject(taskParams, FlinkSqlGatewayParameters.class);
+ }
+}
diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-flink-sqlgateway/src/main/java/org/apache/dolphinscheduler/plugin/task/flinksqlgateway/FlinkSqlGatewayTaskChannelFactory.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-flink-sqlgateway/src/main/java/org/apache/dolphinscheduler/plugin/task/flinksqlgateway/FlinkSqlGatewayTaskChannelFactory.java
new file mode 100644
index 000000000000..bf67b9ec93a8
--- /dev/null
+++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-flink-sqlgateway/src/main/java/org/apache/dolphinscheduler/plugin/task/flinksqlgateway/FlinkSqlGatewayTaskChannelFactory.java
@@ -0,0 +1,37 @@
+/*
+ * 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.flinksqlgateway;
+
+import org.apache.dolphinscheduler.plugin.task.api.TaskChannel;
+import org.apache.dolphinscheduler.plugin.task.api.TaskChannelFactory;
+
+import com.google.auto.service.AutoService;
+
+@AutoService(TaskChannelFactory.class)
+public class FlinkSqlGatewayTaskChannelFactory implements TaskChannelFactory {
+
+ @Override
+ public TaskChannel create() {
+ return new FlinkSqlGatewayTaskChannel();
+ }
+
+ @Override
+ public String getName() {
+ return "FLINK_SGW";
+ }
+}
diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-flink-sqlgateway/src/test/java/org/apache/dolphinscheduler/plugin/task/flinksqlgateway/FlinkSqlGatewayParametersTest.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-flink-sqlgateway/src/test/java/org/apache/dolphinscheduler/plugin/task/flinksqlgateway/FlinkSqlGatewayParametersTest.java
new file mode 100644
index 000000000000..078562b8f8be
--- /dev/null
+++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-flink-sqlgateway/src/test/java/org/apache/dolphinscheduler/plugin/task/flinksqlgateway/FlinkSqlGatewayParametersTest.java
@@ -0,0 +1,127 @@
+/*
+ * 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.flinksqlgateway;
+
+import org.apache.dolphinscheduler.plugin.task.api.enums.SqlSourceType;
+import org.apache.dolphinscheduler.plugin.task.api.model.ResourceInfo;
+
+import java.util.Collections;
+import java.util.Properties;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class FlinkSqlGatewayParametersTest {
+
+ private FlinkSqlGatewayParameters buildValidFileBasedParameters() {
+ FlinkSqlGatewayParameters parameters = new FlinkSqlGatewayParameters();
+ parameters.setFlinkJdbcUrl("jdbc:flink://localhost:8083");
+ parameters.setRawScriptType(SqlSourceType.FILE);
+ ResourceInfo mainResource = new ResourceInfo();
+ mainResource.setResourceName("main.sql");
+ parameters.setResourceList(Collections.singletonList(mainResource));
+ parameters.setInitScriptType(SqlSourceType.FILE);
+ ResourceInfo initResource = new ResourceInfo();
+ initResource.setResourceName("init.sql");
+ parameters.setInitScriptResourceList(Collections.singletonList(initResource));
+ return parameters;
+ }
+
+ @Test
+ public void checkParametersShouldPassWhenFileBasedScriptsAreValid() {
+ FlinkSqlGatewayParameters parameters = buildValidFileBasedParameters();
+ Assertions.assertTrue(parameters.checkParameters());
+ }
+
+ @Test
+ public void checkParametersShouldFailWhenJdbcUrlIsBlank() {
+ FlinkSqlGatewayParameters parameters = buildValidFileBasedParameters();
+ parameters.setFlinkJdbcUrl(" ");
+ Assertions.assertFalse(parameters.checkParameters());
+ }
+
+ @Test
+ public void checkParametersShouldFailWhenMainScriptFileIsMissing() {
+ FlinkSqlGatewayParameters parameters = buildValidFileBasedParameters();
+ parameters.setResourceList(null);
+ Assertions.assertFalse(parameters.checkParameters());
+
+ parameters.setResourceList(Collections.emptyList());
+ Assertions.assertFalse(parameters.checkParameters());
+ }
+
+ @Test
+ public void checkParametersShouldFailWhenInitScriptFileIsMissing() {
+ FlinkSqlGatewayParameters parameters = buildValidFileBasedParameters();
+ parameters.setInitScriptResourceList(null);
+ Assertions.assertFalse(parameters.checkParameters());
+ }
+
+ @Test
+ public void checkParametersShouldPassWhenInlineScriptsAreValid() {
+ FlinkSqlGatewayParameters parameters = new FlinkSqlGatewayParameters();
+ parameters.setFlinkJdbcUrl("jdbc:flink://localhost:8083");
+ parameters.setRawScriptType(SqlSourceType.SCRIPT);
+ parameters.setRawScript("SELECT 1");
+ parameters.setInitScriptType(SqlSourceType.SCRIPT);
+ Assertions.assertTrue(parameters.checkParameters());
+ }
+
+ @Test
+ public void checkParametersShouldFailWhenInlineMainScriptIsBlank() {
+ FlinkSqlGatewayParameters parameters = new FlinkSqlGatewayParameters();
+ parameters.setFlinkJdbcUrl("jdbc:flink://localhost:8083");
+ parameters.setRawScriptType(SqlSourceType.SCRIPT);
+ parameters.setRawScript("");
+ Assertions.assertFalse(parameters.checkParameters());
+ }
+
+ @Test
+ public void getResourceFilesListShouldAggregateInitAndMainResourceFiles() {
+ FlinkSqlGatewayParameters parameters = buildValidFileBasedParameters();
+ Assertions.assertEquals(2, parameters.getResourceFilesList().size());
+ }
+
+ @Test
+ public void getResourceFilesListShouldReturnEmptyWhenScriptsAreInline() {
+ FlinkSqlGatewayParameters parameters = new FlinkSqlGatewayParameters();
+ parameters.setFlinkJdbcUrl("jdbc:flink://localhost:8083");
+ parameters.setRawScriptType(SqlSourceType.SCRIPT);
+ parameters.setInitScriptType(SqlSourceType.SCRIPT);
+ Assertions.assertEquals(0, parameters.getResourceFilesList().size());
+ }
+
+ @Test
+ public void toJdbcPropertiesShouldFilterNullKeysAndValues() {
+ FlinkSqlGatewayParameters parameters = new FlinkSqlGatewayParameters();
+ parameters.setJdbcProperties(null);
+ Assertions.assertEquals(0, parameters.toJdbcProperties().size());
+
+ parameters.setJdbcProperties(new java.util.HashMap() {
+
+ {
+ put("user", "flink");
+ put("badKey", null);
+ put(null, "badValue");
+ }
+ });
+ Properties properties = parameters.toJdbcProperties();
+ Assertions.assertEquals(1, properties.size());
+ Assertions.assertEquals("flink", properties.getProperty("user"));
+ }
+}
diff --git a/dolphinscheduler-task-plugin/dolphinscheduler-task-flink-sqlgateway/src/test/java/org/apache/dolphinscheduler/plugin/task/flinksqlgateway/FlinkSqlGatewayTaskTest.java b/dolphinscheduler-task-plugin/dolphinscheduler-task-flink-sqlgateway/src/test/java/org/apache/dolphinscheduler/plugin/task/flinksqlgateway/FlinkSqlGatewayTaskTest.java
new file mode 100644
index 000000000000..3db51d856b27
--- /dev/null
+++ b/dolphinscheduler-task-plugin/dolphinscheduler-task-flink-sqlgateway/src/test/java/org/apache/dolphinscheduler/plugin/task/flinksqlgateway/FlinkSqlGatewayTaskTest.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.dolphinscheduler.plugin.task.flinksqlgateway;
+
+import java.util.List;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class FlinkSqlGatewayTaskTest {
+
+ @Test
+ public void splitSqlShouldUseDefaultSemicolonWhenSeparatorIsBlank() {
+ List sqlList = FlinkSqlGatewayTask.splitSql("SET a=1;SELECT 2", " ");
+ Assertions.assertEquals(2, sqlList.size());
+ Assertions.assertEquals("SET a=1", sqlList.get(0));
+ Assertions.assertEquals("SELECT 2", sqlList.get(1));
+ }
+
+ @Test
+ public void splitSqlShouldSupportCustomSeparator() {
+ List sqlList = FlinkSqlGatewayTask.splitSql("SET a=1@@SELECT 2", "@@");
+ Assertions.assertEquals(2, sqlList.size());
+ Assertions.assertEquals("SET a=1", sqlList.get(0));
+ Assertions.assertEquals("SELECT 2", sqlList.get(1));
+ }
+
+ @Test
+ public void splitSqlShouldEscapeRegexSpecialCharactersInSeparator() {
+ List sqlList = FlinkSqlGatewayTask.splitSql("SET a=1|SELECT 2", "|");
+ Assertions.assertEquals(2, sqlList.size());
+ }
+
+ @Test
+ public void stripLeadingCommentsAndBlanksShouldRemoveLeadingCommentAndBlankLines() {
+ String sql = FlinkSqlGatewayTask.stripLeadingCommentsAndBlanks(
+ "-- job comment\n\n-- another comment\nSET pipeline.name='demo'");
+ Assertions.assertEquals("SET pipeline.name='demo'", sql);
+ }
+
+ @Test
+ public void stripLeadingCommentsAndBlanksShouldKeepStatementWithoutComments() {
+ String sql = FlinkSqlGatewayTask.stripLeadingCommentsAndBlanks("SELECT 1");
+ Assertions.assertEquals("SELECT 1", sql);
+ }
+
+ @Test
+ public void stripLeadingCommentsAndBlanksShouldReturnEmptyWhenOnlyComments() {
+ Assertions.assertEquals("", FlinkSqlGatewayTask.stripLeadingCommentsAndBlanks("-- comment only\n\n"));
+ Assertions.assertEquals("", FlinkSqlGatewayTask.stripLeadingCommentsAndBlanks(null));
+ }
+
+ @Test
+ public void stripLeadingCommentsAndBlanksShouldKeepInlineCommentInsideStatement() {
+ String sql = FlinkSqlGatewayTask.stripLeadingCommentsAndBlanks(
+ "SELECT 1 -- trailing comment");
+ Assertions.assertEquals("SELECT 1 -- trailing comment", sql);
+ }
+}
diff --git a/dolphinscheduler-task-plugin/pom.xml b/dolphinscheduler-task-plugin/pom.xml
index 830650f50f55..5a9d4f3903b4 100644
--- a/dolphinscheduler-task-plugin/pom.xml
+++ b/dolphinscheduler-task-plugin/pom.xml
@@ -63,6 +63,7 @@
dolphinscheduler-task-remoteshell
dolphinscheduler-task-aliyunserverlessspark
dolphinscheduler-task-emr-serverless
+ dolphinscheduler-task-flink-sqlgateway
diff --git a/dolphinscheduler-ui/src/locales/en_US/project.ts b/dolphinscheduler-ui/src/locales/en_US/project.ts
index 626410631650..7a32201b233c 100644
--- a/dolphinscheduler-ui/src/locales/en_US/project.ts
+++ b/dolphinscheduler-ui/src/locales/en_US/project.ts
@@ -449,6 +449,7 @@ export default {
master_tips: 'Please enter master url(optional)',
init_script: 'Initialization script',
init_script_tips: 'Please enter initialization script',
+ init_script_source: 'Init Script Source',
resources: 'Resources',
resources_tips: 'Please select resources',
resources_limit_tips: 'Please select again, resource limit:',
diff --git a/dolphinscheduler-ui/src/locales/zh_CN/project.ts b/dolphinscheduler-ui/src/locales/zh_CN/project.ts
index 90d526b175b7..0519daf0cf91 100644
--- a/dolphinscheduler-ui/src/locales/zh_CN/project.ts
+++ b/dolphinscheduler-ui/src/locales/zh_CN/project.ts
@@ -436,6 +436,7 @@ export default {
master_tips: '请输入master url(选填)',
init_script: '初始化脚本',
init_script_tips: '请输入初始化脚本',
+ init_script_source: 'Init Script 来源',
resources: '资源',
resources_tips: '请选择资源',
resources_limit_tips: '请重新选择,资源个数限制:',
diff --git a/dolphinscheduler-ui/src/store/project/task-type.ts b/dolphinscheduler-ui/src/store/project/task-type.ts
index 597340750ae3..1bcd0c7dff24 100644
--- a/dolphinscheduler-ui/src/store/project/task-type.ts
+++ b/dolphinscheduler-ui/src/store/project/task-type.ts
@@ -44,6 +44,9 @@ export const TASK_TYPES_MAP = {
FLINK: {
alias: 'FLINK'
},
+ FLINK_SGW: {
+ alias: 'FLINK_SGW'
+ },
MR: {
alias: 'MapReduce',
helperLinkDisable: true
diff --git a/dolphinscheduler-ui/src/store/project/types.ts b/dolphinscheduler-ui/src/store/project/types.ts
index a58135b3e741..1e67171a2ade 100644
--- a/dolphinscheduler-ui/src/store/project/types.ts
+++ b/dolphinscheduler-ui/src/store/project/types.ts
@@ -58,6 +58,7 @@ type TaskType =
| 'DATA_FACTORY'
| 'REMOTESHELL'
| 'ALIYUN_SERVERLESS_SPARK'
+ | 'FLINK_SGW'
type ProgramType = 'JAVA' | 'SCALA' | 'PYTHON'
diff --git a/dolphinscheduler-ui/src/views/projects/task/components/node/fields/index.ts b/dolphinscheduler-ui/src/views/projects/task/components/node/fields/index.ts
index da4cce0763e5..bbf215839414 100644
--- a/dolphinscheduler-ui/src/views/projects/task/components/node/fields/index.ts
+++ b/dolphinscheduler-ui/src/views/projects/task/components/node/fields/index.ts
@@ -90,3 +90,4 @@ export { useDataFactory } from './use-data-factory'
export { useRemoteShell } from './use-remote-shell'
export { useYarnQueue } from './use-queue'
export { useAliyunServerlessSpark } from './use-aliyun-serverless-spark'
+export { useFlinkSqlGateway } from './use-flink-sqlgateway'
diff --git a/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-flink-sqlgateway.ts b/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-flink-sqlgateway.ts
new file mode 100644
index 000000000000..07bc4f77626f
--- /dev/null
+++ b/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-flink-sqlgateway.ts
@@ -0,0 +1,231 @@
+import { computed, watch, ref } from 'vue'
+import { useI18n } from 'vue-i18n'
+import { useResources, useCustomParams } from '.'
+import { viewResource } from '@/service/modules/resources'
+import { useUserStore } from '@/store/user/user'
+import type { IJsonItem } from '../types'
+
+/** Script source: inline input */
+const SCRIPT_SOURCE_SCRIPT = 'SCRIPT'
+/** Script source: resource center file */
+const SCRIPT_SOURCE_FILE = 'FILE'
+
+export function useFlinkSqlGateway(model: { [field: string]: any }): IJsonItem[] {
+ const { t } = useI18n()
+ const userStore = useUserStore()
+ const resourceContentLoading = ref(false)
+
+ if (!model.flinkJdbcUrl) model.flinkJdbcUrl = 'jdbc:flink://host:port'
+ if (!model.statementSeparator) model.statementSeparator = ';'
+ if (!model.maxPrintRows) model.maxPrintRows = 0
+ if (!model.initScript) model.initScript = ''
+ if (!model.rawScript) model.rawScript = ''
+ if (!model.rawScriptType) model.rawScriptType = SCRIPT_SOURCE_FILE
+ if (!model.resourceList) model.resourceList = []
+ if (!model.initScriptType) model.initScriptType = SCRIPT_SOURCE_FILE
+ if (!model.initScriptResourceList) model.initScriptResourceList = []
+
+ const initResourceContentLoading = ref(false)
+ const resourcesRequired = ref(model.rawScriptType === SCRIPT_SOURCE_FILE)
+ const initResourcesRequired = ref(model.initScriptType === SCRIPT_SOURCE_FILE)
+ const resourcesLimit = computed(() =>
+ model.rawScriptType === SCRIPT_SOURCE_SCRIPT ? -1 : 1
+ )
+ const resourcesSpan = computed(() =>
+ model.rawScriptType === SCRIPT_SOURCE_FILE ? 24 : 0
+ )
+ const initResourcesSpan = computed(() =>
+ model.initScriptType === SCRIPT_SOURCE_FILE ? 24 : 0
+ )
+ const scriptEditorReadonly = computed(() => model.rawScriptType === SCRIPT_SOURCE_FILE)
+ const initScriptEditorReadonly = computed(() => model.initScriptType === SCRIPT_SOURCE_FILE)
+
+ const loadResourceContent = (fullName: string) => {
+ const tenantCode = (userStore.getUserInfo as any)?.tenantCode
+ if (!tenantCode) {
+ model.rawScript = ''
+ return
+ }
+ resourceContentLoading.value = true
+ viewResource({
+ fullName,
+ tenantCode,
+ skipLineNum: 0,
+ limit: -1
+ })
+ .then((res: { content: string }) => {
+ model.rawScript = res?.content ?? ''
+ })
+ .catch(() => {
+ model.rawScript = ''
+ })
+ .finally(() => {
+ resourceContentLoading.value = false
+ })
+ }
+
+ const loadInitResourceContent = (fullName: string) => {
+ const tenantCode = (userStore.getUserInfo as any)?.tenantCode
+ if (!tenantCode) {
+ model.initScript = ''
+ return
+ }
+ initResourceContentLoading.value = true
+ viewResource({
+ fullName,
+ tenantCode,
+ skipLineNum: 0,
+ limit: -1
+ })
+ .then((res: { content: string }) => {
+ model.initScript = res?.content ?? ''
+ })
+ .catch(() => {
+ model.initScript = ''
+ })
+ .finally(() => {
+ initResourceContentLoading.value = false
+ })
+ }
+
+ watch(
+ () => model.rawScriptType,
+ () => {
+ resourcesRequired.value = model.rawScriptType === SCRIPT_SOURCE_FILE
+ if (model.rawScriptType === SCRIPT_SOURCE_SCRIPT) {
+ model.resourceList = []
+ } else if (model.resourceList?.length === 1) {
+ loadResourceContent(model.resourceList[0])
+ } else {
+ model.rawScript = ''
+ }
+ }
+ )
+
+ watch(
+ () => model.resourceList,
+ (list) => {
+ if (model.rawScriptType === SCRIPT_SOURCE_FILE && list?.length === 1) {
+ loadResourceContent(list[0])
+ } else if (model.rawScriptType === SCRIPT_SOURCE_FILE) {
+ model.rawScript = ''
+ }
+ },
+ { deep: true, immediate: true }
+ )
+
+ watch(
+ () => model.initScriptType,
+ () => {
+ initResourcesRequired.value = model.initScriptType === SCRIPT_SOURCE_FILE
+ if (model.initScriptType === SCRIPT_SOURCE_SCRIPT) {
+ model.initScriptResourceList = []
+ } else if (model.initScriptResourceList?.length === 1) {
+ loadInitResourceContent(model.initScriptResourceList[0])
+ } else {
+ model.initScript = ''
+ }
+ }
+ )
+
+ watch(
+ () => model.initScriptResourceList,
+ (list) => {
+ if (model.initScriptType === SCRIPT_SOURCE_FILE && list?.length === 1) {
+ loadInitResourceContent(list[0])
+ } else if (model.initScriptType === SCRIPT_SOURCE_FILE) {
+ model.initScript = ''
+ }
+ },
+ { deep: true, immediate: true }
+ )
+
+ const SCRIPT_SOURCE_OPTIONS = [
+ { label: t('project.node.sql_execution_type_from_script'), value: SCRIPT_SOURCE_SCRIPT },
+ { label: t('project.node.sql_execution_type_from_file'), value: SCRIPT_SOURCE_FILE }
+ ]
+
+ return [
+ {
+ type: 'input',
+ field: 'flinkJdbcUrl',
+ span: 24,
+ name: 'JDBC URL',
+ props: { placeholder: 'jdbc:flink://host:port' },
+ value: model.flinkJdbcUrl,
+ validate: { trigger: ['blur', 'input'], required: true }
+ },
+ {
+ type: 'input',
+ field: 'statementSeparator',
+ span: 24,
+ name: 'Statement Separator',
+ props: { placeholder: ';' },
+ value: model.statementSeparator
+ },
+ {
+ type: 'input-number',
+ field: 'maxPrintRows',
+ span: 24,
+ name: 'Max Print Rows',
+ props: { min: 0 },
+ value: model.maxPrintRows
+ },
+ {
+ type: 'select',
+ field: 'initScriptType',
+ span: 12,
+ name: t('project.node.init_script_source'),
+ options: SCRIPT_SOURCE_OPTIONS,
+ validate: { trigger: ['input', 'blur'], required: true }
+ },
+ useResources(
+ initResourcesSpan,
+ initResourcesRequired,
+ computed(() => (model.initScriptType === SCRIPT_SOURCE_FILE ? 1 : -1)),
+ 'initScriptResourceList'
+ ),
+ {
+ type: 'editor',
+ field: 'initScript',
+ span: 24,
+ name: 'Init Script',
+ props: {
+ language: 'sql',
+ readOnly: initScriptEditorReadonly,
+ loading: initResourceContentLoading
+ },
+ value: model.initScript
+ },
+ {
+ type: 'select',
+ field: 'rawScriptType',
+ span: 12,
+ name: t('project.node.sql_execution_type'),
+ options: SCRIPT_SOURCE_OPTIONS,
+ validate: { trigger: ['input', 'blur'], required: true }
+ },
+ useResources(resourcesSpan, resourcesRequired, resourcesLimit),
+ {
+ type: 'editor',
+ field: 'rawScript',
+ span: 24,
+ name: 'Script',
+ props: {
+ language: 'sql',
+ readOnly: scriptEditorReadonly,
+ loading: resourceContentLoading
+ },
+ value: model.rawScript,
+ validate: {
+ trigger: ['blur', 'input'],
+ required: model.rawScriptType === SCRIPT_SOURCE_SCRIPT
+ }
+ },
+ ...useCustomParams({
+ model,
+ field: 'localParams',
+ isSimple: model.readonly
+ })
+ ]
+}
diff --git a/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-resources.ts b/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-resources.ts
index b77e8f0a764f..1b2a83214419 100644
--- a/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-resources.ts
+++ b/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-resources.ts
@@ -28,7 +28,8 @@ import { useClipboard } from '@vueuse/core'
export function useResources(
span: number | Ref = 24,
required: boolean | Ref = false,
- limit: number | Ref = -1
+ limit: number | Ref = -1,
+ field: string = 'resourceList'
): IJsonItem {
const { t } = useI18n()
@@ -141,7 +142,7 @@ export function useResources(
return {
type: 'tree-select',
- field: 'resourceList',
+ field,
class: 'resource-select',
name: t('project.node.resources'),
span: span,
diff --git a/dolphinscheduler-ui/src/views/projects/task/components/node/format-data.ts b/dolphinscheduler-ui/src/views/projects/task/components/node/format-data.ts
index 47498c2ceacb..413476832316 100644
--- a/dolphinscheduler-ui/src/views/projects/task/components/node/format-data.ts
+++ b/dolphinscheduler-ui/src/views/projects/task/components/node/format-data.ts
@@ -90,6 +90,17 @@ export function formatParams(data: INodeData): {
taskParams.taskManager = data.taskManager
taskParams.parallelism = data.parallelism
}
+ if (data.taskType === 'FLINK_SGW') {
+ taskParams.flinkJdbcUrl = data.flinkJdbcUrl
+ taskParams.statementSeparator = data.statementSeparator
+ taskParams.maxPrintRows = data.maxPrintRows
+ taskParams.rawScriptType = data.rawScriptType
+ taskParams.initScriptType = data.initScriptType
+ taskParams.initScript =
+ data.initScriptType === 'FILE' ? '' : (data.initScript ?? '')
+ taskParams.rawScript =
+ data.rawScriptType === 'FILE' ? '' : (data.rawScript ?? '')
+ }
if (data.taskType === 'GRPC') {
taskParams.url = data.url
taskParams.grpcCredentialType = data.grpcCredentialType
@@ -508,13 +519,22 @@ export function formatParams(data: INodeData): {
item.value = item.value || ''
return item
}),
- initScript: data.initScript,
- rawScript: data.rawScript,
+ initScript:
+ data.initScriptType === 'FILE' ? '' : (data.initScript ?? ''),
+ rawScript:
+ data.rawScriptType === 'FILE' ? '' : (data.rawScript ?? ''),
resourceList: data.resourceList?.length
? data.resourceList.map((fullName: string) => ({
resourceName: `${fullName}`
}))
: [],
+ initScriptType: data.initScriptType,
+ initScriptResourceList:
+ (data.initScriptResourceList as string[] | undefined)?.length
+ ? (data.initScriptResourceList as string[]).map((fullName) => ({
+ resourceName: `${fullName}`
+ }))
+ : [],
...taskParams
},
taskPriority: data.taskPriority,
@@ -547,7 +567,12 @@ export function formatModel(data: ITaskData) {
'timeoutNotifyStrategy',
'taskParams'
]),
- ...omit(data.taskParams, ['resourceList', 'mainJar', 'localParams']),
+ ...omit(data.taskParams, [
+ 'resourceList',
+ 'mainJar',
+ 'localParams',
+ 'initScriptResourceList'
+ ]),
environmentCode: data.environmentCode === -1 ? null : data.environmentCode,
timeoutFlag: data.timeoutFlag === 'OPEN',
timeoutNotifyStrategy: data.timeoutNotifyStrategy
@@ -564,6 +589,12 @@ export function formatModel(data: ITaskData) {
(item: { resourceName: string }) => `${item.resourceName}`
)
}
+ if (data.taskParams?.initScriptResourceList) {
+ (params as INodeData).initScriptResourceList =
+ data.taskParams.initScriptResourceList.map(
+ (item: { resourceName: string }) => `${item.resourceName}`
+ )
+ }
if (data.taskParams?.mainJar) {
params.mainJar = data.taskParams?.mainJar.resourceName
}
diff --git a/dolphinscheduler-ui/src/views/projects/task/components/node/tasks/index.ts b/dolphinscheduler-ui/src/views/projects/task/components/node/tasks/index.ts
index 89fa49e17b4a..984ba635f060 100644
--- a/dolphinscheduler-ui/src/views/projects/task/components/node/tasks/index.ts
+++ b/dolphinscheduler-ui/src/views/projects/task/components/node/tasks/index.ts
@@ -52,6 +52,7 @@ import { useLinkis } from './use-linkis'
import { useDataFactory } from './use-data-factory'
import { useRemoteShell } from './use-remote-shell'
import { useAliyunServerlessSpark } from './use-aliyun-serverless-spark'
+import { useFlinkSqlGateway } from './use-flink-sqlgateway'
export default {
SHELL: useShell,
@@ -90,5 +91,6 @@ export default {
LINKIS: useLinkis,
DATA_FACTORY: useDataFactory,
REMOTESHELL: useRemoteShell,
- ALIYUN_SERVERLESS_SPARK: useAliyunServerlessSpark
+ ALIYUN_SERVERLESS_SPARK: useAliyunServerlessSpark,
+ FLINK_SGW: useFlinkSqlGateway
}
diff --git a/dolphinscheduler-ui/src/views/projects/task/components/node/tasks/use-flink-sqlgateway.ts b/dolphinscheduler-ui/src/views/projects/task/components/node/tasks/use-flink-sqlgateway.ts
new file mode 100644
index 000000000000..17c4fc892e1c
--- /dev/null
+++ b/dolphinscheduler-ui/src/views/projects/task/components/node/tasks/use-flink-sqlgateway.ts
@@ -0,0 +1,54 @@
+import { reactive } from 'vue'
+import * as Fields from '../fields/index'
+import type { IJsonItem, INodeData, ITaskData } from '../types'
+
+export function useFlinkSqlGateway(params: any) {
+ const { projectCode, from = 0, readonly, data } = params
+
+ const model = reactive({
+ taskType: 'FLINK_SGW',
+ name: '',
+ flag: 'YES',
+ description: '',
+ timeoutFlag: false,
+ localParams: [],
+ environmentCode: null,
+ failRetryInterval: 1,
+ failRetryTimes: 0,
+ workerGroup: 'default',
+ delayTime: 0,
+ timeout: 30,
+ timeoutNotifyStrategy: ['WARN'],
+
+ // --- FLINK_SGW custom fields ---
+ flinkJdbcUrl: 'jdbc:flink://host:port',
+ rawScriptType: 'FILE',
+ initScriptType: 'FILE',
+ initScript: '',
+ rawScript: '',
+ resourceList: [],
+ initScriptResourceList: [],
+ statementSeparator: ';',
+ maxPrintRows: 0,
+ jdbcProperties: {}
+ })
+
+ return {
+ json: [
+ Fields.useName(from),
+ ...Fields.useTaskDefinition({ projectCode, from, readonly, data, model }),
+ Fields.useRunFlag(),
+ Fields.useDescription(),
+ Fields.useTaskPriority(),
+ Fields.useWorkerGroup(projectCode),
+ Fields.useEnvironmentName(model, !data?.id),
+ ...Fields.useTaskGroup(model, projectCode),
+ ...Fields.useFailed(),
+ Fields.useDelayTime(model),
+ ...Fields.useTimeoutAlarm(model),
+ ...Fields.useFlinkSqlGateway(model),
+ Fields.usePreTasks()
+ ] as IJsonItem[],
+ model
+ }
+}
diff --git a/dolphinscheduler-ui/src/views/projects/task/components/node/types.ts b/dolphinscheduler-ui/src/views/projects/task/components/node/types.ts
index 49d88de66920..c031fabb14ff 100644
--- a/dolphinscheduler-ui/src/views/projects/task/components/node/types.ts
+++ b/dolphinscheduler-ui/src/views/projects/task/components/node/types.ts
@@ -480,12 +480,20 @@ interface ITaskParams {
yarnQueue?: string
awsRegion?: string
kubeConfig?: string
+ flinkJdbcUrl?: string
+ rawScriptType?: 'SCRIPT' | 'FILE'
+ initScriptType?: 'SCRIPT' | 'FILE'
+ initScriptResourceList?: ISourceItem[]
+ statementSeparator?: string
+ maxPrintRows?: number
+ jdbcProperties?: Record
}
interface INodeData
extends Omit<
ITaskParams,
| 'resourceList'
+ | 'initScriptResourceList'
| 'mainJar'
| 'targetParams'
| 'sourceParams'
@@ -522,6 +530,7 @@ interface INodeData
preTaskOptions?: []
postTaskOptions?: []
resourceList?: string[]
+ initScriptResourceList?: string[]
mainJar?: string
timeoutSetting?: boolean
isCustomTask?: boolean
diff --git a/dolphinscheduler-ui/src/views/projects/task/constants/task-type.ts b/dolphinscheduler-ui/src/views/projects/task/constants/task-type.ts
index d0eb36b277a8..afd2040284e6 100644
--- a/dolphinscheduler-ui/src/views/projects/task/constants/task-type.ts
+++ b/dolphinscheduler-ui/src/views/projects/task/constants/task-type.ts
@@ -52,6 +52,7 @@ export type TaskType =
| 'DATA_FACTORY'
| 'REMOTESHELL'
| 'ALIYUN_SERVERLESS_SPARK'
+ | 'FLINK_SGW'
export type TaskExecuteType = 'STREAM' | 'BATCH'
@@ -191,6 +192,11 @@ export const TASK_TYPES_MAP = {
ALIYUN_SERVERLESS_SPARK: {
alias: 'ALIYUN_SERVERLESS_SPARK',
helperLinkDisable: true
+ },
+ FLINK_SGW: {
+ alias: 'FLINK_SGW',
+ helperLinkDisable: true,
+ taskExecuteType: 'BATCH'
}
} as {
[key in TaskType]: {
diff --git a/dolphinscheduler-ui/src/views/projects/workflow/components/dag/dag.module.scss b/dolphinscheduler-ui/src/views/projects/workflow/components/dag/dag.module.scss
index 809bc6fae3cf..cc61323ff8b9 100644
--- a/dolphinscheduler-ui/src/views/projects/workflow/components/dag/dag.module.scss
+++ b/dolphinscheduler-ui/src/views/projects/workflow/components/dag/dag.module.scss
@@ -114,6 +114,7 @@ $bgLight: #ffffff;
background-image: url('/images/task-icons/sql.png');
}
&.icon-flink,
+ &.icon-flink_sgw,
&.icon-flink_stream {
background-image: url('/images/task-icons/flink.png');
}
@@ -224,6 +225,7 @@ $bgLight: #ffffff;
background-image: url('/images/task-icons/sql_hover.png');
}
&.icon-flink,
+ &.icon-flink_sgw,
&.icon-flink_stream {
background-image: url('/images/task-icons/flink_hover.png');
}
diff --git a/dolphinscheduler-ui/src/views/projects/workflow/components/dag/use-cell-active.ts b/dolphinscheduler-ui/src/views/projects/workflow/components/dag/use-cell-active.ts
index 03a19a563d02..61736064ec69 100644
--- a/dolphinscheduler-ui/src/views/projects/workflow/components/dag/use-cell-active.ts
+++ b/dolphinscheduler-ui/src/views/projects/workflow/components/dag/use-cell-active.ts
@@ -90,8 +90,9 @@ export function useCellActive(options: Options) {
let portAttrs = null
if (isHover || isSelected) {
- img = `${import.meta.env.BASE_URL}images/task-icons/${(node.data
- .taskType !== 'FLINK_STREAM'
+ img = `${import.meta.env.BASE_URL}images/task-icons/${(
+ (node.data.taskType !== 'FLINK_STREAM' &&
+ node.data.taskType !== 'FLINK_SGW')
? node.data.taskType
: 'FLINK'
).toLocaleLowerCase()}_hover.png`
@@ -103,8 +104,9 @@ export function useCellActive(options: Options) {
portAttrs = _.merge(portDefault, portSelected)
}
} else {
- img = `${import.meta.env.BASE_URL}images/task-icons/${(node.data
- .taskType !== 'FLINK_STREAM'
+ img = `${import.meta.env.BASE_URL}images/task-icons/${(
+ (node.data.taskType !== 'FLINK_STREAM' &&
+ node.data.taskType !== 'FLINK_SGW' )
? node.data.taskType
: 'FLINK'
).toLocaleLowerCase()}.png`
diff --git a/dolphinscheduler-ui/src/views/projects/workflow/components/dag/use-custom-cell-builder.ts b/dolphinscheduler-ui/src/views/projects/workflow/components/dag/use-custom-cell-builder.ts
index c9ca1a1277a7..4ceceb77f07a 100644
--- a/dolphinscheduler-ui/src/views/projects/workflow/components/dag/use-custom-cell-builder.ts
+++ b/dolphinscheduler-ui/src/views/projects/workflow/components/dag/use-custom-cell-builder.ts
@@ -94,7 +94,9 @@ export function useCustomCellBuilder() {
// Use href instead of xlink:href, you may lose the icon when downloadPNG
'xlink:href': `${
import.meta.env.BASE_URL
- }images/task-icons/${(type !== ('FLINK_STREAM' as TaskType)
+ }images/task-icons/${(
+ (type !== ('FLINK_STREAM' as TaskType) &&
+ type !== ('FLINK_SGW' as TaskType))
? type
: 'FLINK'
).toLocaleLowerCase()}.png`