|
|
|
|
package com.guozhi.bloodanalysis.parser;
|
|
|
|
|
|
|
|
|
|
import com.guozhi.bloodanalysis.entity.DataLineageInfo;
|
|
|
|
|
import com.guozhi.bloodanalysis.exception.BusinessException;
|
|
|
|
|
import com.guozhi.bloodanalysis.parser.clean.GenericLogNormalizer;
|
|
|
|
|
import com.guozhi.bloodanalysis.parser.common.*;
|
|
|
|
|
import com.guozhi.bloodanalysis.parser.utils.ExportParseResultUtil;
|
|
|
|
|
import com.guozhi.bloodanalysis.parser.vo.KColumn;
|
|
|
|
|
import gudusoft.gsqlparser.EDbVendor;
|
|
|
|
|
import gudusoft.gsqlparser.TCustomSqlStatement;
|
|
|
|
|
import gudusoft.gsqlparser.TGSqlParser;
|
|
|
|
|
import gudusoft.gsqlparser.TStatementList;
|
|
|
|
|
import gudusoft.gsqlparser.stmt.TAlterTableStatement;
|
|
|
|
|
import gudusoft.gsqlparser.stmt.TCreateTableSqlStatement;
|
|
|
|
|
import gudusoft.gsqlparser.stmt.TDeleteSqlStatement;
|
|
|
|
|
import gudusoft.gsqlparser.stmt.TInsertSqlStatement;
|
|
|
|
|
import gudusoft.gsqlparser.stmt.TSelectSqlStatement;
|
|
|
|
|
import gudusoft.gsqlparser.stmt.TUpdateSqlStatement;
|
|
|
|
|
import lombok.Data;
|
|
|
|
|
import lombok.NoArgsConstructor;
|
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
import org.apache.commons.lang3.StringUtils;
|
|
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
|
import org.springframework.context.ApplicationContext;
|
|
|
|
|
import org.springframework.context.annotation.Scope;
|
|
|
|
|
import org.springframework.stereotype.Component;
|
|
|
|
|
|
|
|
|
|
import java.util.*;
|
|
|
|
|
import java.util.regex.Matcher;
|
|
|
|
|
import java.util.regex.Pattern;
|
|
|
|
|
|
|
|
|
|
import static com.guozhi.bloodanalysis.parser.utils.DatabaseType.Oracle;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Slf4j
|
|
|
|
|
@Component
|
|
|
|
|
@Data
|
|
|
|
|
@NoArgsConstructor
|
|
|
|
|
@Scope("prototype")
|
|
|
|
|
public class SqlParser {
|
|
|
|
|
//解析器对象
|
|
|
|
|
private TGSqlParser sqlParser = null;
|
|
|
|
|
//sql解析器上下文
|
|
|
|
|
private ParserContext parserContext = new ParserContext();
|
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
ExportParseResultUtil exportParseResultUtil;
|
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
ApplicationContext applicationContext;
|
|
|
|
|
|
|
|
|
|
public void parse(DataLineageInfo dataLineageInfo, List<Map<Integer, String>> databaseList) throws Exception {
|
|
|
|
|
String sqlText = "";
|
|
|
|
|
try {
|
|
|
|
|
List<String> targetSqlList = new ArrayList<>();
|
|
|
|
|
String dbType = "MYSQL";
|
|
|
|
|
if (databaseList !=null && databaseList.size()>0){
|
|
|
|
|
for (Map<Integer, String> map : databaseList) {
|
|
|
|
|
String type = map.get(dataLineageInfo.getSsysId());
|
|
|
|
|
if (type != null) {
|
|
|
|
|
dbType = type;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
String sql = new GenericLogNormalizer().normalizer(dataLineageInfo.getProcText(),dbType);
|
|
|
|
|
sql = optDeclare(sql,dataLineageInfo.getProcName());
|
|
|
|
|
sql = optDeclare2(sql);
|
|
|
|
|
if(sql.trim().equals("")){
|
|
|
|
|
throw new BusinessException("errorSQLparse:"+dataLineageInfo.getProcName());
|
|
|
|
|
}
|
|
|
|
|
targetSqlList.add(sql);
|
|
|
|
|
String defaultSchema = dataLineageInfo.getMdlName();
|
|
|
|
|
Integer defaultSystem = dataLineageInfo.getSsysId();
|
|
|
|
|
this.parserContext.setDefaultDb(defaultSystem);
|
|
|
|
|
this.parserContext.setDefaultSchema(defaultSchema);
|
|
|
|
|
int length = targetSqlList.size();
|
|
|
|
|
for (String s : targetSqlList) {
|
|
|
|
|
sqlText = s;
|
|
|
|
|
if ("ORACLE".equals(dbType)) {
|
|
|
|
|
if (Objects.equals(dbType, Oracle.toString())) {
|
|
|
|
|
if (sqlText != null) {
|
|
|
|
|
sqlText = sqlText.toUpperCase();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
sqlParser = new TGSqlParser(EDbVendor.dbvoracle);
|
|
|
|
|
}
|
|
|
|
|
if ("MYSQL".equals(dbType)) {
|
|
|
|
|
sqlParser = new TGSqlParser(EDbVendor.dbvmysql);
|
|
|
|
|
}
|
|
|
|
|
if ("SQLSERVER".equals(dbType)) {
|
|
|
|
|
sqlParser = new TGSqlParser(EDbVendor.dbvmssql);
|
|
|
|
|
}
|
|
|
|
|
if ("TERADATA".equals(dbType)) {
|
|
|
|
|
sqlParser = new TGSqlParser(EDbVendor.dbvteradata);
|
|
|
|
|
}
|
|
|
|
|
if ("POSTGRESQL".equals(dbType)) {
|
|
|
|
|
sqlParser = new TGSqlParser(EDbVendor.dbvpostgresql);
|
|
|
|
|
}
|
|
|
|
|
if ("DB2".equals(dbType)) {
|
|
|
|
|
sqlParser = new TGSqlParser(EDbVendor.dbvdb2);
|
|
|
|
|
}
|
|
|
|
|
sqlParser.sqltext = sqlText;
|
|
|
|
|
int ret = sqlParser.parse();
|
|
|
|
|
List<KColumn> result = new ArrayList<>();
|
|
|
|
|
if (ret == 0) {
|
|
|
|
|
TStatementList statementList = sqlParser.getSqlstatements();
|
|
|
|
|
while (statementList.hasNext()) {
|
|
|
|
|
TCustomSqlStatement stmt = statementList.next();
|
|
|
|
|
parserContext.getTableInCurrentStatement().clear();
|
|
|
|
|
switch (stmt.sqlstatementtype) {
|
|
|
|
|
case sstselect:
|
|
|
|
|
result = parseSelect(stmt);
|
|
|
|
|
break;
|
|
|
|
|
case sstdelete:
|
|
|
|
|
result = parseDelete(stmt);
|
|
|
|
|
break;
|
|
|
|
|
case sstupdate:
|
|
|
|
|
result = parseUpdate(stmt);
|
|
|
|
|
break;
|
|
|
|
|
case sstinsert:
|
|
|
|
|
result = parseInsert(stmt);
|
|
|
|
|
break;
|
|
|
|
|
case sstcreatetable:
|
|
|
|
|
result = parseCreateTable(stmt);
|
|
|
|
|
break;
|
|
|
|
|
case sstcreateview:
|
|
|
|
|
break;
|
|
|
|
|
case sstoraclealtertablespace:
|
|
|
|
|
// parseAlterTable(stmt);
|
|
|
|
|
break;
|
|
|
|
|
case sstdroptable:
|
|
|
|
|
// parseDropTable(stmt);
|
|
|
|
|
break;
|
|
|
|
|
case sstmerge:
|
|
|
|
|
log.error("sstmerge["
|
|
|
|
|
+ stmt.sqlstatementtype
|
|
|
|
|
+ "][unknow sql type]sqltext:"
|
|
|
|
|
);
|
|
|
|
|
default:
|
|
|
|
|
log.error("[" + stmt.sqlstatementtype
|
|
|
|
|
+ "][unknow sql type]sqltext:"
|
|
|
|
|
);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
log.error(sqlParser.sqltext + sqlParser.getErrormessage());
|
|
|
|
|
}
|
|
|
|
|
if (result.size() > 0) {
|
|
|
|
|
exportParseResultUtil.expResult(result, dataLineageInfo);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String optDeclare(String sql,String procName) {
|
|
|
|
|
String returnSql=sql;
|
|
|
|
|
if(StringUtils.isNotEmpty(sql)){
|
|
|
|
|
//储存过程名称
|
|
|
|
|
String[] sqls = sql.split(";");
|
|
|
|
|
for(String sql2:sqls){
|
|
|
|
|
sql2 = sql2.trim();
|
|
|
|
|
//去掉set和 truncate和delete语句 还有引用其他存储过程的语句
|
|
|
|
|
if(sql2.startsWith("SET")||sql2.startsWith("TRUNCATE")||sql2.startsWith("DELETE")||sql2.startsWith("PERFORM")){
|
|
|
|
|
sql = sql.replace(sql2+";", "");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// String dd = sql2.replaceAll(" ", "");
|
|
|
|
|
// int startIndex = dd.toUpperCase().lastIndexOf("PROCEDURE");
|
|
|
|
|
// if(startIndex >= 0){
|
|
|
|
|
// startIndex += "PROCEDURE".length();
|
|
|
|
|
// int endIndex = dd.indexOf("(");
|
|
|
|
|
// if(endIndex >= 0){
|
|
|
|
|
// procName = dd.substring(startIndex, endIndex);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
/*
|
|
|
|
|
Pattern pat = Pattern.compile("(DECLARE)(\\s*)");
|
|
|
|
|
Matcher mat = pat.matcher(sql2);
|
|
|
|
|
if (mat.find()) {
|
|
|
|
|
sql2 = mat.replaceAll("");
|
|
|
|
|
String sub = sql2.substring(0,sql2.indexOf(" ")).trim();
|
|
|
|
|
if(sql.contains(sub)){
|
|
|
|
|
sql = sql.replaceAll(sub, "'88888888'");
|
|
|
|
|
}
|
|
|
|
|
}*/
|
|
|
|
|
}
|
|
|
|
|
Pattern pat = Pattern.compile("(DECLARE)(\\s).*");
|
|
|
|
|
Matcher mat = pat.matcher(sql);
|
|
|
|
|
while (mat.find()) {
|
|
|
|
|
sql = mat.replaceAll("");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//找出脚本结束的位置
|
|
|
|
|
Pattern lastPattern = Pattern.compile("(END)(\\s)+"+("".equals(procName)?";":procName));
|
|
|
|
|
Matcher lastMatcher = lastPattern.matcher(sql);
|
|
|
|
|
if(lastMatcher.find()){
|
|
|
|
|
int lastIndex = lastMatcher.start();
|
|
|
|
|
if(sql.contains("BEGIN")){
|
|
|
|
|
returnSql = sql.substring(sql.indexOf("BEGIN")+5, lastIndex);
|
|
|
|
|
}else{
|
|
|
|
|
returnSql = sql.substring(0, lastIndex);
|
|
|
|
|
}
|
|
|
|
|
}else{
|
|
|
|
|
Pattern tempPattern = Pattern.compile("(END)(\\s)*;");
|
|
|
|
|
Matcher tempMatcher = tempPattern.matcher(sql);
|
|
|
|
|
Pattern tempPatternBegin = Pattern.compile("(\\s)(BEGIN)(\\s)");
|
|
|
|
|
Matcher tempMatcherBegin = tempPatternBegin.matcher(sql);
|
|
|
|
|
|
|
|
|
|
if(tempMatcher.find()){
|
|
|
|
|
int tempIndex = tempMatcher.start();
|
|
|
|
|
int tempIndexBegin = 0;
|
|
|
|
|
if(tempMatcherBegin.find()){
|
|
|
|
|
tempIndexBegin = tempMatcherBegin.start();
|
|
|
|
|
}
|
|
|
|
|
returnSql = sql.substring(tempIndexBegin+6, tempIndex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return returnSql;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String optDeclare2(String sql) {
|
|
|
|
|
StringBuilder returnVal = new StringBuilder();
|
|
|
|
|
if(StringUtils.isNotEmpty(sql)){
|
|
|
|
|
|
|
|
|
|
String[] sqls = sql.split(";");
|
|
|
|
|
for(String sql2:sqls){
|
|
|
|
|
sql2 = sql2.trim();
|
|
|
|
|
//去掉set和 truncate和delete语句 还有引用其他存储过程的语句
|
|
|
|
|
if(sql2.toUpperCase().trim().startsWith("INSERT")){
|
|
|
|
|
returnVal.append(sql2.substring(sql2.toUpperCase().indexOf("INSERT"))).append(";\r\n");
|
|
|
|
|
|
|
|
|
|
}else if(sql2.toUpperCase().trim().startsWith("UPDATE")){
|
|
|
|
|
returnVal.append(sql2.substring(sql2.toUpperCase().indexOf("UPDATE"))).append(";\r\n");
|
|
|
|
|
|
|
|
|
|
}else if(sql2.toUpperCase().trim().startsWith("MERGE")){
|
|
|
|
|
//TODO wxl merge语句的解析暂时不支持,导致报错
|
|
|
|
|
// returnVal.append(sql2.substring(sql2.toUpperCase().indexOf("MERGE"))+";\r\n");
|
|
|
|
|
|
|
|
|
|
}else if(sql2.toUpperCase().trim().startsWith("CREATE")){
|
|
|
|
|
returnVal.append(sql2.substring(sql2.toUpperCase().indexOf("CREATE"))).append(";\r\n");
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return returnVal.toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private List<KColumn> parseAlterTable(TCustomSqlStatement stmt) {
|
|
|
|
|
TAlterTableStatement alterTableStatement=(TAlterTableStatement)stmt;
|
|
|
|
|
AlterParser parser=new AlterParser(alterTableStatement,parserContext);
|
|
|
|
|
parser.parse();
|
|
|
|
|
return parser.getParseResult();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private List<KColumn> parseUpdate(TCustomSqlStatement stmt) {
|
|
|
|
|
TUpdateSqlStatement dStmt=(TUpdateSqlStatement)stmt;
|
|
|
|
|
UpdateParser parser=new UpdateParser(dStmt,parserContext);
|
|
|
|
|
parser.parse();
|
|
|
|
|
return parser.getParseResult();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private List<KColumn> parseDelete(TCustomSqlStatement stmt) {
|
|
|
|
|
TDeleteSqlStatement dStmt=(TDeleteSqlStatement)stmt;
|
|
|
|
|
DeleteParser parser=new DeleteParser(dStmt,parserContext);
|
|
|
|
|
parser.parse();
|
|
|
|
|
return parser.getParseResult();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private List<KColumn> parseInsert(TCustomSqlStatement stmt) {
|
|
|
|
|
InsertParser parser = applicationContext.getBean(InsertParser.class);
|
|
|
|
|
parser.setMInsertSql((TInsertSqlStatement)stmt);
|
|
|
|
|
parser.setMParserContext(this.parserContext);
|
|
|
|
|
parser.parse();
|
|
|
|
|
return parser.getParseResult();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// private void parseDropTable(TCustomSqlStatement stmt) {
|
|
|
|
|
// DropParser dp=new DropParser(stmt,parserContext);
|
|
|
|
|
// dp.parse();
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
public List<KColumn> parseCreateTable(TCustomSqlStatement stmt) {
|
|
|
|
|
TCreateTableSqlStatement ctSql=(TCreateTableSqlStatement)stmt;
|
|
|
|
|
CreateParser parser=new CreateParser(ctSql,parserContext);
|
|
|
|
|
parser.parse();
|
|
|
|
|
return parser.getParseResult();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public List<KColumn> parseSelect(TCustomSqlStatement stmt) {
|
|
|
|
|
TSelectSqlStatement selectSqlStatement = (TSelectSqlStatement) stmt;
|
|
|
|
|
SelectParser parser=new SelectParser(selectSqlStatement,parserContext);
|
|
|
|
|
parser.parse();
|
|
|
|
|
return parser.getParseResult();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|