Browse Source
* feature:data synchronization function * feature:data synchronization function * feature:data synchronization function * fix:add license * fix:resource close bug * fix:remove class author * fix:Improve test coverage * fix:add UT * fix:add UT * fix:data sync node renamed to datax * fix:add UT * fix: UT bug * fix:Optimize variable name * fix:pom * fix:Variable name error * fix:optimize the codepull/2/head
魔方不在手
5 years ago
committed by
GitHub
19 changed files with 1645 additions and 4 deletions
@ -0,0 +1,192 @@ |
|||||||
|
/* |
||||||
|
* 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.common.task.datax; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import org.apache.commons.lang.StringUtils; |
||||||
|
import org.apache.dolphinscheduler.common.task.AbstractParameters; |
||||||
|
|
||||||
|
/** |
||||||
|
* DataX parameter |
||||||
|
*/ |
||||||
|
public class DataxParameters extends AbstractParameters { |
||||||
|
|
||||||
|
/** |
||||||
|
* data source type,eg MYSQL, POSTGRES ... |
||||||
|
*/ |
||||||
|
private String dsType; |
||||||
|
|
||||||
|
/** |
||||||
|
* datasource id |
||||||
|
*/ |
||||||
|
private int dataSource; |
||||||
|
|
||||||
|
/** |
||||||
|
* data target type,eg MYSQL, POSTGRES ... |
||||||
|
*/ |
||||||
|
private String dtType; |
||||||
|
|
||||||
|
/** |
||||||
|
* datatarget id |
||||||
|
*/ |
||||||
|
private int dataTarget; |
||||||
|
|
||||||
|
/** |
||||||
|
* sql |
||||||
|
*/ |
||||||
|
private String sql; |
||||||
|
|
||||||
|
/** |
||||||
|
* target table |
||||||
|
*/ |
||||||
|
private String targetTable; |
||||||
|
|
||||||
|
/** |
||||||
|
* Pre Statements |
||||||
|
*/ |
||||||
|
private List<String> preStatements; |
||||||
|
|
||||||
|
/** |
||||||
|
* Post Statements |
||||||
|
*/ |
||||||
|
private List<String> postStatements; |
||||||
|
|
||||||
|
/** |
||||||
|
* speed byte num |
||||||
|
*/ |
||||||
|
private int jobSpeedByte; |
||||||
|
|
||||||
|
/** |
||||||
|
* speed record count |
||||||
|
*/ |
||||||
|
private int jobSpeedRecord; |
||||||
|
|
||||||
|
public String getDsType() { |
||||||
|
return dsType; |
||||||
|
} |
||||||
|
|
||||||
|
public void setDsType(String dsType) { |
||||||
|
this.dsType = dsType; |
||||||
|
} |
||||||
|
|
||||||
|
public int getDataSource() { |
||||||
|
return dataSource; |
||||||
|
} |
||||||
|
|
||||||
|
public void setDataSource(int dataSource) { |
||||||
|
this.dataSource = dataSource; |
||||||
|
} |
||||||
|
|
||||||
|
public String getDtType() { |
||||||
|
return dtType; |
||||||
|
} |
||||||
|
|
||||||
|
public void setDtType(String dtType) { |
||||||
|
this.dtType = dtType; |
||||||
|
} |
||||||
|
|
||||||
|
public int getDataTarget() { |
||||||
|
return dataTarget; |
||||||
|
} |
||||||
|
|
||||||
|
public void setDataTarget(int dataTarget) { |
||||||
|
this.dataTarget = dataTarget; |
||||||
|
} |
||||||
|
|
||||||
|
public String getSql() { |
||||||
|
return sql; |
||||||
|
} |
||||||
|
|
||||||
|
public void setSql(String sql) { |
||||||
|
this.sql = sql; |
||||||
|
} |
||||||
|
|
||||||
|
public String getTargetTable() { |
||||||
|
return targetTable; |
||||||
|
} |
||||||
|
|
||||||
|
public void setTargetTable(String targetTable) { |
||||||
|
this.targetTable = targetTable; |
||||||
|
} |
||||||
|
|
||||||
|
public List<String> getPreStatements() { |
||||||
|
return preStatements; |
||||||
|
} |
||||||
|
|
||||||
|
public void setPreStatements(List<String> preStatements) { |
||||||
|
this.preStatements = preStatements; |
||||||
|
} |
||||||
|
|
||||||
|
public List<String> getPostStatements() { |
||||||
|
return postStatements; |
||||||
|
} |
||||||
|
|
||||||
|
public void setPostStatements(List<String> postStatements) { |
||||||
|
this.postStatements = postStatements; |
||||||
|
} |
||||||
|
|
||||||
|
public int getJobSpeedByte() { |
||||||
|
return jobSpeedByte; |
||||||
|
} |
||||||
|
|
||||||
|
public void setJobSpeedByte(int jobSpeedByte) { |
||||||
|
this.jobSpeedByte = jobSpeedByte; |
||||||
|
} |
||||||
|
|
||||||
|
public int getJobSpeedRecord() { |
||||||
|
return jobSpeedRecord; |
||||||
|
} |
||||||
|
|
||||||
|
public void setJobSpeedRecord(int jobSpeedRecord) { |
||||||
|
this.jobSpeedRecord = jobSpeedRecord; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean checkParameters() { |
||||||
|
if (!(dataSource != 0 |
||||||
|
&& dataTarget != 0 |
||||||
|
&& StringUtils.isNotEmpty(sql) |
||||||
|
&& StringUtils.isNotEmpty(targetTable))) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<String> getResourceFilesList() { |
||||||
|
return new ArrayList<>(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
return "DataxParameters{" + |
||||||
|
"dsType='" + dsType + '\'' + |
||||||
|
", dataSource=" + dataSource + |
||||||
|
", dtType='" + dtType + '\'' + |
||||||
|
", dataTarget=" + dataTarget + |
||||||
|
", sql='" + sql + '\'' + |
||||||
|
", targetTable='" + targetTable + '\'' + |
||||||
|
", preStatements=" + preStatements + |
||||||
|
", postStatements=" + postStatements + |
||||||
|
", jobSpeedByte=" + jobSpeedByte + |
||||||
|
", jobSpeedRecord=" + jobSpeedRecord + |
||||||
|
'}'; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,129 @@ |
|||||||
|
/* |
||||||
|
* 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.server.utils; |
||||||
|
|
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.common.enums.DbType; |
||||||
|
|
||||||
|
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser; |
||||||
|
import com.alibaba.druid.sql.dialect.oracle.parser.OracleStatementParser; |
||||||
|
import com.alibaba.druid.sql.dialect.postgresql.parser.PGSQLStatementParser; |
||||||
|
import com.alibaba.druid.sql.dialect.sqlserver.parser.SQLServerStatementParser; |
||||||
|
import com.alibaba.druid.sql.parser.SQLStatementParser; |
||||||
|
|
||||||
|
|
||||||
|
public class DataxUtils { |
||||||
|
|
||||||
|
public static final String DATAX_READER_PLUGIN_MYSQL = "mysqlreader"; |
||||||
|
|
||||||
|
public static final String DATAX_READER_PLUGIN_POSTGRESQL = "postgresqlreader"; |
||||||
|
|
||||||
|
public static final String DATAX_READER_PLUGIN_ORACLE = "oraclereader"; |
||||||
|
|
||||||
|
public static final String DATAX_READER_PLUGIN_SQLSERVER = "sqlserverreader"; |
||||||
|
|
||||||
|
public static final String DATAX_WRITER_PLUGIN_MYSQL = "mysqlwriter"; |
||||||
|
|
||||||
|
public static final String DATAX_WRITER_PLUGIN_POSTGRESQL = "postgresqlwriter"; |
||||||
|
|
||||||
|
public static final String DATAX_WRITER_PLUGIN_ORACLE = "oraclewriter"; |
||||||
|
|
||||||
|
public static final String DATAX_WRITER_PLUGIN_SQLSERVER = "sqlserverwriter"; |
||||||
|
|
||||||
|
public static String getReaderPluginName(DbType dbType) { |
||||||
|
switch (dbType) { |
||||||
|
case MYSQL: |
||||||
|
return DATAX_READER_PLUGIN_MYSQL; |
||||||
|
case POSTGRESQL: |
||||||
|
return DATAX_READER_PLUGIN_POSTGRESQL; |
||||||
|
case ORACLE: |
||||||
|
return DATAX_READER_PLUGIN_ORACLE; |
||||||
|
case SQLSERVER: |
||||||
|
return DATAX_READER_PLUGIN_SQLSERVER; |
||||||
|
default: |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static String getWriterPluginName(DbType dbType) { |
||||||
|
switch (dbType) { |
||||||
|
case MYSQL: |
||||||
|
return DATAX_WRITER_PLUGIN_MYSQL; |
||||||
|
case POSTGRESQL: |
||||||
|
return DATAX_WRITER_PLUGIN_POSTGRESQL; |
||||||
|
case ORACLE: |
||||||
|
return DATAX_WRITER_PLUGIN_ORACLE; |
||||||
|
case SQLSERVER: |
||||||
|
return DATAX_WRITER_PLUGIN_SQLSERVER; |
||||||
|
default: |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static SQLStatementParser getSqlStatementParser(DbType dbType, String sql) { |
||||||
|
switch (dbType) { |
||||||
|
case MYSQL: |
||||||
|
return new MySqlStatementParser(sql); |
||||||
|
case POSTGRESQL: |
||||||
|
return new PGSQLStatementParser(sql); |
||||||
|
case ORACLE: |
||||||
|
return new OracleStatementParser(sql); |
||||||
|
case SQLSERVER: |
||||||
|
return new SQLServerStatementParser(sql); |
||||||
|
default: |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static String[] convertKeywordsColumns(DbType dbType, String[] columns) { |
||||||
|
if (columns == null) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
String[] toColumns = new String[columns.length]; |
||||||
|
for (int i = 0; i < columns.length; i++ ) { |
||||||
|
toColumns[i] = doConvertKeywordsColumn(dbType, columns[i]); |
||||||
|
} |
||||||
|
|
||||||
|
return toColumns; |
||||||
|
} |
||||||
|
|
||||||
|
public static String doConvertKeywordsColumn(DbType dbType, String column) { |
||||||
|
if (column == null) { |
||||||
|
return column; |
||||||
|
} |
||||||
|
|
||||||
|
column = column.trim(); |
||||||
|
column = column.replace("`", ""); |
||||||
|
column = column.replace("\"", ""); |
||||||
|
column = column.replace("'", ""); |
||||||
|
|
||||||
|
switch (dbType) { |
||||||
|
case MYSQL: |
||||||
|
return String.format("`%s`", column); |
||||||
|
case POSTGRESQL: |
||||||
|
return String.format("\"%s\"", column); |
||||||
|
case ORACLE: |
||||||
|
return String.format("\"%s\"", column); |
||||||
|
case SQLSERVER: |
||||||
|
return String.format("`%s`", column); |
||||||
|
default: |
||||||
|
return column; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,522 @@ |
|||||||
|
/* |
||||||
|
* 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.server.worker.task.datax; |
||||||
|
|
||||||
|
|
||||||
|
import java.io.File; |
||||||
|
import java.nio.charset.Charset; |
||||||
|
import java.nio.file.Files; |
||||||
|
import java.nio.file.Path; |
||||||
|
import java.nio.file.StandardOpenOption; |
||||||
|
import java.nio.file.attribute.FileAttribute; |
||||||
|
import java.nio.file.attribute.PosixFilePermission; |
||||||
|
import java.nio.file.attribute.PosixFilePermissions; |
||||||
|
import java.sql.Connection; |
||||||
|
import java.sql.DriverManager; |
||||||
|
import java.sql.PreparedStatement; |
||||||
|
import java.sql.ResultSet; |
||||||
|
import java.sql.ResultSetMetaData; |
||||||
|
import java.sql.SQLException; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
import org.apache.commons.io.FileUtils; |
||||||
|
import org.apache.dolphinscheduler.common.Constants; |
||||||
|
import org.apache.dolphinscheduler.common.enums.DbType; |
||||||
|
import org.apache.dolphinscheduler.common.job.db.BaseDataSource; |
||||||
|
import org.apache.dolphinscheduler.common.job.db.DataSourceFactory; |
||||||
|
import org.apache.dolphinscheduler.common.process.Property; |
||||||
|
import org.apache.dolphinscheduler.common.task.AbstractParameters; |
||||||
|
import org.apache.dolphinscheduler.common.task.datax.DataxParameters; |
||||||
|
import org.apache.dolphinscheduler.common.utils.CollectionUtils; |
||||||
|
import org.apache.dolphinscheduler.common.utils.JSONUtils; |
||||||
|
import org.apache.dolphinscheduler.common.utils.ParameterUtils; |
||||||
|
import org.apache.dolphinscheduler.dao.ProcessDao; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.DataSource; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.ProcessInstance; |
||||||
|
import org.apache.dolphinscheduler.server.utils.DataxUtils; |
||||||
|
import org.apache.dolphinscheduler.server.utils.ParamUtils; |
||||||
|
import org.apache.dolphinscheduler.common.utils.SpringApplicationContext; |
||||||
|
import org.apache.dolphinscheduler.server.worker.task.AbstractTask; |
||||||
|
import org.apache.dolphinscheduler.server.worker.task.ShellCommandExecutor; |
||||||
|
import org.apache.dolphinscheduler.server.worker.task.TaskProps; |
||||||
|
import org.slf4j.Logger; |
||||||
|
|
||||||
|
import com.alibaba.druid.sql.ast.SQLStatement; |
||||||
|
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; |
||||||
|
import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr; |
||||||
|
import com.alibaba.druid.sql.ast.statement.SQLSelect; |
||||||
|
import com.alibaba.druid.sql.ast.statement.SQLSelectItem; |
||||||
|
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; |
||||||
|
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; |
||||||
|
import com.alibaba.druid.sql.ast.statement.SQLUnionQuery; |
||||||
|
import com.alibaba.druid.sql.parser.SQLStatementParser; |
||||||
|
import com.alibaba.fastjson.JSONObject; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* DataX task |
||||||
|
*/ |
||||||
|
public class DataxTask extends AbstractTask { |
||||||
|
|
||||||
|
/** |
||||||
|
* python process(datax only supports version 2.7 by default) |
||||||
|
*/ |
||||||
|
private static final String DATAX_PYTHON = "python2.7"; |
||||||
|
|
||||||
|
/** |
||||||
|
* datax home path |
||||||
|
*/ |
||||||
|
private static final String DATAX_HOME_EVN = "${DATAX_HOME}"; |
||||||
|
|
||||||
|
/** |
||||||
|
* datax channel count |
||||||
|
*/ |
||||||
|
private static final int DATAX_CHANNEL_COUNT = 1; |
||||||
|
|
||||||
|
/** |
||||||
|
* datax parameters |
||||||
|
*/ |
||||||
|
private DataxParameters dataXParameters; |
||||||
|
|
||||||
|
/** |
||||||
|
* task dir |
||||||
|
*/ |
||||||
|
private String taskDir; |
||||||
|
|
||||||
|
/** |
||||||
|
* shell command executor |
||||||
|
*/ |
||||||
|
private ShellCommandExecutor shellCommandExecutor; |
||||||
|
|
||||||
|
/** |
||||||
|
* process database access |
||||||
|
*/ |
||||||
|
private ProcessDao processDao; |
||||||
|
|
||||||
|
/** |
||||||
|
* constructor |
||||||
|
* |
||||||
|
* @param props |
||||||
|
* props |
||||||
|
* @param logger |
||||||
|
* logger |
||||||
|
*/ |
||||||
|
public DataxTask(TaskProps props, Logger logger) { |
||||||
|
super(props, logger); |
||||||
|
|
||||||
|
this.taskDir = props.getTaskDir(); |
||||||
|
logger.info("task dir : {}", taskDir); |
||||||
|
|
||||||
|
this.shellCommandExecutor = new ShellCommandExecutor(this::logHandle, props.getTaskDir(), props.getTaskAppId(), |
||||||
|
props.getTaskInstId(), props.getTenantCode(), props.getEnvFile(), props.getTaskStartTime(), |
||||||
|
props.getTaskTimeout(), logger); |
||||||
|
|
||||||
|
this.processDao = SpringApplicationContext.getBean(ProcessDao.class); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* init DataX config |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void init() { |
||||||
|
logger.info("datax task params {}", taskProps.getTaskParams()); |
||||||
|
dataXParameters = JSONUtils.parseObject(taskProps.getTaskParams(), DataxParameters.class); |
||||||
|
|
||||||
|
if (!dataXParameters.checkParameters()) { |
||||||
|
throw new RuntimeException("datax task params is not valid"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* run DataX process |
||||||
|
* |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void handle() |
||||||
|
throws Exception { |
||||||
|
try { |
||||||
|
// set the name of the current thread
|
||||||
|
String threadLoggerInfoName = String.format("TaskLogInfo-%s", taskProps.getTaskAppId()); |
||||||
|
Thread.currentThread().setName(threadLoggerInfoName); |
||||||
|
|
||||||
|
// run datax process
|
||||||
|
String jsonFilePath = buildDataxJsonFile(); |
||||||
|
String shellCommandFilePath = buildShellCommandFile(jsonFilePath); |
||||||
|
exitStatusCode = shellCommandExecutor.run(shellCommandFilePath, processDao); |
||||||
|
} |
||||||
|
catch (Exception e) { |
||||||
|
exitStatusCode = -1; |
||||||
|
throw e; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* cancel DataX process |
||||||
|
* |
||||||
|
* @param cancelApplication |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void cancelApplication(boolean cancelApplication) |
||||||
|
throws Exception { |
||||||
|
// cancel process
|
||||||
|
shellCommandExecutor.cancelApplication(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* build datax configuration file |
||||||
|
* |
||||||
|
* @return |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
private String buildDataxJsonFile() |
||||||
|
throws Exception { |
||||||
|
// generate json
|
||||||
|
String fileName = String.format("%s/%s_job.json", taskDir, taskProps.getTaskAppId()); |
||||||
|
|
||||||
|
Path path = new File(fileName).toPath(); |
||||||
|
if (Files.exists(path)) { |
||||||
|
return fileName; |
||||||
|
} |
||||||
|
|
||||||
|
JSONObject job = new JSONObject(); |
||||||
|
job.put("content", buildDataxJobContentJson()); |
||||||
|
job.put("setting", buildDataxJobSettingJson()); |
||||||
|
|
||||||
|
JSONObject root = new JSONObject(); |
||||||
|
root.put("job", job); |
||||||
|
root.put("core", buildDataxCoreJson()); |
||||||
|
|
||||||
|
logger.debug("datax job json : {}", root.toString()); |
||||||
|
|
||||||
|
// create datax json file
|
||||||
|
FileUtils.writeStringToFile(new File(fileName), root.toString(), Charset.forName("UTF-8")); |
||||||
|
return fileName; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* build datax job config |
||||||
|
* |
||||||
|
* @return |
||||||
|
* @throws SQLException |
||||||
|
*/ |
||||||
|
private List<JSONObject> buildDataxJobContentJson() |
||||||
|
throws SQLException { |
||||||
|
DataSource dataSource = processDao.findDataSourceById(dataXParameters.getDataSource()); |
||||||
|
BaseDataSource dataSourceCfg = DataSourceFactory.getDatasource(dataSource.getType(), |
||||||
|
dataSource.getConnectionParams()); |
||||||
|
|
||||||
|
DataSource dataTarget = processDao.findDataSourceById(dataXParameters.getDataTarget()); |
||||||
|
BaseDataSource dataTargetCfg = DataSourceFactory.getDatasource(dataTarget.getType(), |
||||||
|
dataTarget.getConnectionParams()); |
||||||
|
|
||||||
|
List<JSONObject> readerConnArr = new ArrayList<>(); |
||||||
|
JSONObject readerConn = new JSONObject(); |
||||||
|
readerConn.put("querySql", new String[] {dataXParameters.getSql()}); |
||||||
|
readerConn.put("jdbcUrl", new String[] {dataSourceCfg.getJdbcUrl()}); |
||||||
|
readerConnArr.add(readerConn); |
||||||
|
|
||||||
|
JSONObject readerParam = new JSONObject(); |
||||||
|
readerParam.put("username", dataSourceCfg.getUser()); |
||||||
|
readerParam.put("password", dataSourceCfg.getPassword()); |
||||||
|
readerParam.put("connection", readerConnArr); |
||||||
|
|
||||||
|
JSONObject reader = new JSONObject(); |
||||||
|
reader.put("name", DataxUtils.getReaderPluginName(dataSource.getType())); |
||||||
|
reader.put("parameter", readerParam); |
||||||
|
|
||||||
|
List<JSONObject> writerConnArr = new ArrayList<>(); |
||||||
|
JSONObject writerConn = new JSONObject(); |
||||||
|
writerConn.put("table", new String[] {dataXParameters.getTargetTable()}); |
||||||
|
writerConn.put("jdbcUrl", dataTargetCfg.getJdbcUrl()); |
||||||
|
writerConnArr.add(writerConn); |
||||||
|
|
||||||
|
JSONObject writerParam = new JSONObject(); |
||||||
|
writerParam.put("username", dataTargetCfg.getUser()); |
||||||
|
writerParam.put("password", dataTargetCfg.getPassword()); |
||||||
|
writerParam.put("column", |
||||||
|
parsingSqlColumnNames(dataSource.getType(), dataTarget.getType(), dataSourceCfg, dataXParameters.getSql())); |
||||||
|
writerParam.put("connection", writerConnArr); |
||||||
|
|
||||||
|
if (CollectionUtils.isNotEmpty(dataXParameters.getPreStatements())) { |
||||||
|
writerParam.put("preSql", dataXParameters.getPreStatements()); |
||||||
|
} |
||||||
|
|
||||||
|
if (CollectionUtils.isNotEmpty(dataXParameters.getPostStatements())) { |
||||||
|
writerParam.put("postSql", dataXParameters.getPostStatements()); |
||||||
|
} |
||||||
|
|
||||||
|
JSONObject writer = new JSONObject(); |
||||||
|
writer.put("name", DataxUtils.getWriterPluginName(dataTarget.getType())); |
||||||
|
writer.put("parameter", writerParam); |
||||||
|
|
||||||
|
List<JSONObject> contentList = new ArrayList<>(); |
||||||
|
JSONObject content = new JSONObject(); |
||||||
|
content.put("reader", reader); |
||||||
|
content.put("writer", writer); |
||||||
|
contentList.add(content); |
||||||
|
|
||||||
|
return contentList; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* build datax setting config |
||||||
|
* |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
private JSONObject buildDataxJobSettingJson() { |
||||||
|
JSONObject speed = new JSONObject(); |
||||||
|
speed.put("channel", DATAX_CHANNEL_COUNT); |
||||||
|
|
||||||
|
if (dataXParameters.getJobSpeedByte() > 0) { |
||||||
|
speed.put("byte", dataXParameters.getJobSpeedByte()); |
||||||
|
} |
||||||
|
|
||||||
|
if (dataXParameters.getJobSpeedRecord() > 0) { |
||||||
|
speed.put("record", dataXParameters.getJobSpeedRecord()); |
||||||
|
} |
||||||
|
|
||||||
|
JSONObject errorLimit = new JSONObject(); |
||||||
|
errorLimit.put("record", 0); |
||||||
|
errorLimit.put("percentage", 0); |
||||||
|
|
||||||
|
JSONObject setting = new JSONObject(); |
||||||
|
setting.put("speed", speed); |
||||||
|
setting.put("errorLimit", errorLimit); |
||||||
|
|
||||||
|
return setting; |
||||||
|
} |
||||||
|
|
||||||
|
private JSONObject buildDataxCoreJson() { |
||||||
|
JSONObject speed = new JSONObject(); |
||||||
|
speed.put("channel", DATAX_CHANNEL_COUNT); |
||||||
|
|
||||||
|
if (dataXParameters.getJobSpeedByte() > 0) { |
||||||
|
speed.put("byte", dataXParameters.getJobSpeedByte()); |
||||||
|
} |
||||||
|
|
||||||
|
if (dataXParameters.getJobSpeedRecord() > 0) { |
||||||
|
speed.put("record", dataXParameters.getJobSpeedRecord()); |
||||||
|
} |
||||||
|
|
||||||
|
JSONObject channel = new JSONObject(); |
||||||
|
channel.put("speed", speed); |
||||||
|
|
||||||
|
JSONObject transport = new JSONObject(); |
||||||
|
transport.put("channel", channel); |
||||||
|
|
||||||
|
JSONObject core = new JSONObject(); |
||||||
|
core.put("transport", transport); |
||||||
|
|
||||||
|
return core; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* create command |
||||||
|
* |
||||||
|
* @return |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
private String buildShellCommandFile(String jobConfigFilePath) |
||||||
|
throws Exception { |
||||||
|
// generate scripts
|
||||||
|
String fileName = String.format("%s/%s_node.sh", taskDir, taskProps.getTaskAppId()); |
||||||
|
Path path = new File(fileName).toPath(); |
||||||
|
|
||||||
|
if (Files.exists(path)) { |
||||||
|
return fileName; |
||||||
|
} |
||||||
|
|
||||||
|
// datax python command
|
||||||
|
StringBuilder sbr = new StringBuilder(); |
||||||
|
sbr.append(DATAX_PYTHON); |
||||||
|
sbr.append(" "); |
||||||
|
sbr.append(DATAX_HOME_EVN); |
||||||
|
sbr.append(" "); |
||||||
|
sbr.append(jobConfigFilePath); |
||||||
|
String dataxCommand = sbr.toString(); |
||||||
|
|
||||||
|
// find process instance by task id
|
||||||
|
ProcessInstance processInstance = processDao.findProcessInstanceByTaskId(taskProps.getTaskInstId()); |
||||||
|
|
||||||
|
// combining local and global parameters
|
||||||
|
Map<String, Property> paramsMap = ParamUtils.convert(taskProps.getUserDefParamsMap(), |
||||||
|
taskProps.getDefinedParams(), dataXParameters.getLocalParametersMap(), |
||||||
|
processInstance.getCmdTypeIfComplement(), processInstance.getScheduleTime()); |
||||||
|
if (paramsMap != null) { |
||||||
|
dataxCommand = ParameterUtils.convertParameterPlaceholders(dataxCommand, ParamUtils.convert(paramsMap)); |
||||||
|
} |
||||||
|
|
||||||
|
logger.debug("raw script : {}", dataxCommand); |
||||||
|
|
||||||
|
// create shell command file
|
||||||
|
Set<PosixFilePermission> perms = PosixFilePermissions.fromString(Constants.RWXR_XR_X); |
||||||
|
FileAttribute<Set<PosixFilePermission>> attr = PosixFilePermissions.asFileAttribute(perms); |
||||||
|
Files.createFile(path, attr); |
||||||
|
Files.write(path, dataxCommand.getBytes(), StandardOpenOption.APPEND); |
||||||
|
|
||||||
|
return fileName; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* parsing synchronized column names in SQL statements |
||||||
|
* |
||||||
|
* @param dsType |
||||||
|
* the database type of the data source |
||||||
|
* @param dtType |
||||||
|
* the database type of the data target |
||||||
|
* @param dataSourceCfg |
||||||
|
* the database connection parameters of the data source |
||||||
|
* @param sql |
||||||
|
* sql for data synchronization |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
private String[] parsingSqlColumnNames(DbType dsType, DbType dtType, BaseDataSource dataSourceCfg, String sql) { |
||||||
|
String[] columnNames = tryGrammaticalAnalysisSqlColumnNames(dsType, sql); |
||||||
|
|
||||||
|
if (columnNames == null || columnNames.length == 0) { |
||||||
|
logger.info("try to execute sql analysis query column name"); |
||||||
|
columnNames = tryExecuteSqlResolveColumnNames(dataSourceCfg, sql); |
||||||
|
} |
||||||
|
|
||||||
|
notNull(columnNames, String.format("parsing sql columns failed : %s", sql)); |
||||||
|
|
||||||
|
return DataxUtils.convertKeywordsColumns(dtType, columnNames); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* try grammatical parsing column |
||||||
|
* |
||||||
|
* @param dbType |
||||||
|
* database type |
||||||
|
* @param sql |
||||||
|
* sql for data synchronization |
||||||
|
* @return column name array |
||||||
|
* @throws RuntimeException |
||||||
|
*/ |
||||||
|
private String[] tryGrammaticalAnalysisSqlColumnNames(DbType dbType, String sql) { |
||||||
|
String[] columnNames; |
||||||
|
|
||||||
|
try { |
||||||
|
SQLStatementParser parser = DataxUtils.getSqlStatementParser(dbType, sql); |
||||||
|
notNull(parser, String.format("database driver [%s] is not support", dbType.toString())); |
||||||
|
|
||||||
|
SQLStatement sqlStatement = parser.parseStatement(); |
||||||
|
SQLSelectStatement sqlSelectStatement = (SQLSelectStatement)sqlStatement; |
||||||
|
SQLSelect sqlSelect = sqlSelectStatement.getSelect(); |
||||||
|
|
||||||
|
List<SQLSelectItem> selectItemList = null; |
||||||
|
if (sqlSelect.getQuery() instanceof SQLSelectQueryBlock) { |
||||||
|
SQLSelectQueryBlock block = (SQLSelectQueryBlock)sqlSelect.getQuery(); |
||||||
|
selectItemList = block.getSelectList(); |
||||||
|
} else if (sqlSelect.getQuery() instanceof SQLUnionQuery) { |
||||||
|
SQLUnionQuery unionQuery = (SQLUnionQuery)sqlSelect.getQuery(); |
||||||
|
SQLSelectQueryBlock block = (SQLSelectQueryBlock)unionQuery.getRight(); |
||||||
|
selectItemList = block.getSelectList(); |
||||||
|
} |
||||||
|
|
||||||
|
notNull(selectItemList, |
||||||
|
String.format("select query type [%s] is not support", sqlSelect.getQuery().toString())); |
||||||
|
|
||||||
|
columnNames = new String[selectItemList.size()]; |
||||||
|
for (int i = 0; i < selectItemList.size(); i++ ) { |
||||||
|
SQLSelectItem item = selectItemList.get(i); |
||||||
|
|
||||||
|
String columnName = null; |
||||||
|
|
||||||
|
if (item.getAlias() != null) { |
||||||
|
columnName = item.getAlias(); |
||||||
|
} else if (item.getExpr() != null) { |
||||||
|
if (item.getExpr() instanceof SQLPropertyExpr) { |
||||||
|
SQLPropertyExpr expr = (SQLPropertyExpr)item.getExpr(); |
||||||
|
columnName = expr.getName(); |
||||||
|
} else if (item.getExpr() instanceof SQLIdentifierExpr) { |
||||||
|
SQLIdentifierExpr expr = (SQLIdentifierExpr)item.getExpr(); |
||||||
|
columnName = expr.getName(); |
||||||
|
} |
||||||
|
} else { |
||||||
|
throw new RuntimeException( |
||||||
|
String.format("grammatical analysis sql column [ %s ] failed", item.toString())); |
||||||
|
} |
||||||
|
|
||||||
|
if (columnName == null) { |
||||||
|
throw new RuntimeException( |
||||||
|
String.format("grammatical analysis sql column [ %s ] failed", item.toString())); |
||||||
|
} |
||||||
|
|
||||||
|
columnNames[i] = columnName; |
||||||
|
} |
||||||
|
} |
||||||
|
catch (Exception e) { |
||||||
|
logger.warn(e.getMessage(), e); |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
return columnNames; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* try to execute sql to resolve column names |
||||||
|
* |
||||||
|
* @param baseDataSource |
||||||
|
* the database connection parameters |
||||||
|
* @param sql |
||||||
|
* sql for data synchronization |
||||||
|
* @return column name array |
||||||
|
*/ |
||||||
|
public String[] tryExecuteSqlResolveColumnNames(BaseDataSource baseDataSource, String sql) { |
||||||
|
String[] columnNames; |
||||||
|
sql = String.format("SELECT t.* FROM ( %s ) t WHERE 0 = 1", sql); |
||||||
|
sql = sql.replace(";", ""); |
||||||
|
|
||||||
|
try ( |
||||||
|
Connection connection = DriverManager.getConnection(baseDataSource.getJdbcUrl(), baseDataSource.getUser(), |
||||||
|
baseDataSource.getPassword()); |
||||||
|
PreparedStatement stmt = connection.prepareStatement(sql); |
||||||
|
ResultSet resultSet = stmt.executeQuery()) { |
||||||
|
|
||||||
|
ResultSetMetaData md = resultSet.getMetaData(); |
||||||
|
int num = md.getColumnCount(); |
||||||
|
columnNames = new String[num]; |
||||||
|
for (int i = 1; i <= num; i++ ) { |
||||||
|
columnNames[i - 1] = md.getColumnName(i); |
||||||
|
} |
||||||
|
} |
||||||
|
catch (SQLException e) { |
||||||
|
logger.warn(e.getMessage(), e); |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
return columnNames; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public AbstractParameters getParameters() { |
||||||
|
return dataXParameters; |
||||||
|
} |
||||||
|
|
||||||
|
private void notNull(Object obj, String message) { |
||||||
|
if (obj == null) { |
||||||
|
throw new RuntimeException(message); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,108 @@ |
|||||||
|
/* |
||||||
|
* 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.server.utils; |
||||||
|
|
||||||
|
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser; |
||||||
|
import com.alibaba.druid.sql.dialect.oracle.parser.OracleStatementParser; |
||||||
|
import com.alibaba.druid.sql.dialect.postgresql.parser.PGSQLStatementParser; |
||||||
|
import com.alibaba.druid.sql.dialect.sqlserver.parser.SQLServerStatementParser; |
||||||
|
import org.apache.dolphinscheduler.common.enums.DbType; |
||||||
|
import org.junit.Assert; |
||||||
|
import org.junit.Test; |
||||||
|
import static org.junit.Assert.assertEquals; |
||||||
|
import static org.junit.Assert.assertTrue; |
||||||
|
|
||||||
|
/** |
||||||
|
* DataxUtils Tester. |
||||||
|
*/ |
||||||
|
public class DataxUtilsTest { |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* Method: getReaderPluginName(DbType dbType) |
||||||
|
* |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void testGetReaderPluginName() { |
||||||
|
assertEquals(DataxUtils.DATAX_READER_PLUGIN_MYSQL, DataxUtils.getReaderPluginName(DbType.MYSQL)); |
||||||
|
assertEquals(DataxUtils.DATAX_READER_PLUGIN_POSTGRESQL, DataxUtils.getReaderPluginName(DbType.POSTGRESQL)); |
||||||
|
assertEquals(DataxUtils.DATAX_READER_PLUGIN_SQLSERVER, DataxUtils.getReaderPluginName(DbType.SQLSERVER)); |
||||||
|
assertEquals(DataxUtils.DATAX_READER_PLUGIN_ORACLE, DataxUtils.getReaderPluginName(DbType.ORACLE)); |
||||||
|
assertTrue(DataxUtils.getReaderPluginName(DbType.DB2) == null); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* Method: getWriterPluginName(DbType dbType) |
||||||
|
* |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void testGetWriterPluginName() { |
||||||
|
assertEquals(DataxUtils.DATAX_WRITER_PLUGIN_MYSQL, DataxUtils.getWriterPluginName(DbType.MYSQL)); |
||||||
|
assertEquals(DataxUtils.DATAX_WRITER_PLUGIN_POSTGRESQL, DataxUtils.getWriterPluginName(DbType.POSTGRESQL)); |
||||||
|
assertEquals(DataxUtils.DATAX_WRITER_PLUGIN_SQLSERVER, DataxUtils.getWriterPluginName(DbType.SQLSERVER)); |
||||||
|
assertEquals(DataxUtils.DATAX_WRITER_PLUGIN_ORACLE, DataxUtils.getWriterPluginName(DbType.ORACLE)); |
||||||
|
assertTrue(DataxUtils.getWriterPluginName(DbType.DB2) == null); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* Method: getSqlStatementParser(DbType dbType, String sql) |
||||||
|
* |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void testGetSqlStatementParser() throws Exception { |
||||||
|
assertTrue(DataxUtils.getSqlStatementParser(DbType.MYSQL, "select 1") instanceof MySqlStatementParser); |
||||||
|
assertTrue(DataxUtils.getSqlStatementParser(DbType.POSTGRESQL, "select 1") instanceof PGSQLStatementParser); |
||||||
|
assertTrue(DataxUtils.getSqlStatementParser(DbType.ORACLE, "select 1") instanceof OracleStatementParser); |
||||||
|
assertTrue(DataxUtils.getSqlStatementParser(DbType.SQLSERVER, "select 1") instanceof SQLServerStatementParser); |
||||||
|
assertTrue(DataxUtils.getSqlStatementParser(DbType.DB2, "select 1") == null); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* Method: convertKeywordsColumns(DbType dbType, String[] columns) |
||||||
|
* |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void testConvertKeywordsColumns() throws Exception { |
||||||
|
String[] fromColumns = new String[]{"`select`", "from", "\"where\"", " table "}; |
||||||
|
String[] targetColumns = new String[]{"`select`", "`from`", "`where`", "`table`"}; |
||||||
|
|
||||||
|
String[] toColumns = DataxUtils.convertKeywordsColumns(DbType.MYSQL, fromColumns); |
||||||
|
|
||||||
|
assertTrue(fromColumns.length == toColumns.length); |
||||||
|
|
||||||
|
for (int i = 0; i < toColumns.length; i++) { |
||||||
|
assertEquals(targetColumns[i], toColumns[i]); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* Method: doConvertKeywordsColumn(DbType dbType, String column) |
||||||
|
* |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void testDoConvertKeywordsColumn() throws Exception { |
||||||
|
assertEquals("`select`", DataxUtils.doConvertKeywordsColumn(DbType.MYSQL, " \"`select`\" ")); |
||||||
|
assertEquals("\"select\"", DataxUtils.doConvertKeywordsColumn(DbType.POSTGRESQL, " \"`select`\" ")); |
||||||
|
assertEquals("`select`", DataxUtils.doConvertKeywordsColumn(DbType.SQLSERVER, " \"`select`\" ")); |
||||||
|
assertEquals("\"select\"", DataxUtils.doConvertKeywordsColumn(DbType.ORACLE, " \"`select`\" ")); |
||||||
|
assertEquals("select", DataxUtils.doConvertKeywordsColumn(DbType.DB2, " \"`select`\" ")); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,352 @@ |
|||||||
|
/* |
||||||
|
* 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.server.worker.task.datax; |
||||||
|
|
||||||
|
|
||||||
|
import java.lang.reflect.Method; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.Date; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject; |
||||||
|
import org.apache.dolphinscheduler.common.enums.CommandType; |
||||||
|
import org.apache.dolphinscheduler.common.enums.DbType; |
||||||
|
import org.apache.dolphinscheduler.common.job.db.BaseDataSource; |
||||||
|
import org.apache.dolphinscheduler.common.job.db.DataSourceFactory; |
||||||
|
import org.apache.dolphinscheduler.common.utils.SpringApplicationContext; |
||||||
|
import org.apache.dolphinscheduler.dao.ProcessDao; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.DataSource; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.ProcessInstance; |
||||||
|
import org.apache.dolphinscheduler.server.utils.DataxUtils; |
||||||
|
import org.apache.dolphinscheduler.server.worker.task.ShellCommandExecutor; |
||||||
|
import org.apache.dolphinscheduler.server.worker.task.TaskProps; |
||||||
|
import org.junit.After; |
||||||
|
import org.junit.Assert; |
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.Test; |
||||||
|
import org.mockito.Mockito; |
||||||
|
import org.powermock.api.mockito.PowerMockito; |
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
import org.springframework.context.ApplicationContext; |
||||||
|
|
||||||
|
/** |
||||||
|
* DataxTask Tester. |
||||||
|
*/ |
||||||
|
public class DataxTaskTest { |
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(DataxTaskTest.class); |
||||||
|
|
||||||
|
private DataxTask dataxTask; |
||||||
|
|
||||||
|
private ProcessDao processDao; |
||||||
|
|
||||||
|
private ShellCommandExecutor shellCommandExecutor; |
||||||
|
|
||||||
|
private ApplicationContext applicationContext; |
||||||
|
|
||||||
|
@Before |
||||||
|
public void before() |
||||||
|
throws Exception { |
||||||
|
processDao = Mockito.mock(ProcessDao.class); |
||||||
|
shellCommandExecutor = Mockito.mock(ShellCommandExecutor.class); |
||||||
|
|
||||||
|
applicationContext = Mockito.mock(ApplicationContext.class); |
||||||
|
SpringApplicationContext springApplicationContext = new SpringApplicationContext(); |
||||||
|
springApplicationContext.setApplicationContext(applicationContext); |
||||||
|
Mockito.when(applicationContext.getBean(ProcessDao.class)).thenReturn(processDao); |
||||||
|
|
||||||
|
TaskProps props = new TaskProps(); |
||||||
|
props.setTaskDir("/tmp"); |
||||||
|
props.setTaskAppId(String.valueOf(System.currentTimeMillis())); |
||||||
|
props.setTaskInstId(1); |
||||||
|
props.setTenantCode("1"); |
||||||
|
props.setEnvFile(".dolphinscheduler_env.sh"); |
||||||
|
props.setTaskStartTime(new Date()); |
||||||
|
props.setTaskTimeout(0); |
||||||
|
props.setTaskParams( |
||||||
|
"{\"targetTable\":\"test\",\"postStatements\":[],\"jobSpeedByte\":1024,\"jobSpeedRecord\":1000,\"dtType\":\"MYSQL\",\"datasource\":1,\"dsType\":\"MYSQL\",\"datatarget\":2,\"jobSpeedByte\":0,\"sql\":\"select 1 as test from dual\",\"preStatements\":[\"delete from test\"],\"postStatements\":[\"delete from test\"]}"); |
||||||
|
dataxTask = PowerMockito.spy(new DataxTask(props, logger)); |
||||||
|
dataxTask.init(); |
||||||
|
|
||||||
|
Mockito.when(processDao.findDataSourceById(1)).thenReturn(getDataSource()); |
||||||
|
Mockito.when(processDao.findDataSourceById(2)).thenReturn(getDataSource()); |
||||||
|
Mockito.when(processDao.findProcessInstanceByTaskId(1)).thenReturn(getProcessInstance()); |
||||||
|
|
||||||
|
String fileName = String.format("%s/%s_node.sh", props.getTaskDir(), props.getTaskAppId()); |
||||||
|
Mockito.when(shellCommandExecutor.run(fileName, processDao)).thenReturn(0); |
||||||
|
} |
||||||
|
|
||||||
|
private DataSource getDataSource() { |
||||||
|
DataSource dataSource = new DataSource(); |
||||||
|
dataSource.setType(DbType.MYSQL); |
||||||
|
dataSource.setConnectionParams( |
||||||
|
"{\"user\":\"root\",\"password\":\"123456\",\"address\":\"jdbc:mysql://127.0.0.1:3306\",\"database\":\"test\",\"jdbcUrl\":\"jdbc:mysql://127.0.0.1:3306/test\"}"); |
||||||
|
dataSource.setUserId(1); |
||||||
|
return dataSource; |
||||||
|
} |
||||||
|
|
||||||
|
private ProcessInstance getProcessInstance() { |
||||||
|
ProcessInstance processInstance = new ProcessInstance(); |
||||||
|
processInstance.setCommandType(CommandType.START_PROCESS); |
||||||
|
processInstance.setScheduleTime(new Date()); |
||||||
|
return processInstance; |
||||||
|
} |
||||||
|
|
||||||
|
@After |
||||||
|
public void after() |
||||||
|
throws Exception {} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method: DataxTask() |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void testDataxTask() |
||||||
|
throws Exception { |
||||||
|
TaskProps props = new TaskProps(); |
||||||
|
props.setTaskDir("/tmp"); |
||||||
|
props.setTaskAppId(String.valueOf(System.currentTimeMillis())); |
||||||
|
props.setTaskInstId(1); |
||||||
|
props.setTenantCode("1"); |
||||||
|
Assert.assertNotNull(new DataxTask(props, logger)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method: init |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void testInit() |
||||||
|
throws Exception { |
||||||
|
try { |
||||||
|
dataxTask.init(); |
||||||
|
} catch (Exception e) { |
||||||
|
Assert.fail(e.getMessage()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method: handle() |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void testHandle() |
||||||
|
throws Exception { |
||||||
|
try { |
||||||
|
dataxTask.handle(); |
||||||
|
} catch (RuntimeException e) { |
||||||
|
if (e.getMessage().indexOf("process error . exitCode is : -1") < 0) { |
||||||
|
Assert.fail(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method: cancelApplication() |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void testCancelApplication() |
||||||
|
throws Exception { |
||||||
|
try { |
||||||
|
dataxTask.cancelApplication(true); |
||||||
|
} catch (Exception e) { |
||||||
|
Assert.fail(e.getMessage()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method: parsingSqlColumnNames(DbType dsType, DbType dtType, BaseDataSource |
||||||
|
* dataSourceCfg, String sql) |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void testParsingSqlColumnNames() |
||||||
|
throws Exception { |
||||||
|
try { |
||||||
|
BaseDataSource dataSource = DataSourceFactory.getDatasource(getDataSource().getType(), |
||||||
|
getDataSource().getConnectionParams()); |
||||||
|
|
||||||
|
Method method = DataxTask.class.getDeclaredMethod("parsingSqlColumnNames", DbType.class, DbType.class, BaseDataSource.class, String.class); |
||||||
|
method.setAccessible(true); |
||||||
|
String[] columns = (String[]) method.invoke(dataxTask, DbType.MYSQL, DbType.MYSQL, dataSource, "select 1 as a, 2 as `table` from dual"); |
||||||
|
|
||||||
|
Assert.assertNotNull(columns); |
||||||
|
|
||||||
|
Assert.assertTrue(columns.length == 2); |
||||||
|
|
||||||
|
Assert.assertEquals("[`a`, `table`]", Arrays.toString(columns)); |
||||||
|
} |
||||||
|
catch (Exception e) { |
||||||
|
Assert.fail(e.getMessage()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method: tryGrammaticalParsingSqlColumnNames(DbType dbType, String sql) |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void testTryGrammaticalAnalysisSqlColumnNames() |
||||||
|
throws Exception { |
||||||
|
try { |
||||||
|
Method method = DataxTask.class.getDeclaredMethod("tryGrammaticalAnalysisSqlColumnNames", DbType.class, String.class); |
||||||
|
method.setAccessible(true); |
||||||
|
String[] columns = (String[]) method.invoke(dataxTask, DbType.MYSQL, "select t1.a, t1.b from test t1 union all select a, t2.b from (select a, b from test) t2"); |
||||||
|
|
||||||
|
Assert.assertNotNull(columns); |
||||||
|
|
||||||
|
Assert.assertTrue(columns.length == 2); |
||||||
|
|
||||||
|
Assert.assertEquals("[a, b]", Arrays.toString(columns)); |
||||||
|
} |
||||||
|
catch (Exception e) { |
||||||
|
Assert.fail(e.getMessage()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method: tryExecuteSqlResolveColumnNames(BaseDataSource baseDataSource, |
||||||
|
* String sql) |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void testTryExecuteSqlResolveColumnNames() |
||||||
|
throws Exception { |
||||||
|
// TODO: Test goes here...
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method: buildDataxJsonFile() |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void testBuildDataxJsonFile() |
||||||
|
throws Exception { |
||||||
|
try { |
||||||
|
Method method = DataxTask.class.getDeclaredMethod("buildDataxJsonFile"); |
||||||
|
method.setAccessible(true); |
||||||
|
String filePath = (String) method.invoke(dataxTask, null); |
||||||
|
Assert.assertNotNull(filePath); |
||||||
|
} |
||||||
|
catch (Exception e) { |
||||||
|
Assert.fail(e.getMessage()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method: buildDataxJobContentJson() |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void testBuildDataxJobContentJson() |
||||||
|
throws Exception { |
||||||
|
try { |
||||||
|
Method method = DataxTask.class.getDeclaredMethod("buildDataxJobContentJson"); |
||||||
|
method.setAccessible(true); |
||||||
|
List<JSONObject> contentList = (List<JSONObject>) method.invoke(dataxTask, null); |
||||||
|
Assert.assertNotNull(contentList); |
||||||
|
|
||||||
|
JSONObject content = contentList.get(0); |
||||||
|
JSONObject reader = (JSONObject) content.get("reader"); |
||||||
|
Assert.assertNotNull(reader); |
||||||
|
|
||||||
|
String readerPluginName = (String) reader.get("name"); |
||||||
|
Assert.assertEquals(DataxUtils.DATAX_READER_PLUGIN_MYSQL, readerPluginName); |
||||||
|
|
||||||
|
JSONObject writer = (JSONObject) content.get("writer"); |
||||||
|
Assert.assertNotNull(writer); |
||||||
|
|
||||||
|
String writerPluginName = (String) writer.get("name"); |
||||||
|
Assert.assertEquals(DataxUtils.DATAX_WRITER_PLUGIN_MYSQL, writerPluginName); |
||||||
|
} |
||||||
|
catch (Exception e) { |
||||||
|
Assert.fail(e.getMessage()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method: buildDataxJobSettingJson() |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void testBuildDataxJobSettingJson() |
||||||
|
throws Exception { |
||||||
|
try { |
||||||
|
Method method = DataxTask.class.getDeclaredMethod("buildDataxJobSettingJson"); |
||||||
|
method.setAccessible(true); |
||||||
|
JSONObject setting = (JSONObject) method.invoke(dataxTask, null); |
||||||
|
Assert.assertNotNull(setting); |
||||||
|
Assert.assertNotNull(setting.get("speed")); |
||||||
|
Assert.assertNotNull(setting.get("errorLimit")); |
||||||
|
} |
||||||
|
catch (Exception e) { |
||||||
|
Assert.fail(e.getMessage()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method: buildDataxCoreJson() |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void testBuildDataxCoreJson() |
||||||
|
throws Exception { |
||||||
|
try { |
||||||
|
Method method = DataxTask.class.getDeclaredMethod("buildDataxCoreJson"); |
||||||
|
method.setAccessible(true); |
||||||
|
JSONObject coreConfig = (JSONObject) method.invoke(dataxTask, null); |
||||||
|
Assert.assertNotNull(coreConfig); |
||||||
|
Assert.assertNotNull(coreConfig.get("transport")); |
||||||
|
} |
||||||
|
catch (Exception e) { |
||||||
|
Assert.fail(e.getMessage()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method: buildShellCommandFile(String jobConfigFilePath) |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void testBuildShellCommandFile() |
||||||
|
throws Exception { |
||||||
|
try { |
||||||
|
Method method = DataxTask.class.getDeclaredMethod("buildShellCommandFile", String.class); |
||||||
|
method.setAccessible(true); |
||||||
|
Assert.assertNotNull(method.invoke(dataxTask, "test.json")); |
||||||
|
} |
||||||
|
catch (Exception e) { |
||||||
|
Assert.fail(e.getMessage()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method: getParameters |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void testGetParameters() |
||||||
|
throws Exception { |
||||||
|
Assert.assertTrue(dataxTask.getParameters() != null); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method: notNull(Object obj, String message) |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void testNotNull() |
||||||
|
throws Exception { |
||||||
|
try { |
||||||
|
Method method = DataxTask.class.getDeclaredMethod("notNull", Object.class, String.class); |
||||||
|
method.setAccessible(true); |
||||||
|
method.invoke(dataxTask, "abc", "test throw RuntimeException"); |
||||||
|
} |
||||||
|
catch (Exception e) { |
||||||
|
Assert.fail(e.getMessage()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,292 @@ |
|||||||
|
/* |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
<template> |
||||||
|
<div class="datax-model"> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('Datasource')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<m-datasource |
||||||
|
ref="refDs" |
||||||
|
@on-dsData="_onDsData" |
||||||
|
:supportType="['MYSQL','POSTGRESQL', 'ORACLE', 'SQLSERVER']" |
||||||
|
:data="{ type:dsType,datasource:datasource }"> |
||||||
|
</m-datasource> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('SQL Statement')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<div class="from-mirror"> |
||||||
|
<textarea |
||||||
|
id="code-sql-mirror" |
||||||
|
name="code-sql-mirror" |
||||||
|
style="opacity: 0;"> |
||||||
|
</textarea> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('TargetDataBase')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<m-datasource |
||||||
|
ref="refDt" |
||||||
|
@on-dsData="_onDtData" |
||||||
|
:supportType="['MYSQL','POSTGRESQL', 'ORACLE', 'SQLSERVER']" |
||||||
|
:data="{ type:dtType,datasource:datatarget }"> |
||||||
|
</m-datasource> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('TargetTable')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<x-input |
||||||
|
type="input" |
||||||
|
v-model="targetTable" |
||||||
|
:placeholder="$t('Please enter the table of target')" |
||||||
|
autocomplete="off"> |
||||||
|
</x-input> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('TargetDataBase')}}{{$t('Pre Statement')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<m-statement-list |
||||||
|
ref="refPreStatements" |
||||||
|
@on-statement-list="_onPreStatements" |
||||||
|
:statement-list="preStatements"> |
||||||
|
</m-statement-list> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text">{{$t('TargetDataBase')}}{{$t('Post Statement')}}</div> |
||||||
|
<div slot="content"> |
||||||
|
<m-statement-list |
||||||
|
ref="refPostStatements" |
||||||
|
@on-statement-list="_onPostStatements" |
||||||
|
:statement-list="postStatements"> |
||||||
|
</m-statement-list> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text"> |
||||||
|
<span>{{$t('SpeedByte')}}</span> |
||||||
|
</div> |
||||||
|
<div slot="content"> |
||||||
|
<m-select-input v-model="jobSpeedByte" :list="[0,1,10,50,100,512]"> |
||||||
|
</m-select-input> |
||||||
|
<span>({{$t('0 means unlimited by byte')}})</span> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
<m-list-box> |
||||||
|
<div slot="text"> |
||||||
|
<span>{{$t('SpeedRecord')}}</span> |
||||||
|
</div> |
||||||
|
<div slot="content"> |
||||||
|
<m-select-input v-model="jobSpeedRecord" :list="[0,500,1000,1500,2000,2500,3000]"> |
||||||
|
</m-select-input> |
||||||
|
<span>({{$t('0 means unlimited by count')}})</span> |
||||||
|
</div> |
||||||
|
</m-list-box> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import _ from 'lodash' |
||||||
|
import i18n from '@/module/i18n' |
||||||
|
import mListBox from './_source/listBox' |
||||||
|
import mDatasource from './_source/datasource' |
||||||
|
import mLocalParams from './_source/localParams' |
||||||
|
import mStatementList from './_source/statementList' |
||||||
|
import disabledState from '@/module/mixin/disabledState' |
||||||
|
import mSelectInput from '../_source/selectInput' |
||||||
|
import codemirror from '@/conf/home/pages/resource/pages/file/pages/_source/codemirror' |
||||||
|
|
||||||
|
let editor |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'datax', |
||||||
|
|
||||||
|
data () { |
||||||
|
return { |
||||||
|
// Data source type |
||||||
|
dsType: '', |
||||||
|
// data source |
||||||
|
datasource: '', |
||||||
|
// Data source type |
||||||
|
dtType: '', |
||||||
|
// data source |
||||||
|
datatarget: '', |
||||||
|
// Return to the selected data source |
||||||
|
rtDatasource: '', |
||||||
|
// Return to the selected data target |
||||||
|
rtDatatarget: '', |
||||||
|
// Sql statement |
||||||
|
sql: '', |
||||||
|
// target table |
||||||
|
targetTable: '', |
||||||
|
// Pre statements |
||||||
|
preStatements: [], |
||||||
|
// Post statements |
||||||
|
postStatements: [], |
||||||
|
// speed byte |
||||||
|
jobSpeedByte: 0, |
||||||
|
// speed record |
||||||
|
jobSpeedRecord: 1000, |
||||||
|
} |
||||||
|
}, |
||||||
|
mixins: [disabledState], |
||||||
|
props: { |
||||||
|
backfillItem: Object, |
||||||
|
createNodeId: Number |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
/** |
||||||
|
* return data source |
||||||
|
*/ |
||||||
|
_onDsData (o) { |
||||||
|
this.dsType = o.type |
||||||
|
this.rtDatasource = o.datasource |
||||||
|
}, |
||||||
|
/** |
||||||
|
* return data target |
||||||
|
*/ |
||||||
|
_onDtData (o) { |
||||||
|
this.dtType = o.type |
||||||
|
this.rtDatatarget = o.datasource |
||||||
|
}, |
||||||
|
/** |
||||||
|
* return pre statements |
||||||
|
*/ |
||||||
|
_onPreStatements (a) { |
||||||
|
this.preStatements = a |
||||||
|
}, |
||||||
|
/** |
||||||
|
* return post statements |
||||||
|
*/ |
||||||
|
_onPostStatements (a) { |
||||||
|
this.postStatements = a |
||||||
|
}, |
||||||
|
/** |
||||||
|
* verification |
||||||
|
*/ |
||||||
|
_verification () { |
||||||
|
if (!editor.getValue()) { |
||||||
|
this.$message.warning(`${i18n.$t('Please enter a SQL Statement(required)')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
// datasource Subcomponent verification |
||||||
|
if (!this.$refs.refDs._verifDatasource()) { |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
// datasource Subcomponent verification |
||||||
|
if (!this.$refs.refDt._verifDatasource()) { |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
if (!this.targetTable) { |
||||||
|
this.$message.warning(`${i18n.$t('Please enter a Target Table(required)')}`) |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
// preStatements Subcomponent verification |
||||||
|
if (!this.$refs.refPreStatements._verifProp()) { |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
// postStatements Subcomponent verification |
||||||
|
if (!this.$refs.refPostStatements._verifProp()) { |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
// storage |
||||||
|
this.$emit('on-params', { |
||||||
|
dsType: this.dsType, |
||||||
|
dataSource: this.rtDatasource, |
||||||
|
dtType: this.dtType, |
||||||
|
dataTarget: this.rtDatatarget, |
||||||
|
sql: editor.getValue(), |
||||||
|
targetTable: this.targetTable, |
||||||
|
jobSpeedByte: this.jobSpeedByte * 1024, |
||||||
|
jobSpeedRecord: this.jobSpeedRecord, |
||||||
|
preStatements: this.preStatements, |
||||||
|
postStatements: this.postStatements |
||||||
|
}) |
||||||
|
return true |
||||||
|
}, |
||||||
|
/** |
||||||
|
* Processing code highlighting |
||||||
|
*/ |
||||||
|
_handlerEditor () { |
||||||
|
// editor |
||||||
|
editor = codemirror('code-sql-mirror', { |
||||||
|
mode: 'sql', |
||||||
|
readOnly: this.isDetails |
||||||
|
}) |
||||||
|
|
||||||
|
this.keypress = () => { |
||||||
|
if (!editor.getOption('readOnly')) { |
||||||
|
editor.showHint({ |
||||||
|
completeSingle: false |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Monitor keyboard |
||||||
|
editor.on('keypress', this.keypress) |
||||||
|
|
||||||
|
editor.setValue(this.sql) |
||||||
|
|
||||||
|
return editor |
||||||
|
} |
||||||
|
}, |
||||||
|
created () { |
||||||
|
let o = this.backfillItem |
||||||
|
|
||||||
|
// Non-null objects represent backfill |
||||||
|
if (!_.isEmpty(o)) { |
||||||
|
// backfill |
||||||
|
this.dsType = o.params.dsType || '' |
||||||
|
this.datasource = o.params.dataSource || '' |
||||||
|
this.dtType = o.params.dtType || '' |
||||||
|
this.datatarget = o.params.dataTarget || '' |
||||||
|
this.sql = o.params.sql || '' |
||||||
|
this.targetTable = o.params.targetTable || '' |
||||||
|
this.jobSpeedByte = o.params.jobSpeedByte / 1024 || 0 |
||||||
|
this.jobSpeedRecord = o.params.jobSpeedRecord || 0 |
||||||
|
this.preStatements = o.params.preStatements || [] |
||||||
|
this.postStatements = o.params.postStatements || [] |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
setTimeout(() => { |
||||||
|
this._handlerEditor() |
||||||
|
}, 200) |
||||||
|
}, |
||||||
|
destroyed () { |
||||||
|
/** |
||||||
|
* Destroy the editor instance |
||||||
|
*/ |
||||||
|
if (editor) { |
||||||
|
editor.toTextArea() // Uninstall |
||||||
|
editor.off($('.code-sql-mirror'), 'keypress', this.keypress) |
||||||
|
} |
||||||
|
}, |
||||||
|
computed: {}, |
||||||
|
components: { mListBox, mDatasource, mLocalParams, mStatementList, mSelectInput } |
||||||
|
} |
||||||
|
</script> |
After Width: | Height: | Size: 571 B |
After Width: | Height: | Size: 3.0 KiB |
Loading…
Reference in new issue