001package gudusoft.gsqlparser.dlineage.util; 002 003import gudusoft.gsqlparser.EDbVendor; 004import gudusoft.gsqlparser.dlineage.DataFlowAnalyzer; 005import gudusoft.gsqlparser.dlineage.ParallelDataFlowAnalyzer; 006import gudusoft.gsqlparser.dlineage.dataflow.metadata.MetadataReader; 007import gudusoft.gsqlparser.dlineage.dataflow.metadata.sqldep.SQLDepMetadataAnalyzer; 008import gudusoft.gsqlparser.dlineage.dataflow.model.ModelBindingManager; 009import gudusoft.gsqlparser.dlineage.dataflow.model.Option; 010import gudusoft.gsqlparser.dlineage.dataflow.model.RelationshipType; 011import gudusoft.gsqlparser.dlineage.dataflow.model.json.Error; 012import gudusoft.gsqlparser.dlineage.dataflow.model.json.Process; 013import gudusoft.gsqlparser.dlineage.dataflow.model.json.*; 014import gudusoft.gsqlparser.dlineage.dataflow.model.xml.*; 015import gudusoft.gsqlparser.dlineage.metadata.Sqlflow; 016import gudusoft.gsqlparser.util.Logger; 017import gudusoft.gsqlparser.util.LoggerFactory; 018import gudusoft.gsqlparser.util.SQLUtil; 019import gudusoft.gsqlparser.util.json.JSON; 020 021import java.io.File; 022import java.util.*; 023import java.util.concurrent.atomic.AtomicLong; 024import java.util.stream.Collectors; 025 026public class DataflowUtility { 027 028 private static final Logger logger = LoggerFactory.getLogger(FunctionUtility.class); 029 030 public static dataflow mergeFunctionCallDataflow(dataflow dataflow, EDbVendor dbVendor) { 031 if (ModelBindingManager.getGlobalVendor() == null) { 032 ModelBindingManager.setGlobalVendor(dbVendor); 033 } 034 dataflow instance = cloneDataflow(dataflow); 035 List<procedure> procedures = new ArrayList<>(instance.getProcedures()); 036 if (instance.getPackages() != null) { 037 for (oraclePackage pkg : instance.getPackages()) { 038 if (pkg.getProcedures() != null) { 039 for (procedure procedure : pkg.getProcedures()) { 040 procedure.setOraclePackage(pkg); 041 procedures.add(procedure); 042 } 043 } 044 } 045 } 046 047 Map<String, procedure> procedureIdMap = procedures.stream().collect(Collectors.toMap( 048 t -> t.getId(), 049 t -> t, 050 (existingValue, newValue) -> newValue 051 )); 052 Map<String, table> functionIdMap = dataflow.getResultsets().stream().collect(Collectors.toMap( 053 t -> t.getId(), 054 t -> t, 055 (existingValue, newValue) -> newValue 056 )); 057 058 Map<String, table> functionMap = new HashMap<>(); 059 Map<String, procedure> procedureMap = new HashMap<>(); 060 Map<String, oraclePackage> oraclePackageMap = new HashMap<>(); 061 Map<String, Set<String>> oraclePackageProcedureMap = new HashMap<>(); 062 if (instance.getPackages() != null) { 063 for (oraclePackage pkg : instance.getPackages()) { 064 String qualifiedPackageName = DlineageUtil.getIdentifierOraclePackageNameWithArgNum(pkg); 065 if (!oraclePackageMap.containsKey(qualifiedPackageName)) { 066 oraclePackageMap.put(qualifiedPackageName, pkg); 067 } 068 for (procedure procedure : pkg.getProcedures()) { 069 String qualifiedProcedureName = qualifiedPackageName + "." + DlineageUtil.getIdentifierProcedureNameWithArgNum(procedure); 070 if (!oraclePackageProcedureMap.containsKey(qualifiedPackageName)) { 071 oraclePackageProcedureMap.put(qualifiedPackageName, new HashSet<>()); 072 } 073 oraclePackageProcedureMap.get(qualifiedPackageName).add(qualifiedProcedureName); 074 } 075 } 076 } 077 078 079 080 for (procedure procedure : procedures) { 081 String qualifiedProcedureName = DlineageUtil.getIdentifierProcedureNameWithArgNum(procedure); 082 if (procedure.getOraclePackage() != null) { 083 String qualifiedPackageName = DlineageUtil.getIdentifierOraclePackageNameWithArgNum(procedure.getOraclePackage()); 084 qualifiedProcedureName = qualifiedPackageName + "." + DlineageUtil.getIdentifierProcedureNameWithArgNum(procedure); 085 } 086 if (!procedureMap.containsKey(qualifiedProcedureName)) { 087 procedureMap.put(qualifiedProcedureName, procedure); 088 } 089 } 090 091 for (table function : instance.getResultsets()) { 092 String qualifiedFunctionName = DlineageUtil.getIdentifierFunctionName(function); 093 if (!functionMap.containsKey(qualifiedFunctionName)) { 094 functionMap.put(qualifiedFunctionName, function); 095 } 096 } 097 098 Set<oraclePackage> oraclePackages = new LinkedHashSet<>(); 099 for (String key : oraclePackageMap.keySet()) { 100 oraclePackage standardPackage = oraclePackageMap.get(key); 101 oraclePackages.add(standardPackage); 102 Set<String> procedureNames = oraclePackageProcedureMap.get(key); 103 if (procedureNames != null) { 104 for (String procedureName : procedureNames) { 105 procedureName = key + "." + procedureName; 106 if (procedureMap.containsKey(procedureName)) { 107 procedure standardProcedure = procedureMap.get(procedureName); 108 if (!standardPackage.getProcedures().contains(standardProcedure)) { 109 standardPackage.getProcedures().add(standardProcedure); 110 } 111 procedureMap.remove(procedureName); 112 } 113 } 114 } 115 } 116 117 instance.setPackages(new ArrayList<>(oraclePackages)); 118 instance.setProcedures(new ArrayList<>(procedureMap.values())); 119 instance.setResultsets(new ArrayList<>(functionMap.values())); 120 121 Map<String, relationship> mergeRelations = new LinkedHashMap<String, relationship>(); 122 123 for (relationship relationship : instance.getRelationships()) { 124 if (relationship.getCaller() == null || relationship.getCallees() == null || relationship.getCallees().size() == 0) { 125 continue; 126 } 127 128 String targetId = relationship.getCaller().getId(); 129 if (procedureIdMap.containsKey(targetId)) { 130 procedure procedure = procedureIdMap.get(targetId); 131 String procedureName = DlineageUtil.getIdentifierProcedureNameWithArgNum(procedure); 132 if (procedure.getOraclePackage() != null) { 133 String qualifiedPackageName = DlineageUtil.getIdentifierOraclePackageNameWithArgNum(procedure.getOraclePackage()); 134 procedureName = qualifiedPackageName + "." + procedureName; 135 } 136 procedure standardProcedure = procedureMap.get(procedureName); 137 relationship.getCaller().setId(standardProcedure.getId()); 138 } else if (functionIdMap.containsKey(targetId)) { 139 table function = functionIdMap.get(targetId); 140 String functionName = DlineageUtil.getIdentifierFunctionName(function); 141 table standardFunction = functionMap.get(functionName); 142 relationship.getCaller().setId(standardFunction.getId()); 143 } 144 145 for (sourceColumn sourceColumn : relationship.getCallees()) { 146 String sourceId = sourceColumn.getId(); 147 if (procedureIdMap.containsKey(sourceId)) { 148 procedure procedure = procedureIdMap.get(sourceId); 149 String procedureName = DlineageUtil.getIdentifierProcedureNameWithArgNum(procedure); 150 if (procedure.getOraclePackage() != null) { 151 String qualifiedPackageName = DlineageUtil.getIdentifierOraclePackageNameWithArgNum(procedure.getOraclePackage()); 152 procedureName = qualifiedPackageName + "." + procedureName; 153 } 154 procedure standardProcedure = procedureMap.get(procedureName); 155 sourceColumn.setId(standardProcedure.getId()); 156 } else if (functionIdMap.containsKey(sourceId)) { 157 table function = functionIdMap.get(sourceId); 158 String functionName = DlineageUtil.getIdentifierFunctionName(function); 159 table standardFunction = functionMap.get(functionName); 160 sourceColumn.setId(standardFunction.getId()); 161 } 162 } 163 164 String jsonString = JSON.toJSONString(relationship).replaceAll("\"id\":\".+?\"", ""); 165 String key = SHA256.getMd5(jsonString); 166 if (!mergeRelations.containsKey(key)) { 167 mergeRelations.put(key, relationship); 168 } 169 } 170 171 instance.setRelationships(new ArrayList<relationship>(mergeRelations.values())); 172 173 if (instance.getPackages() != null) { 174 for (oraclePackage pkg : instance.getPackages()) { 175 if (pkg.getProcedures() != null) { 176 for (procedure procedure : pkg.getProcedures()) { 177 procedure.setOraclePackage(null); 178 } 179 } 180 } 181 } 182 183 return instance; 184 } 185 186 public static dataflow convertTableLevelToFunctionCallDataflow(dataflow dataflow, boolean showBuiltIn, EDbVendor dbVendor) { 187 if (ModelBindingManager.getGlobalVendor() == null) { 188 ModelBindingManager.setGlobalVendor(dbVendor); 189 } 190 191 dataflow instance = cloneDataflow(dataflow); 192 193 if (instance.getRelationships() == null) { 194 return instance; 195 } 196 197 List<relationship> callRelationships = instance.getRelationships().stream() 198 .filter(t -> RelationshipType.call.name().equals(t.getType())) 199 .filter(t -> !showBuiltIn ? !Boolean.TRUE.equals(t.getBuiltIn()): true).collect(Collectors.toList()); 200 instance.setRelationships(callRelationships); 201 202 Set<String> ids = new HashSet<>(); 203 204 205 callRelationships.stream().forEach(t -> { 206 ids.add(t.getCaller().getId()); 207 t.getCallees().stream().forEach(t1 -> ids.add(t1.getId())); 208 }); 209 210 Iterator<table> iterator = instance.getTables().iterator(); 211 while (iterator.hasNext()) { 212 table t = iterator.next(); 213 if (!ids.contains(t.getId())) { 214 iterator.remove(); 215 } 216 } 217 218 iterator = instance.getResultsets().iterator(); 219 while (iterator.hasNext()) { 220 table t = iterator.next(); 221 if (!ids.contains(t.getId())) { 222 iterator.remove(); 223 } 224 } 225 226 iterator = instance.getViews().iterator(); 227 while (iterator.hasNext()) { 228 table t = iterator.next(); 229 if (!ids.contains(t.getId())) { 230 iterator.remove(); 231 } 232 } 233 234 iterator = instance.getStages().iterator(); 235 while (iterator.hasNext()) { 236 table t = iterator.next(); 237 if (!ids.contains(t.getId())) { 238 iterator.remove(); 239 } 240 } 241 242 iterator = instance.getStreams().iterator(); 243 while (iterator.hasNext()) { 244 table t = iterator.next(); 245 if (!ids.contains(t.getId())) { 246 iterator.remove(); 247 } 248 } 249 250 iterator = instance.getVariables().iterator(); 251 while (iterator.hasNext()) { 252 table t = iterator.next(); 253 if (!ids.contains(t.getId())) { 254 iterator.remove(); 255 } 256 } 257 258 iterator = instance.getPaths().iterator(); 259 while (iterator.hasNext()) { 260 table t = iterator.next(); 261 if (!ids.contains(t.getId())) { 262 iterator.remove(); 263 } 264 } 265 266 iterator = instance.getDatasources().iterator(); 267 while (iterator.hasNext()) { 268 table t = iterator.next(); 269 if (!ids.contains(t.getId())) { 270 iterator.remove(); 271 } 272 } 273 274 iterator = instance.getDatabases().iterator(); 275 while (iterator.hasNext()) { 276 table t = iterator.next(); 277 if (!ids.contains(t.getId())) { 278 iterator.remove(); 279 } 280 } 281 282 iterator = instance.getSchemas().iterator(); 283 while (iterator.hasNext()) { 284 table t = iterator.next(); 285 if (!ids.contains(t.getId())) { 286 iterator.remove(); 287 } 288 } 289 290 iterator = instance.getSequences().iterator(); 291 while (iterator.hasNext()) { 292 table t = iterator.next(); 293 if (!ids.contains(t.getId())) { 294 iterator.remove(); 295 } 296 } 297 298 return mergeFunctionCallDataflow(instance, dbVendor); 299 } 300 301 public static dataflow convertToTableLevelDataflow(dataflow dataflow) { 302 dataflow instance = cloneDataflow(dataflow); 303 304 if (instance.getRelationships() == null) { 305 return instance; 306 } 307 308 Map<String, LinkedHashSet<Pair<String, String>>> relationMap = new HashMap<String, LinkedHashSet<Pair<String, String>>>(); 309 Map<String, LinkedHashSet<Pair3<String, String, relationship>>> callRelationMap = new HashMap<String, LinkedHashSet<Pair3<String, String, relationship>>>(); 310 for (RelationshipType type : RelationshipType.values()) { 311 relationMap.put(type.name(), new LinkedHashSet<Pair<String, String>>()); 312 callRelationMap.put(type.name(), new LinkedHashSet<Pair3<String, String, relationship>>()); 313 } 314 for (relationship relationship : instance.getRelationships()) { 315 if (RelationshipType.call.name().equals(relationship.getType())) { 316 String targetId = relationship.getCaller().getId(); 317 for (sourceColumn sourceColumn : relationship.getCallees()) { 318 String sourceId = sourceColumn.getId(); 319 callRelationMap.get(relationship.getType()).add(new Pair3<>(targetId, sourceId, relationship)); 320 } 321 } else { 322 String targetId = relationship.getTarget().getParent_id(); 323 for (sourceColumn sourceColumn : relationship.getSources()) { 324 String sourceId = sourceColumn.getParent_id(); 325 relationMap.get(relationship.getType()).add(new Pair<>(targetId, sourceId)); 326 } 327 } 328 } 329 330 long maxId = 0; 331 Map<String, table> dbObjMap = getDataflowDbObjMap(instance); 332 333 List<procedure> procedures = new ArrayList<>(instance.getProcedures()); 334 if (instance.getPackages() != null) { 335 for (oraclePackage pkg : instance.getPackages()) { 336 procedures.addAll(pkg.getProcedures()); 337 } 338 } 339 340 Map<String, procedure> procedureMap = procedures.stream().collect(Collectors.toMap( 341 t -> t.getId(), 342 t -> t, 343 (existingValue, newValue) -> newValue 344 )); 345 346 for (table table : dbObjMap.values()) { 347 if (Long.valueOf(table.getId()) > maxId) { 348 maxId = Long.valueOf(table.getId()); 349 } 350 } 351 352 AtomicLong id = new AtomicLong(maxId + 10000000); 353 354 for (table table : dbObjMap.values()) { 355 column column = new column(); 356 column.setId(String.valueOf(id.incrementAndGet())); 357 column.setName(table.getType()); 358 table.setColumns(Arrays.asList(column)); 359 } 360 361 List<relationship> relations = new ArrayList<relationship>(); 362 for (RelationshipType type : RelationshipType.values()) { 363 LinkedHashSet<Pair<String, String>> relationSet = relationMap.get(type.name()); 364 LinkedHashSet<Pair3<String, String, relationship>> callRelationSet = callRelationMap.get(type.name()); 365 if (RelationshipType.call.equals(type)) { 366 for (Pair3<String, String, relationship> pair : callRelationSet) { 367 if ((dbObjMap.get(pair.first) == null && procedureMap.get(pair.first) == null) 368 || (dbObjMap.get(pair.second) == null && procedureMap.get(pair.second) == null)) { 369 continue; 370 } 371 372 relationship relationship = new relationship(); 373 relationship.setType(type.name()); 374 relationship.setId(String.valueOf(id.incrementAndGet())); 375 relationship.setCallStmt(pair.third.getCallStmt()); 376 relationship.setCallCoordinate(pair.third.getCallCoordinate()); 377 378 targetColumn targetColumn = new targetColumn(); 379 if (dbObjMap.containsKey(pair.first)) { 380 targetColumn.setId(dbObjMap.get(pair.first).getId()); 381 targetColumn.setName(dbObjMap.get(pair.first).getName()); 382 targetColumn.setCoordinate(dbObjMap.get(pair.first).getCoordinate()); 383 } else { 384 targetColumn.setId(procedureMap.get(pair.first).getId()); 385 targetColumn.setName(procedureMap.get(pair.first).getName()); 386 targetColumn.setCoordinate(procedureMap.get(pair.first).getCoordinate()); 387 } 388 389 sourceColumn sourceColumn = new sourceColumn(); 390 if (dbObjMap.containsKey(pair.second)) { 391 sourceColumn.setId(dbObjMap.get(pair.second).getId()); 392 sourceColumn.setName(dbObjMap.get(pair.second).getName()); 393 sourceColumn.setCoordinate(dbObjMap.get(pair.second).getCoordinate()); 394 } else { 395 sourceColumn.setId(procedureMap.get(pair.second).getId()); 396 sourceColumn.setName(procedureMap.get(pair.second).getName()); 397 sourceColumn.setCoordinate(procedureMap.get(pair.second).getCoordinate()); 398 } 399 400 relationship.setCaller(targetColumn); 401 relationship.setCallees(Arrays.asList(sourceColumn)); 402 relationship.setBuiltIn(pair.third.getBuiltIn()); 403 relations.add(relationship); 404 } 405 } else { 406 for (Pair<String, String> pair : relationSet) { 407 if (dbObjMap.get(pair.first) == null || dbObjMap.get(pair.second) == null) { 408 continue; 409 } 410 relationship relationship = new relationship(); 411 relationship.setType(type.name()); 412 relationship.setId(String.valueOf(id.incrementAndGet())); 413 targetColumn targetColumn = new targetColumn(); 414 targetColumn.setId(dbObjMap.get(pair.first).getColumns().get(0).getId()); 415 targetColumn.setColumn(dbObjMap.get(pair.first).getColumns().get(0).getName()); 416 targetColumn.setParent_id(pair.first); 417 targetColumn.setParent_name(dbObjMap.get(pair.first).getName()); 418 sourceColumn sourceColumn = new sourceColumn(); 419 sourceColumn.setId(dbObjMap.get(pair.second).getColumns().get(0).getId()); 420 sourceColumn.setColumn(dbObjMap.get(pair.second).getColumns().get(0).getName()); 421 sourceColumn.setParent_id(pair.second); 422 sourceColumn.setParent_name(dbObjMap.get(pair.second).getName()); 423 relationship.setTarget(targetColumn); 424 relationship.setSources(Arrays.asList(sourceColumn)); 425 relations.add(relationship); 426 } 427 } 428 } 429 instance.setRelationships(relations); 430 return instance; 431 } 432 433 public static dataflow convertToSchemaLevelDataflow(dataflow dataflow, EDbVendor dbVendor) throws Exception { 434 return convertToSchemaLevelDataflow(dataflow, dbVendor, false); 435 } 436 437 public static dataflow convertToSchemaLevelDataflow(dataflow dataflow, EDbVendor dbVendor, boolean isSimple) throws Exception { 438 dataflow instance = cloneDataflow(dataflow); 439 440 if (!isSimple) { 441 DataFlowAnalyzer analyzer = new DataFlowAnalyzer("", dbVendor, true); 442 instance = analyzer.getSimpleDataflow(instance, true, Arrays.asList(new String[]{"fdd", "fdr"})); 443 } 444 445 List<table> allTables = new ArrayList<table>(); 446 allTables.addAll(instance.getTables()); 447 allTables.addAll(instance.getViews()); 448 449 ModelBindingManager.setGlobalVendor(dbVendor); 450 451 Map<String, String> tableIdSchameNameMap = allTables.stream().collect(Collectors.toMap(table -> table.getId(), table -> table.getFullSchemaName(), (existingValue, newValue) -> newValue)); 452 453 if (instance.getRelationships() == null) { 454 return instance; 455 } 456 457 Map<String, LinkedHashSet<Pair<String, String>>> relationMap = new HashMap<String, LinkedHashSet<Pair<String, String>>>(); 458 for (RelationshipType type : RelationshipType.values()) { 459 relationMap.put(type.name(), new LinkedHashSet<Pair<String, String>>()); 460 } 461 for (relationship relationship : instance.getRelationships()) { 462 String targetId = relationship.getTarget().getParent_id(); 463 for (sourceColumn sourceColumn : relationship.getSources()) { 464 String sourceId = sourceColumn.getParent_id(); 465 relationMap.get(relationship.getType()).add(new Pair<>(tableIdSchameNameMap.get(targetId), tableIdSchameNameMap.get(sourceId))); 466 } 467 } 468 469 Map<String, table> dbObjMap = getDataflowDbObjMap(instance); 470 LinkedHashSet<String> schemaNameSet = new LinkedHashSet<String>(); 471 schemaNameSet.addAll(tableIdSchameNameMap.values()); 472 List<table> schemaTables = new ArrayList<table>(); 473 474 AtomicLong id = new AtomicLong(0); 475 476 for (String schemaName : schemaNameSet) { 477 table table = new table(); 478 table.setId(String.valueOf(id.incrementAndGet())); 479 table.setName(schemaName); 480 table.setType("schema"); 481 schemaTables.add(table); 482 dbObjMap.put(schemaName, table); 483 } 484 485 for (table table : schemaTables) { 486 column column = new column(); 487 column.setId(String.valueOf(id.incrementAndGet())); 488 column.setName(table.getType()); 489 table.setColumns(Arrays.asList(column)); 490 } 491 492 List<relationship> relations = new ArrayList<relationship>(); 493 for (RelationshipType type : RelationshipType.values()) { 494 LinkedHashSet<Pair<String, String>> relationSet = relationMap.get(type.name()); 495 496 for (Pair<String, String> pair : relationSet) { 497 if (dbObjMap.get(pair.first) == null || dbObjMap.get(pair.second) == null) { 498 continue; 499 } 500 relationship relationship = new relationship(); 501 relationship.setType(type.name()); 502 relationship.setId(String.valueOf(id.incrementAndGet())); 503 targetColumn targetColumn = new targetColumn(); 504 targetColumn.setId(dbObjMap.get(pair.first).getColumns().get(0).getId()); 505 targetColumn.setColumn(dbObjMap.get(pair.first).getColumns().get(0).getName()); 506 targetColumn.setParent_id(dbObjMap.get(pair.first).getId()); 507 targetColumn.setParent_name(dbObjMap.get(pair.first).getName()); 508 sourceColumn sourceColumn = new sourceColumn(); 509 sourceColumn.setId(dbObjMap.get(pair.second).getColumns().get(0).getId()); 510 sourceColumn.setColumn(dbObjMap.get(pair.second).getColumns().get(0).getName()); 511 sourceColumn.setParent_id(dbObjMap.get(pair.second).getId()); 512 sourceColumn.setParent_name(dbObjMap.get(pair.second).getName()); 513 relationship.setTarget(targetColumn); 514 relationship.setSources(Arrays.asList(sourceColumn)); 515 relations.add(relationship); 516 } 517 } 518 519 dataflow schemaDataflow = new dataflow(); 520 schemaDataflow.setTables(schemaTables); 521 schemaDataflow.setRelationships(relations); 522 return schemaDataflow; 523 } 524 525 public static dataflow cloneDataflow(dataflow dataflow) { 526 dataflow dataflowCopy = new dataflow(); 527 if (dataflow.getTables() != null) { 528 dataflowCopy.setTables(cloneTables(dataflow.getTables())); 529 } 530 if (dataflow.getViews() != null) { 531 dataflowCopy.setViews(cloneTables(dataflow.getViews())); 532 } 533 if (dataflow.getRelationships() != null) { 534 dataflowCopy.setRelationships(new ArrayList<>(dataflow.getRelationships())); 535 } 536 if (dataflow.getErrors() != null) { 537 dataflowCopy.setErrors(new ArrayList<>(dataflow.getErrors())); 538 } 539 if (dataflow.getPaths() != null) { 540 dataflowCopy.setPaths(cloneTables(dataflow.getPaths())); 541 } 542 if (dataflow.getPackages() != null) { 543 dataflowCopy.setPackages(new ArrayList<>(dataflow.getPackages())); 544 } 545 if (dataflow.getProcedures() != null) { 546 dataflowCopy.setProcedures(new ArrayList<>(dataflow.getProcedures())); 547 } 548 if (dataflow.getProcesses() != null) { 549 dataflowCopy.setProcesses(new ArrayList<>(dataflow.getProcesses())); 550 } 551 if (dataflow.getResultsets() != null) { 552 dataflowCopy.setResultsets(cloneTables(dataflow.getResultsets())); 553 } 554 if (dataflow.getVariables() != null) { 555 dataflowCopy.setVariables(cloneTables(dataflow.getVariables())); 556 } 557 if (dataflow.getStages() != null) { 558 dataflowCopy.setStages(cloneTables(dataflow.getStages())); 559 } 560 if (dataflow.getSequences() != null) { 561 dataflowCopy.setSequences(cloneTables(dataflow.getSequences())); 562 } 563 if (dataflow.getDatasources() != null) { 564 dataflowCopy.setDatasources(cloneTables(dataflow.getDatasources())); 565 } 566 if (dataflow.getDatabases() != null) { 567 dataflowCopy.setDatabases(cloneTables(dataflow.getDatabases())); 568 } 569 if (dataflow.getSchemas() != null) { 570 dataflowCopy.setSchemas(cloneTables(dataflow.getSchemas())); 571 } 572 if (dataflow.getStreams() != null) { 573 dataflowCopy.setStreams(cloneTables(dataflow.getStreams())); 574 } 575 dataflowCopy.setOrientation(dataflow.getOrientation()); 576 return dataflowCopy; 577 } 578 579 private static List<table> cloneTables(List<table> tableList) { 580 if (tableList == null) { 581 return null; 582 } 583 List<table> tables = new ArrayList<>(tableList.size()); 584 for (table item : tableList) { 585 try { 586 table table = (table) item.clone(); 587 if (item.getColumns() != null) { 588 table.setColumns(new ArrayList<column>(item.getColumns())); 589 } 590 tables.add(table); 591 } catch (CloneNotSupportedException e) { 592 logger.error("Clone table failed.", e); 593 } 594 } 595 return tables; 596 } 597 598 public static Map<String, table> getDataflowDbObjMap(dataflow dataflow) { 599 List<table> tables = new ArrayList<table>(); 600 if (dataflow.getTables() != null) { 601 tables.addAll(dataflow.getTables()); 602 } 603 if (dataflow.getViews() != null) { 604 tables.addAll(dataflow.getViews()); 605 } 606 if (dataflow.getPaths() != null) { 607 tables.addAll(dataflow.getPaths()); 608 } 609 if (dataflow.getResultsets() != null) { 610 tables.addAll(dataflow.getResultsets()); 611 } 612 if (dataflow.getVariables() != null) { 613 tables.addAll(dataflow.getVariables()); 614 } 615 if (dataflow.getStages() != null) { 616 tables.addAll(dataflow.getStages()); 617 } 618 if (dataflow.getSequences() != null) { 619 tables.addAll(dataflow.getSequences()); 620 } 621 if (dataflow.getDatasources() != null) { 622 tables.addAll(dataflow.getDatasources()); 623 } 624 if (dataflow.getDatabases() != null) { 625 tables.addAll(dataflow.getDatabases()); 626 } 627 if (dataflow.getSchemas() != null) { 628 tables.addAll(dataflow.getSchemas()); 629 } 630 if (dataflow.getStreams() != null) { 631 tables.addAll(dataflow.getStreams()); 632 } 633 634 Map<String, table> dbObjMap = new HashMap<>(); 635 for (table table : tables) { 636 dbObjMap.put(table.getId(), table); 637 } 638 return dbObjMap; 639 } 640 public static Map<String, table> getDataflowDbObjNameMap(dataflow dataflow) { 641 List<table> tables = new ArrayList<table>(); 642 if (dataflow.getTables() != null) { 643 tables.addAll(dataflow.getTables()); 644 } 645 if (dataflow.getViews() != null) { 646 tables.addAll(dataflow.getViews()); 647 } 648 if (dataflow.getPaths() != null) { 649 tables.addAll(dataflow.getPaths()); 650 } 651 if (dataflow.getResultsets() != null) { 652 tables.addAll(dataflow.getResultsets()); 653 } 654 if (dataflow.getVariables() != null) { 655 tables.addAll(dataflow.getVariables()); 656 } 657 if (dataflow.getStages() != null) { 658 tables.addAll(dataflow.getStages()); 659 } 660 if (dataflow.getSequences() != null) { 661 tables.addAll(dataflow.getSequences()); 662 } 663 if (dataflow.getDatasources() != null) { 664 tables.addAll(dataflow.getDatasources()); 665 } 666 if (dataflow.getDatabases() != null) { 667 tables.addAll(dataflow.getDatabases()); 668 } 669 if (dataflow.getSchemas() != null) { 670 tables.addAll(dataflow.getSchemas()); 671 } 672 if (dataflow.getStreams() != null) { 673 tables.addAll(dataflow.getStreams()); 674 } 675 676 Map<String, table> dbObjMap = new HashMap<>(); 677 for(table table: tables){ 678 dbObjMap.put(table.getFullName(), table); 679 } 680 return dbObjMap; 681 } 682 public static dataflow mergeDataflowsWithDifferentStartId(Collection<dataflow> dataflows, EDbVendor vendor) { 683 ModelBindingManager.setGlobalVendor(vendor); 684 try { 685 return mergeDataflowsByStartId(dataflows, DATAFLOW_ID_RANGE * dataflows.size()); 686 } finally { 687 ModelBindingManager.removeGlobalVendor(); 688 } 689 } 690 691 /** 692 * 内部合并实现:调用方需保证所有输入 dataflow 的 ID 空间不冲突,并且已提前设置好 ModelBindingManager。 693 * <p> 694 * 该方法代替之前位于 {@code ParallelDataFlowAnalyzer} 的同名实现,外部调用者应使用 695 * {@link #mergeDataflowsWithDifferentStartId(Collection, EDbVendor)} 或 696 * {@link #mergeDataflows(Collection, EDbVendor)}。 697 */ 698 public static dataflow mergeDataflowsByStartId(Collection<dataflow> dataflows, long startId) { 699 dataflow mergeDataflow = new dataflow(); 700 701 List<table> tableCopy = new ArrayList<table>(); 702 List<table> viewCopy = new ArrayList<table>(); 703 List<table> databaseCopy = new ArrayList<table>(); 704 List<table> schemaCopy = new ArrayList<table>(); 705 List<table> stageCopy = new ArrayList<table>(); 706 List<table> dataSourceCopy = new ArrayList<table>(); 707 List<table> streamCopy = new ArrayList<table>(); 708 List<table> fileCopy = new ArrayList<table>(); 709 List<table> variableCopy = new ArrayList<table>(); 710 List<table> resultSetCopy = new ArrayList<table>(); 711 List<table> sequenceCopy = new ArrayList<table>(); 712 713 List<process> processCopy = new ArrayList<process>(); 714 List<relationship> relationshipCopy = new ArrayList<relationship>(); 715 List<procedure> procedureCopy = new ArrayList<procedure>(); 716 List<oraclePackage> packageCopy = new ArrayList<oraclePackage>(); 717 List<error> errorCopy = new ArrayList<error>(); 718 719 List<table> tables = new ArrayList<table>(); 720 for (dataflow dataflow : dataflows) { 721 if (dataflow == null) { 722 continue; 723 } 724 725 if (dataflow.getTables() != null) { 726 tableCopy.addAll(dataflow.getTables()); 727 } 728 mergeDataflow.setTables(tableCopy); 729 if (dataflow.getViews() != null) { 730 viewCopy.addAll(dataflow.getViews()); 731 } 732 mergeDataflow.setViews(viewCopy); 733 if (dataflow.getDatabases() != null) { 734 databaseCopy.addAll(dataflow.getDatabases()); 735 } 736 mergeDataflow.setDatabases(databaseCopy); 737 if (dataflow.getSchemas() != null) { 738 schemaCopy.addAll(dataflow.getSchemas()); 739 } 740 mergeDataflow.setSchemas(schemaCopy); 741 if (dataflow.getStages() != null) { 742 stageCopy.addAll(dataflow.getStages()); 743 } 744 mergeDataflow.setStages(stageCopy); 745 if (dataflow.getDatasources() != null) { 746 dataSourceCopy.addAll(dataflow.getDatasources()); 747 } 748 mergeDataflow.setDatasources(dataSourceCopy); 749 if (dataflow.getStreams() != null) { 750 streamCopy.addAll(dataflow.getStreams()); 751 } 752 mergeDataflow.setStreams(streamCopy); 753 if (dataflow.getPaths() != null) { 754 fileCopy.addAll(dataflow.getPaths()); 755 } 756 mergeDataflow.setPaths(fileCopy); 757 if (dataflow.getVariables() != null) { 758 variableCopy.addAll(dataflow.getVariables()); 759 } 760 mergeDataflow.setVariables(variableCopy); 761 if (dataflow.getResultsets() != null) { 762 resultSetCopy.addAll(dataflow.getResultsets()); 763 } 764 mergeDataflow.setResultsets(resultSetCopy); 765 if (dataflow.getSequences() != null) { 766 sequenceCopy.addAll(dataflow.getSequences()); 767 } 768 mergeDataflow.setSequences(sequenceCopy); 769 if (dataflow.getProcesses() != null) { 770 processCopy.addAll(dataflow.getProcesses()); 771 } 772 mergeDataflow.setProcesses(processCopy); 773 if (dataflow.getRelationships() != null) { 774 relationshipCopy.addAll(dataflow.getRelationships()); 775 } 776 mergeDataflow.setRelationships(relationshipCopy); 777 if (dataflow.getProcedures() != null) { 778 procedureCopy.addAll(dataflow.getProcedures()); 779 } 780 mergeDataflow.setProcedures(procedureCopy); 781 if (dataflow.getPackages() != null) { 782 packageCopy.addAll(dataflow.getPackages()); 783 } 784 mergeDataflow.setPackages(packageCopy); 785 if (dataflow.getErrors() != null) { 786 errorCopy.addAll(dataflow.getErrors()); 787 } 788 if (errorCopy.size() > 10000) { 789 errorCopy = errorCopy.subList(0, 10000); 790 } 791 mergeDataflow.setErrors(errorCopy); 792 793 tables.addAll(dataflow.getTables()); 794 tables.addAll(dataflow.getViews()); 795 tables.addAll(dataflow.getDatabases()); 796 tables.addAll(dataflow.getSchemas()); 797 tables.addAll(dataflow.getStages()); 798 tables.addAll(dataflow.getDatasources()); 799 tables.addAll(dataflow.getStreams()); 800 tables.addAll(dataflow.getPaths()); 801 tables.addAll(dataflow.getResultsets()); 802 tables.addAll(dataflow.getVariables()); 803 if (dataflow.getSequences() != null) { 804 tables.addAll(dataflow.getSequences()); 805 } 806 } 807 808 Map<String, List<table>> tableMap = new HashMap<String, List<table>>(); 809 Map<String, String> tableTypeMap = new HashMap<String, String>(); 810 Map<String, String> tableIdMap = new HashMap<String, String>(); 811 812 Map<String, List<column>> columnMap = new HashMap<String, List<column>>(); 813 Map<String, Set<String>> tableColumnMap = new HashMap<String, Set<String>>(); 814 Map<String, String> columnIdMap = new HashMap<String, String>(); 815 Map<String, column> columnMergeIdMap = new HashMap<String, column>(); 816 817 List<procedure> procedures = new ArrayList<>(mergeDataflow.getProcedures()); 818 if (mergeDataflow.getPackages() != null) { 819 for (oraclePackage pkg : mergeDataflow.getPackages()) { 820 procedures.addAll(pkg.getProcedures()); 821 } 822 } 823 824 Set<String> procedureIdSet = procedures.stream().map(t -> t.getId()).collect(Collectors.toSet()); 825 826 for (table table : tables) { 827 String qualifiedTableName = DlineageUtil.getQualifiedTableName(table); 828 String tableFullName = DlineageUtil.getIdentifierNormalTableName(qualifiedTableName); 829 if ("variable".endsWith(table.getType()) && !SQLUtil.isEmpty(table.getParent())) { 830 tableFullName = table.getParent() + "." + tableFullName; 831 } 832 833 if (!tableMap.containsKey(tableFullName)) { 834 tableMap.put(tableFullName, new ArrayList<table>()); 835 } 836 837 tableMap.get(tableFullName).add(table); 838 839 if (!tableTypeMap.containsKey(tableFullName)) { 840 tableTypeMap.put(tableFullName, table.getType()); 841 } else if ("view".equals(table.getSubType())) { 842 tableTypeMap.put(tableFullName, table.getType()); 843 } else if ("database".equals(table.getSubType())) { 844 tableTypeMap.put(tableFullName, table.getType()); 845 } else if ("schema".equals(table.getSubType())) { 846 tableTypeMap.put(tableFullName, table.getType()); 847 } else if ("stage".equals(table.getSubType())) { 848 tableTypeMap.put(tableFullName, table.getType()); 849 } else if ("datasource".equals(table.getSubType())) { 850 tableTypeMap.put(tableFullName, table.getType()); 851 } else if ("stream".equals(table.getSubType())) { 852 tableTypeMap.put(tableFullName, table.getType()); 853 } else if ("file".equals(table.getSubType())) { 854 tableTypeMap.put(tableFullName, table.getType()); 855 } else if ("sequence".equals(table.getSubType())) { 856 tableTypeMap.put(tableFullName, table.getType()); 857 } else if ("table".equals(tableTypeMap.get(tableFullName))) { 858 tableTypeMap.put(tableFullName, table.getType()); 859 } else if ("variable".equals(tableTypeMap.get(tableFullName))) { 860 tableTypeMap.put(tableFullName, table.getType()); 861 } 862 863 if (table.getColumns() != null) { 864 if (!tableColumnMap.containsKey(tableFullName)) { 865 tableColumnMap.put(tableFullName, new LinkedHashSet<String>()); 866 } 867 for (column column : table.getColumns()) { 868 String columnFullName = tableFullName + "." 869 + DlineageUtil.getIdentifierNormalColumnName(column.getName()); 870 871 if (!columnMap.containsKey(columnFullName)) { 872 columnMap.put(columnFullName, new ArrayList<column>()); 873 tableColumnMap.get(tableFullName).add(columnFullName); 874 } 875 876 columnMap.get(columnFullName).add(column); 877 } 878 } 879 } 880 881 Iterator<String> tableNameIter = tableMap.keySet().iterator(); 882 while (tableNameIter.hasNext()) { 883 String tableName = tableNameIter.next(); 884 List<table> tableList = tableMap.get(tableName); 885 table table; 886 if (tableList.size() > 1) { 887 table standardTable = tableList.get(0); 888 //Function允许重名,不做合并处理 889 if (standardTable.isFunction()) { 890 continue; 891 } 892 893 String type = tableTypeMap.get(tableName); 894 table = new table(); 895 table.setId(String.valueOf(++startId)); 896 table.setServer(standardTable.getServer()); 897 table.setDatabase(standardTable.getDatabase()); 898 table.setSchema(standardTable.getSchema()); 899 table.setName(standardTable.getName()); 900 table.setDisplayName(standardTable.getDisplayName()); 901 table.setParent(standardTable.getParent()); 902 table.setColumns(new ArrayList<column>()); 903 String subType = null; 904 for(table item: tableList){ 905 if (item.getSubType() != null) { 906 subType = item.getSubType(); 907 break; 908 } 909 } 910 if (subType != null) { 911 table.setSubType(subType); 912 } else { 913 table.setSubType(standardTable.getSubType()); 914 } 915 Set<String> processIds = new LinkedHashSet<String>(); 916 for (int k = 0; k < tableList.size(); k++) { 917 if (tableList.get(k).getProcessIds() != null) { 918 processIds.addAll(tableList.get(k).getProcessIds()); 919 } 920 } 921 if (!processIds.isEmpty()) { 922 table.setProcessIds(new ArrayList<String>(processIds)); 923 } 924 table.setType(type); 925 for (table item : tableList) { 926 if (!SQLUtil.isEmpty(table.getCoordinate()) && !SQLUtil.isEmpty(item.getCoordinate())) { 927 if (table.getCoordinate().indexOf(item.getCoordinate()) == -1) { 928 table.appendCoordinate(item.getCoordinate()); 929 } 930 } else if (!SQLUtil.isEmpty(item.getCoordinate())) { 931 table.setCoordinate(item.getCoordinate()); 932 } 933 934 if (!SQLUtil.isEmpty(table.getAlias()) && !SQLUtil.isEmpty(item.getAlias())) { 935 table.setAlias(table.getAlias() + "," + item.getAlias()); 936 } else if (!SQLUtil.isEmpty(item.getAlias())) { 937 table.setAlias(item.getAlias()); 938 } 939 940 tableIdMap.put(item.getId(), table.getId()); 941 942 if (item.isView()) { 943 mergeDataflow.getViews().remove(item); 944 } else if (item.isDatabaseType()) { 945 mergeDataflow.getDatabases().remove(item); 946 } else if (item.isSchemaType()) { 947 mergeDataflow.getSchemas().remove(item); 948 } else if (item.isStage()) { 949 mergeDataflow.getStages().remove(item); 950 } else if (item.isDataSource()) { 951 mergeDataflow.getDatasources().remove(item); 952 } else if (item.isStream()) { 953 mergeDataflow.getStreams().remove(item); 954 } else if (item.isFile()) { 955 mergeDataflow.getPaths().remove(item); 956 } else if (item.isVariable()) { 957 mergeDataflow.getVariables().remove(item); 958 } else if (item.isTable()) { 959 mergeDataflow.getTables().remove(item); 960 } else if (item.isResultSet()) { 961 mergeDataflow.getResultsets().remove(item); 962 } else if (item.isSequence()) { 963 mergeDataflow.getSequences().remove(item); 964 } 965 } 966 967 if (table.isView()) { 968 mergeDataflow.getViews().add(table); 969 } else if (table.isDatabaseType()) { 970 mergeDataflow.getDatabases().add(table); 971 } else if (table.isSchemaType()) { 972 mergeDataflow.getSchemas().add(table); 973 } else if (table.isStage()) { 974 mergeDataflow.getStages().add(table); 975 } else if (table.isDataSource()) { 976 mergeDataflow.getDatasources().add(table); 977 } else if (table.isStream()) { 978 mergeDataflow.getStreams().add(table); 979 } else if (table.isFile()) { 980 mergeDataflow.getPaths().add(table); 981 } else if (table.isVariable()) { 982 mergeDataflow.getVariables().add(table); 983 } else if (table.isResultSet()) { 984 mergeDataflow.getResultsets().add(table); 985 } else if (table.isSequence()) { 986 mergeDataflow.getSequences().add(table); 987 } else { 988 mergeDataflow.getTables().add(table); 989 } 990 } else { 991 table = tableList.get(0); 992 } 993 994 Set<String> columns = tableColumnMap.get(tableName); 995 Iterator<String> columnIter = columns.iterator(); 996 List<column> mergeColumns = new ArrayList<column>(); 997 while (columnIter.hasNext()) { 998 String columnName = columnIter.next(); 999 List<column> columnList = columnMap.get(columnName); 1000 List<column> functions = new ArrayList<column>(); 1001 for (column t : columnList) { 1002 if (Boolean.TRUE.toString().equals(t.getIsFunction())) { 1003 functions.add(t); 1004 } 1005 } 1006 if (functions != null && !functions.isEmpty()) { 1007 for (column function : functions) { 1008 mergeColumns.add(function); 1009 columnIdMap.put(function.getId(), function.getId()); 1010 columnMergeIdMap.put(function.getId(), function); 1011 } 1012 1013 columnList.removeAll(functions); 1014 } 1015 if (!columnList.isEmpty()) { 1016 column firstColumn = columnList.iterator().next(); 1017 if (columnList.size() > 1) { 1018 column mergeColumn = new column(); 1019 mergeColumn.setId(String.valueOf(++startId)); 1020 mergeColumn.setName(firstColumn.getName()); 1021 mergeColumn.setDisplayName(firstColumn.getDisplayName()); 1022 mergeColumn.setSource(firstColumn.getSource()); 1023 mergeColumn.setQualifiedTable(firstColumn.getQualifiedTable()); 1024 mergeColumns.add(mergeColumn); 1025 for (column item : columnList) { 1026 mergeColumn.appendCoordinate(item.getCoordinate()); 1027 columnIdMap.put(item.getId(), mergeColumn.getId()); 1028 //add by grq 2023.02.06 issue=I6DB5S 1029 if (item.getDataType() != null) { 1030 mergeColumn.setDataType(item.getDataType()); 1031 } 1032 if (item.isForeignKey() != null) { 1033 mergeColumn.setForeignKey(item.isForeignKey()); 1034 } 1035 if (item.isUnqiueKey() != null) { 1036 mergeColumn.setUnqiueKey(item.isUnqiueKey()); 1037 } 1038 if (item.isIndexKey() != null) { 1039 mergeColumn.setIndexKey(item.isIndexKey()); 1040 } 1041 if (item.isPrimaryKey() != null) { 1042 mergeColumn.setPrimaryKey(item.isPrimaryKey()); 1043 } 1044 //end by grq 1045 } 1046 columnMergeIdMap.put(mergeColumn.getId(), mergeColumn); 1047 } else { 1048 mergeColumns.add(firstColumn); 1049 columnIdMap.put(firstColumn.getId(), firstColumn.getId()); 1050 columnMergeIdMap.put(firstColumn.getId(), firstColumn); 1051 } 1052 } 1053 } 1054 table.setColumns(mergeColumns); 1055 } 1056 1057 if (mergeDataflow.getRelationships() != null) { 1058 Map<String, relationship> mergeRelations = new LinkedHashMap<String, relationship>(); 1059 for (int i = 0; i < mergeDataflow.getRelationships().size(); i++) { 1060 relationship relation = mergeDataflow.getRelationships().get(i); 1061 if (RelationshipType.call.name().equals(relation.getType())) { 1062 targetColumn target = relation.getCaller(); 1063 if (target == null) { 1064 continue; 1065 } 1066 if (target != null && tableIdMap.containsKey(target.getId())) { 1067 target.setId(tableIdMap.get(target.getId())); 1068 } 1069 1070 List<sourceColumn> sources = relation.getCallees(); 1071 Set<sourceColumn> sourceSet = new LinkedHashSet<sourceColumn>(); 1072 if (sources != null) { 1073 for (sourceColumn source : sources) { 1074 if (tableIdMap.containsKey(source.getId())) { 1075 source.setId(tableIdMap.get(source.getId())); 1076 } 1077 } 1078 sourceSet.addAll(sources); 1079 relation.setCallees(new ArrayList<sourceColumn>(sourceSet)); 1080 } 1081 1082 String jsonString = JSON.toJSONString(relation, true); 1083 String key = SHA256.getMd5(jsonString); 1084 if (!mergeRelations.containsKey(key)) { 1085 mergeRelations.put(key, relation); 1086 } 1087 } else { 1088 targetColumn target = relation.getTarget(); 1089 if (target == null) { 1090 continue; 1091 } 1092 if (target != null && tableIdMap.containsKey(target.getParent_id())) { 1093 target.setParent_id(tableIdMap.get(target.getParent_id())); 1094 } 1095 1096 if (columnIdMap.containsKey(target.getId())) { 1097 target.setId(columnIdMap.get(target.getId())); 1098 target.setCoordinate(columnMergeIdMap.get(target.getId()).getCoordinate()); 1099 } 1100 1101 List<sourceColumn> sources = relation.getSources(); 1102 Set<sourceColumn> sourceSet = new LinkedHashSet<sourceColumn>(); 1103 if (sources != null) { 1104 for (sourceColumn source : sources) { 1105 if (tableIdMap.containsKey(source.getParent_id())) { 1106 source.setParent_id(tableIdMap.get(source.getParent_id())); 1107 } 1108 if (tableIdMap.containsKey(source.getSource_id())) { 1109 source.setSource_id(tableIdMap.get(source.getSource_id())); 1110 } 1111 if (columnIdMap.containsKey(source.getId())) { 1112 source.setId(columnIdMap.get(source.getId())); 1113 source.setCoordinate(columnMergeIdMap.get(source.getId()).getCoordinate()); 1114 } 1115 } 1116 1117 sourceSet.addAll(sources); 1118 relation.setSources(new ArrayList<sourceColumn>(sourceSet)); 1119 } 1120 1121 String jsonString = JSON.toJSONString(relation, true); 1122 String key = SHA256.getMd5(jsonString); 1123 if (!mergeRelations.containsKey(key)) { 1124 mergeRelations.put(key, relation); 1125 } 1126 } 1127 } 1128 1129 mergeDataflow.setRelationships(new ArrayList<relationship>(mergeRelations.values())); 1130 } 1131 1132 startId = addStarColumnBridgingRelations(mergeDataflow, startId); 1133 1134 tableMap.clear(); 1135 tableTypeMap.clear(); 1136 tableIdMap.clear(); 1137 columnMap.clear(); 1138 tableColumnMap.clear(); 1139 columnIdMap.clear(); 1140 columnMergeIdMap.clear(); 1141 tables.clear(); 1142 1143 return mergeDataflow; 1144 } 1145 1146 /** 1147 * 合并后同一张表可能同时拥有 * 列(来自只做 SELECT * 的来源)和具名列(来自显式引用列名的来源), 1148 * 但缺少 * -> 具名列 的 fdd 关系,会导致 上游.* -> 表.* 与 表.具名列 -> 下游.具名列 之间链路断开。 1149 * 本方法为这类表补齐 * -> 每个具名列 的 fdd 桥接(已存在则跳过;忽略 system / function 列)。 1150 */ 1151 private static long addStarColumnBridgingRelations(dataflow df, long startId) { 1152 if (df == null) { 1153 return startId; 1154 } 1155 List<relationship> newRelations = new ArrayList<>(); 1156 for (table t : dataflow.getAllTables(df)) { 1157 if (t.getColumns() == null || t.getColumns().size() < 2) { 1158 continue; 1159 } 1160 column starColumn = null; 1161 List<column> regularColumns = new ArrayList<>(); 1162 for (column c : t.getColumns()) { 1163 if ("system".equals(c.getSource())) { 1164 continue; 1165 } 1166 if (Boolean.TRUE.toString().equals(c.getIsFunction())) { 1167 continue; 1168 } 1169 if ("*".equals(c.getName())) { 1170 if (starColumn == null) { 1171 starColumn = c; 1172 } 1173 } else { 1174 regularColumns.add(c); 1175 } 1176 } 1177 if (starColumn == null || regularColumns.isEmpty()) { 1178 continue; 1179 } 1180 1181 Set<String> existingBridges = new HashSet<>(); 1182 if (df.getRelationships() != null) { 1183 for (relationship rel : df.getRelationships()) { 1184 if (!RelationshipType.fdd.name().equals(rel.getType())) { 1185 continue; 1186 } 1187 if (rel.getTarget() == null || rel.getSources() == null) { 1188 continue; 1189 } 1190 if (!t.getId().equals(rel.getTarget().getParent_id())) { 1191 continue; 1192 } 1193 for (sourceColumn sc : rel.getSources()) { 1194 if (t.getId().equals(sc.getParent_id())) { 1195 existingBridges.add(rel.getTarget().getId() + "<-" + sc.getId()); 1196 } 1197 } 1198 } 1199 } 1200 1201 String starId = starColumn.getId(); 1202 for (column target : regularColumns) { 1203 if (existingBridges.contains(target.getId() + "<-" + starId)) { 1204 continue; 1205 } 1206 relationship rel = new relationship(); 1207 rel.setId(String.valueOf(++startId)); 1208 rel.setType(RelationshipType.fdd.name()); 1209 rel.setEffectType("expand_star"); 1210 1211 targetColumn tc = new targetColumn(); 1212 tc.setId(target.getId()); 1213 tc.setColumn(target.getName()); 1214 tc.setParent_id(t.getId()); 1215 tc.setParent_name(t.getName()); 1216 rel.setTarget(tc); 1217 1218 sourceColumn sc = new sourceColumn(); 1219 sc.setId(starId); 1220 sc.setColumn(starColumn.getName()); 1221 sc.setParent_id(t.getId()); 1222 sc.setParent_name(t.getName()); 1223 rel.setSources(Arrays.asList(sc)); 1224 1225 newRelations.add(rel); 1226 } 1227 } 1228 if (!newRelations.isEmpty()) { 1229 List<relationship> all = df.getRelationships() != null 1230 ? new ArrayList<>(df.getRelationships()) 1231 : new ArrayList<>(); 1232 all.addAll(newRelations); 1233 df.setRelationships(all); 1234 } 1235 return startId; 1236 } 1237 1238 /** 1239 * 单个 dataflow 的 ID 跨度(与 ParallelDataFlowAnalyzer 中的常量保持一致)。 1240 */ 1241 private static final long DATAFLOW_ID_RANGE = 5000000L; 1242 1243 /** 1244 * 合并一组 startId 都为 0(即 ID 空间相互冲突)的 dataflow。 1245 * <p> 1246 * 标准合并 {@link #mergeDataflowsWithDifferentStartId(Collection, EDbVendor)} 的前提是 1247 * 每个 dataflow 在生成时已通过 {@code optionCopy.setStartId(5000000L * i)} 占用了 1248 * 不重叠的 ID 段;当外部调用方拿到的 dataflow 都是用默认 startId=0 生成时,直接合并 1249 * 会因为 ID 冲突而错乱。本方法会先按下标把每个 dataflow 的全部 ID 偏移 1250 * {@link #DATAFLOW_ID_RANGE} * index,再委托给标准合并逻辑。 1251 * <p> 1252 * 注意:此方法会原地修改入参 dataflow 的 ID(与标准合并行为一致)。 1253 */ 1254 public static dataflow mergeDataflows(Collection<dataflow> dataflows, EDbVendor vendor) { 1255 if (dataflows == null || dataflows.isEmpty()) { 1256 return null; 1257 } 1258 ModelBindingManager.setGlobalVendor(vendor); 1259 boolean optionSet = false; 1260 if (ModelBindingManager.getGlobalOption() == null) { 1261 Option option = new Option(); 1262 option.setVendor(vendor); 1263 ModelBindingManager.setGlobalOption(option); 1264 optionSet = true; 1265 } 1266 try { 1267 // ID 按下标 * DATAFLOW_ID_RANGE 偏移,避免 ID 冲突; 1268 // coordinate 第三维 fileIdx 按前面所有 dataflow 累积的源文件数偏移, 1269 // 使得合并后每个来源的 fileIdx 保持连续且不重叠。 1270 long cumulativeFileIdx = 0L; 1271 int i = 0; 1272 for (dataflow df : dataflows) { 1273 if (df != null) { 1274 int maxFileIdx = findMaxFileIdx(df); 1275 offsetDataflowIds(df, DATAFLOW_ID_RANGE * i, cumulativeFileIdx); 1276 if (maxFileIdx >= 0) { 1277 cumulativeFileIdx += (maxFileIdx + 1L); 1278 } 1279 } 1280 i++; 1281 } 1282 return mergeDataflowsWithDifferentStartId(dataflows, vendor); 1283 } finally { 1284 ModelBindingManager.removeGlobalVendor(); 1285 if (optionSet) { 1286 ModelBindingManager.removeGlobalOption(); 1287 } 1288 } 1289 } 1290 1291 /** 1292 * 从一组临时 XML 文件迭代加载并合并 dataflow,节约内存。 1293 * <p> 1294 * 与 {@link #iterativeMergeDataflowsFromFilesByStartId(List, long)} 不同的是,本方法假定文件中的 1295 * dataflow 是用默认 startId=0 生成的(ID 空间互相冲突),因此会按下标先做 ID 偏移再合并。 1296 * <p> 1297 * 注意:本方法按入参 {@code tempFiles} 顺序迭代合并,不做任何排序。 1298 * coordinate 第三维 fileIdx 的偏移也是严格按入参顺序累积的, 1299 * 调用方传入的顺序应与原始源文件的语义顺序保持一致。 1300 */ 1301 public static dataflow iterativeMergeDataflowsFromFiles(List<File> tempFiles, EDbVendor vendor) { 1302 if (tempFiles == null || tempFiles.isEmpty()) { 1303 return null; 1304 } 1305 ModelBindingManager.setGlobalVendor(vendor); 1306 boolean optionSet = false; 1307 if (ModelBindingManager.getGlobalOption() == null) { 1308 Option option = new Option(); 1309 option.setVendor(vendor); 1310 ModelBindingManager.setGlobalOption(option); 1311 optionSet = true; 1312 } 1313 try { 1314 return iterativeMergeFromFiles(tempFiles, DATAFLOW_ID_RANGE * tempFiles.size(), true); 1315 } finally { 1316 ModelBindingManager.removeGlobalVendor(); 1317 if (optionSet) { 1318 ModelBindingManager.removeGlobalOption(); 1319 } 1320 } 1321 } 1322 1323 /** 1324 * 从一组临时 XML 文件迭代加载并合并 dataflow,调用方需保证文件中的 dataflow ID 空间互不冲突, 1325 * 且已设置好 ModelBindingManager。 1326 * <p> 1327 * 主要供 {@code ParallelDataFlowAnalyzer} 等内部生成方使用:每个临时文件中的 dataflow 已通过 1328 * {@code optionCopy.setStartId(DATAFLOW_ID_RANGE * i)} 占用了不重叠的 ID 段。 1329 * <p> 1330 * 注意:本方法按入参 {@code tempFiles} 顺序迭代合并,不做任何排序。 1331 * coordinate 第三维 fileIdx 的偏移严格按入参顺序累积。 1332 */ 1333 public static dataflow iterativeMergeDataflowsFromFilesByStartId(List<File> tempFiles, long startId) { 1334 return iterativeMergeFromFiles(tempFiles, startId, false); 1335 } 1336 1337 private static dataflow iterativeMergeFromFiles(List<File> tempFiles, long startId, boolean offsetIds) { 1338 if (tempFiles == null || tempFiles.isEmpty()) { 1339 logger.warn("iterativeMergeDataflowsFromFiles: tempFiles is null or empty"); 1340 return null; 1341 } 1342 1343 // 注意:此处不再按文件大小排序,保持入参顺序。 1344 // 因为 coordinate 第三维 fileIdx 表示原始源文件下标,偏移必须与入参顺序一致, 1345 // 否则合并后 fileIdx 与原始源文件对不上。 1346 logger.info("iterativeMergeDataflowsFromFiles: total dataflows: " + tempFiles.size()); 1347 1348 long startTime = System.currentTimeMillis(); 1349 int totalIterations = tempFiles.size() - 1; 1350 logger.info("iterativeMergeDataflowsFromFiles: start merging, total iterations: " + totalIterations); 1351 1352 long loadStartTime = System.currentTimeMillis(); 1353 dataflow mergedDataflow = XML2Model.loadXML(dataflow.class, tempFiles.get(0)); 1354 long cumulativeFileIdx = 0L; 1355 if (mergedDataflow != null) { 1356 // 即便 ID 不需偏移(byStartId 路径),coordinate 第三维 fileIdx 仍要偏移, 1357 // 避免合并后不同来源的 fileIdx 撞在一起。 1358 long idOffset = offsetIds ? 0L : 0L; 1359 offsetDataflowIds(mergedDataflow, idOffset, 0L); 1360 int maxFileIdx = findMaxFileIdx(mergedDataflow); 1361 if (maxFileIdx >= 0) { 1362 cumulativeFileIdx = maxFileIdx + 1L; 1363 } 1364 } 1365 long loadEndTime = System.currentTimeMillis(); 1366 int initialRelationCount = mergedDataflow != null && mergedDataflow.getRelationships() != null ? mergedDataflow.getRelationships().size() : 0; 1367 logger.info("iterativeMergeDataflowsFromFiles: loaded initial dataflow, relation count: " + initialRelationCount + ", time: " + (loadEndTime - loadStartTime) + "ms"); 1368 1369 for (int i = 1; i < tempFiles.size(); i++) { 1370 long iterationStartTime = System.currentTimeMillis(); 1371 int currentIteration = i; 1372 int remainingIterations = totalIterations - currentIteration + 1; 1373 1374 logger.info("iterativeMergeDataflowsFromFiles: iteration " + currentIteration + "/" + totalIterations + ", remaining: " + remainingIterations); 1375 1376 long loadCurrentStartTime = System.currentTimeMillis(); 1377 dataflow currentDataflow = XML2Model.loadXML(dataflow.class, tempFiles.get(i)); 1378 if (currentDataflow != null) { 1379 int maxFileIdx = findMaxFileIdx(currentDataflow); 1380 long idOffset = offsetIds ? (DATAFLOW_ID_RANGE * i) : 0L; 1381 offsetDataflowIds(currentDataflow, idOffset, cumulativeFileIdx); 1382 if (maxFileIdx >= 0) { 1383 cumulativeFileIdx += (maxFileIdx + 1L); 1384 } 1385 } 1386 long loadCurrentEndTime = System.currentTimeMillis(); 1387 int currentRelationCount = currentDataflow != null && currentDataflow.getRelationships() != null ? currentDataflow.getRelationships().size() : 0; 1388 logger.info("iterativeMergeDataflowsFromFiles: loaded dataflow[" + i + "], relation count: " + currentRelationCount + ", time: " + (loadCurrentEndTime - loadCurrentStartTime) + "ms"); 1389 1390 List<dataflow> tempList = new ArrayList<>(2); 1391 tempList.add(mergedDataflow); 1392 tempList.add(currentDataflow); 1393 1394 long mergeStartTime = System.currentTimeMillis(); 1395 mergedDataflow = mergeDataflowsByStartId(tempList, startId + DATAFLOW_ID_RANGE * i); 1396 long mergeEndTime = System.currentTimeMillis(); 1397 int mergedRelationCount = mergedDataflow != null && mergedDataflow.getRelationships() != null ? mergedDataflow.getRelationships().size() : 0; 1398 1399 long iterationEndTime = System.currentTimeMillis(); 1400 long iterationTime = iterationEndTime - iterationStartTime; 1401 long mergeTime = mergeEndTime - mergeStartTime; 1402 logger.info("iterativeMergeDataflowsFromFiles: iteration " + currentIteration + " completed, merged relation count: " + mergedRelationCount + ", merge time: " + mergeTime + "ms, total iteration time: " + iterationTime + "ms"); 1403 1404 currentDataflow = null; 1405 tempList.clear(); 1406 } 1407 1408 long endTime = System.currentTimeMillis(); 1409 long totalTime = endTime - startTime; 1410 int finalRelationCount = mergedDataflow != null && mergedDataflow.getRelationships() != null ? mergedDataflow.getRelationships().size() : 0; 1411 logger.info("iterativeMergeDataflowsFromFiles: all iterations completed, final relation count: " + finalRelationCount + ", total time: " + totalTime + "ms (" + (totalTime / 1000.0) + "s)"); 1412 1413 return mergedDataflow; 1414 } 1415 1416 private static String offsetId(String id, long offset) { 1417 if (id == null || id.isEmpty()) { 1418 return id; 1419 } 1420 try { 1421 return String.valueOf(Long.parseLong(id) + offset); 1422 } catch (NumberFormatException ignore) { 1423 return id; 1424 } 1425 } 1426 1427 /** 1428 * 偏移 coordinate 第三维(fileIdx)。 1429 * <p> 1430 * coordinate 字符串格式为 {@code [line,col,fileIdx],[line,col,fileIdx]}, 1431 * 合并多个独立生成的 dataflow 时,它们的 fileIdx 都从 0 起始会互相冲突, 1432 * 通过给第三维加上 offset 来区分不同的来源。 1433 */ 1434 private static String offsetCoordinate(String coordinate, long offset) { 1435 if (coordinate == null || coordinate.isEmpty() || offset == 0L) { 1436 return coordinate; 1437 } 1438 StringBuilder sb = new StringBuilder(coordinate.length() + 8); 1439 int i = 0; 1440 int len = coordinate.length(); 1441 while (i < len) { 1442 int open = coordinate.indexOf('[', i); 1443 if (open < 0) { 1444 sb.append(coordinate, i, len); 1445 break; 1446 } 1447 int close = coordinate.indexOf(']', open); 1448 if (close < 0) { 1449 sb.append(coordinate, i, len); 1450 break; 1451 } 1452 sb.append(coordinate, i, open + 1); 1453 String inner = coordinate.substring(open + 1, close); 1454 String[] parts = inner.split(",", -1); 1455 for (int k = 0; k < parts.length; k++) { 1456 if (k > 0) sb.append(','); 1457 if (k == 2) { 1458 String p = parts[k].trim(); 1459 try { 1460 sb.append(Long.parseLong(p) + offset); 1461 } catch (NumberFormatException ignore) { 1462 sb.append(parts[k]); 1463 } 1464 } else { 1465 sb.append(parts[k]); 1466 } 1467 } 1468 sb.append(']'); 1469 i = close + 1; 1470 } 1471 return sb.toString(); 1472 } 1473 1474 /** 1475 * 偏移 dataflow 中所有节点的 ID 和 coordinate 第三维 fileIdx。 1476 * 1477 * @param df 待偏移的 dataflow(原地修改) 1478 * @param idOffset 给所有 id / xxxId 字段加上的偏移量 1479 * @param fileIdxOffset 给所有 coordinate 第三维 (fileIdx) 加上的偏移量, 1480 * 通常为合并时前面所有 dataflow 累积的源文件数, 1481 * 以便合并后不同来源的 fileIdx 保持连续且不重叠。 1482 */ 1483 private static void offsetDataflowIds(dataflow df, long idOffset, long fileIdxOffset) { 1484 if (idOffset == 0L && fileIdxOffset == 0L) { 1485 return; 1486 } 1487 1488 // tables / views / databases / schemas / stages / datasources / streams / paths / variables / resultsets / sequences 1489 for (table t : dataflow.getAllTables(df)) { 1490 offsetTableIds(t, idOffset); 1491 t.setCoordinate(offsetCoordinate(t.getCoordinate(), fileIdxOffset)); 1492 if (t.getColumns() != null) { 1493 for (column c : t.getColumns()) { 1494 c.setCoordinate(offsetCoordinate(c.getCoordinate(), fileIdxOffset)); 1495 } 1496 } 1497 } 1498 1499 // processes 1500 if (df.getProcesses() != null) { 1501 for (process p : df.getProcesses()) { 1502 p.setId(offsetId(p.getId(), idOffset)); 1503 p.setProcedureId(offsetId(p.getProcedureId(), idOffset)); 1504 p.setCoordinate(offsetCoordinate(p.getCoordinate(), fileIdxOffset)); 1505 } 1506 } 1507 1508 // procedures 1509 if (df.getProcedures() != null) { 1510 for (procedure p : df.getProcedures()) { 1511 p.setId(offsetId(p.getId(), idOffset)); 1512 p.setCoordinate(offsetCoordinate(p.getCoordinate(), fileIdxOffset)); 1513 if (p.getArguments() != null) { 1514 for (argument arg : p.getArguments()) { 1515 arg.setId(offsetId(arg.getId(), idOffset)); 1516 arg.setCoordinate(offsetCoordinate(arg.getCoordinate(), fileIdxOffset)); 1517 } 1518 } 1519 } 1520 } 1521 1522 // oracle packages 1523 if (df.getPackages() != null) { 1524 for (oraclePackage pkg : df.getPackages()) { 1525 pkg.setId(offsetId(pkg.getId(), idOffset)); 1526 if (pkg.getProcedures() != null) { 1527 for (procedure pp : pkg.getProcedures()) { 1528 pp.setId(offsetId(pp.getId(), idOffset)); 1529 pp.setCoordinate(offsetCoordinate(pp.getCoordinate(), fileIdxOffset)); 1530 if (pp.getArguments() != null) { 1531 for (argument arg : pp.getArguments()) { 1532 arg.setId(offsetId(arg.getId(), idOffset)); 1533 arg.setCoordinate(offsetCoordinate(arg.getCoordinate(), fileIdxOffset)); 1534 } 1535 } 1536 } 1537 } 1538 } 1539 } 1540 1541 // relationships 1542 if (df.getRelationships() != null) { 1543 for (relationship rel : df.getRelationships()) { 1544 rel.setId(offsetId(rel.getId(), idOffset)); 1545 rel.setProcessId(offsetId(rel.getProcessId(), idOffset)); 1546 rel.setProcedureId(offsetId(rel.getProcedureId(), idOffset)); 1547 if (rel.getTarget() != null) { 1548 offsetTargetColumnIds(rel.getTarget(), idOffset); 1549 } 1550 if (rel.getCaller() != null) { 1551 offsetTargetColumnIds(rel.getCaller(), idOffset); 1552 } 1553 if (rel.getSources() != null) { 1554 for (sourceColumn sc : rel.getSources()) { 1555 offsetSourceColumnIds(sc, idOffset); 1556 } 1557 } 1558 if (rel.getCallees() != null) { 1559 for (sourceColumn sc : rel.getCallees()) { 1560 offsetSourceColumnIds(sc, idOffset); 1561 } 1562 } 1563 } 1564 } 1565 } 1566 1567 /** 1568 * 扫描 dataflow 中所有 coordinate,返回最大的第三维 (fileIdx) 值; 1569 * 若没有任何 coordinate 则返回 -1。 1570 */ 1571 private static int findMaxFileIdx(dataflow df) { 1572 if (df == null) { 1573 return -1; 1574 } 1575 int max = -1; 1576 for (table t : dataflow.getAllTables(df)) { 1577 max = Math.max(max, maxFileIdxInCoordinate(t.getCoordinate())); 1578 if (t.getColumns() != null) { 1579 for (column c : t.getColumns()) { 1580 max = Math.max(max, maxFileIdxInCoordinate(c.getCoordinate())); 1581 } 1582 } 1583 } 1584 if (df.getProcesses() != null) { 1585 for (process p : df.getProcesses()) { 1586 max = Math.max(max, maxFileIdxInCoordinate(p.getCoordinate())); 1587 } 1588 } 1589 if (df.getProcedures() != null) { 1590 for (procedure p : df.getProcedures()) { 1591 max = Math.max(max, maxFileIdxInCoordinate(p.getCoordinate())); 1592 if (p.getArguments() != null) { 1593 for (argument arg : p.getArguments()) { 1594 max = Math.max(max, maxFileIdxInCoordinate(arg.getCoordinate())); 1595 } 1596 } 1597 } 1598 } 1599 if (df.getPackages() != null) { 1600 for (oraclePackage pkg : df.getPackages()) { 1601 if (pkg.getProcedures() != null) { 1602 for (procedure pp : pkg.getProcedures()) { 1603 max = Math.max(max, maxFileIdxInCoordinate(pp.getCoordinate())); 1604 if (pp.getArguments() != null) { 1605 for (argument arg : pp.getArguments()) { 1606 max = Math.max(max, maxFileIdxInCoordinate(arg.getCoordinate())); 1607 } 1608 } 1609 } 1610 } 1611 } 1612 } 1613 return max; 1614 } 1615 1616 /** 1617 * 从 coordinate 字符串中解析出最大的第三维 (fileIdx) 值; 1618 * 若 coordinate 为空或没有任何可解析的数值则返回 -1。 1619 */ 1620 private static int maxFileIdxInCoordinate(String coordinate) { 1621 if (coordinate == null || coordinate.isEmpty()) { 1622 return -1; 1623 } 1624 int max = -1; 1625 int i = 0; 1626 int len = coordinate.length(); 1627 while (i < len) { 1628 int open = coordinate.indexOf('[', i); 1629 if (open < 0) break; 1630 int close = coordinate.indexOf(']', open); 1631 if (close < 0) break; 1632 String inner = coordinate.substring(open + 1, close); 1633 String[] parts = inner.split(",", -1); 1634 if (parts.length >= 3) { 1635 try { 1636 int v = Integer.parseInt(parts[2].trim()); 1637 if (v > max) max = v; 1638 } catch (NumberFormatException ignore) { 1639 // 不是数字,跳过 1640 } 1641 } 1642 i = close + 1; 1643 } 1644 return max; 1645 } 1646 1647 private static void offsetTableIds(table t, long offset) { 1648 if (t == null) { 1649 return; 1650 } 1651 t.setId(offsetId(t.getId(), offset)); 1652 if (t.getProcessIds() != null) { 1653 List<String> newProcessIds = new ArrayList<>(t.getProcessIds().size()); 1654 for (String pid : t.getProcessIds()) { 1655 newProcessIds.add(offsetId(pid, offset)); 1656 } 1657 t.setProcessIds(newProcessIds); 1658 } 1659 if (t.getColumns() != null) { 1660 for (column c : t.getColumns()) { 1661 c.setId(offsetId(c.getId(), offset)); 1662 } 1663 } 1664 } 1665 1666 private static void offsetTargetColumnIds(targetColumn col, long offset) { 1667 col.setId(offsetId(col.getId(), offset)); 1668 col.setParent_id(offsetId(col.getParent_id(), offset)); 1669 col.setTarget_id(offsetId(col.getTarget_id(), offset)); 1670 } 1671 1672 private static void offsetSourceColumnIds(sourceColumn col, long offset) { 1673 col.setId(offsetId(col.getId(), offset)); 1674 col.setParent_id(offsetId(col.getParent_id(), offset)); 1675 col.setSource_id(offsetId(col.getSource_id(), offset)); 1676 } 1677 1678 public static dataflow readDataflowFromCsvMetadata(String csvMetadata, EDbVendor vendor) { 1679 if (!MetadataReader.isMetadata(csvMetadata)) { 1680 throw new IllegalArgumentException("Illegal csv metadata."); 1681 } 1682 return new SQLDepMetadataAnalyzer().analyzeMetadata(vendor, csvMetadata); 1683 } 1684 1685 public static Dataflow mergeDataflowsAndCsv(List<Pair<EDbVendor,dataflow>> pairs, String csvMetadata) { 1686 //重置ID防止重复 1687 Long index = 0L; 1688 for(int i=0; i<pairs.size(); i++){ 1689 dataflow dataflow = pairs.get(i).second; 1690 Map<String, table> objIDMap = getDataflowDbObjMap(dataflow); 1691 Map<String, String> idMaps = new HashMap<>(); 1692 for (Map.Entry<String, table> entry : objIDMap.entrySet()) { 1693 index = index + 1; 1694 String id = index.toString(); 1695 idMaps.put(entry.getKey(), id); 1696 table table = entry.getValue(); 1697 table.setId(id); 1698 if(table.getColumns() != null){ 1699 for(column col: table.getColumns()){ 1700 index = index + 1; 1701 id = index.toString(); 1702 idMaps.put(col.getId(), id); 1703 col.setId(id); 1704 } 1705 } 1706 } 1707 if(dataflow.getProcedures() != null){ 1708 for(procedure procedure: dataflow.getProcedures()){ 1709 index = index + 1; 1710 String id = index.toString(); 1711 idMaps.put(procedure.getId(), id); 1712 procedure.setId(id); 1713 } 1714 } 1715 if(dataflow.getProcesses() != null){ 1716 for(process process: dataflow.getProcesses()){ 1717 index = index + 1; 1718 String id = index.toString(); 1719 idMaps.put(process.getId(), id); 1720 process.setId(id); 1721 } 1722 } 1723 if(dataflow.getPackages() != null){ 1724 for(oraclePackage oraclePackage: dataflow.getPackages()){ 1725 index = index + 1; 1726 String id = index.toString(); 1727 idMaps.put(oraclePackage.getId(), id); 1728 oraclePackage.setId(id); 1729 if(oraclePackage.getProcedures() != null){ 1730 for(procedure procedure: oraclePackage.getProcedures()){ 1731 index = index + 1; 1732 id = index.toString(); 1733 idMaps.put(procedure.getId(), id); 1734 procedure.setId(id); 1735 } 1736 } 1737 } 1738 } 1739 if(dataflow.getRelationships() != null && dataflow.getRelationships().size()>0){ 1740 for(relationship rel: dataflow.getRelationships()){ 1741 index = index + 1; 1742 String id = index.toString(); 1743 rel.setId(id); 1744 rel.setProcedureId(idMaps.get(rel.getProcedureId())); 1745 rel.setProcessId(idMaps.get(rel.getProcessId())); 1746 rel.getTarget().setParent_id(idMaps.get(rel.getTarget().getParent_id())); 1747 rel.getTarget().setTarget_id(idMaps.get(rel.getTarget().getTarget_id())); 1748 rel.getTarget().setId(idMaps.get(rel.getTarget().getId())); 1749 for(sourceColumn column: rel.getSources()){ 1750 column.setParent_id(idMaps.get(column.getParent_id())); 1751 column.setId(idMaps.get(column.getId())); 1752 } 1753 } 1754 } 1755 } 1756 Dataflow mDataflow = DataFlowAnalyzer.getSqlflowJSONModel(pairs.get(0).first, pairs.get(0).second, false); 1757 Map<String, table> objNameMap = getDataflowDbObjNameMap(pairs.get(0).second); 1758 Sqlflow dbobjs = mDataflow.getDbobjs(); 1759 List<Relationship> mRelationshipList = new ArrayList<>(); 1760 if(mDataflow.getRelationships() != null && mDataflow.getRelationships().length>0){ 1761 mRelationshipList = new LinkedList<>(Arrays.asList(mDataflow.getRelationships())); 1762 } 1763 1764 List<Error> mErrorList = new ArrayList<>(); 1765 if(mDataflow.getErrors() != null && mDataflow.getErrors().length>0){ 1766 mErrorList = new LinkedList<>(Arrays.asList(mDataflow.getErrors())); 1767 } 1768 1769 List<Process> mProcessList = new ArrayList<>(); 1770 if(mDataflow.getProcesses() != null && mDataflow.getProcesses().length>0){ 1771 mProcessList = new LinkedList<>(Arrays.asList(mDataflow.getProcesses())); 1772 } 1773 1774 for(int i=1; i<pairs.size(); i++){ 1775 objNameMap.putAll(getDataflowDbObjNameMap(pairs.get(i).second)); 1776 Dataflow dataflow = DataFlowAnalyzer.getSqlflowJSONModel(pairs.get(i).first, pairs.get(i).second, false); 1777 if(dataflow.getDbobjs().getServers() != null && dataflow.getDbobjs().getServers().size()>0){ 1778 if(dbobjs.getServers() == null){ 1779 dbobjs.setServers(new ArrayList<>()); 1780 } 1781 dbobjs.getServers().addAll(dataflow.getDbobjs().getServers()); 1782 } 1783 1784 if(dataflow.getDbobjs().getErrorMessages() != null && dataflow.getDbobjs().getErrorMessages().size()>0){ 1785 if(dbobjs.getErrorMessages() == null){ 1786 dbobjs.setErrorMessages(new ArrayList<>()); 1787 } 1788 dbobjs.getErrorMessages().addAll(dataflow.getDbobjs().getErrorMessages()); 1789 } 1790 1791 if(dataflow.getRelationships() != null && dataflow.getRelationships().length>0){ 1792 List<Relationship> relationshipList = new LinkedList<>(Arrays.asList(dataflow.getRelationships())); 1793 mRelationshipList.addAll(relationshipList); 1794 } 1795 1796 if(dataflow.getErrors() != null && dataflow.getErrors().length>0){ 1797 List<Error> errorList = new LinkedList<>(Arrays.asList(dataflow.getErrors())); 1798 mErrorList.addAll(errorList); 1799 } 1800 1801 if(dataflow.getProcesses() != null && dataflow.getProcesses().length>0){ 1802 List<Process> processList = new LinkedList<>(Arrays.asList(dataflow.getProcesses())); 1803 mProcessList.addAll(processList); 1804 } 1805 1806 } 1807 if(!SQLUtil.isEmpty(csvMetadata)){ 1808 /** 1809 * excel内的血缘 只合并关系 就是只做关联,如果找不到obj 就算了 1810 */ 1811 dataflow df = readDataflowFromCsvMetadata(csvMetadata); 1812 Map<String, table> objIDMap = getDataflowDbObjMap(df); 1813 if(df.getRelationships() != null && df.getRelationships().size()>0){ 1814 for(relationship rel: df.getRelationships()){ 1815 rel.setId("m"+rel.getId()); 1816 table sTable = objIDMap.get(rel.getTarget().getParent_id()); 1817 table tTable = objNameMap.get(sTable.getFullName()); 1818 rel.getTarget().setParent_id(tTable.getId()); 1819 for(column col: tTable.getColumns()){ 1820 if(col.getName().equalsIgnoreCase(rel.getTarget().getColumn())){ 1821 rel.getTarget().setId(col.getId()); 1822 break; 1823 } 1824 } 1825 for(sourceColumn column: rel.getSources()){ 1826 sTable = objIDMap.get(column.getParent_id()); 1827 tTable = objNameMap.get(sTable.getFullName()); 1828 column.setParent_id(tTable.getId()); 1829 for(column col: tTable.getColumns()){ 1830 if(col.getName().equalsIgnoreCase(column.getColumn())){ 1831 column.setId(col.getId()); 1832 break; 1833 } 1834 } 1835 } 1836 mRelationshipList.add(toRelationship(rel)); 1837 } 1838 } 1839 } 1840 1841 mDataflow.setDbobjs(dbobjs); 1842 mDataflow.setRelationships(mRelationshipList.toArray(new Relationship[mRelationshipList.size()])); 1843 mDataflow.setProcesses(mProcessList.toArray(new Process[mProcessList.size()])); 1844 mDataflow.setErrors(mErrorList.toArray(new Error[mErrorList.size()])); 1845 return mDataflow; 1846 } 1847 1848 public static dataflow readDataflowFromCsvMetadata(String csvMetadata) { 1849 if (!MetadataReader.isMetadata(csvMetadata)) { 1850 throw new IllegalArgumentException("Illegal csv metadata."); 1851 } 1852 return new SQLDepMetadataAnalyzer().analyzeMetadata(null, csvMetadata); 1853 } 1854 1855 private static Relationship toRelationship(relationship relation){ 1856 Relationship relationModel; 1857 if (relation.getType().equals("join")) { 1858 JoinRelationship joinRelationModel = new JoinRelationship(); 1859 joinRelationModel.setCondition(relation.getCondition()); 1860 joinRelationModel.setJoinType(relation.getJoinType()); 1861 joinRelationModel.setClause(relation.getClause()); 1862 relationModel = joinRelationModel; 1863 } else { 1864 relationModel = new Relationship(); 1865 } 1866 relationModel.setId(relation.getId()); 1867 relationModel.setProcessId(relation.getProcessId()); 1868 relationModel.setProcessType(relation.getProcessType()); 1869 relationModel.setType(relation.getType()); 1870 relationModel.setEffectType(relation.getEffectType()); 1871 relationModel.setPartition(relation.getPartition()); 1872 relationModel.setFunction(relation.getFunction()); 1873 relationModel.setProcedureId(relation.getProcedureId()); 1874 relationModel.setSqlHash(relation.getSqlHash()); 1875 relationModel.setCondition(relation.getCondition()); 1876 relationModel.setSqlComment(relation.getSqlComment()); 1877 relationModel.setTimestampMax(relation.getTimestampMax()); 1878 relationModel.setTimestampMin(relation.getTimestampMin()); 1879 1880 if (relation.getTarget() != null && relation.getSources() != null && !relation.getSources().isEmpty()) { 1881 RelationshipElement targetModel = new RelationshipElement(); 1882 targetColumn target = relation.getTarget(); 1883 targetModel.setColumn(target.getColumn()); 1884 targetModel.setParentName(target.getParent_name()); 1885 targetModel.setTargetName(target.getTarget_name()); 1886 targetModel.setId(target.getId()); 1887 targetModel.setTargetId(target.getTarget_id()); 1888 targetModel.setParentId(target.getParent_id()); 1889 targetModel.setCoordinates(Coordinate.parse(target.getCoordinate())); 1890 targetModel.setFunction(target.getFunction()); 1891 targetModel.setType(target.getType()); 1892 relationModel.setTarget(targetModel); 1893 1894 List<RelationshipElement> sourceModels = new ArrayList<>(); 1895 for (sourceColumn source : relation.getSources()) { 1896 RelationshipElement sourceModel = new RelationshipElement(); 1897 sourceModel.setColumn(source.getColumn()); 1898 sourceModel.setParentName(source.getParent_name()); 1899 sourceModel.setSourceName(source.getSource_name()); 1900 sourceModel.setColumnType(source.getColumn_type()); 1901 sourceModel.setId(source.getId()); 1902 sourceModel.setParentId(source.getParent_id()); 1903 sourceModel.setSourceId(source.getSource_id()); 1904 sourceModel.setCoordinates(Coordinate.parse(source.getCoordinate())); 1905 sourceModel.setClauseType(source.getClauseType()); 1906 sourceModel.setType(source.getType()); 1907 sourceModels.add(sourceModel); 1908 if (source.getTransforms() != null && !source.getTransforms().isEmpty()) { 1909 List<Transform> transforms = new ArrayList<gudusoft.gsqlparser.dlineage.dataflow.model.json.Transform>(); 1910 for (transform transform : source.getTransforms()) { 1911 Transform item = new Transform(); 1912 item.setCode(transform.getCode()); 1913 item.setType(transform.getType()); 1914 item.setCoordinate(transform.getCoordinate(true)); 1915 transforms.add(item); 1916 } 1917 sourceModel.setTransforms(transforms.toArray(new Transform[0])); 1918 } 1919 } 1920 relationModel.setSources(sourceModels.toArray(new RelationshipElement[0])); 1921 } else if (relation.getCaller() != null && relation.getCallees() != null 1922 && !relation.getCallees().isEmpty()) { 1923 RelationshipElement targetModel = new RelationshipElement(); 1924 targetColumn target = relation.getCaller(); 1925 targetModel.setName(target.getName()); 1926 targetModel.setId(target.getId()); 1927 targetModel.setCoordinates(Coordinate.parse(target.getCoordinate())); 1928 targetModel.setType(target.getType()); 1929 relationModel.setCaller(targetModel); 1930 List<RelationshipElement> sourceModels = new ArrayList<gudusoft.gsqlparser.dlineage.dataflow.model.json.RelationshipElement>(); 1931 for (sourceColumn source : relation.getCallees()) { 1932 RelationshipElement sourceModel = new RelationshipElement(); 1933 sourceModel.setName(source.getName()); 1934 sourceModel.setId(source.getId()); 1935 sourceModel.setCoordinates(Coordinate.parse(source.getCoordinate())); 1936 sourceModel.setType(source.getType()); 1937 sourceModels.add(sourceModel); 1938 } 1939 relationModel.setCallees(sourceModels.toArray(new RelationshipElement[0])); 1940 } 1941 return relationModel; 1942 } 1943 1944// public static void main(String[] args) throws Exception { 1945// // 基于文件的迭代合并(节约内存,适合大数据量) 1946// dataflow dataflow = iterativeMergeDataflowsFromFiles(Arrays.asList(new File("C:\\Users\\KK\\xwechat_files\\wxid_z9ci6s8b7g0d21_9365\\msg\\file\\2026-06\\dataflow_item").listFiles()), EDbVendor.dbvoracle); 1947// System.out.println(XML2Model.saveXML(dataflow)); 1948// } 1949// 1950// public static void main(String[] args) throws Exception { 1951// // 基于内存的合并(一次性加载所有文件到内存,适合小数据量) 1952// File[] files = new File("C:\\Users\\KK\\xwechat_files\\wxid_z9ci6s8b7g0d21_9365\\msg\\file\\2026-06\\dataflow_item").listFiles(); 1953// if (files == null || files.length == 0) { 1954// System.out.println("No dataflow files found."); 1955// return; 1956// } 1957// 1958// List<dataflow> dataflows = new ArrayList<>(); 1959// for (File file : files) { 1960// dataflow df = XML2Model.loadXML(dataflow.class, file); 1961// if (df != null) { 1962// dataflows.add(df); 1963// } 1964// } 1965// 1966// dataflow mergedDataflow = mergeDataflows(dataflows, EDbVendor.dbvoracle); 1967// System.out.println(XML2Model.saveXML(mergedDataflow)); 1968// } 1969// 1970// public static void main(String[] args) throws Exception { 1971// String sqlDirPath = "C:\\Users\\KK\\Desktop\\同义词验证"; 1972// File sqlDir = new File(sqlDirPath); 1973// 1974// if (!sqlDir.exists() || !sqlDir.isDirectory()) { 1975// System.err.println("目录不存在或不是目录: " + sqlDirPath); 1976// return; 1977// } 1978// 1979// File[] sqlFiles = sqlDir.listFiles((dir, name) -> name.toLowerCase().endsWith(".sql")); 1980// 1981// if (sqlFiles == null || sqlFiles.length == 0) { 1982// System.err.println("目录下没有找到 SQL 文件: " + sqlDirPath); 1983// return; 1984// } 1985// 1986// System.out.println("找到 " + sqlFiles.length + " 个 SQL 文件"); 1987// for (File file : sqlFiles) { 1988// System.out.println(" - " + file.getName()); 1989// } 1990// 1991// Option option = new Option(); 1992// option.setVendor(EDbVendor.dbvoracle); 1993// option.setOutput(true); 1994// option.setSimpleOutput(true); 1995// option.setSimpleShowSynonym(true); 1996// option.setParallel(4); 1997// 1998// ParallelDataFlowAnalyzer analyzer = new ParallelDataFlowAnalyzer( 1999// sqlFiles, 2000// option 2001// ); 2002// 2003// System.out.println("\n开始分析..."); 2004// long startTime = System.currentTimeMillis(); 2005// analyzer.generateDataFlow(false, true); 2006// long endTime = System.currentTimeMillis(); 2007// 2008// dataflow dataflow = analyzer.getDataFlow(); 2009// 2010// analyzer.dispose(); 2011// 2012// if (dataflow == null) { 2013// System.err.println("分析失败,未生成数据流"); 2014// return; 2015// } 2016// 2017// Option option1 = new Option(); 2018// option1.setVendor(EDbVendor.dbvoracle); 2019// option1.setSimpleOutput(true); 2020// dataflow simpleDataflow = new DataFlowAnalyzer("", option1).getSimpleDataflow(dataflow, true); 2021// 2022// 2023// System.out.println("分析完成,耗时: " + (endTime - startTime) + " ms"); 2024// System.out.println("表数量: " + (simpleDataflow.getTables() != null ? simpleDataflow.getTables().size() : 0)); 2025// System.out.println("视图数量: " + (simpleDataflow.getViews() != null ? simpleDataflow.getViews().size() : 0)); 2026// System.out.println("关系数量: " + (simpleDataflow.getRelationships() != null ? simpleDataflow.getRelationships().size() : 0)); 2027// System.out.println("错误数量: " + (simpleDataflow.getErrors() != null ? simpleDataflow.getErrors().size() : 0)); 2028// 2029// System.out.println(XML2Model.saveXML(simpleDataflow)); 2030// 2031// } 2032}