001package gudusoft.gsqlparser.dlineage.dataflow.model.xml; 002 003import java.util.Comparator; 004import java.util.LinkedHashSet; 005import java.util.Set; 006 007import javax.xml.bind.annotation.XmlAttribute; 008import javax.xml.bind.annotation.XmlElement; 009import javax.xml.bind.annotation.XmlElementWrapper; 010import javax.xml.bind.annotation.XmlTransient; 011import javax.xml.bind.annotation.XmlType; 012 013import gudusoft.gsqlparser.TSourceToken; 014import gudusoft.gsqlparser.dlineage.dataflow.model.ModelBindingManager; 015import gudusoft.gsqlparser.dlineage.dataflow.model.Transform; 016import gudusoft.gsqlparser.dlineage.util.DlineageUtil; 017import gudusoft.gsqlparser.dlineage.util.LegacyDlineageWireNamesV1; 018import gudusoft.gsqlparser.dlineage.util.Pair3; 019import gudusoft.gsqlparser.util.SQLUtil; 020 021@XmlType(propOrder = { "id", "name", "column", "value", "source_id", "source_name", "column_type", "parent_id", "parent_name", "parent_alias", 022 "coordinate", "clauseType", "source", "type", "transforms", "candidateParents"}) 023public class sourceColumn { 024 025 private String id; 026 027 private String name; 028 029 private String column; 030 031 private String value; 032 033 private String source_id; 034 035 private String source_name; 036 037 private String column_type; 038 039 private String parent_id; 040 041 private String parent_name; 042 043 private String parent_alias; 044 045 private String coordinate; 046 047 private String clauseType; 048 049 private String source; 050 051 private String type; 052 053 private Set<transform> transforms; 054 055 private Set<candidateTable> candidateParents; 056 057 @XmlTransient 058 private Boolean struct; 059 060 @XmlTransient 061 private boolean positionUnproven; 062 063 private String dedupCoordinate; 064 065 @XmlElementWrapper(name="candidateTables") 066 @XmlElement(name="candidateTable", required = false) 067 public Set<candidateTable> getCandidateParents() { 068 if (ModelBindingManager.getGlobalOption()!=null && !ModelBindingManager.getGlobalOption().isShowCandidateTable()) { 069 return null; 070 } 071 return candidateParents; 072 } 073 074 public void setCandidateParents(Set<candidateTable> candidateParents) { 075 if (ModelBindingManager.getGlobalOption()!=null && !ModelBindingManager.getGlobalOption().isShowCandidateTable()) { 076 return; 077 } 078 this.candidateParents = candidateParents; 079 } 080 081 public void addCandidateParent(candidateTable candidateParent) { 082 if (ModelBindingManager.getGlobalOption()!=null && !ModelBindingManager.getGlobalOption().isShowCandidateTable()) { 083 return; 084 } 085 if(candidateParent == null) 086 return; 087 if(candidateParents == null) { 088 candidateParents = new LinkedHashSet<candidateTable>(); 089 } 090 candidateParents.add(candidateParent); 091 } 092 093 @XmlElementWrapper(name="transforms") 094 @XmlElement(name="transform", required = false) 095 public Set<transform> getTransforms() { 096 if (ModelBindingManager.getGlobalOption()!=null && !ModelBindingManager.getGlobalOption().isTransform()) { 097 return null; 098 } 099 return transforms; 100 } 101 102 public void setTransforms(Set<transform> transforms) { 103 if (ModelBindingManager.getGlobalOption()!=null && !ModelBindingManager.getGlobalOption().isTransform()) { 104 return; 105 } 106 this.transforms = transforms; 107 } 108 109 public void addTransform(Transform transform) { 110 if (ModelBindingManager.getGlobalOption()!=null && !ModelBindingManager.getGlobalOption().isTransform()) { 111 return; 112 } 113 if(transform == null) 114 return; 115 if(transforms == null) { 116 transforms = new LinkedHashSet<transform>(); 117 } 118 119 transform t = new transform(); 120 if (transform.getCode() != null) { 121 if (ModelBindingManager.getGlobalOption().isTransformCoordinate()) { 122 TSourceToken startToken = transform.getCode().getStartToken(); 123 TSourceToken endToken = transform.getCode().getEndToken(); 124 Pair3<Long, Long, String> startPosition = new Pair3<Long, Long, String>(startToken.lineNo, 125 startToken.columnNo, ModelBindingManager.getGlobalHash()); 126 Pair3<Long, Long, String> endPosition = new Pair3<Long, Long, String>(endToken.lineNo, 127 endToken.columnNo + SQLUtil.endTrim(endToken.getAstext()).length(), ModelBindingManager.getGlobalHash()); 128 t.setCoordinate(convertCoordinate(startPosition) + "," + convertCoordinate(endPosition)); 129 } 130 t.setCode(transform.getCode().toString()); 131 } else if (!SQLUtil.isEmpty(transform.getCodeString())) { 132 if (ModelBindingManager.getGlobalOption().isTransformCoordinate()) { 133 TSourceToken startToken = transform.getStartToken(); 134 TSourceToken endToken = transform.getEndToken(); 135 Pair3<Long, Long, String> startPosition = new Pair3<Long, Long, String>(startToken.lineNo, 136 startToken.columnNo, ModelBindingManager.getGlobalHash()); 137 Pair3<Long, Long, String> endPosition = new Pair3<Long, Long, String>(endToken.lineNo, 138 endToken.columnNo + SQLUtil.endTrim(endToken.getAstext()).length(), ModelBindingManager.getGlobalHash()); 139 t.setCoordinate(convertCoordinate(startPosition) + "," + convertCoordinate(endPosition)); 140 } 141 t.setCode(transform.getCodeString()); 142 } 143 t.setType(transform.getType()); 144 transforms.add(t); 145 } 146 147 public void addTransform(transform transform) { 148 if (ModelBindingManager.getGlobalOption()!=null && !ModelBindingManager.getGlobalOption().isTransform()) { 149 return; 150 } 151 if(transform == null) 152 return; 153 if(transforms == null) { 154 transforms = new LinkedHashSet<transform>(); 155 } 156 transforms.add(transform); 157 } 158 159 private Pair3<Long, Long, Integer> convertCoordinate(Pair3<Long, Long, String> position) { 160 return new Pair3<Long, Long, Integer>(position.first, position.second, 161 ModelBindingManager.getGlobalSqlInfo().getIndexOf(position.third)); 162 } 163 164 @XmlAttribute(required = false) 165 public String getCoordinate() { 166// if (ModelBindingManager.getGlobalOption()!=null && ModelBindingManager.getGlobalOption().isIgnoreCoordinate()) { 167// return null; 168// } 169 return coordinate; 170 } 171 172 public void setCoordinate(String coordinate) { 173// if (ModelBindingManager.getGlobalOption()!=null && ModelBindingManager.getGlobalOption().isIgnoreCoordinate()) { 174// return; 175// } 176 this.coordinate = coordinate; 177 } 178 179 @XmlAttribute(required = false) 180 public String getColumn() { 181 return column; 182 } 183 184 public void setColumn(String column) { 185 this.column = column; 186 } 187 188 @XmlAttribute(required = false) 189 public String getId() { 190 return id; 191 } 192 193 public void setId(String id) { 194 this.id = id; 195 } 196 197 @XmlAttribute(name = "parent_id", required = false) 198 public String getParent_id() { 199 return parent_id; 200 } 201 202 public void setParent_id(String parent_id) { 203 this.parent_id = parent_id; 204 } 205 206 @XmlAttribute(name = "parent_name", required = false) 207 public String getParent_name() { 208 return parent_name; 209 } 210 211 public void setParent_name(String parent_name) { 212 this.parent_name = parent_name; 213 } 214 215 @XmlAttribute(name = "parent_alias", required = false) 216 public String getParent_alias() { 217 return parent_alias; 218 } 219 220 public void setParent_alias(String parent_alias) { 221 this.parent_alias = parent_alias; 222 } 223 224 @XmlAttribute(required = false) 225 public String getValue() { 226 return value; 227 } 228 229 public void setValue(String value) { 230 this.value = value; 231 } 232 233 @XmlAttribute(name = "source_name", required = false) 234 public String getSource_name() { 235 return source_name; 236 } 237 238 public void setSource_name(String source_name) { 239 this.source_name = source_name; 240 } 241 242 @XmlAttribute(name = "source_id", required = false) 243 public String getSource_id() { 244 return source_id; 245 } 246 247 public void setSource_id(String source_id) { 248 this.source_id = source_id; 249 } 250 251 @XmlAttribute(required = false) 252 public String getClauseType() { 253 return clauseType; 254 } 255 256 public void setClauseType(String clauseType) { 257 this.clauseType = clauseType; 258 } 259 260 @XmlAttribute(name = "column_type", required = false) 261 public String getColumn_type() { 262 return column_type; 263 } 264 265 public void setColumn_type(String column_type) { 266 this.column_type = column_type; 267 } 268 269 @XmlAttribute(required = false) 270 public String getSource() { 271 return source; 272 } 273 274 public void setSource(String source) { 275 this.source = source; 276 } 277 278 @XmlAttribute(required = false) 279 public String getType() { 280 return type; 281 } 282 283 public void setType(String type) { 284 this.type = type; 285 } 286 287 @Override 288 public int hashCode() { 289 final int prime = 31; 290 int result = 1; 291 String columnName = getColumnName(this); 292 result = prime * result + ((columnName == null) ? 0 : columnName.hashCode()); 293 result = prime * result + ((coordinate == null) ? 0 : coordinate.hashCode()); 294 result = prime * result + ((parent_id == null) ? 0 : parent_id.hashCode()); 295 return result; 296 } 297 298 private String getColumnName(sourceColumn column) { 299 if ("constant".equals(column.getColumn_type())) { 300 return column.column; 301 } 302 if (ModelBindingManager.getGlobalVendor() != null) { 303 // equal published endpoints: the label's output-v1 bucket, beside the coordinate and the parent 304 return LegacyDlineageWireNamesV1.columnBucket(column.column); 305 } 306 return column.column; 307 } 308 309 @Override 310 public boolean equals(Object obj) { 311 if (this == obj) 312 return true; 313 if (obj == null) 314 return false; 315 if (getClass() != obj.getClass()) 316 return false; 317 sourceColumn other = (sourceColumn) obj; 318 if (column == null) { 319 if (other.column != null) 320 return false; 321 } else if (!getColumnName(this).equals(getColumnName(other))) 322 return false; 323 if (coordinate == null) { 324 if (other.coordinate != null) 325 return false; 326 } else if (coordinate.hashCode() != other.coordinate.hashCode()) 327 return false; 328 if (parent_id == null) { 329 if (other.parent_id != null) 330 return false; 331 } else if (!parent_id.equals(other.parent_id)) 332 return false; 333 return true; 334 } 335 336 @XmlAttribute(required = false) 337 public String getName() { 338 return name; 339 } 340 341 public void setName(String name) { 342 this.name = name; 343 } 344 345 /** 346 * Whether this source is a {@code *} read at a position its members' unknown order cannot tell (Mantis 4856): 347 * the simple output follows it to the {@code *} of the table that fills it, never to the column named like the 348 * target. Never serialized. 349 */ 350 @XmlTransient 351 public boolean isPositionUnproven() { 352 return positionUnproven; 353 } 354 355 public void setPositionUnproven(boolean positionUnproven) { 356 this.positionUnproven = positionUnproven; 357 } 358 359 @XmlTransient 360 public Boolean isStruct() { 361 return struct; 362 } 363 364 public void setStruct(Boolean struct) { 365 this.struct = struct; 366 } 367 368 public String toDedupKey() { 369 StringBuilder sb = new StringBuilder(128); 370 appendDedupKey(sb); 371 return sb.toString(); 372 } 373 374 public long toDedupHash() { 375 StringBuilder sb = new StringBuilder(128); 376 appendDedupKey(sb); 377 return SQLUtil.hash64(sb); 378 } 379 380 /** 381 * The coordinate this source would have carried before reference-site 382 * publishing — the column model's definition span. The table-merge pass 383 * stamps it in for its dedup steps (equals/hashCode and toDedupHash include 384 * the coordinate), so sources and relations keep collapsing exactly as they 385 * did when every reference was rendered with the model span, then restores 386 * the published reference-site coordinate on the survivors. Never 387 * serialized. 388 */ 389 @XmlTransient 390 public String getDedupCoordinate() { 391 return dedupCoordinate; 392 } 393 394 public void setDedupCoordinate(String dedupCoordinate) { 395 this.dedupCoordinate = dedupCoordinate; 396 } 397 398 void appendDedupKey(StringBuilder sb) { 399 if (name != null) { sb.append("name=").append(name).append('|'); } 400 if (column != null) { sb.append("column=").append(column).append('|'); } 401 if (parent_id != null) { sb.append("parent_id=").append(parent_id).append('|'); } 402 if (source_id != null) { sb.append("source_id=").append(source_id).append('|'); } 403 if (value != null) { sb.append("value=").append(value).append('|'); } 404 if (source_name != null) { sb.append("source_name=").append(source_name).append('|'); } 405 if (column_type != null) { sb.append("column_type=").append(column_type).append('|'); } 406 if (parent_name != null) { sb.append("parent_name=").append(parent_name).append('|'); } 407 if (parent_alias != null) { sb.append("parent_alias=").append(parent_alias).append('|'); } 408 if (coordinate != null) { sb.append("coordinate=").append(coordinate).append('|'); } 409 if (clauseType != null) { sb.append("clauseType=").append(clauseType).append('|'); } 410 if (source != null) { sb.append("source=").append(source).append('|'); } 411 if (type != null) { sb.append("type=").append(type).append('|'); } 412 if (transforms != null && !transforms.isEmpty()) { 413 sb.append("transforms=["); 414 transforms.stream().sorted(Comparator.comparing(transform::getType, Comparator.nullsFirst(Comparator.<String>naturalOrder()))) 415 .forEach(t -> { sb.append('{'); t.appendDedupKey(sb); sb.append("},"); }); 416 sb.setLength(sb.length() - 1); 417 sb.append("]|"); 418 } 419 if (candidateParents != null && !candidateParents.isEmpty()) { 420 sb.append("candidateParents=["); 421 candidateParents.stream().sorted(Comparator.comparing(candidateTable::getId, Comparator.nullsFirst(Comparator.<String>naturalOrder()))) 422 .forEach(c -> { sb.append('{'); c.appendDedupKey(sb); sb.append("},"); }); 423 sb.setLength(sb.length() - 1); 424 sb.append("]|"); 425 } 426 } 427}