001package gudusoft.gsqlparser.dlineage.dataflow.model; 002 003import gudusoft.gsqlparser.EDbVendor; 004import gudusoft.gsqlparser.ESetOperatorType; 005import gudusoft.gsqlparser.TCustomSqlStatement; 006import gudusoft.gsqlparser.TSourceToken; 007import gudusoft.gsqlparser.dlineage.util.DlineageUtil; 008import gudusoft.gsqlparser.dlineage.util.Pair3; 009import gudusoft.gsqlparser.nodes.TCTE; 010import gudusoft.gsqlparser.nodes.TFunctionCall; 011import gudusoft.gsqlparser.nodes.TJoinList; 012import gudusoft.gsqlparser.pp.utils.SourceTokenSearcher; 013import gudusoft.gsqlparser.sqlenv.TSQLEnv; 014import gudusoft.gsqlparser.stmt.*; 015import gudusoft.gsqlparser.stmt.hive.THiveLoad; 016import gudusoft.gsqlparser.stmt.mssql.TCreateExternalDataSourceStmt; 017import gudusoft.gsqlparser.stmt.mssql.TMssqlCreateFunction; 018import gudusoft.gsqlparser.stmt.mssql.TMssqlDeclare; 019import gudusoft.gsqlparser.stmt.mssql.TMssqlExecute; 020import gudusoft.gsqlparser.stmt.snowflake.TCreateStageStmt; 021import gudusoft.gsqlparser.stmt.snowflake.TCreateStreamStmt; 022import gudusoft.gsqlparser.stmt.snowflake.TSnowflakeCopyIntoStmt; 023import gudusoft.gsqlparser.stmt.teradata.TTeradataCreateProcedure; 024import gudusoft.gsqlparser.util.Logger; 025import gudusoft.gsqlparser.util.LoggerFactory; 026import gudusoft.gsqlparser.util.SQLUtil; 027 028import java.io.ByteArrayInputStream; 029import java.io.IOException; 030import java.util.ArrayDeque; 031import java.util.ArrayList; 032import java.util.Deque; 033import java.util.List; 034import java.util.Properties; 035 036public class Process { 037 private static final Logger logger = LoggerFactory.getLogger(Process.class); 038 private long id; 039 protected String server; 040 protected String schema; 041 protected String database; 042 private String name; 043 private String procedureName; 044 private Long procedureId; 045 private String queryHashId; 046 private String type; 047 private String customType; 048 private TCustomSqlStatement gspObject; 049 private Pair3<Long, Long, String> startPosition; 050 private Pair3<Long, Long, String> endPosition; 051 private List<Object> targetColumns = new ArrayList<Object>(); 052 private List<Transform> transforms = new ArrayList<Transform>(); 053 054 public Process(TCustomSqlStatement gspObject) { 055 056 if (gspObject == null) { 057 throw new IllegalArgumentException("Process arguments can't be null."); 058 } 059 060 id = ++ModelBindingManager.get().TABLE_COLUMN_ID; 061 062 this.gspObject = gspObject; 063 064 TSourceToken startToken = gspObject.getStartToken(); 065 TSourceToken endToken = gspObject.getEndToken(); 066 if (startToken != null) { 067 this.startPosition = new Pair3<Long, Long, String>(startToken.lineNo, startToken.columnNo, 068 ModelBindingManager.getGlobalHash()); 069 } 070 071 if (endToken != null) { 072 this.endPosition = new Pair3<Long, Long, String>(endToken.lineNo, 073 endToken.columnNo + SQLUtil.endTrim(endToken.getAstext()).length(), ModelBindingManager.getGlobalHash()); 074 } 075 076 this.schema = ModelBindingManager.getGlobalSchema(); 077 this.database = ModelBindingManager.getGlobalDatabase(); 078 this.queryHashId = SQLUtil.stringToMD5(gspObject.asCanonical().replaceAll("\r?\n", "\r\n")); 079 080 EDbVendor vendor = ModelBindingManager.getGlobalOption().getVendor(); 081 boolean supportCatalog = TSQLEnv.supportCatalog(vendor); 082 boolean supportSchema = TSQLEnv.supportSchema(vendor); 083 084 fillSchemaInfo(); 085 086 if (!supportCatalog) { 087 this.database = null; 088 } else if (this.database == null && !TSQLEnv.DEFAULT_DB_NAME.equals(getDefaultDatabase())) { 089 this.database = getDefaultDatabase(); 090 } 091 092 if (!supportSchema) { 093 this.schema = null; 094 } else if (this.schema == null && !TSQLEnv.DEFAULT_SCHEMA_NAME.equals(getDefaultSchema())) { 095 this.schema = getDefaultSchema(); 096 } 097 098 String procedureParent = getProcedureParentName(gspObject); 099 if (procedureParent != null) { 100 procedureName = procedureParent; 101 Procedure procedure = ModelBindingManager.get() 102 .getProcedureByName(DlineageUtil.getIdentifierNormalTableName( 103 DlineageUtil.getProcedureNameWithArgs(getParentProcedure(gspObject)))); 104 if (procedure == null) { 105 procedure = ModelBindingManager.get().getProcedureByName(DlineageUtil.getIdentifierNormalTableName( 106 DlineageUtil.getProcedureNameWithArgNum(getParentProcedure(gspObject)))); 107 } 108 if (procedure != null) { 109 this.procedureId = procedure.getId(); 110 } 111 } else { 112 procedureName = "batchQueries"; 113 } 114 115 TCustomSqlStatement stmt = DlineageUtil.getTopStmt(ModelBindingManager.getGlobalStmtStack().peek()); 116 String sqlComment = null; 117 try { 118 sqlComment = stmt.getCommentBeforeNode(); 119 } catch (Exception e) { 120 } 121 if (!SQLUtil.isEmpty(sqlComment) && sqlComment.indexOf("process") != -1) { 122 Properties properties = new Properties(); 123 try { 124 properties.load( 125 new ByteArrayInputStream(sqlComment.replace("--", "").trim().replace(",", "\n").getBytes())); 126 if (properties.containsKey("process_label")) { 127 this.customType = properties.getProperty("process_label"); 128 } else if (properties.containsKey("process")) { 129 this.customType = properties.getProperty("process"); 130 } 131 } catch (IOException e) { 132 logger.error("load sql comment properties failed.", e); 133 } 134 } 135 136 if (gspObject instanceof TCreateTableSqlStatement) { 137 this.type = "Create Table"; 138 } else if (gspObject instanceof TCreateViewSqlStatement) { 139 this.type = "Create View"; 140 } else if (gspObject instanceof TUpdateSqlStatement) { 141 this.type = "Update"; 142 } else if (gspObject instanceof TMergeSqlStatement) { 143 this.type = "Merge"; 144 } else if (gspObject instanceof TInsertSqlStatement) { 145 this.type = "Insert"; 146 } else if (gspObject instanceof TSelectSqlStatement 147 && ((TSelectSqlStatement) gspObject).getIntoClause() != null) { 148 this.type = "Select Into"; 149 } else if (gspObject instanceof TCreateTriggerStmt) { 150 this.type = "Create Trigger"; 151 } else if (gspObject instanceof TCreateFunctionStmt) { 152 this.type = "Create Function"; 153 } else if (gspObject instanceof TMssqlCreateFunction) { 154 this.type = "Create Function"; 155 } else if (gspObject instanceof TCreateProcedureStmt) { 156 this.type = "Create Procedure"; 157 } else if (gspObject instanceof THiveLoad) { 158 this.type = "Hive Load"; 159 } else if (gspObject instanceof TSnowflakeCopyIntoStmt) { 160 this.type = "Copy Into"; 161 } else if (gspObject instanceof TAlterTableStatement) { 162 this.type = "Alter Table"; 163 } else if (gspObject instanceof TRenameStmt) { 164 this.type = "Rename Table"; 165 } else if (gspObject instanceof TMssqlDeclare) { 166 this.type = "Mssql Declare"; 167 } else if (gspObject instanceof TCreateStageStmt) { 168 this.type = "Create Stage"; 169 } else if (gspObject instanceof TCreateSynonymStmt) { 170 this.type = "Create Synonym"; 171 } else if (gspObject instanceof TCreateExternalDataSourceStmt) { 172 this.type = "Create Datasource"; 173 } else if (gspObject instanceof TCreateStreamStmt) { 174 this.type = "Create Stream"; 175 } else if (gspObject instanceof TCreateDatabaseSqlStatement) { 176 this.type = "Create Database"; 177 } else if (gspObject instanceof TCreateSchemaSqlStatement) { 178 this.type = "Create Schema"; 179 } else if (gspObject instanceof TMssqlExecute && ((TMssqlExecute)gspObject).getModuleName().toString().equalsIgnoreCase("sp_rename")) { 180 this.type = "Rename Table"; 181 } else if (gspObject instanceof TCallStatement){ 182 this.type = "Function Call"; 183 } else { 184 this.type = gspObject.getClass().getSimpleName(); 185 } 186 187 if (this.server == null && !TSQLEnv.DEFAULT_SERVER_NAME.equals(getDefaultServer())) { 188 this.server = getDefaultServer(); 189 } 190 191 if (stmt.getStatements() != null) { 192 for (int i = 0; i < stmt.getStatements().size(); i++) { 193 TCustomSqlStatement subquery = stmt.getStatements().get(i); 194 if (subquery instanceof TSelectSqlStatement) { 195 TSelectSqlStatement select = (TSelectSqlStatement) subquery; 196 appendTransform(select, ESetOperatorType.none); 197 } 198 } 199 } 200 } 201 202 public Process(TFunctionCall gspObject) { 203 204 if (gspObject == null) { 205 throw new IllegalArgumentException("Process arguments can't be null."); 206 } 207 208 id = ++ModelBindingManager.get().TABLE_COLUMN_ID; 209 210 211 TSourceToken startToken = gspObject.getStartToken(); 212 TSourceToken endToken = gspObject.getEndToken(); 213 if (startToken != null) { 214 this.startPosition = new Pair3<Long, Long, String>(startToken.lineNo, startToken.columnNo, 215 ModelBindingManager.getGlobalHash()); 216 } 217 218 if (endToken != null) { 219 this.endPosition = new Pair3<Long, Long, String>(endToken.lineNo, 220 endToken.columnNo + SQLUtil.endTrim(endToken.getAstext()).length(), ModelBindingManager.getGlobalHash()); 221 } 222 223 TCustomSqlStatement stmt = DlineageUtil.getTopStmt(ModelBindingManager.getGlobalStmtStack().peek()); 224 this.gspObject = stmt; 225 226 this.schema = ModelBindingManager.getGlobalSchema(); 227 this.database = ModelBindingManager.getGlobalDatabase(); 228 229 if (stmt != null) { 230 this.queryHashId = SQLUtil.stringToMD5(stmt.asCanonical().replaceAll("\r?\n", "\r\n")); 231 } 232 233 EDbVendor vendor = ModelBindingManager.getGlobalOption().getVendor(); 234 boolean supportCatalog = TSQLEnv.supportCatalog(vendor); 235 boolean supportSchema = TSQLEnv.supportSchema(vendor); 236 237 fillSchemaInfo(); 238 239 if (!supportCatalog) { 240 this.database = null; 241 } else if (this.database == null && !TSQLEnv.DEFAULT_DB_NAME.equals(getDefaultDatabase())) { 242 this.database = getDefaultDatabase(); 243 } 244 245 if (!supportSchema) { 246 this.schema = null; 247 } else if (this.schema == null && !TSQLEnv.DEFAULT_SCHEMA_NAME.equals(getDefaultSchema())) { 248 this.schema = getDefaultSchema(); 249 } 250 251 String procedureParent = getProcedureParentName(stmt); 252 if (procedureParent != null) { 253 procedureName = procedureParent; 254 Procedure procedure = ModelBindingManager.get() 255 .getProcedureByName(DlineageUtil.getIdentifierNormalTableName( 256 DlineageUtil.getProcedureNameWithArgs(getParentProcedure(stmt)))); 257 if (procedure == null) { 258 procedure = ModelBindingManager.get().getProcedureByName(DlineageUtil.getIdentifierNormalTableName( 259 DlineageUtil.getProcedureNameWithArgNum(getParentProcedure(stmt)))); 260 } 261 if (procedure != null) { 262 this.procedureId = procedure.getId(); 263 } 264 } else { 265 procedureName = "batchQueries"; 266 } 267 268 String sqlComment = null; 269 try { 270 sqlComment = stmt.getCommentBeforeNode(); 271 } catch (Exception e) { 272 } 273 if (!SQLUtil.isEmpty(sqlComment) && sqlComment.indexOf("process") != -1) { 274 Properties properties = new Properties(); 275 try { 276 properties.load( 277 new ByteArrayInputStream(sqlComment.replace("--", "").trim().replace(",", "\n").getBytes())); 278 if (properties.containsKey("process_label")) { 279 this.customType = properties.getProperty("process_label"); 280 } else if (properties.containsKey("process")) { 281 this.customType = properties.getProperty("process"); 282 } 283 } catch (IOException e) { 284 logger.error("load sql comment properties failed.", e); 285 } 286 } 287 288 this.type = "Function Call"; 289 290 if (this.server == null && !TSQLEnv.DEFAULT_SERVER_NAME.equals(getDefaultServer())) { 291 this.server = getDefaultServer(); 292 } 293 } 294 295 private void appendTransform(TSelectSqlStatement select, ESetOperatorType operatorType) { 296 // Iterative traversal of the UNION tree to avoid StackOverflow with deeply nested unions. 297 Deque<Object[]> stack = new ArrayDeque<>(); 298 stack.push(new Object[]{select, operatorType}); 299 300 while (!stack.isEmpty()) { 301 Object[] entry = stack.pop(); 302 TSelectSqlStatement current = (TSelectSqlStatement) entry[0]; 303 ESetOperatorType currentOp = (ESetOperatorType) entry[1]; 304 305 if (currentOp != ESetOperatorType.none) { 306 Transform transform = new Transform(); 307 transform.setType(currentOp.name()); 308 transform.setCodeString(current.toString()); 309 transform.setStartToken(current.getStartToken()); 310 transform.setEndToken(current.getEndToken()); 311 transforms.add(transform); 312 } else { 313 if (current.getCteList() != null && current.getCteList().size() > 0) { 314 for (int i = 0; i < current.getCteList().size(); i++) { 315 TCTE cte = current.getCteList().getCTE(i); 316 Transform transform = new Transform(); 317 transform.setType(Transform.CTE); 318 transform.setCodeString(cte.toString()); 319 transform.setStartToken(cte.getStartToken()); 320 transform.setEndToken(cte.getEndToken()); 321 transforms.add(transform); 322 } 323 } 324 if (current.getSetOperatorType() != ESetOperatorType.none) { 325 // Push right first so left is processed first (stack is LIFO) 326 if (current.getRightStmt() != null) { 327 ESetOperatorType rightOp = current.getRightStmt().getSetOperatorType() != ESetOperatorType.none 328 ? ESetOperatorType.none : current.getSetOperatorType(); 329 stack.push(new Object[]{current.getRightStmt(), rightOp}); 330 } 331 if (current.getLeftStmt() != null) { 332 ESetOperatorType leftOp = current.getLeftStmt().getSetOperatorType() != ESetOperatorType.none 333 ? ESetOperatorType.none : current.getSetOperatorType(); 334 stack.push(new Object[]{current.getLeftStmt(), leftOp}); 335 } 336 } else { 337 if (current.getJoins() != null && current.getJoins().size() > 0) { 338 TJoinList joins = current.getJoins(); 339 TSourceToken startToken = joins.getStartToken(); 340 TSourceToken fromToken = SourceTokenSearcher.backforwardSearch(startToken, 10, "from"); 341 if (fromToken == null) { 342 if (startToken.getAstext().equalsIgnoreCase("from")) { 343 fromToken = startToken; 344 } else { 345 continue; 346 } 347 } 348 StringBuilder builder = new StringBuilder(); 349 if (joins.getEndToken().posinlist < fromToken.container.size() 350 && joins.getEndToken().posinlist >= fromToken.posinlist) { 351 for (int j = fromToken.posinlist; j <= joins.getEndToken().posinlist; j++) { 352 builder.append(fromToken.container.get(j)); 353 } 354 } else { 355 System.err.println("Handle statement transform error, statemet is:"); 356 System.err.println(current.toString()); 357 } 358 Transform transform = new Transform(); 359 transform.setType(Transform.FROM); 360 transform.setCodeString(builder.toString()); 361 transform.setStartToken(fromToken); 362 transform.setEndToken(joins.getEndToken()); 363 transforms.add(transform); 364 } 365 } 366 } 367 } 368 } 369 370 private TSelectSqlStatement getFirstSubquery(TSelectSqlStatement select) { 371 // Iterative left-chain walk to avoid StackOverflow with deeply nested unions. 372 TSelectSqlStatement current = select; 373 while (current.getSetOperatorType() != ESetOperatorType.none) { 374 current = current.getLeftStmt(); 375 } 376 return current; 377 } 378 379 private TSelectSqlStatement getLastSubquery(TSelectSqlStatement select) { 380 // Iterative right-chain walk to avoid StackOverflow with deeply nested unions. 381 TSelectSqlStatement current = select; 382 while (current.getSetOperatorType() != ESetOperatorType.none) { 383 current = current.getRightStmt(); 384 } 385 return current; 386 } 387 388 private void fillSchemaInfo() { 389 TCustomSqlStatement stmt = DlineageUtil.getTopStmt(ModelBindingManager.getGlobalStmtStack().peek()); 390 String sqlComment = null; 391 try { 392 sqlComment = stmt.getCommentBeforeNode(); 393 } catch (Exception e) { 394 } 395 if (!SQLUtil.isEmpty(sqlComment) && (sqlComment.indexOf("db") != -1 || sqlComment.indexOf("schema") != -1)) { 396 Properties properties = new Properties(); 397 try { 398 properties.load( 399 new ByteArrayInputStream(sqlComment.replace("--", "").trim().replace(",", "\n").getBytes())); 400 if (SQLUtil.isEmpty(this.server) && properties.containsKey("db-instance")) { 401 this.server = properties.getProperty("db-instance"); 402 } 403 if (SQLUtil.isEmpty(this.database) && properties.containsKey("db")) { 404 this.database = properties.getProperty("db"); 405 if (this.database.indexOf(".") != -1) { 406 String delimitedChar = TSQLEnv.delimitedChar(ModelBindingManager.getGlobalOption().getVendor()); 407 this.database = delimitedChar + SQLUtil.trimColumnStringQuote(this.database) + delimitedChar; 408 } 409 } 410 if (SQLUtil.isEmpty(this.schema) && properties.containsKey("schema")) { 411 this.schema = properties.getProperty("schema"); 412 if (this.schema.indexOf(".") != -1) { 413 String delimitedChar = TSQLEnv.delimitedChar(ModelBindingManager.getGlobalOption().getVendor()); 414 this.schema = delimitedChar + SQLUtil.trimColumnStringQuote(this.schema) + delimitedChar; 415 } 416 } 417 } catch (IOException e) { 418 logger.error("load sql comment properties failed.", e); 419 } 420 } 421 } 422 423 protected String getDefaultServer() { 424 String defaultServer = null; 425 if (ModelBindingManager.getGlobalSQLEnv() != null) { 426 defaultServer = ModelBindingManager.getGlobalSQLEnv().getDefaultServerName(); 427 } 428 if (!SQLUtil.isEmpty(defaultServer)) 429 return defaultServer; 430 return TSQLEnv.DEFAULT_SERVER_NAME; 431 } 432 433 protected String getDefaultSchema() { 434 String defaultSchema = null; 435 if (ModelBindingManager.getGlobalSQLEnv() != null) { 436 defaultSchema = ModelBindingManager.getGlobalSQLEnv().getDefaultSchemaName(); 437 } 438 if (!SQLUtil.isEmpty(defaultSchema)) 439 return defaultSchema; 440 return TSQLEnv.DEFAULT_SCHEMA_NAME; 441 } 442 443 protected String getDefaultDatabase() { 444 String defaultDatabase = null; 445 if (ModelBindingManager.getGlobalSQLEnv() != null) { 446 defaultDatabase = ModelBindingManager.getGlobalSQLEnv().getDefaultCatalogName(); 447 } 448 if (!SQLUtil.isEmpty(defaultDatabase)) 449 return defaultDatabase; 450 return TSQLEnv.DEFAULT_DB_NAME; 451 } 452 453 private String getProcedureParentName(TCustomSqlStatement stmt) { 454 if (stmt instanceof TStoredProcedureSqlStatement) { 455 if (((TStoredProcedureSqlStatement) stmt).getStoredProcedureName() != null) { 456 return ((TStoredProcedureSqlStatement) stmt).getStoredProcedureName().toString(); 457 } 458 } 459 460 if (stmt == null) { 461 return null; 462 } 463 464 if (stmt instanceof TTeradataCreateProcedure) { 465 if (((TTeradataCreateProcedure) stmt).getProcedureName() != null) { 466 return ((TTeradataCreateProcedure) stmt).getProcedureName().toString(); 467 } 468 } 469 470 if (stmt instanceof TStoredProcedureSqlStatement) { 471 if (((TStoredProcedureSqlStatement) stmt).getStoredProcedureName() != null) { 472 return ((TStoredProcedureSqlStatement) stmt).getStoredProcedureName().toString(); 473 } 474 475 if (stmt instanceof TCommonBlock) { 476 if (((TCommonBlock) stmt).getBlockBody().getParentObjectName() instanceof TStoredProcedureSqlStatement) { 477 stmt = (TStoredProcedureSqlStatement) ((TCommonBlock) stmt).getBlockBody().getParentObjectName(); 478 } 479 else { 480 return getProcedureParentName(stmt.getParentStmt()); 481 } 482 } 483 484 return null; 485 } 486 487 stmt = stmt.getParentStmt(); 488 if (stmt == null) { 489 if(ModelBindingManager.getGlobalProcedure()!=null) { 490 return getProcedureParentName(ModelBindingManager.getGlobalProcedure()); 491 } 492 else { 493 return null; 494 } 495 } 496 497 498 if (stmt instanceof TCommonBlock) { 499 if (((TCommonBlock) stmt).getBlockBody().getParentObjectName() instanceof TStoredProcedureSqlStatement) { 500 stmt = (TStoredProcedureSqlStatement) ((TCommonBlock) stmt).getBlockBody().getParentObjectName(); 501 } 502 } 503 504 return getProcedureParentName(stmt); 505 } 506 507 private TStoredProcedureSqlStatement getParentProcedure(TCustomSqlStatement stmt) { 508 if (stmt == null) { 509 return null; 510 } 511 512 if (stmt instanceof TStoredProcedureSqlStatement) { 513 if (((TStoredProcedureSqlStatement) stmt).getStoredProcedureName() != null) { 514 return ((TStoredProcedureSqlStatement) stmt); 515 } 516 517 if (stmt instanceof TCommonBlock) { 518 if (((TCommonBlock) stmt).getBlockBody().getParentObjectName() instanceof TStoredProcedureSqlStatement) { 519 return (TStoredProcedureSqlStatement) ((TCommonBlock) stmt).getBlockBody().getParentObjectName(); 520 } 521 else { 522 return getParentProcedure(stmt.getParentStmt()); 523 } 524 } 525 526 return null; 527 } 528 529 stmt = stmt.getParentStmt(); 530 if (stmt == null) { 531 if(ModelBindingManager.getGlobalProcedure()!=null) { 532 return ModelBindingManager.getGlobalProcedure(); 533 } 534 else { 535 return null; 536 } 537 } 538 539 if (stmt instanceof TCommonBlock) { 540 if (((TCommonBlock) stmt).getBlockBody().getParentObjectName() instanceof TStoredProcedureSqlStatement) { 541 stmt = (TStoredProcedureSqlStatement) ((TCommonBlock) stmt).getBlockBody().getParentObjectName(); 542 } 543 } 544 545 return getParentProcedure(stmt); 546 } 547 548 public Pair3<Long, Long, String> getStartPosition() { 549 return startPosition; 550 } 551 552 public Pair3<Long, Long, String> getEndPosition() { 553 return endPosition; 554 } 555 556 public TCustomSqlStatement getGspObject() { 557 return gspObject; 558 } 559 560 public long getId() { 561 return id; 562 } 563 564 public String getSchema() { 565 return schema; 566 } 567 568 public String getDatabase() { 569 return database; 570 } 571 572 public String getName() { 573 return name; 574 } 575 576 public String getType() { 577 return type; 578 } 579 580 public void setName(String name) { 581 this.name = name; 582 } 583 584 public void setType(String type) { 585 this.type = type; 586 } 587 588 public String getProcedureName() { 589 return procedureName; 590 } 591 592 public void setProcedureName(String procedureName) { 593 this.procedureName = procedureName; 594 } 595 596 public String getQueryHashId() { 597 return queryHashId; 598 } 599 600 public void setQueryHashId(String queryHashId) { 601 this.queryHashId = queryHashId; 602 } 603 604 public void appendColumn(Object tableColumn) { 605 if (tableColumn != null && !targetColumns.contains(tableColumn)) { 606 targetColumns.add(tableColumn); 607 } 608 } 609 610 public List<Object> getTargetColumns() { 611 return targetColumns; 612 } 613 614 public String getCustomType() { 615 return customType; 616 } 617 618 public Long getProcedureId() { 619 return procedureId; 620 } 621 622 public String getServer() { 623 return server; 624 } 625 626 public List<Transform> getTransforms() { 627 return transforms; 628 } 629}