001package gudusoft.gsqlparser.dlineage.dataflow.model.xml; 002 003import gudusoft.gsqlparser.dlineage.dataflow.model.ModelBindingManager; 004import gudusoft.gsqlparser.dlineage.dataflow.model.json.Coordinate; 005import gudusoft.gsqlparser.dlineage.util.DlineageUtil; 006import gudusoft.gsqlparser.sqlenv.ESQLDataObjectType; 007import gudusoft.gsqlparser.sqlenv.TSQLEnv; 008import gudusoft.gsqlparser.util.SQLUtil; 009 010import javax.xml.bind.annotation.XmlAttribute; 011import javax.xml.bind.annotation.XmlElement; 012import javax.xml.bind.annotation.XmlTransient; 013import javax.xml.bind.annotation.XmlType; 014import java.util.ArrayList; 015import java.util.LinkedHashSet; 016import java.util.List; 017 018@XmlType( 019 propOrder = {"id", "server", "userName", "database", "schema", "name", "displayName", "alias", "uri", "type", "subType", 020 "processIds", "fileType", "fileFormat", "location", "namespace", "isTarget", "coordinate", "columns", "parent", "more", "fromDDL"} 021) 022public class table implements Cloneable { 023 024 private String id; 025 026 private String server; 027 028 private String userName; 029 030 private String database; 031 032 private String schema; 033 034 private String name; 035 036 private String displayName; 037 038 private String alias; 039 040 private String type; 041 042 private String subType; 043 044 private String uri; 045 046 private List<String> processIds; 047 048 private String isTarget; 049 050 private StringBuffer coordinate = new StringBuffer(); 051 052 private List<column> columns; 053 054 private String parent; 055 056 private String fileType; 057 058 private String fileFormat; 059 060 private String location; 061 062 private String namespace; 063 064 @XmlTransient 065 private String starStmt; 066 067 private Boolean more; 068 069 @XmlTransient 070 private String isDetermined; 071 072 private String fromDDL; 073 074 @XmlTransient 075 private LinkedHashSet<String> coordinateItems = new LinkedHashSet<String>(); 076 077 @XmlAttribute(required = false) 078 public String getAlias() { 079 return alias; 080 } 081 082 public void setAlias(String alias) { 083 this.alias = alias; 084 } 085 086 @XmlElement(name = "column", required = false) 087 public List<column> getColumns() { 088 if (this.columns == null) { 089 this.columns = new ArrayList<column>(); 090 } 091 return columns; 092 } 093 094 public void setColumns(List<column> columns) { 095 this.columns = columns; 096 } 097 098 @XmlAttribute(required = false) 099 public String getCoordinate() { 100 String result = coordinate.toString(); 101 if (SQLUtil.isEmpty(result)) 102 return null; 103 return result; 104 } 105 106 public void appendCoordinate(String coordinate) { 107 if (!coordinateItems.contains(coordinate)) { 108 coordinateItems.add(coordinate); 109 rebuildCoordinate(); 110 } 111 } 112 113 private void rebuildCoordinate() { 114 this.coordinate.setLength(0); 115 116 List<String> itemsList = new ArrayList<>(coordinateItems); 117 boolean hasMultiplePairs = itemsList.size() > 1; 118 119 String separator = ""; 120 for (String coordPair : itemsList) { 121 // 只有多对坐标时才过滤无效对 122 if (!hasMultiplePairs || !isBothCoordsInvalid(coordPair)) { 123 this.coordinate.append(separator).append(coordPair); 124 separator = ","; 125 } 126 } 127 } 128 129 /** 130 * 判断一对坐标是否两个都是无效坐标([-1,-1,x] 格式) 131 */ 132 private static boolean isBothCoordsInvalid(String coordPair) { 133 return coordPair != null 134 && coordPair.contains("[-1,-1,") 135 && countOccurrences(coordPair, "[-1,-1,") >= 2; 136 } 137 138 private static int countOccurrences(String str, String target) { 139 if (str == null || target == null || target.isEmpty()) { 140 return 0; 141 } 142 int count = 0; 143 int idx = 0; 144 while ((idx = str.indexOf(target, idx)) != -1) { 145 count++; 146 idx += target.length(); 147 } 148 return count; 149 } 150 151 public void setCoordinate(String coordinate) { 152 if (SQLUtil.isEmpty(coordinate)) { 153 return; 154 } 155 this.coordinate.setLength(0); 156 this.coordinateItems.clear(); 157 158 // 先分割出所有坐标 [line,col,fileIdx] 159 List<String> allCoords = new ArrayList<>(); 160 int start = 0; 161 while (start < coordinate.length()) { 162 int open = coordinate.indexOf('[', start); 163 if (open < 0) break; 164 int close = coordinate.indexOf(']', open); 165 if (close < 0) break; 166 allCoords.add(coordinate.substring(open, close + 1)); 167 start = close + 1; 168 } 169 170 // 计算坐标对数量(每两个坐标组成一对) 171 int pairCount = (allCoords.size() + 1) / 2; 172 173 // 如果只有一对坐标,直接保留 174 if (pairCount <= 1) { 175 this.coordinate.append(coordinate); 176 this.coordinateItems.add(coordinate); 177 return; 178 } 179 180 // 有多对坐标时,过滤掉无效的坐标对(两个坐标都是 [-1,-1,x] 格式) 181 StringBuilder sb = new StringBuilder(); 182 for (int i = 0; i < allCoords.size(); i += 2) { 183 String coord1 = allCoords.get(i); 184 String coord2 = (i + 1 < allCoords.size()) ? allCoords.get(i + 1) : ""; 185 186 // 检查这一对是否都是无效坐标 187 boolean pairIsInvalid = isInvalidCoord(coord1) && isInvalidCoord(coord2); 188 189 if (!pairIsInvalid) { 190 if (sb.length() > 0) { 191 sb.append(","); 192 } 193 sb.append(coord1); 194 this.coordinateItems.add(coord1); 195 if (!coord2.isEmpty()) { 196 sb.append(",").append(coord2); 197 this.coordinateItems.add(coord2); 198 } 199 } 200 } 201 this.coordinate.append(sb.toString()); 202 } 203 204 private static boolean isInvalidCoord(String coord) { 205 if (coord == null || coord.isEmpty()) { 206 return false; 207 } 208 String trimmed = coord.trim(); 209 if (trimmed.indexOf("-1") != -1 && trimmed.startsWith("[") && trimmed.endsWith("]")) { 210 String inner = trimmed.substring(1, trimmed.length() - 1); 211 String[] coords = inner.split(","); 212 if (coords.length >= 2 && "-1".equals(coords[0].trim()) && "-1".equals(coords[1].trim())) { 213 return true; 214 } 215 } 216 return false; 217 } 218 219 public void clearCoordinate() { 220 this.coordinate = new StringBuffer(); 221 } 222 223 @XmlAttribute(required = false) 224 public String getUserName() { 225 return userName; 226 } 227 228 public void setUserName(String userName) { 229 this.userName = userName; 230 } 231 232 @XmlAttribute(required = false) 233 public String getServer() { 234 return server; 235 } 236 237 public void setServer(String server) { 238 this.server = server; 239 } 240 241 @XmlAttribute(required = false) 242 public String getName() { 243 return name; 244 } 245 246 public void setName(String name) { 247 this.name = name; 248 } 249 250 @XmlAttribute(required = false) 251 public String getDisplayName() { 252 return displayName; 253 } 254 255 public void setDisplayName(String displayName) { 256 this.displayName = displayName; 257 } 258 259 @XmlAttribute(required = false) 260 public String getId() { 261 return id; 262 } 263 264 public void setId(String id) { 265 this.id = id; 266 } 267 268 @XmlAttribute(required = false) 269 public List<String> getProcessIds() { 270 return processIds; 271 } 272 273 public void setProcessIds(List<String> processIds) { 274 this.processIds = processIds; 275 } 276 277 @XmlAttribute(required = false) 278 public String getType() { 279 return type; 280 } 281 282 public void setType(String type) { 283 this.type = type; 284 } 285 286 @XmlAttribute(required = false) 287 public String getUri() { 288 return uri; 289 } 290 291 public void setUri(String uri) { 292 this.uri = uri; 293 } 294 295 @XmlAttribute(required = false) 296 public String getFileType() { 297 return fileType; 298 } 299 300 public void setFileType(String fileType) { 301 this.fileType = fileType; 302 } 303 304 @XmlAttribute(required = false) 305 public String getFileFormat() { 306 return fileFormat; 307 } 308 309 public void setFileFormat(String fileFormat) { 310 this.fileFormat = fileFormat; 311 } 312 313 @XmlAttribute(required = false) 314 public String getLocation() { 315 return location; 316 } 317 318 public void setLocation(String location) { 319 this.location = location; 320 } 321 322 @XmlAttribute(required = false) 323 public String getNamespace() { 324 return namespace; 325 } 326 327 public void setNamespace(String namespace) { 328 this.namespace = namespace; 329 } 330 331 @XmlTransient 332 public String getStarStmt() { 333 return starStmt; 334 } 335 336 public void setStarStmt(String starStmt) { 337 this.starStmt = starStmt; 338 } 339 340 @XmlTransient 341 public String getIsDetermined() { 342 return isDetermined; 343 } 344 345 public void setIsDetermined(String isDetermined) { 346 this.isDetermined = isDetermined; 347 } 348 349 public boolean isFunction() { 350 return "function".equals(type) || "function".equals(subType); 351 } 352 353 public boolean isView() { 354 return "view".equals(type); 355 } 356 357 public boolean isDatabaseType() { 358 return "database".equals(type); 359 } 360 361 public boolean isSchemaType() { 362 return "schema".equals(type); 363 } 364 365 public boolean isSequence() { 366 return "sequence".equals(type); 367 } 368 369 public boolean isStage() { 370 return "stage".equals(type); 371 } 372 373 public boolean isDataSource() { 374 return "dataSource".equals(type); 375 } 376 377 public boolean isStream() { 378 return "stream".equals(type); 379 } 380 381 public boolean isVariable() { 382 return "variable".equals(type); 383 } 384 385 public boolean isCursor() { 386 return "cursor".equals(type); 387 } 388 389 public boolean isFile() { 390 return "file".equals(type) || "path".equals(type); 391 } 392 393 public boolean isTable() { 394 return "table".equals(type) || "pseudoTable".equals(type) || "constantTable".equals(type); 395 } 396 397 public boolean isPseudoTable() { 398 return "pseudoTable".equals(type); 399 } 400 401 public boolean isConstantTable() { 402 return "pseudoTable".equals(type); 403 } 404 405 public boolean isResultSet() { 406 return type != null && !isView() && !isCursor() && !isTable() && !isStage() && !isSequence() && !isDataSource() && !isDatabaseType() && !isSchemaType() && !isStream() && !isVariable() && !isFile(); 407 } 408 409 @XmlAttribute(name = "isTarget", required = false) 410 public String getIsTarget() { 411 return isTarget; 412 } 413 414 public boolean isTarget() { 415 return "true".equals(isTarget); 416 } 417 418 @XmlAttribute(required = false) 419 public String getParent() { 420 return parent; 421 } 422 423 public void setParent(String parent) { 424 this.parent = parent; 425 } 426 427 @XmlAttribute(required = false) 428 public String getDatabase() { 429 return database; 430 } 431 432 public void setDatabase(String database) { 433 if (SQLUtil.parseNames(database).size() > 1) { 434 database = "\"" + database + "\""; 435 } 436 this.database = database; 437 } 438 439 @XmlAttribute(required = false) 440 public String getSchema() { 441 return schema; 442 } 443 444 public void setSchema(String schema) { 445 if (SQLUtil.parseNames(schema).size() > 1) { 446 schema = "\"" + schema + "\""; 447 } 448 this.schema = schema; 449 } 450 451 @XmlAttribute(required = false) 452 public String getSubType() { 453 return subType; 454 } 455 456 public void setSubType(String subType) { 457 this.subType = subType; 458 } 459 460 public String getFullName() { 461 if (isDatabaseType()) { 462 return database; 463 } 464 StringBuilder fullName = new StringBuilder(); 465 if (!SQLUtil.isEmpty(database)) { 466 fullName.append(database).append("."); 467 } 468 if (!SQLUtil.isEmpty(schema)) { 469 fullName.append(schema).append("."); 470 } 471 if (fullName.length() > 0) { 472 fullName.append(getTableNameOnly()); 473 } else { 474 fullName.append(name); 475 } 476 return fullName.toString(); 477 } 478 479 public String getFullSchemaName() { 480 StringBuilder fullName = new StringBuilder(); 481 if (!SQLUtil.isEmpty(database)) { 482 if(ModelBindingManager.getGlobalVendor()!=null) { 483 fullName.append(DlineageUtil.getIdentifierNormalName(database, ESQLDataObjectType.dotCatalog)).append("."); 484 } 485 else{ 486 fullName.append(database).append("."); 487 } 488 } 489 if (!SQLUtil.isEmpty(schema)) { 490 if(ModelBindingManager.getGlobalVendor()!=null) { 491 fullName.append(DlineageUtil.getIdentifierNormalName(schema, ESQLDataObjectType.dotSchema)); 492 } 493 else { 494 fullName.append(schema).append("."); 495 } 496 } 497 String fullSchemaName = fullName.toString(); 498 if (fullSchemaName.endsWith(".")) { 499 fullSchemaName = fullSchemaName.substring(0, fullSchemaName.length() - 1); 500 } 501 if (fullSchemaName.length() == 0) { 502 fullSchemaName = TSQLEnv.DEFAULT_SCHEMA_NAME; 503 } 504 return fullSchemaName; 505 } 506 507 public String getTableNameOnly() { 508 if (name.indexOf("@") != -1 && SQLUtil.trimColumnStringQuote(name.substring(name.lastIndexOf("@") + 1).trim()).equals(SQLUtil.trimColumnStringQuote(database))) { 509 List<String> segments = SQLUtil.parseNames(name.substring(0, name.lastIndexOf("@")).trim()); 510 if (segments.size() > 2) { 511 return SQLUtil.mergeSegments(segments, 2); 512 } 513 return segments.get(segments.size() - 1); 514 } else { 515 List<String> segments = SQLUtil.parseNames(name); 516 if (segments.size() > 2) { 517 return SQLUtil.mergeSegments(segments, 2); 518 } 519 return segments.get(segments.size() - 1); 520 } 521 } 522 523 public void setIsTarget(String isTarget) { 524 this.isTarget = isTarget; 525 } 526 527 public int getOccurrencesNumber() { 528 return PositionUtil.getOccurrencesNumber(coordinate.toString()); 529 } 530 531 public Coordinate getStartPos(int index) { 532 return PositionUtil.getStartPos(coordinate.toString(), index); 533 } 534 535 public Coordinate getEndPos(int index) { 536 return PositionUtil.getEndPos(coordinate.toString(), index); 537 } 538 539 public Boolean getMore() { 540 return more; 541 } 542 543 public void setMore(Boolean more) { 544 this.more = more; 545 } 546 547 @XmlAttribute(required = false) 548 public String getFromDDL() { 549 return fromDDL; 550 } 551 552 public void setFromDDL(String fromDDL) { 553 this.fromDDL = fromDDL; 554 } 555 556 @Override 557 public Object clone() throws CloneNotSupportedException { 558 return super.clone(); 559 } 560}