未验证 提交 67711442 编写于 作者: K kyoty 提交者: GitHub

[Improvement][SQL] Query return number In SQL should be configurable (#5632)

* [Improvement][SQL] Query return number should be configurable #5580

* Update SqlTaskTest.java

* Update sql.vue
上级 e2d6265e
...@@ -94,6 +94,16 @@ public class SqlParameters extends AbstractParameters { ...@@ -94,6 +94,16 @@ public class SqlParameters extends AbstractParameters {
*/ */
private String title; private String title;
private int limit;
public int getLimit() {
return limit;
}
public void setLimit(int limit) {
this.limit = limit;
}
public String getType() { public String getType() {
return type; return type;
} }
...@@ -217,6 +227,7 @@ public class SqlParameters extends AbstractParameters { ...@@ -217,6 +227,7 @@ public class SqlParameters extends AbstractParameters {
+ ", sqlType=" + sqlType + ", sqlType=" + sqlType
+ ", sendEmail=" + sendEmail + ", sendEmail=" + sendEmail
+ ", displayRows=" + displayRows + ", displayRows=" + displayRows
+ ", limit=" + limit
+ ", udfs='" + udfs + '\'' + ", udfs='" + udfs + '\''
+ ", showType='" + showType + '\'' + ", showType='" + showType + '\''
+ ", connParams='" + connParams + '\'' + ", connParams='" + connParams + '\''
......
...@@ -35,6 +35,7 @@ public class SqlParametersTest { ...@@ -35,6 +35,7 @@ public class SqlParametersTest {
private final String showType = "TABLE"; private final String showType = "TABLE";
private final String title = "sql test"; private final String title = "sql test";
private final int groupId = 0; private final int groupId = 0;
private final int limit = 0;
@Test @Test
public void testSqlParameters() { public void testSqlParameters() {
...@@ -51,6 +52,7 @@ public class SqlParametersTest { ...@@ -51,6 +52,7 @@ public class SqlParametersTest {
sqlParameters.setShowType(showType); sqlParameters.setShowType(showType);
sqlParameters.setTitle(title); sqlParameters.setTitle(title);
sqlParameters.setGroupId(groupId); sqlParameters.setGroupId(groupId);
sqlParameters.setLimit(limit);
Assert.assertEquals(type, sqlParameters.getType()); Assert.assertEquals(type, sqlParameters.getType());
Assert.assertEquals(sql, sqlParameters.getSql()); Assert.assertEquals(sql, sqlParameters.getSql());
...@@ -62,6 +64,7 @@ public class SqlParametersTest { ...@@ -62,6 +64,7 @@ public class SqlParametersTest {
Assert.assertEquals(showType, sqlParameters.getShowType()); Assert.assertEquals(showType, sqlParameters.getShowType());
Assert.assertEquals(title, sqlParameters.getTitle()); Assert.assertEquals(title, sqlParameters.getTitle());
Assert.assertEquals(groupId, sqlParameters.getGroupId()); Assert.assertEquals(groupId, sqlParameters.getGroupId());
Assert.assertEquals(limit, sqlParameters.getLimit());
Assert.assertTrue(sqlParameters.checkParameters()); Assert.assertTrue(sqlParameters.checkParameters());
} }
......
...@@ -86,12 +86,6 @@ public class SqlTask extends AbstractTask { ...@@ -86,12 +86,6 @@ public class SqlTask extends AbstractTask {
*/ */
private TaskExecutionContext taskExecutionContext; private TaskExecutionContext taskExecutionContext;
/**
* default query sql limit
*/
private static final int LIMIT = 10000;
private AlertClientService alertClientService; private AlertClientService alertClientService;
public SqlTask(TaskExecutionContext taskExecutionContext, Logger logger, AlertClientService alertClientService) { public SqlTask(TaskExecutionContext taskExecutionContext, Logger logger, AlertClientService alertClientService) {
...@@ -117,14 +111,16 @@ public class SqlTask extends AbstractTask { ...@@ -117,14 +111,16 @@ public class SqlTask extends AbstractTask {
Thread.currentThread().setName(threadLoggerInfoName); Thread.currentThread().setName(threadLoggerInfoName);
logger.info("Full sql parameters: {}", sqlParameters); logger.info("Full sql parameters: {}", sqlParameters);
logger.info("sql type : {}, datasource : {}, sql : {} , localParams : {},udfs : {},showType : {},connParams : {}", logger.info("sql type : {}, datasource : {}, sql : {} , localParams : {}, udfs : {},showType : {}, "
+ "connParams : {}, query max result limit : {}",
sqlParameters.getType(), sqlParameters.getType(),
sqlParameters.getDatasource(), sqlParameters.getDatasource(),
sqlParameters.getSql(), sqlParameters.getSql(),
sqlParameters.getLocalParams(), sqlParameters.getLocalParams(),
sqlParameters.getUdfs(), sqlParameters.getUdfs(),
sqlParameters.getShowType(), sqlParameters.getShowType(),
sqlParameters.getConnParams()); sqlParameters.getConnParams(),
sqlParameters.getLimit());
try { try {
SQLTaskExecutionContext sqlTaskExecutionContext = taskExecutionContext.getSqlTaskExecutionContext(); SQLTaskExecutionContext sqlTaskExecutionContext = taskExecutionContext.getSqlTaskExecutionContext();
...@@ -309,7 +305,7 @@ public class SqlTask extends AbstractTask { ...@@ -309,7 +305,7 @@ public class SqlTask extends AbstractTask {
int rowCount = 0; int rowCount = 0;
while (rowCount < LIMIT && resultSet.next()) { while (rowCount < sqlParameters.getLimit() && resultSet.next()) {
ObjectNode mapOfColValues = JSONUtils.createObjectNode(); ObjectNode mapOfColValues = JSONUtils.createObjectNode();
for (int i = 1; i <= num; i++) { for (int i = 1; i <= num; i++) {
mapOfColValues.set(md.getColumnLabel(i), JSONUtils.toJsonNode(resultSet.getObject(i))); mapOfColValues.set(md.getColumnLabel(i), JSONUtils.toJsonNode(resultSet.getObject(i)));
...@@ -326,12 +322,11 @@ public class SqlTask extends AbstractTask { ...@@ -326,12 +322,11 @@ public class SqlTask extends AbstractTask {
logger.info("row {} : {}", i + 1, row); logger.info("row {} : {}", i + 1, row);
} }
} }
String result = JSONUtils.toJsonString(resultJSONArray); String result = JSONUtils.toJsonString(resultJSONArray);
if (sqlParameters.getSendEmail() == null || sqlParameters.getSendEmail()) { if (sqlParameters.getSendEmail() == null || sqlParameters.getSendEmail()) {
sendAttachment(sqlParameters.getGroupId(), StringUtils.isNotEmpty(sqlParameters.getTitle()) sendAttachment(sqlParameters.getGroupId(), StringUtils.isNotEmpty(sqlParameters.getTitle())
? sqlParameters.getTitle() ? sqlParameters.getTitle()
: taskExecutionContext.getTaskName() + " query result sets", result); : taskExecutionContext.getTaskName() + " query result sets", result);
} }
logger.debug("execute sql result : {}", result); logger.debug("execute sql result : {}", result);
return result; return result;
......
...@@ -19,6 +19,7 @@ package org.apache.dolphinscheduler.server.worker.task.sql; ...@@ -19,6 +19,7 @@ package org.apache.dolphinscheduler.server.worker.task.sql;
import org.apache.dolphinscheduler.common.Constants; import org.apache.dolphinscheduler.common.Constants;
import org.apache.dolphinscheduler.common.datasource.DatasourceUtil; import org.apache.dolphinscheduler.common.datasource.DatasourceUtil;
import org.apache.dolphinscheduler.common.task.sql.SqlParameters;
import org.apache.dolphinscheduler.common.utils.ParameterUtils; import org.apache.dolphinscheduler.common.utils.ParameterUtils;
import org.apache.dolphinscheduler.dao.AlertDao; import org.apache.dolphinscheduler.dao.AlertDao;
import org.apache.dolphinscheduler.remote.command.alert.AlertSendResponseCommand; import org.apache.dolphinscheduler.remote.command.alert.AlertSendResponseCommand;
...@@ -148,4 +149,60 @@ public class SqlTaskTest { ...@@ -148,4 +149,60 @@ public class SqlTaskTest {
String result = Whitebox.invokeMethod(sqlTask, "resultProcess", resultSet); String result = Whitebox.invokeMethod(sqlTask, "resultProcess", resultSet);
Assert.assertNotNull(result); Assert.assertNotNull(result);
} }
@Test
public void testQueryBySQLUsingLimit() throws Exception {
TaskExecutionContext localTaskExecutionContext;
TaskProps props = new TaskProps();
props.setExecutePath("/tmp");
props.setTaskAppId(String.valueOf(System.currentTimeMillis()));
props.setTaskInstanceId(1);
props.setTenantCode("1");
props.setEnvFile(".dolphinscheduler_env.sh");
props.setTaskStartTime(new Date());
props.setTaskTimeout(0);
props.setTaskParams(
"{\"localParams\":[{\"prop\":\"ret\", \"direct\":\"OUT\", \"type\":\"VARCHAR\", \"value\":\"\"}],"
+ "\"type\":\"POSTGRESQL\",\"datasource\":1,\"sql\":\"SELECT * FROM tb_1\","
+ "\"sqlType\":0, \"limit\":1, \"sendEmail\":\"false\"}");
localTaskExecutionContext = PowerMockito.mock(TaskExecutionContext.class);
PowerMockito.when(localTaskExecutionContext.getTaskParams()).thenReturn(props.getTaskParams());
PowerMockito.when(localTaskExecutionContext.getExecutePath()).thenReturn("/tmp");
PowerMockito.when(localTaskExecutionContext.getTaskAppId()).thenReturn("1");
PowerMockito.when(localTaskExecutionContext.getTenantCode()).thenReturn("root");
PowerMockito.when(localTaskExecutionContext.getStartTime()).thenReturn(new Date());
PowerMockito.when(localTaskExecutionContext.getTaskTimeout()).thenReturn(10000);
PowerMockito.when(localTaskExecutionContext.getLogPath()).thenReturn("/tmp/dx");
SQLTaskExecutionContext sqlTaskExecutionContext = new SQLTaskExecutionContext();
sqlTaskExecutionContext.setConnectionParams(CONNECTION_PARAMS);
PowerMockito.when(localTaskExecutionContext.getSqlTaskExecutionContext()).thenReturn(sqlTaskExecutionContext);
PowerMockito.mockStatic(SpringApplicationContext.class);
PowerMockito.when(SpringApplicationContext.getBean(Mockito.any())).thenReturn(new AlertDao());
AlertClientService localAlertClientService = PowerMockito.mock(AlertClientService.class);
SqlTask localSqlTask = new SqlTask(localTaskExecutionContext, logger, localAlertClientService);
localSqlTask.init();
ResultSet resultSet = PowerMockito.mock(ResultSet.class);
ResultSetMetaData mockResultMetaData = PowerMockito.mock(ResultSetMetaData.class);
PowerMockito.when(resultSet.getMetaData()).thenReturn(mockResultMetaData);
PowerMockito.when(mockResultMetaData.getColumnCount()).thenReturn(2);
PowerMockito.when(resultSet.next()).thenReturn(true);
PowerMockito.when(resultSet.getObject(Mockito.anyInt())).thenReturn(1);
PowerMockito.when(mockResultMetaData.getColumnLabel(Mockito.anyInt())).thenReturn("a");
AlertSendResponseCommand mockResponseCommand = PowerMockito.mock(AlertSendResponseCommand.class);
PowerMockito.when(mockResponseCommand.getResStatus()).thenReturn(true);
PowerMockito.when(localAlertClientService.sendAlert(Mockito.anyInt(), Mockito.anyString(), Mockito.anyString()))
.thenReturn(mockResponseCommand);
String result = Whitebox.invokeMethod(localSqlTask, "resultProcess", resultSet);
Assert.assertEquals(1, ((SqlParameters) localSqlTask.getParameters()).getLimit());
// In fact, the target table has 2 rows, as we set the limit to 1, if the limit works, the `resultProcess` method
// should return [{"a":1}] rather then [{"a":1},{"a":1}]
Assert.assertEquals("[{\"a\":1}]", result);
}
} }
...@@ -43,6 +43,13 @@ ...@@ -43,6 +43,13 @@
</div> </div>
</div> </div>
</m-list-box> </m-list-box>
<m-list-box v-show="sqlType === '0'">
<div slot="text"><strong class='requiredIcon'>*</strong>{{$t('Max Numbers Return')}}</div>
<div slot="content">
<el-input type="input" :disabled="isDetails" size="medium" v-model="limit" :placeholder="$t('Max Numbers Return placeholder')">
</el-input>
</div>
</m-list-box>
<template v-if="sqlType === '0' && sendEmail"> <template v-if="sqlType === '0' && sendEmail">
<m-list-box> <m-list-box>
<div slot="text"><strong class='requiredIcon'>*</strong>{{$t('Title')}}</div> <div slot="text"><strong class='requiredIcon'>*</strong>{{$t('Title')}}</div>
...@@ -178,6 +185,8 @@ ...@@ -178,6 +185,8 @@
sendEmail: false, sendEmail: false,
// Display rows // Display rows
displayRows: 10, displayRows: 10,
// Max returned rows
limit: 10000,
// Email title // Email title
title: '', title: '',
// Sql parameter // Sql parameter
...@@ -197,6 +206,13 @@ ...@@ -197,6 +206,13 @@
createNodeId: Number createNodeId: Number
}, },
methods: { methods: {
/**
* limit should't be empty;limit should be a non-negative number str;
* limit should be a number smaller or equal than Integer.MAX_VALUE in java.
*/
isLimitInvalid () {
return !this.limit || !/^(0|[1-9]\d*)$/.test(this.limit) || parseInt(this.limit, 10) > 2147483647
},
setEditorVal () { setEditorVal () {
this.item = editor.getValue() this.item = editor.getValue()
this.scriptBoxDialog = true this.scriptBoxDialog = true
...@@ -258,6 +274,10 @@ ...@@ -258,6 +274,10 @@
this.$message.warning(`${i18n.$t('Mail subject required')}`) this.$message.warning(`${i18n.$t('Mail subject required')}`)
return false return false
} }
if (this.sqlType === '0' && this.isLimitInvalid()) {
this.$message.warning(`${i18n.$t('Max Numbers Return required')}`)
return false
}
if (this.sqlType === '0' && this.sendEmail && (this.groupId === '' || this.groupId === null)) { if (this.sqlType === '0' && this.sendEmail && (this.groupId === '' || this.groupId === null)) {
this.$message.warning(`${i18n.$t('Alarm group required')}`) this.$message.warning(`${i18n.$t('Alarm group required')}`)
return false return false
...@@ -293,6 +313,7 @@ ...@@ -293,6 +313,7 @@
sqlType: this.sqlType, sqlType: this.sqlType,
sendEmail: this.sendEmail, sendEmail: this.sendEmail,
displayRows: this.displayRows, displayRows: this.displayRows,
limit: this.limit,
title: this.title, title: this.title,
groupId: this.groupId, groupId: this.groupId,
localParams: this.localParams, localParams: this.localParams,
...@@ -344,6 +365,7 @@ ...@@ -344,6 +365,7 @@
sqlType: this.sqlType, sqlType: this.sqlType,
sendEmail: this.sendEmail, sendEmail: this.sendEmail,
displayRows: this.displayRows, displayRows: this.displayRows,
limit: this.limit,
title: this.title, title: this.title,
groupId: this.groupId, groupId: this.groupId,
localParams: this.localParams, localParams: this.localParams,
...@@ -392,6 +414,7 @@ ...@@ -392,6 +414,7 @@
this.sqlType = o.params.sqlType this.sqlType = o.params.sqlType
this.sendEmail = o.params.sendEmail || false this.sendEmail = o.params.sendEmail || false
this.displayRows = o.params.displayRows || 10 this.displayRows = o.params.displayRows || 10
this.limit = o.params.limit || 10000
this.connParams = o.params.connParams || '' this.connParams = o.params.connParams || ''
this.localParams = o.params.localParams || [] this.localParams = o.params.localParams || []
this.preStatements = o.params.preStatements || [] this.preStatements = o.params.preStatements || []
...@@ -424,6 +447,7 @@ ...@@ -424,6 +447,7 @@
sqlType: this.sqlType, sqlType: this.sqlType,
sendEmail: this.sendEmail, sendEmail: this.sendEmail,
displayRows: this.displayRows, displayRows: this.displayRows,
limit: this.limit,
title: this.title, title: this.title,
groupId: this.groupId, groupId: this.groupId,
localParams: this.localParams, localParams: this.localParams,
......
...@@ -133,6 +133,9 @@ export default { ...@@ -133,6 +133,9 @@ export default {
'SQL Type': 'SQL Type', 'SQL Type': 'SQL Type',
'Send Email': 'Send Email', 'Send Email': 'Send Email',
'Log display': 'Log display', 'Log display': 'Log display',
'Max Numbers Return': 'Number of records to return',
'Max Numbers Return placeholder': 'Default is 10000, a large value may cause high pressure on the memory',
'Max Numbers Return required': 'Number of records to return parameter must be a number in the range of 0 - 2147483647',
'rows of result': 'rows of result', 'rows of result': 'rows of result',
Title: 'Title', Title: 'Title',
'Please enter the title of email': 'Please enter the title of email', 'Please enter the title of email': 'Please enter the title of email',
......
...@@ -134,6 +134,9 @@ export default { ...@@ -134,6 +134,9 @@ export default {
'Send Email': '发送邮件', 'Send Email': '发送邮件',
'Log display': '日志显示', 'Log display': '日志显示',
'rows of result': '行查询结果', 'rows of result': '行查询结果',
'Max Numbers Return': '返回的记录行数',
'Max Numbers Return placeholder': '默认值10000,如果值过大可能会对内存造成较大压力',
'Max Numbers Return required': '返回的记录行数值必须是一个在0-2147483647范围内的整数',
Title: '主题', Title: '主题',
'Please enter the title of email': '请输入邮件主题', 'Please enter the title of email': '请输入邮件主题',
Table: '表名', Table: '表名',
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册