|
@@ -18,7 +18,9 @@ package org.apache.dolphinscheduler.server.worker.task.sql;
|
|
|
|
|
|
import com.fasterxml.jackson.databind.node.ArrayNode;
|
|
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
|
|
+
|
|
|
import org.apache.commons.lang.StringUtils;
|
|
|
+
|
|
|
import org.apache.dolphinscheduler.alert.utils.MailUtils;
|
|
|
import org.apache.dolphinscheduler.common.Constants;
|
|
|
import org.apache.dolphinscheduler.common.enums.*;
|
|
@@ -41,6 +43,7 @@ import org.apache.dolphinscheduler.server.utils.ParamUtils;
|
|
|
import org.apache.dolphinscheduler.server.utils.UDFUtils;
|
|
|
import org.apache.dolphinscheduler.server.worker.task.AbstractTask;
|
|
|
import org.apache.dolphinscheduler.service.bean.SpringApplicationContext;
|
|
|
+
|
|
|
import org.slf4j.Logger;
|
|
|
|
|
|
import java.sql.*;
|
|
@@ -51,17 +54,18 @@ import java.util.stream.Collectors;
|
|
|
|
|
|
import static org.apache.dolphinscheduler.common.Constants.*;
|
|
|
import static org.apache.dolphinscheduler.common.enums.DbType.HIVE;
|
|
|
+
|
|
|
/**
|
|
|
* sql task
|
|
|
*/
|
|
|
public class SqlTask extends AbstractTask {
|
|
|
|
|
|
/**
|
|
|
- * sql parameters
|
|
|
+ * sql parameters
|
|
|
*/
|
|
|
private SqlParameters sqlParameters;
|
|
|
/**
|
|
|
- * alert dao
|
|
|
+ * alert dao
|
|
|
*/
|
|
|
private AlertDao alertDao;
|
|
|
/**
|
|
@@ -148,10 +152,11 @@ public class SqlTask extends AbstractTask {
|
|
|
|
|
|
/**
|
|
|
* ready to execute SQL and parameter entity Map
|
|
|
+ *
|
|
|
* @return SqlBinds
|
|
|
*/
|
|
|
private SqlBinds getSqlAndSqlParamsMap(String sql) {
|
|
|
- Map<Integer,Property> sqlParamsMap = new HashMap<>();
|
|
|
+ Map<Integer, Property> sqlParamsMap = new HashMap<>();
|
|
|
StringBuilder sqlBuilder = new StringBuilder();
|
|
|
|
|
|
// find process instance by task id
|
|
@@ -164,25 +169,27 @@ public class SqlTask extends AbstractTask {
|
|
|
taskExecutionContext.getScheduleTime());
|
|
|
|
|
|
// spell SQL according to the final user-defined variable
|
|
|
- if(paramsMap == null){
|
|
|
+ if (paramsMap == null) {
|
|
|
sqlBuilder.append(sql);
|
|
|
return new SqlBinds(sqlBuilder.toString(), sqlParamsMap);
|
|
|
}
|
|
|
|
|
|
- if (StringUtils.isNotEmpty(sqlParameters.getTitle())){
|
|
|
+ if (StringUtils.isNotEmpty(sqlParameters.getTitle())) {
|
|
|
String title = ParameterUtils.convertParameterPlaceholders(sqlParameters.getTitle(),
|
|
|
ParamUtils.convert(paramsMap));
|
|
|
- logger.info("SQL title : {}",title);
|
|
|
+ logger.info("SQL title : {}", title);
|
|
|
sqlParameters.setTitle(title);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
//new
|
|
|
//replace variable TIME with $[YYYYmmddd...] in sql when history run job and batch complement job
|
|
|
sql = ParameterUtils.replaceScheduleTime(sql, taskExecutionContext.getScheduleTime());
|
|
|
// special characters need to be escaped, ${} needs to be escaped
|
|
|
String rgex = "['\"]*\\$\\{(.*?)\\}['\"]*";
|
|
|
setSqlParamsMap(sql, rgex, sqlParamsMap, paramsMap);
|
|
|
-
|
|
|
+ //Replace the original value in sql !{...} ,Does not participate in precompilation
|
|
|
+ String rgexo = "['\"]*\\!\\{(.*?)\\}['\"]*";
|
|
|
+ sql = replaceOriginalValue(sql, rgexo, paramsMap);
|
|
|
// replace the ${} of the SQL statement with the Placeholder
|
|
|
String formatSql = sql.replaceAll(rgex, "?");
|
|
|
sqlBuilder.append(formatSql);
|
|
@@ -192,6 +199,20 @@ public class SqlTask extends AbstractTask {
|
|
|
return new SqlBinds(sqlBuilder.toString(), sqlParamsMap);
|
|
|
}
|
|
|
|
|
|
+ public String replaceOriginalValue(String content, String rgex, Map<String, Property> sqlParamsMap) {
|
|
|
+ Pattern pattern = Pattern.compile(rgex);
|
|
|
+ while (true) {
|
|
|
+ Matcher m = pattern.matcher(content);
|
|
|
+ if (!m.find()) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ String paramName = m.group(1);
|
|
|
+ String paramValue = sqlParamsMap.get(paramName).getValue();
|
|
|
+ content = m.replaceFirst(paramValue);
|
|
|
+ }
|
|
|
+ return content;
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
public AbstractParameters getParameters() {
|
|
|
return this.sqlParameters;
|
|
@@ -199,15 +220,16 @@ public class SqlTask extends AbstractTask {
|
|
|
|
|
|
/**
|
|
|
* execute function and sql
|
|
|
- * @param mainSqlBinds main sql binds
|
|
|
- * @param preStatementsBinds pre statements binds
|
|
|
- * @param postStatementsBinds post statements binds
|
|
|
- * @param createFuncs create functions
|
|
|
+ *
|
|
|
+ * @param mainSqlBinds main sql binds
|
|
|
+ * @param preStatementsBinds pre statements binds
|
|
|
+ * @param postStatementsBinds post statements binds
|
|
|
+ * @param createFuncs create functions
|
|
|
*/
|
|
|
public void executeFuncAndSql(SqlBinds mainSqlBinds,
|
|
|
- List<SqlBinds> preStatementsBinds,
|
|
|
- List<SqlBinds> postStatementsBinds,
|
|
|
- List<String> createFuncs){
|
|
|
+ List<SqlBinds> preStatementsBinds,
|
|
|
+ List<SqlBinds> postStatementsBinds,
|
|
|
+ List<String> createFuncs) {
|
|
|
Connection connection = null;
|
|
|
PreparedStatement stmt = null;
|
|
|
ResultSet resultSet = null;
|
|
@@ -218,11 +240,11 @@ public class SqlTask extends AbstractTask {
|
|
|
connection = createConnection();
|
|
|
// create temp function
|
|
|
if (CollectionUtils.isNotEmpty(createFuncs)) {
|
|
|
- createTempFunction(connection,createFuncs);
|
|
|
+ createTempFunction(connection, createFuncs);
|
|
|
}
|
|
|
|
|
|
// pre sql
|
|
|
- preSql(connection,preStatementsBinds);
|
|
|
+ preSql(connection, preStatementsBinds);
|
|
|
stmt = prepareStatementAndBind(connection, mainSqlBinds);
|
|
|
|
|
|
// decide whether to executeQuery or executeUpdate based on sqlType
|
|
@@ -236,13 +258,13 @@ public class SqlTask extends AbstractTask {
|
|
|
stmt.executeUpdate();
|
|
|
}
|
|
|
|
|
|
- postSql(connection,postStatementsBinds);
|
|
|
+ postSql(connection, postStatementsBinds);
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
- logger.error("execute sql error",e);
|
|
|
+ logger.error("execute sql error", e);
|
|
|
throw new RuntimeException("execute sql error");
|
|
|
} finally {
|
|
|
- close(resultSet,stmt,connection);
|
|
|
+ close(resultSet, stmt, connection);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -252,7 +274,7 @@ public class SqlTask extends AbstractTask {
|
|
|
* @param resultSet resultSet
|
|
|
* @throws Exception Exception
|
|
|
*/
|
|
|
- private void resultProcess(ResultSet resultSet) throws Exception{
|
|
|
+ private void resultProcess(ResultSet resultSet) throws Exception {
|
|
|
ArrayNode resultJSONArray = JSONUtils.createArrayNode();
|
|
|
ResultSetMetaData md = resultSet.getMetaData();
|
|
|
int num = md.getColumnCount();
|
|
@@ -271,22 +293,22 @@ public class SqlTask extends AbstractTask {
|
|
|
logger.debug("execute sql : {}", result);
|
|
|
|
|
|
sendAttachment(StringUtils.isNotEmpty(sqlParameters.getTitle()) ?
|
|
|
- sqlParameters.getTitle(): taskExecutionContext.getTaskName() + " query result sets",
|
|
|
+ sqlParameters.getTitle() : taskExecutionContext.getTaskName() + " query result sets",
|
|
|
JSONUtils.toJsonString(resultJSONArray));
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * pre sql
|
|
|
+ * pre sql
|
|
|
*
|
|
|
* @param connection connection
|
|
|
* @param preStatementsBinds preStatementsBinds
|
|
|
*/
|
|
|
private void preSql(Connection connection,
|
|
|
- List<SqlBinds> preStatementsBinds) throws Exception{
|
|
|
- for (SqlBinds sqlBind: preStatementsBinds) {
|
|
|
- try (PreparedStatement pstmt = prepareStatementAndBind(connection, sqlBind)){
|
|
|
+ List<SqlBinds> preStatementsBinds) throws Exception {
|
|
|
+ for (SqlBinds sqlBind : preStatementsBinds) {
|
|
|
+ try (PreparedStatement pstmt = prepareStatementAndBind(connection, sqlBind)) {
|
|
|
int result = pstmt.executeUpdate();
|
|
|
- logger.info("pre statement execute result: {}, for sql: {}",result,sqlBind.getSql());
|
|
|
+ logger.info("pre statement execute result: {}, for sql: {}", result, sqlBind.getSql());
|
|
|
|
|
|
}
|
|
|
}
|
|
@@ -297,26 +319,25 @@ public class SqlTask extends AbstractTask {
|
|
|
*
|
|
|
* @param connection connection
|
|
|
* @param postStatementsBinds postStatementsBinds
|
|
|
- * @throws Exception
|
|
|
*/
|
|
|
private void postSql(Connection connection,
|
|
|
- List<SqlBinds> postStatementsBinds) throws Exception{
|
|
|
- for (SqlBinds sqlBind: postStatementsBinds) {
|
|
|
- try (PreparedStatement pstmt = prepareStatementAndBind(connection, sqlBind)){
|
|
|
+ List<SqlBinds> postStatementsBinds) throws Exception {
|
|
|
+ for (SqlBinds sqlBind : postStatementsBinds) {
|
|
|
+ try (PreparedStatement pstmt = prepareStatementAndBind(connection, sqlBind)) {
|
|
|
int result = pstmt.executeUpdate();
|
|
|
- logger.info("post statement execute result: {},for sql: {}",result,sqlBind.getSql());
|
|
|
+ logger.info("post statement execute result: {},for sql: {}", result, sqlBind.getSql());
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
/**
|
|
|
* create temp function
|
|
|
*
|
|
|
* @param connection connection
|
|
|
* @param createFuncs createFuncs
|
|
|
- * @throws Exception
|
|
|
*/
|
|
|
private void createTempFunction(Connection connection,
|
|
|
- List<String> createFuncs) throws Exception{
|
|
|
+ List<String> createFuncs) throws Exception {
|
|
|
try (Statement funcStmt = connection.createStatement()) {
|
|
|
for (String createFunc : createFuncs) {
|
|
|
logger.info("hive create function sql: {}", createFunc);
|
|
@@ -324,14 +345,14 @@ public class SqlTask extends AbstractTask {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
* create connection
|
|
|
*
|
|
|
* @return connection
|
|
|
* @throws Exception Exception
|
|
|
*/
|
|
|
- private Connection createConnection() throws Exception{
|
|
|
+ private Connection createConnection() throws Exception {
|
|
|
// if hive , load connection params if exists
|
|
|
Connection connection = null;
|
|
|
if (HIVE == DbType.valueOf(sqlParameters.getType())) {
|
|
@@ -345,7 +366,7 @@ public class SqlTask extends AbstractTask {
|
|
|
|
|
|
connection = DriverManager.getConnection(baseDataSource.getJdbcUrl(),
|
|
|
paramProp);
|
|
|
- }else{
|
|
|
+ } else {
|
|
|
connection = DriverManager.getConnection(baseDataSource.getJdbcUrl(),
|
|
|
baseDataSource.getUser(),
|
|
|
baseDataSource.getPassword());
|
|
@@ -354,7 +375,7 @@ public class SqlTask extends AbstractTask {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * close jdbc resource
|
|
|
+ * close jdbc resource
|
|
|
*
|
|
|
* @param resultSet resultSet
|
|
|
* @param pstmt pstmt
|
|
@@ -362,36 +383,37 @@ public class SqlTask extends AbstractTask {
|
|
|
*/
|
|
|
private void close(ResultSet resultSet,
|
|
|
PreparedStatement pstmt,
|
|
|
- Connection connection){
|
|
|
- if (resultSet != null){
|
|
|
+ Connection connection) {
|
|
|
+ if (resultSet != null) {
|
|
|
try {
|
|
|
resultSet.close();
|
|
|
} catch (SQLException e) {
|
|
|
- logger.error("close result set error : {}",e.getMessage(),e);
|
|
|
+ logger.error("close result set error : {}", e.getMessage(), e);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (pstmt != null){
|
|
|
+ if (pstmt != null) {
|
|
|
try {
|
|
|
pstmt.close();
|
|
|
} catch (SQLException e) {
|
|
|
- logger.error("close prepared statement error : {}",e.getMessage(),e);
|
|
|
+ logger.error("close prepared statement error : {}", e.getMessage(), e);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (connection != null){
|
|
|
+ if (connection != null) {
|
|
|
try {
|
|
|
connection.close();
|
|
|
} catch (SQLException e) {
|
|
|
- logger.error("close connection error : {}",e.getMessage(),e);
|
|
|
+ logger.error("close connection error : {}", e.getMessage(), e);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* preparedStatement bind
|
|
|
+ *
|
|
|
* @param connection connection
|
|
|
- * @param sqlBinds sqlBinds
|
|
|
+ * @param sqlBinds sqlBinds
|
|
|
* @return PreparedStatement
|
|
|
* @throws Exception Exception
|
|
|
*/
|
|
@@ -400,11 +422,11 @@ public class SqlTask extends AbstractTask {
|
|
|
boolean timeoutFlag = TaskTimeoutStrategy.of(taskExecutionContext.getTaskTimeoutStrategy()) == TaskTimeoutStrategy.FAILED ||
|
|
|
TaskTimeoutStrategy.of(taskExecutionContext.getTaskTimeoutStrategy()) == TaskTimeoutStrategy.WARNFAILED;
|
|
|
PreparedStatement stmt = connection.prepareStatement(sqlBinds.getSql());
|
|
|
- if(timeoutFlag){
|
|
|
+ if (timeoutFlag) {
|
|
|
stmt.setQueryTimeout(taskExecutionContext.getTaskTimeout());
|
|
|
}
|
|
|
Map<Integer, Property> params = sqlBinds.getParamsMap();
|
|
|
- if(params != null) {
|
|
|
+ if (params != null) {
|
|
|
for (Map.Entry<Integer, Property> entry : params.entrySet()) {
|
|
|
Property prop = entry.getValue();
|
|
|
ParameterUtils.setInParameter(entry.getKey(), stmt, prop.getType(), prop.getValue());
|
|
@@ -416,23 +438,24 @@ public class SqlTask extends AbstractTask {
|
|
|
|
|
|
/**
|
|
|
* send mail as an attachment
|
|
|
- * @param title title
|
|
|
- * @param content content
|
|
|
+ *
|
|
|
+ * @param title title
|
|
|
+ * @param content content
|
|
|
*/
|
|
|
- public void sendAttachment(String title,String content){
|
|
|
+ public void sendAttachment(String title, String content) {
|
|
|
|
|
|
List<User> users = alertDao.queryUserByAlertGroupId(taskExecutionContext.getSqlTaskExecutionContext().getWarningGroupId());
|
|
|
|
|
|
// receiving group list
|
|
|
List<String> receiversList = new ArrayList<>();
|
|
|
- for(User user:users){
|
|
|
+ for (User user : users) {
|
|
|
receiversList.add(user.getEmail().trim());
|
|
|
}
|
|
|
// custom receiver
|
|
|
String receivers = sqlParameters.getReceivers();
|
|
|
- if (StringUtils.isNotEmpty(receivers)){
|
|
|
+ if (StringUtils.isNotEmpty(receivers)) {
|
|
|
String[] splits = receivers.split(COMMA);
|
|
|
- for (String receiver : splits){
|
|
|
+ for (String receiver : splits) {
|
|
|
receiversList.add(receiver.trim());
|
|
|
}
|
|
|
}
|
|
@@ -441,60 +464,62 @@ public class SqlTask extends AbstractTask {
|
|
|
List<String> receiversCcList = new ArrayList<>();
|
|
|
// Custom Copier
|
|
|
String receiversCc = sqlParameters.getReceiversCc();
|
|
|
- if (StringUtils.isNotEmpty(receiversCc)){
|
|
|
+ if (StringUtils.isNotEmpty(receiversCc)) {
|
|
|
String[] splits = receiversCc.split(COMMA);
|
|
|
- for (String receiverCc : splits){
|
|
|
+ for (String receiverCc : splits) {
|
|
|
receiversCcList.add(receiverCc.trim());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- String showTypeName = sqlParameters.getShowType().replace(COMMA,"").trim();
|
|
|
- if(EnumUtils.isValidEnum(ShowType.class,showTypeName)){
|
|
|
+ String showTypeName = sqlParameters.getShowType().replace(COMMA, "").trim();
|
|
|
+ if (EnumUtils.isValidEnum(ShowType.class, showTypeName)) {
|
|
|
Map<String, Object> mailResult = MailUtils.sendMails(receiversList,
|
|
|
receiversCcList, title, content, ShowType.valueOf(showTypeName).getDescp());
|
|
|
- if(!(boolean) mailResult.get(STATUS)){
|
|
|
+ if (!(boolean) mailResult.get(STATUS)) {
|
|
|
throw new RuntimeException("send mail failed!");
|
|
|
}
|
|
|
- }else{
|
|
|
- logger.error("showType: {} is not valid " ,showTypeName);
|
|
|
- throw new RuntimeException(String.format("showType: %s is not valid ",showTypeName));
|
|
|
+ } else {
|
|
|
+ logger.error("showType: {} is not valid ", showTypeName);
|
|
|
+ throw new RuntimeException(String.format("showType: %s is not valid ", showTypeName));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* regular expressions match the contents between two specified strings
|
|
|
- * @param content content
|
|
|
- * @param rgex rgex
|
|
|
- * @param sqlParamsMap sql params map
|
|
|
- * @param paramsPropsMap params props map
|
|
|
+ *
|
|
|
+ * @param content content
|
|
|
+ * @param rgex rgex
|
|
|
+ * @param sqlParamsMap sql params map
|
|
|
+ * @param paramsPropsMap params props map
|
|
|
*/
|
|
|
- public void setSqlParamsMap(String content, String rgex, Map<Integer,Property> sqlParamsMap, Map<String,Property> paramsPropsMap){
|
|
|
+ public void setSqlParamsMap(String content, String rgex, Map<Integer, Property> sqlParamsMap, Map<String, Property> paramsPropsMap) {
|
|
|
Pattern pattern = Pattern.compile(rgex);
|
|
|
Matcher m = pattern.matcher(content);
|
|
|
int index = 1;
|
|
|
while (m.find()) {
|
|
|
|
|
|
String paramName = m.group(1);
|
|
|
- Property prop = paramsPropsMap.get(paramName);
|
|
|
+ Property prop = paramsPropsMap.get(paramName);
|
|
|
|
|
|
- sqlParamsMap.put(index,prop);
|
|
|
- index ++;
|
|
|
+ sqlParamsMap.put(index, prop);
|
|
|
+ index++;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* print replace sql
|
|
|
- * @param content content
|
|
|
- * @param formatSql format sql
|
|
|
- * @param rgex rgex
|
|
|
- * @param sqlParamsMap sql params map
|
|
|
+ *
|
|
|
+ * @param content content
|
|
|
+ * @param formatSql format sql
|
|
|
+ * @param rgex rgex
|
|
|
+ * @param sqlParamsMap sql params map
|
|
|
*/
|
|
|
- public void printReplacedSql(String content, String formatSql,String rgex, Map<Integer,Property> sqlParamsMap){
|
|
|
+ public void printReplacedSql(String content, String formatSql, String rgex, Map<Integer, Property> sqlParamsMap) {
|
|
|
//parameter print style
|
|
|
- logger.info("after replace sql , preparing : {}" , formatSql);
|
|
|
+ logger.info("after replace sql , preparing : {}", formatSql);
|
|
|
StringBuilder logPrint = new StringBuilder("replaced sql , parameters:");
|
|
|
- for(int i=1;i<=sqlParamsMap.size();i++){
|
|
|
- logPrint.append(sqlParamsMap.get(i).getValue()+"("+sqlParamsMap.get(i).getType()+")");
|
|
|
+ for (int i = 1; i <= sqlParamsMap.size(); i++) {
|
|
|
+ logPrint.append(sqlParamsMap.get(i).getValue() + "(" + sqlParamsMap.get(i).getType() + ")");
|
|
|
}
|
|
|
logger.info("Sql Params are {}", logPrint);
|
|
|
}
|