001 002package gudusoft.gsqlparser.dlineage.dataflow.model; 003 004import gudusoft.gsqlparser.EDbVendor; 005import gudusoft.gsqlparser.ESqlStatementType; 006import gudusoft.gsqlparser.ETableSource; 007import gudusoft.gsqlparser.TCustomSqlStatement; 008import gudusoft.gsqlparser.dlineage.util.DlineageUtil; 009import gudusoft.gsqlparser.dlineage.util.Objects; 010import gudusoft.gsqlparser.dlineage.util.Pair; 011import gudusoft.gsqlparser.nodes.TAliasClause; 012import gudusoft.gsqlparser.nodes.TCaseExpression; 013import gudusoft.gsqlparser.nodes.TConstant; 014import gudusoft.gsqlparser.nodes.TDeclareVariable; 015import gudusoft.gsqlparser.nodes.TExpression; 016import gudusoft.gsqlparser.nodes.TFunctionCall; 017import gudusoft.gsqlparser.nodes.TObjectName; 018import gudusoft.gsqlparser.nodes.TObjectNameList; 019import gudusoft.gsqlparser.nodes.TParameterDeclaration; 020import gudusoft.gsqlparser.nodes.TParseTreeNode; 021import gudusoft.gsqlparser.nodes.TPivotClause; 022import gudusoft.gsqlparser.nodes.TResultColumn; 023import gudusoft.gsqlparser.nodes.TTable; 024import gudusoft.gsqlparser.nodes.TWhenClauseItemList; 025import gudusoft.gsqlparser.sqlenv.TSQLColumn; 026import gudusoft.gsqlparser.sqlenv.TSQLEnv; 027import gudusoft.gsqlparser.sqlenv.TSQLTable; 028import gudusoft.gsqlparser.stmt.TCreateTableSqlStatement; 029import gudusoft.gsqlparser.stmt.TCreateViewSqlStatement; 030import gudusoft.gsqlparser.stmt.TCursorDeclStmt; 031import gudusoft.gsqlparser.stmt.TForStmt; 032import gudusoft.gsqlparser.stmt.TInsertSqlStatement; 033import gudusoft.gsqlparser.stmt.TLoopStmt; 034import gudusoft.gsqlparser.stmt.TMergeSqlStatement; 035import gudusoft.gsqlparser.stmt.TOpenforStmt; 036import gudusoft.gsqlparser.stmt.TSelectSqlStatement; 037import gudusoft.gsqlparser.stmt.TStoredProcedureSqlStatement; 038import gudusoft.gsqlparser.stmt.mssql.TMssqlDeclare; 039import gudusoft.gsqlparser.stmt.oracle.TPlsqlCreatePackage; 040import gudusoft.gsqlparser.util.SQLUtil; 041 042import java.util.ArrayList; 043import java.util.LinkedHashMap; 044import java.util.List; 045import java.util.Map; 046import java.util.Set; 047 048public class ModelFactory { 049 050 private ModelBindingManager modelManager; 051 052 public ModelFactory(ModelBindingManager modelManager) { 053 this.modelManager = modelManager; 054 } 055 056 public ResultSet createResultSet(TSelectSqlStatement select, boolean isTarget) { 057 if (select.getResultColumnList() != null) { 058 if (modelManager.getModel(select.getResultColumnList()) instanceof ResultSet) { 059 return (ResultSet) modelManager.getModel(select.getResultColumnList()); 060 } 061 SelectResultSet resultSet = new SelectResultSet(select, isTarget); 062 modelManager.bindModel(select.getResultColumnList(), resultSet); 063 return resultSet; 064 } else if (select.getTransformClause() != null) { 065 if (modelManager.getModel(select.getTransformClause()) instanceof ResultSet) { 066 return (ResultSet) modelManager.getModel(select.getTransformClause()); 067 } 068 SelectResultSet resultSet = new SelectResultSet(select, isTarget); 069 modelManager.bindModel(select.getTransformClause(), resultSet); 070 return resultSet; 071 } else 072 return null; 073 } 074 075 public ResultSet createResultSet(TParseTreeNode gspObject, boolean isTarget) { 076 if (modelManager.getModel(gspObject) instanceof ResultSet) { 077 return (ResultSet) modelManager.getModel(gspObject); 078 } 079 ResultSet resultSet = new ResultSet(gspObject, isTarget); 080 modelManager.bindModel(gspObject, resultSet); 081 return resultSet; 082 } 083 084 public ResultColumn createResultColumn(ResultSet resultSet, TResultColumn resultColumn) { 085 if (modelManager.getModel(resultColumn) instanceof ResultColumn) { 086 return (ResultColumn) modelManager.getModel(resultColumn); 087 } 088 ResultColumn column = new ResultColumn(resultSet, resultColumn); 089 modelManager.bindModel(resultColumn, column); 090 return column; 091 } 092 093 public ResultColumn createStarResultColumn(ResultSet resultSetModel, TResultColumn resultColumn, 094 String refColumnName) { 095 if (modelManager.getModel(resultColumn) instanceof LinkedHashMap) { 096 LinkedHashMap<String, ResultColumn> resultColumns = (LinkedHashMap<String, ResultColumn>) modelManager 097 .getModel(resultColumn); 098 if (resultColumns.containsKey(refColumnName)) { 099 return resultColumns.get(refColumnName); 100 } 101 102 ResultColumn column = new ResultColumn(resultSetModel, resultColumn, refColumnName); 103 resultColumns.put(refColumnName, column); 104 return column; 105 } else { 106 LinkedHashMap<String, ResultColumn> resultColumns = new LinkedHashMap<String, ResultColumn>(); 107 ResultColumn column = new ResultColumn(resultSetModel, resultColumn, refColumnName); 108 resultColumns.put(refColumnName, column); 109 modelManager.bindModel(resultColumn, resultColumns); 110 return column; 111 } 112 } 113 114 public ResultColumn createSelectSetResultColumn(ResultSet resultSet, ResultColumn resultColumn) { 115 if (modelManager.getModel(resultColumn) instanceof ResultColumn) { 116 return (ResultColumn) modelManager.getModel(resultColumn); 117 } 118 String columnName = DlineageUtil.getIdentifierNormalColumnName(resultColumn.getName()); 119 for (int i = 0; i < resultSet.getColumns().size(); i++) { 120 ResultColumn columnModel = resultSet.getColumns().get(i); 121 if (DlineageUtil.getIdentifierNormalColumnName(columnModel.getName()).equals(columnName)) { 122 modelManager.bindModel(resultColumn, columnModel); 123 return columnModel; 124 } 125 } 126 ResultColumn column = new SelectSetResultColumn(resultSet, resultColumn); 127 if(resultColumn.isStruct()) { 128 column.setStruct(true); 129 } 130 modelManager.bindModel(resultColumn, column); 131 return column; 132 } 133 134 public ResultColumn createSelectSetResultColumn(ResultSet resultSet, TResultColumn resultColumn, int index) { 135 136 for (int i = 0; i < resultSet.getColumns().size(); i++) { 137 ResultColumn columnModel = resultSet.getColumns().get(i); 138 if(columnModel.getColumnObject() == resultColumn) { 139 return columnModel; 140 } 141 } 142 143 SelectSetResultColumn column = new SelectSetResultColumn(resultSet, resultColumn, index); 144 modelManager.bindModel(resultColumn, column); 145 return column; 146 } 147 148 public ResultColumn createAndBindingSelectSetResultColumn(ResultSet resultSet, TResultColumn resultColumn, 149 int index) { 150 if (modelManager.getModel(resultColumn) instanceof ResultColumn) { 151 return (ResultColumn) modelManager.getModel(resultColumn); 152 } 153 ResultColumn column = new SelectSetResultColumn(resultSet, resultColumn, index); 154 modelManager.bindModel(resultColumn, column); 155 return column; 156 } 157 158 public ResultColumn createResultColumn(ResultSet resultSet, TObjectName resultColumn) { 159 if (modelManager.getModel(resultColumn) instanceof ResultColumn) { 160 return (ResultColumn) modelManager.getModel(resultColumn); 161 } 162 if(EDbVendor.dbvoracle == ModelBindingManager.getGlobalVendor()){ 163 ResultColumn column = new ResultColumn(resultSet, resultColumn); 164 modelManager.bindModel(resultColumn, column); 165 return column; 166 } 167 else { 168 String columnName = DlineageUtil.getIdentifierNormalColumnName(resultColumn.toString()); 169 for (int i = 0; i < resultSet.getColumns().size(); i++) { 170 ResultColumn columnModel = resultSet.getColumns().get(i); 171 if (DlineageUtil.getIdentifierNormalColumnName(columnModel.getName()).equals(columnName)) { 172 modelManager.bindModel(resultColumn, columnModel); 173 return columnModel; 174 } 175 } 176 ResultColumn column = new ResultColumn(resultSet, resultColumn); 177 modelManager.bindModel(resultColumn, column); 178 return column; 179 } 180 } 181 182 public ResultColumn createDeterminedResultColumn(ResultSet resultSet, TObjectName resultColumn) { 183 ResultColumn column = new ResultColumn(resultSet, resultColumn); 184 modelManager.bindModel(resultColumn, column); 185 return column; 186 } 187 188 public ResultColumn createResultColumn(ResultSet resultSet, TExpression expression) { 189 if (modelManager.getModel(expression) instanceof ResultColumn) { 190 return (ResultColumn) modelManager.getModel(expression); 191 } 192 ResultColumn column = new ResultColumn(resultSet, expression); 193 modelManager.bindModel(expression, column); 194 return column; 195 } 196 197 public ResultColumn createResultColumn(ResultSet resultSet, TObjectName resultColumn, boolean forceCreate) { 198 if (!forceCreate) { 199 if (modelManager.getModel(resultColumn) instanceof ResultColumn) { 200 return (ResultColumn) modelManager.getModel(resultColumn); 201 } 202 } 203 204 String columnName = DlineageUtil.getIdentifierNormalColumnName(resultColumn.toString()); 205 for (int i = 0; i < resultSet.getColumns().size(); i++) { 206 ResultColumn columnModel = resultSet.getColumns().get(i); 207 if (DlineageUtil.getIdentifierNormalColumnName(columnModel.getName()).equals(columnName)) { 208 modelManager.bindModel(resultColumn, columnModel); 209 return columnModel; 210 } 211 } 212 213 ResultColumn column = new ResultColumn(resultSet, resultColumn); 214 modelManager.bindModel(resultColumn, column); 215 return column; 216 } 217 218 public FunctionResultColumn createFunctionResultColumn(Function function, TObjectName functionName) { 219 if (modelManager.getModel(functionName) instanceof FunctionResultColumn) { 220 return (FunctionResultColumn) modelManager.getModel(functionName); 221 } 222 FunctionResultColumn column = new FunctionResultColumn(function, function.getFunctionObject(), functionName); 223 modelManager.bindModel(functionName, column); 224 return column; 225 } 226 227 public FunctionResultColumn createFunctionResultColumn(Function function, TWhenClauseItemList caseFunction) { 228 if (modelManager.getModel(caseFunction) instanceof FunctionResultColumn) { 229 return (FunctionResultColumn) modelManager.getModel(caseFunction); 230 } 231 FunctionResultColumn column = new FunctionResultColumn(function, function.getFunctionObject(), caseFunction); 232 modelManager.bindModel(caseFunction, column); 233 return column; 234 } 235 236 public ResultColumn createMergeResultColumn(ResultSet resultSet, TObjectName resultColumn) { 237 if (modelManager.getMergeModel(resultColumn) instanceof ResultColumn) { 238 return (ResultColumn) modelManager.getMergeModel(resultColumn); 239 } 240 ResultColumn column = new ResultColumn(resultSet, resultColumn); 241 modelManager.bindMergeModel(resultColumn, column); 242 return column; 243 } 244 245 public ResultColumn createUpdateResultColumn(ResultSet resultSet, TObjectName resultColumn) { 246 if (modelManager.getUpdateModel(resultColumn) instanceof ResultColumn) { 247 return (ResultColumn) modelManager.getUpdateModel(resultColumn); 248 } 249 ResultColumn column = new ResultColumn(resultSet, resultColumn); 250 modelManager.bindUpdateModel(resultColumn, column); 251 return column; 252 } 253 254 public ResultColumn createResultColumn(QueryTable queryTableModel, TResultColumn resultColumn) { 255 if (modelManager.getModel(resultColumn) instanceof ResultColumn) { 256 return (ResultColumn) modelManager.getModel(resultColumn); 257 } 258 ResultColumn column = new ResultColumn(queryTableModel, resultColumn); 259 modelManager.bindModel(resultColumn, column); 260 return column; 261 } 262 263 public Table createTableFromCreateDDL(TTable table, boolean fromDDL, String tableName) { 264 if (modelManager.getCreateModel(table) instanceof Table) { 265 Table tableModel = (Table) modelManager.getCreateModel(table); 266 tableModel.setPosition(table); 267 return tableModel; 268 } 269 if (modelManager.getModel(table) instanceof Table) { 270 Table tableModel = (Table) modelManager.getModel(table); 271 tableModel.setPosition(table); 272 return tableModel; 273 } 274 if (modelManager 275 .getTableByName(DlineageUtil.getTableFullName(tableName.toString())) instanceof Table) { 276 Table tableModel = (Table) modelManager.getTableByName(DlineageUtil.getTableFullName(tableName.toString())); 277 tableModel.setPosition(table); 278 return tableModel; 279 } 280 if (modelManager.getTableByName( 281 DlineageUtil.getTableFullNameWithDefaultSchema(tableName.toString())) instanceof Table) { 282 Table tableModel = (Table) modelManager 283 .getTableByName(DlineageUtil.getTableFullNameWithDefaultSchema(tableName.toString())); 284 tableModel.setPosition(table); 285 return tableModel; 286 } 287 Table tableModel = new Table(table, tableName); 288 tableModel.setCreateTable(fromDDL); 289 if (!fromDDL) { 290 Table existTable = modelManager.getTableByName(DlineageUtil.getTableFullName(tableModel.getName())); 291 if (existTable != null) { 292 return existTable; 293 } 294 } 295 modelManager.bindCreateModel(table, tableModel); 296 if(table.getTableType() == ETableSource.unnest) { 297 298 } 299 else { 300 modelManager.bindTableByName(DlineageUtil.getTableFullName(tableName.toString()), tableModel); 301 } 302 return tableModel; 303 } 304 305 public Table createTableFromCreateDDL(TTable table, boolean fromDDL) { 306 if (modelManager.getCreateModel(table) instanceof Table) { 307 Table tableModel = (Table) modelManager.getCreateModel(table); 308 tableModel.setPosition(table); 309 return tableModel; 310 } 311 if (modelManager.getModel(table) instanceof Table) { 312 Table tableModel = (Table) modelManager.getModel(table); 313 tableModel.setPosition(table); 314 return tableModel; 315 } 316 if (modelManager 317 .getTableByName(DlineageUtil.getTableFullName(table.getTableName().toString())) instanceof Table) { 318 Table tableModel = (Table) modelManager.getTableByName(DlineageUtil.getTableFullName(table.getTableName().toString())); 319 tableModel.setPosition(table); 320 return tableModel; 321 } 322 if (modelManager.getTableByName( 323 DlineageUtil.getTableFullNameWithDefaultSchema(table.getTableName().toString())) instanceof Table) { 324 Table tableModel = (Table) modelManager 325 .getTableByName(DlineageUtil.getTableFullNameWithDefaultSchema(table.getTableName().toString())); 326 tableModel.setPosition(table); 327 return tableModel; 328 } 329 Table tableModel = new Table(table); 330 tableModel.setCreateTable(fromDDL, fromDDL); 331 if (!fromDDL) { 332 Table existTable = modelManager.getTableByName(DlineageUtil.getTableFullName(tableModel.getName())); 333 if (existTable != null) { 334 return existTable; 335 } 336 } 337 modelManager.bindCreateModel(table, tableModel); 338 modelManager.bindTableByName(DlineageUtil.getTableFullName(table.getTableName().toString()), tableModel); 339 modelManager.bindTableByName(DlineageUtil.getTableFullName(tableModel.getName()), tableModel); 340 return tableModel; 341 } 342 343 public Table createJsonTable(TTable table) { 344 String tableName = table.toString(); 345 if (tableName.toLowerCase().indexOf("with") != -1) { 346 tableName = table.toString().substring(0, tableName.toLowerCase().indexOf("with")).trim(); 347 } 348 349 if (table.isLinkTable()) { 350 table = table.getLinkTable(); 351 } 352 353 if (modelManager.getCreateTable(table) != null) { 354 Table tableModel = modelManager.getCreateTable(table); 355 tableModel.setPosition(table); 356 return tableModel; 357 } 358 if (modelManager.getModel(table) instanceof Table) { 359 Table tableModel = (Table) modelManager.getModel(table); 360 tableModel.setPosition(table); 361 return tableModel; 362 } 363 if (modelManager.getTableByName(DlineageUtil.getTableFullName(tableName)) instanceof Table) { 364 Table tableModel = (Table) modelManager.getTableByName(DlineageUtil.getTableFullName(tableName)); 365 tableModel.setPosition(table); 366 return tableModel; 367 } 368 369 if (modelManager.getTableByName(DlineageUtil.getTableFullNameWithDefaultSchema(tableName)) instanceof Table) { 370 Table tableModel = (Table) modelManager.getTableByName(DlineageUtil.getTableFullNameWithDefaultSchema(tableName)); 371 tableModel.setPosition(table); 372 return tableModel; 373 } 374 375 Table tableModel = new Table(table); 376 tableModel.setName(tableName); 377 modelManager.bindModel(table, tableModel); 378 modelManager.bindTableByName(DlineageUtil.getTableFullName(tableName), tableModel); 379 return tableModel; 380 } 381 382 public Table createXmlTable(TTable table) { 383 String tableName = table.toString(); 384 if (tableName.toLowerCase().indexOf("with") != -1) { 385 tableName = table.toString().substring(0, tableName.toLowerCase().indexOf("with")).trim(); 386 } 387 388 if (table.isLinkTable()) { 389 table = table.getLinkTable(); 390 } 391 392 if (modelManager.getCreateTable(table) != null) { 393 Table tableModel = modelManager.getCreateTable(table); 394 tableModel.setPosition(table); 395 return tableModel; 396 } 397 if (modelManager.getModel(table) instanceof Table) { 398 Table tableModel = (Table) modelManager.getModel(table); 399 tableModel.setPosition(table); 400 return tableModel; 401 } 402 if (modelManager.getTableByName(DlineageUtil.getTableFullName(tableName)) instanceof Table) { 403 Table tableModel = (Table) modelManager.getTableByName(DlineageUtil.getTableFullName(tableName)); 404 tableModel.setPosition(table); 405 return tableModel; 406 } 407 408 if (modelManager.getTableByName(DlineageUtil.getTableFullNameWithDefaultSchema(tableName)) instanceof Table) { 409 Table tableModel = (Table) modelManager.getTableByName(DlineageUtil.getTableFullNameWithDefaultSchema(tableName)); 410 tableModel.setPosition(table); 411 return tableModel; 412 } 413 414 Table tableModel = new Table(table); 415 tableModel.setName(tableName); 416 modelManager.bindModel(table, tableModel); 417 modelManager.bindTableByName(DlineageUtil.getTableFullName(tableName), tableModel); 418 return tableModel; 419 } 420 421 public Table createTable(TTable table, TObjectName tableBinding) { 422 Table tableModel = createTable(table); 423 modelManager.bindModel(table, tableModel); 424 modelManager.bindTableByName(DlineageUtil.getTableFullName(tableBinding.toString()), tableModel); 425 return tableModel; 426 } 427 428 public Table createTable(TTable table) { 429 if (table.isLinkTable()) { 430 table = table.getLinkTable(); 431 } 432 433 Table tableModel = null; 434 if (modelManager.getCreateTable(table) != null) { 435 tableModel = modelManager.getCreateTable(table); 436 } 437 if (tableModel == null && modelManager.getModel(table) instanceof Table) { 438 tableModel = (Table) modelManager.getModel(table); 439 } 440 441 String tableName = table.getTableName().toString(); 442 if (table.getSubquery() != null && table.getAliasClause() != null) { 443 tableName = table.getAliasClause().toString(); 444 } 445 446 if (tableModel == null 447 && modelManager.getTableByName(DlineageUtil.getTableFullName(tableName)) instanceof Table) { 448 tableModel = modelManager.getTableByName(DlineageUtil.getTableFullName(tableName)); 449 } 450 451 if (tableModel == null && modelManager 452 .getTableByName(DlineageUtil.getTableFullNameWithDefaultSchema(tableName)) instanceof Table) { 453 tableModel = modelManager.getTableByName(DlineageUtil.getTableFullNameWithDefaultSchema(tableName)); 454 } 455 456 if (tableModel != null) { 457 if (table.getAliasClause() != null) { 458 tableModel.setAlias(table.getAliasName()); 459 } 460 tableModel.setCurrentAlias(table.getAliasName()); 461 modelManager.updateTableAliasMap(table); 462 tableModel.setPosition(table); 463 return tableModel; 464 } 465 466 tableModel = new Table(table); 467 Table existTable = modelManager.getTableByName(DlineageUtil.getTableFullName(tableModel.getName())); 468 if (existTable != null) { 469 return existTable; 470 } 471 modelManager.bindModel(table, tableModel); 472 modelManager.bindTableByName(DlineageUtil.getTableFullName(tableName), tableModel); 473 modelManager.bindTableByName(DlineageUtil.getTableFullName(tableModel.getName()), tableModel); 474 475 appendTableColumns(tableModel); 476 477 return tableModel; 478 } 479 480 protected void appendTableColumns(Table tableModel) { 481 TCustomSqlStatement stmt = ModelBindingManager.getGlobalStmtStack().peek(); 482 if (stmt instanceof TCreateTableSqlStatement || stmt instanceof TCreateViewSqlStatement) { 483 return; 484 } 485 if (stmt instanceof TInsertSqlStatement && ((TInsertSqlStatement) stmt).getColumnList() != null) { 486 return; 487 } 488 if (ModelBindingManager.getGlobalSQLEnv() != null) { 489 ArrayList<String> columns = ModelBindingManager.getGlobalSQLEnv() 490 .getColumnsInTable(DlineageUtil.getTableFullName(tableModel.getName()), true); 491 if (columns != null && !columns.isEmpty()) { 492 for (String column : columns) { 493 if (SQLUtil.isEmpty(column)) { 494 continue; 495 } 496 createInsertTableColumn(tableModel, column); 497 } 498 tableModel.setFromDDL(true); 499 tableModel.setCreateTable(true); 500 } 501 } 502 } 503 504 public Table createTriggerOnTable(TTable table) { 505 if (modelManager.getCreateTable(table) != null) { 506 Table tableModel = modelManager.getCreateTable(table); 507 tableModel.setPosition(table); 508 return tableModel; 509 } 510 if (modelManager.getModel(table) instanceof Table) { 511 Table tableModel = (Table) modelManager.getModel(table); 512 tableModel.setPosition(table); 513 return tableModel; 514 } 515 if (modelManager 516 .getTableByName(DlineageUtil.getTableFullName(table.getTableName().toString())) instanceof Table) { 517 Table tableModel = (Table) modelManager.getTableByName(DlineageUtil.getTableFullName(table.getTableName().toString())); 518 tableModel.setPosition(table); 519 return tableModel; 520 } 521 if (modelManager.getTableByName( 522 DlineageUtil.getTableFullNameWithDefaultSchema(table.getTableName().toString())) instanceof Table) { 523 Table tableModel = (Table) modelManager.getTableByName(DlineageUtil.getTableFullNameWithDefaultSchema(table.getTableName().toString())); 524 tableModel.setPosition(table); 525 return tableModel; 526 } 527 Table tableModel = new Table(table); 528 Table existTable = modelManager.getTableByName(DlineageUtil.getTableFullName(tableModel.getName())); 529 if (existTable != null) { 530 return existTable; 531 } 532 modelManager.bindModel(table, tableModel); 533 modelManager.bindTableByName(DlineageUtil.getTableFullName(table.getTableName().toString()), tableModel); 534 modelManager.bindTableByName(DlineageUtil.getTableFullName(tableModel.getName()), tableModel); 535 return tableModel; 536 } 537 538 public Table createTableByName(TObjectName tableName) { 539 return createTableByName(tableName, false); 540 } 541 542 public Table createTableByName(TObjectName tableName, boolean create) { 543 if (modelManager.getTableByName(DlineageUtil.getTableFullName(tableName.toString())) instanceof Table) { 544 Table tableModel = (Table) modelManager.getTableByName(DlineageUtil.getTableFullName(tableName.toString())); 545 tableModel.setPosition(tableName); 546 return tableModel; 547 } 548 Table tableModel = new Table(tableName); 549 Table existTable = modelManager.getTableByName(DlineageUtil.getTableFullName(tableModel.getName())); 550 if (existTable != null) { 551 existTable.setPosition(tableName); 552 return existTable; 553 } 554 if (tableModel.getColumns() == null || tableModel.getColumns().isEmpty()) { 555 tableModel.addColumnsFromSQLEnv(); 556 } 557 modelManager.bindTableByName(DlineageUtil.getTableFullName(tableName.toString()), tableModel); 558 modelManager.bindTableByName(DlineageUtil.getTableFullName(tableModel.getName()), tableModel); 559 if (create) { 560 modelManager.bindCreateModel(tableName, tableModel); 561 } 562 return tableModel; 563 } 564 565 public Table createTableByName(String tableName, boolean create) { 566 if (modelManager.getTableByName(DlineageUtil.getTableFullName(tableName.toString())) instanceof Table) { 567 return (Table) modelManager.getTableByName(DlineageUtil.getTableFullName(tableName.toString())); 568 } 569 Table tableModel = new Table(tableName); 570 Table existTable = modelManager.getTableByName(DlineageUtil.getTableFullName(tableModel.getName())); 571 if (existTable != null) { 572 return existTable; 573 } 574 if (tableModel.getColumns() == null || tableModel.getColumns().isEmpty()) { 575 tableModel.addColumnsFromSQLEnv(); 576 } 577 modelManager.bindTableByName(DlineageUtil.getTableFullName(tableName.toString()), tableModel); 578 modelManager.bindTableByName(DlineageUtil.getTableFullName(tableModel.getName()), tableModel); 579 if (create) { 580 modelManager.bindCreateModel(tableName, tableModel); 581 } 582 return tableModel; 583 } 584 585 public Table createStage(TObjectName stageName) { 586 if (modelManager.getTableByName(DlineageUtil.getTableFullName(stageName.toString())) instanceof Table) { 587 return (Table) modelManager.getTableByName(DlineageUtil.getTableFullName(stageName.toString())); 588 } 589 Table tableModel = new Table(stageName); 590 modelManager.bindTableByName(DlineageUtil.getTableFullName(stageName.toString()), tableModel); 591 modelManager.bindCreateModel(stageName, tableModel); 592 593 TObjectName stageVariableName = new TObjectName(); 594 stageVariableName.setString("@" + stageName.getColumnNameOnly()); 595 modelManager.bindCreateModel(stageVariableName, tableModel); 596 597 return tableModel; 598 } 599 600 public Table createDataSource(TObjectName dataSourceName) { 601 if (modelManager.getTableByName(DlineageUtil.getTableFullName(dataSourceName.toString())) instanceof Table) { 602 return (Table) modelManager.getTableByName(DlineageUtil.getTableFullName(dataSourceName.toString())); 603 } 604 Table tableModel = new Table(dataSourceName); 605 tableModel.setDataSource(true); 606 modelManager.bindTableByName(DlineageUtil.getTableFullName(dataSourceName.toString()), tableModel); 607 modelManager.bindCreateModel(dataSourceName, tableModel); 608 609 return tableModel; 610 } 611 612 public Table createStream(TObjectName streamName) { 613 if (modelManager.getTableByName(DlineageUtil.getTableFullName(streamName.toString())) instanceof Table) { 614 return (Table) modelManager.getTableByName(DlineageUtil.getTableFullName(streamName.toString())); 615 } 616 Table tableModel = new Table(streamName); 617 tableModel.setStream(true); 618 modelManager.bindTableByName(DlineageUtil.getTableFullName(streamName.toString()), tableModel); 619 modelManager.bindCreateModel(streamName, tableModel); 620 return tableModel; 621 } 622 623 public Table createConstantsTable(TCustomSqlStatement stmt) { 624 stmt = DlineageUtil.getTopStmt(stmt); 625 String sqlHash = String.valueOf(stmt.hashCode()); 626 if (modelManager.getTableByName(sqlHash) instanceof Table) { 627 return (Table) modelManager.getTableByName(sqlHash); 628 } 629 Table tableModel = new Table("SQL_CONSTANTS"); 630 tableModel.setConstant(true); 631 modelManager.bindTableByName(sqlHash, tableModel); 632 modelManager.bindCreateModel(sqlHash, tableModel); 633 return tableModel; 634 } 635 636 public Table createConstantsTable(String sqlHash) { 637 if (modelManager.getTableByName(sqlHash) instanceof Table) { 638 return (Table) modelManager.getTableByName(sqlHash); 639 } 640 Table tableModel = new Table("SQL_CONSTANTS"); 641 tableModel.setConstant(true); 642 modelManager.bindTableByName(sqlHash, tableModel); 643 modelManager.bindCreateModel(sqlHash, tableModel); 644 return tableModel; 645 } 646 647 public Table createJsonVariable(TObjectName jsonVariable) { 648 if (modelManager.getTableByName(DlineageUtil.getTableFullName(jsonVariable.toString())) instanceof Table) { 649 return (Table) modelManager.getTableByName(DlineageUtil.getTableFullName(jsonVariable.toString())); 650 } 651 Table tableModel = new Table(jsonVariable); 652 modelManager.bindTableByName(DlineageUtil.getTableFullName(jsonVariable.toString()), tableModel); 653 modelManager.bindCreateModel(jsonVariable, tableModel); 654 655 modelManager.bindCreateModel(jsonVariable, tableModel); 656 657 return tableModel; 658 } 659 660 public Alias createAlias(TAliasClause aliasClause) { 661 if (modelManager.getModel(aliasClause) instanceof Alias) { 662 return (Alias) modelManager.getModel(aliasClause); 663 } 664 665 Alias alias = new Alias(aliasClause); 666 modelManager.bindModel(aliasClause, alias); 667 668 return alias; 669 } 670 671 public Function createFunction(TFunctionCall functionCall) { 672 if (modelManager.getModel(functionCall) instanceof Function) { 673 return (Function) modelManager.getModel(functionCall); 674 } 675 676 Function function = new Function(functionCall); 677 function.setDetermined(false); 678 modelManager.bindModel(functionCall, function); 679 680 return function; 681 } 682 683 public Function createFunction(TObjectName functionName) { 684 if (modelManager.getModel(functionName) instanceof Function) { 685 return (Function) modelManager.getModel(functionName); 686 } 687 688 Function function = new Function(functionName); 689 function.setDetermined(false); 690 modelManager.bindModel(functionName, function); 691 692 return function; 693 } 694 695 public Function createFunction(TCaseExpression caseExpression) { 696 if (modelManager.getModel(caseExpression) instanceof Function) { 697 return (Function) modelManager.getModel(caseExpression); 698 } 699 700 Function function = new Function(caseExpression); 701 modelManager.bindModel(caseExpression, function); 702 703 return function; 704 } 705 706 public QueryTable createQueryTable(TTable table) { 707 QueryTable tableModel = null; 708 709 if (table.getCTE() != null) { 710 if (modelManager.getModel(table.getCTE()) instanceof QueryTable) { 711 return (QueryTable) modelManager.getModel(table.getCTE()); 712 } 713 714 tableModel = new QueryTable(table); 715 716 modelManager.bindModel(table.getCTE(), tableModel); 717 } else if (table.getAliasClause() != null && table.getAliasClause().getColumns() != null) { 718 if (modelManager.getModel(table.getAliasClause().getColumns()) instanceof QueryTable) { 719 return (QueryTable) modelManager.getModel(table.getAliasClause().getColumns()); 720 } 721 722 tableModel = new QueryTable(table); 723 TObjectNameList columns = table.getAliasClause().getColumns(); 724 modelManager.bindModel(columns, tableModel); 725 for (int i = 0; i < columns.size(); i++) { 726 createResultColumn(tableModel, columns.getObjectName(i)); 727 } 728 modelManager.bindModel(table, tableModel); 729 } else if (table.getSubquery() != null && !table.getSubquery().isCombinedQuery()) { 730 if (modelManager.getModel(table.getSubquery().getResultColumnList()) instanceof QueryTable) { 731 return (QueryTable) modelManager.getModel(table.getSubquery().getResultColumnList()); 732 } 733 734 tableModel = new QueryTable(table); 735 if (table.getSubquery().getResultColumnList() != null) { 736 modelManager.bindModel(table.getSubquery().getResultColumnList(), tableModel); 737 } else if (table.getSubquery().getTransformClause() != null) { 738 modelManager.bindModel(table.getSubquery().getTransformClause(), tableModel); 739 } 740 modelManager.bindModel(table, tableModel); 741 } else if (table.getOutputMerge() != null) { 742 if (modelManager 743 .getModel(table.getOutputMerge().getOutputClause().getSelectItemList()) instanceof QueryTable) { 744 return (QueryTable) modelManager.getModel(table.getOutputMerge().getOutputClause().getSelectItemList()); 745 } 746 747 tableModel = new QueryTable(table); 748 modelManager.bindModel(table.getOutputMerge().getOutputClause().getSelectItemList(), tableModel); 749 modelManager.bindModel(table, tableModel); 750 } else { 751 if (modelManager.getModel(table) instanceof QueryTable) { 752 return (QueryTable) modelManager.getModel(table); 753 } 754 755 if(ModelBindingManager.getGlobalStmtStack().peek() instanceof TMergeSqlStatement) { 756 TMergeSqlStatement mergeStmt = (TMergeSqlStatement)ModelBindingManager.getGlobalStmtStack().peek(); 757 if (modelManager.getModel(mergeStmt) instanceof QueryTable) { 758 return (QueryTable) modelManager.getModel(mergeStmt); 759 } 760 tableModel = new QueryTable(mergeStmt); 761 modelManager.bindModel(mergeStmt, tableModel); 762 } 763 else { 764 tableModel = new QueryTable(table); 765 modelManager.bindModel(table, tableModel); 766 } 767 } 768 return tableModel; 769 } 770 771 /** 772 * Check if a column reference is a standard qualified table.column reference 773 * (not a struct field access). Returns true when tableToken matches the source table's name. 774 */ 775 private boolean isQualifiedColumnReference(TObjectName column) { 776 if (column.getSourceTable() == null || column.getTableToken() == null) { 777 return false; 778 } 779 String tableTokenStr = column.getTableToken().getAstext(); 780 TTable src = column.getSourceTable(); 781 String tableName = src.getTableName() != null ? src.getTableName().getTableString() : ""; 782 java.util.List<String> parts = gudusoft.gsqlparser.util.SQLUtil.parseNames(tableName); 783 String simpleTableName = parts.isEmpty() ? tableName : parts.get(parts.size() - 1); 784 if (tableTokenStr.equalsIgnoreCase(simpleTableName)) { 785 return true; 786 } 787 String aliasName = src.getAliasName(); 788 if (aliasName != null && tableTokenStr.equalsIgnoreCase(aliasName)) { 789 return true; 790 } 791 return false; 792 } 793 794 public TableColumn createTableColumn(Table table, TObjectName column, boolean fromCreateTable) { 795 if (modelManager.getModel(new Pair<Table, TObjectName>(table, column)) instanceof TableColumn) { 796 return (TableColumn) modelManager.getModel(new Pair<Table, TObjectName>(table, column)); 797 } 798 799 if (table.isCreateTable() && !fromCreateTable) { 800 String columnName = DlineageUtil.getColumnName(column); 801 for (int i = 0; i < table.getColumns().size(); i++) { 802 TableColumn columnModel = table.getColumns().get(i); 803 if (DlineageUtil.getIdentifierNormalColumnName(columnModel.getName()).equals(columnName)) { 804 return columnModel; 805 } 806 } 807 808 for (int i = 0; i < table.getColumns().size(); i++) { 809 TableColumn columnModel = table.getColumns().get(i); 810 if (columnModel.isVariant()) { 811 columnModel.bindStarLinkColumn(column); 812 return columnModel; 813 } 814 if (columnModel.hasStarLinkColumn()) { 815 columnModel.bindStarLinkColumn(column); 816 return columnModel; 817 } 818 } 819 820 if(table.isDetermined()) { 821 return null; 822 } 823 } else { 824 String columnName = DlineageUtil.getColumnName(column); 825 // For BigQuery/Redshift struct fields, use full struct path for lookup 826 // to prevent collision between base column and struct field (e.g., "customer" vs "customer.name") 827 if (ModelBindingManager.getGlobalVendor() == EDbVendor.dbvbigquery 828 || ModelBindingManager.getGlobalVendor() == EDbVendor.dbvredshift) { 829 String structName = null; 830 gudusoft.gsqlparser.resolver2.model.ColumnSource cs = column.getColumnSource(); 831 if (cs != null && cs.isStructFieldAccess() && cs.hasFieldPath()) { 832 structName = cs.getFieldPath().toFullReference(cs.getExposedName()); 833 } 834 if (structName == null) { 835 gudusoft.gsqlparser.resolver2.model.StructFieldHint hint = column.getStructFieldHint(); 836 if (hint != null && hint.getFieldPath() != null 837 && !isQualifiedColumnReference(column)) { 838 structName = hint.toFullReference(); 839 } 840 } 841 if (structName == null && column.getPropertyToken() != null) { 842 structName = column.getPartToken().getAstext() + "." + column.getPropertyToken().getAstext(); 843 } 844 if (structName != null) { 845 columnName = DlineageUtil.getIdentifierNormalColumnName(structName); 846 } 847 } 848 for (int i = 0; i < table.getColumns().size(); i++) { 849 TableColumn columnModel = table.getColumns().get(i); 850 if (DlineageUtil.getIdentifierNormalColumnName(columnModel.getName()).equals(columnName)) { 851 return columnModel; 852 } 853 } 854 } 855 856 if ("*".equals(column.toString())) { 857 if (!fromCreateTable && table.isCreateTable()) { 858 return null; 859 } 860 for (int i = 0; i < table.getColumns().size(); i++) { 861 TableColumn columnModel = table.getColumns().get(i); 862 if (DlineageUtil.getIdentifierNormalColumnName(columnModel.getName()).equals("*")) { 863 return columnModel; 864 } 865 } 866 } 867 868 if (table.isCreateTable() && !fromCreateTable && "*".equals(column.getColumnNameOnly())) { 869 return null; 870 } 871 872 if (table.isDetermined() && "*".equals(column.getColumnNameOnly())) { 873 return null; 874 } 875 876 TableColumn columnModel = new TableColumn(table, column); 877 modelManager.bindModel(new Pair<Table, TObjectName>(table, column), columnModel); 878 879 if ("*".equals(column.getColumnNameOnly())) { 880 TSQLEnv sqlenv = ModelBindingManager.getGlobalSQLEnv(); 881 if (sqlenv != null && sqlenv.searchTable(getQualifiedTableName(table)) != null) { 882 table.setHasSQLEnv(true); 883 TSQLTable sqlTable = sqlenv.searchTable(getQualifiedTableName(table)); 884 if (sqlTable.getColumnList() != null) { 885 boolean isDetermine = true; 886 for (TSQLColumn sqlColumn : sqlTable.getColumnList()) { 887 TObjectName objectName = new TObjectName(); 888 if(sqlColumn.getName() == null){ 889 System.err.println("sqlevn table " + getQualifiedTableName(table) + " sqlColumn getName() returns null."); 890 continue; 891 } 892 if(sqlColumn.getName().endsWith("*")) { 893 isDetermine = false; 894 continue; 895 } 896 objectName.setString(sqlColumn.getName()); 897 columnModel.bindStarLinkColumn(objectName); 898 } 899 if (isDetermine) { 900 columnModel.setShowStar(false); 901 columnModel.setExpandStar(true); 902 } 903 } 904 } else if (column.getSourceTable() != null) { 905 TObjectNameList columns = column.getSourceTable().getLinkedColumns(); 906 Map<String, TObjectName> columnMap = new LinkedHashMap<String, TObjectName>(); 907 for (int i = 0; i < columns.size(); i++) { 908 TObjectName item = columns.getObjectName(i); 909 String columnName = item.getColumnNameOnly(); 910 if (Objects.equal(item.getSourceTable(), column.getSourceTable()) && !"*".equals(columnName)) { 911 columnMap.put(DlineageUtil.getIdentifierNormalColumnName(columnName), item); 912 } 913 } 914 for (int i = 0; i < columns.size(); i++) { 915 TObjectName item = columns.getObjectName(i); 916 String columnName = item.getColumnNameOnly(); 917 if (!Objects.equal(item.getSourceTable(), column.getSourceTable()) && !"*".equals(columnName)) { 918 String key = DlineageUtil.getIdentifierNormalColumnName(columnName); 919 if (!columnMap.containsKey(key)) { 920 columnMap.put(key, item); 921 } 922 } 923 } 924 columnModel.bindStarLinkColumns(new LinkedHashMap<String, Set<TObjectName>>()); 925 } 926 } 927 928 return columnModel; 929 } 930 931 public static String getQualifiedTableName(Table table) { 932 List<String> segments = SQLUtil.parseNames(table.name); 933 boolean supportCatalog = TSQLEnv.supportCatalog(ModelBindingManager.getGlobalVendor()); 934 boolean supportSchema = TSQLEnv.supportSchema(ModelBindingManager.getGlobalVendor()); 935 if (segments.size() < 2) { 936 if (supportCatalog && supportSchema) { 937 return getDefaultDatabase() + "." + getDefaultSchema() + "." + table.name; 938 } else if (supportCatalog) { 939 return TSQLEnv.DEFAULT_DB_NAME + "." + getDefaultDatabase() + "." + table.name; 940 } else { 941 return TSQLEnv.DEFAULT_DB_NAME + "." + getDefaultSchema() + "." + table.name; 942 } 943 } else if (segments.size() < 3) { 944 if (supportCatalog && supportSchema) { 945 return getDefaultDatabase() + "." + table.name; 946 } else { 947 return TSQLEnv.DEFAULT_DB_NAME + "." + table.name; 948 } 949 } else { 950 return table.name; 951 } 952 } 953 954 protected static String getDefaultSchema() { 955 return ModelBindingManager.getEffectiveDefaultSchema(); 956 } 957 958 protected static String getDefaultDatabase() { 959 return ModelBindingManager.getEffectiveDefaultDatabase(); 960 } 961 962 public TableColumn createStageLocation(Table table, TObjectName location) { 963 if (modelManager.getModel(new Pair<Table, TObjectName>(table, location)) instanceof TableColumn) { 964 return (TableColumn) modelManager.getModel(new Pair<Table, TObjectName>(table, location)); 965 } 966 967 StageLocation columnModel = new StageLocation(table, location); 968 modelManager.bindModel(new Pair<Table, TObjectName>(table, location), columnModel); 969 return columnModel; 970 } 971 972 public TableColumn createFileUri(Table table, TObjectName fileUri) { 973 if (modelManager.getModel(new Pair<Table, TObjectName>(table, fileUri)) instanceof TableColumn) { 974 return (TableColumn) modelManager.getModel(new Pair<Table, TObjectName>(table, fileUri)); 975 } 976 977 FileUri columnModel = new FileUri(table, fileUri); 978 modelManager.bindModel(new Pair<Table, TObjectName>(table, fileUri), columnModel); 979 return columnModel; 980 } 981 982 public TableColumn createVariableProperty(Table variableTable, TDeclareVariable variable) { 983 if (modelManager.getModel(new Pair<Table, TDeclareVariable>(variableTable, variable)) instanceof TableColumn) { 984 return (TableColumn) modelManager.getModel(new Pair<Table, TDeclareVariable>(variableTable, variable)); 985 } 986 987 TObjectName variableName = new TObjectName(); 988 variableName.setString("property"); 989 VariableProperty columnModel = new VariableProperty(variableTable, variableName, variable); 990 modelManager.bindModel(new Pair<Table, TDeclareVariable>(variableTable, variable), columnModel); 991 return columnModel; 992 } 993 994 public TableColumn createJsonTableColumn(Table table, TObjectName column) { 995 if (modelManager.getModel(new Pair<Table, TObjectName>(table, column)) instanceof TableColumn) { 996 return (TableColumn) modelManager.getModel(new Pair<Table, TObjectName>(table, column)); 997 } 998 999 JsonTableColumn columnModel = new JsonTableColumn(table, column); 1000 modelManager.bindModel(new Pair<Table, TObjectName>(table, column), columnModel); 1001 return columnModel; 1002 } 1003 1004 public DataFlowRelationship createDataFlowRelation() { 1005 DataFlowRelationship relation = new DataFlowRelationship(); 1006 modelManager.addRelation(relation); 1007 return relation; 1008 } 1009 1010 public CallRelationship createCallRelation() { 1011 CallRelationship relation = new CallRelationship(); 1012 modelManager.addRelation(relation); 1013 return relation; 1014 } 1015 1016 public CrudRelationship createCrudRelation() { 1017 CrudRelationship relation = new CrudRelationship(); 1018 modelManager.addRelation(relation); 1019 return relation; 1020 } 1021 1022 public ERRelationship createERRelation() { 1023 ERRelationship relation = new ERRelationship(); 1024 modelManager.addRelation(relation); 1025 return relation; 1026 } 1027 1028 public TableColumn createTableColumn(Table table, TResultColumn column) { 1029 if (column.getAliasClause() != null && column.getAliasClause().getAliasName() != null) { 1030 TableColumn columnModel = new TableColumn(table, column.getAliasClause().getAliasName()); 1031 modelManager.bindModel(column, columnModel); 1032 return columnModel; 1033 } else if (column.getFieldAttr() != null) { 1034 TableColumn columnModel = new TableColumn(table, column.getFieldAttr()); 1035 modelManager.bindModel(column, columnModel); 1036 return columnModel; 1037 } 1038 return null; 1039 } 1040 1041 public TableColumn createTableColumn(Table table, TConstant constant) { 1042 if (modelManager.getModel(new Pair<Table, TConstant>(table, constant)) instanceof TableColumn) { 1043 return (TableColumn) modelManager.getModel(new Pair<Table, TConstant>(table, constant)); 1044 } 1045 1046 TableColumn columnModel = new TableColumn(table, constant); 1047 modelManager.bindModel(new Pair<Table, TConstant>(table, constant), columnModel); 1048 return columnModel; 1049 } 1050 1051 public TableColumn createTableColumn(Table table, TFunctionCall constantFunction) { 1052 if (modelManager.getModel(new Pair<Table, TFunctionCall>(table, constantFunction)) instanceof TableColumn) { 1053 return (TableColumn) modelManager.getModel(new Pair<Table, TFunctionCall>(table, constantFunction)); 1054 } 1055 1056 TableColumn columnModel = new TableColumn(table, constantFunction); 1057 modelManager.bindModel(new Pair<Table, TFunctionCall>(table, constantFunction), columnModel); 1058 return columnModel; 1059 } 1060 1061 public TableColumn createTableColumn(Table table, String columnName) { 1062 for (TableColumn col : table.getColumns()) { 1063 if (col.getName().equals(columnName)) { 1064 return col; 1065 } 1066 } 1067 TableColumn columnModel = new TableColumn(table, columnName); 1068 return columnModel; 1069 } 1070 1071 public RecordSetRelationship createRecordSetRelation() { 1072 RecordSetRelationship relation = new RecordSetRelationship(); 1073 modelManager.addRelation(relation); 1074 return relation; 1075 } 1076 1077 public ImpactRelationship createImpactRelation() { 1078 ImpactRelationship relation = new ImpactRelationship(); 1079 modelManager.addRelation(relation); 1080 return relation; 1081 } 1082 1083 public IndirectImpactRelationship createIndirectImpactRelation() { 1084 IndirectImpactRelationship relation = new IndirectImpactRelationship(); 1085 modelManager.addRelation(relation); 1086 return relation; 1087 } 1088 1089 public JoinRelationship createJoinRelation() { 1090 JoinRelationship relation = new JoinRelationship(); 1091 modelManager.addRelation(relation); 1092 return relation; 1093 } 1094 1095 public Table createView(TCustomSqlStatement viewStmt, TObjectName viewName) { 1096 return createView(viewStmt, viewName, false); 1097 } 1098 1099 public Table createView(TCustomSqlStatement viewStmt, TObjectName viewName, boolean fromCreateView) { 1100 if (modelManager.getViewModel(viewStmt) instanceof Table) { 1101 Table table = (Table) modelManager.getViewModel(viewStmt); 1102 table.setView(true); 1103 table.setPosition(viewStmt); 1104 return table; 1105 } 1106 1107 if (modelManager.getTableByName(DlineageUtil.getTableFullName(viewName.toString())) != null) { 1108 Table table = modelManager.getTableByName(DlineageUtil.getTableFullName(viewName.toString())); 1109 table.setView(true); 1110 table.setPosition(viewStmt); 1111 return table; 1112 } 1113 1114 Table viewModel = new Table(viewStmt, viewName); 1115 viewModel.setCreateTable(fromCreateView); 1116 viewModel.setView(true); 1117 modelManager.bindViewModel(viewStmt, viewModel); 1118 modelManager.bindTableByName(DlineageUtil.getTableFullName(viewName.toString()), viewModel); 1119 return viewModel; 1120 } 1121 1122 public Process createProcess(TCustomSqlStatement processStmt) { 1123 if (modelManager.getProcessModel(processStmt) instanceof Process) { 1124 Process process = (Process) modelManager.getProcessModel(processStmt); 1125 return process; 1126 } 1127 1128 Process processModel = new Process(processStmt); 1129 modelManager.bindProcessModel(processStmt, processModel); 1130 return processModel; 1131 } 1132 1133 public Process createProcess(TFunctionCall functionCall) { 1134 if (modelManager.getProcessModel(functionCall) instanceof Process) { 1135 Process process = (Process) modelManager.getProcessModel(functionCall); 1136 return process; 1137 } 1138 1139 Process processModel = new Process(functionCall); 1140 modelManager.bindProcessModel(functionCall, processModel); 1141 return processModel; 1142 } 1143 1144 public TableColumn createViewColumn(Table viewModel, TObjectName column, int index, boolean fromCreateView) { 1145 Pair<Table, TObjectName> bindingModel = new Pair<Table, TObjectName>(viewModel, column); 1146 if (modelManager.getViewModel(bindingModel) instanceof TableColumn) { 1147 return (TableColumn) modelManager.getViewModel(bindingModel); 1148 } 1149 1150 if (viewModel.isCreateTable() && !fromCreateView) { 1151 if (index < viewModel.getColumns().size()) { 1152 return (TableColumn) viewModel.getColumns().get(index); 1153 } else { 1154 return null; 1155 } 1156 } 1157 1158 TableColumn columnModel = new TableColumn(viewModel, column, index); 1159 modelManager.bindViewModel(bindingModel, columnModel); 1160 return columnModel; 1161 } 1162 1163 public TableColumn createInsertTableColumn(Table tableModel, String columnName) { 1164 TObjectName columnNameObject = new TObjectName(); 1165 columnNameObject.setString(columnName); 1166 Pair<Table, String> bindingModel = new Pair<Table, String>(tableModel, columnName); 1167 1168 if (tableModel.isCreateTable()) { 1169 for (int i = 0; i < tableModel.getColumns().size(); i++) { 1170 TableColumn columnModel = tableModel.getColumns().get(i); 1171 if (DlineageUtil.getIdentifierNormalColumnName(columnModel.getName()).equals(columnName)) { 1172 modelManager.bindInsertModel(bindingModel, columnModel); 1173 return columnModel; 1174 } 1175 } 1176 } 1177 1178 if (modelManager.getInsertModel(bindingModel) instanceof TableColumn) { 1179 return (TableColumn) modelManager.getInsertModel(bindingModel); 1180 } 1181 TableColumn columnModel = new TableColumn(tableModel, columnNameObject); 1182 modelManager.bindInsertModel(bindingModel, columnModel); 1183 return columnModel; 1184 } 1185 1186 public TableColumn createInsertTableColumn(Table tableModel, TObjectName column) { 1187 Pair<Table, TObjectName> bindingModel = new Pair<Table, TObjectName>(tableModel, column); 1188 1189 if (tableModel.isCreateTable()) { 1190 String columnName = DlineageUtil.getColumnName(column); 1191 for (int i = 0; i < tableModel.getColumns().size(); i++) { 1192 TableColumn columnModel = tableModel.getColumns().get(i); 1193 if (DlineageUtil.getIdentifierNormalColumnName(columnModel.getName()).equals(columnName)) { 1194 modelManager.bindInsertModel(bindingModel, columnModel); 1195 return columnModel; 1196 } 1197 } 1198 } 1199 1200 if (modelManager.getInsertModel(bindingModel) instanceof TableColumn) { 1201 return (TableColumn) modelManager.getInsertModel(bindingModel); 1202 } 1203 TableColumn columnModel = new TableColumn(tableModel, column); 1204 modelManager.bindInsertModel(bindingModel, columnModel); 1205 return columnModel; 1206 } 1207 1208 public TableColumn createInsertTableColumn(Table tableModel, TExpression column, int columnIndex) { 1209 Pair<Table, TExpression> bindingModel = new Pair<Table, TExpression>(tableModel, column); 1210 1211 if (tableModel.isCreateTable()) { 1212 if (columnIndex < tableModel.getColumns().size()) { 1213 TableColumn columnModel = tableModel.getColumns().get(columnIndex); 1214 modelManager.bindInsertModel(bindingModel, columnModel); 1215 return columnModel; 1216 } else { 1217 return null; 1218 } 1219 } 1220 1221 if (modelManager.getInsertModel(bindingModel) instanceof TableColumn) { 1222 return (TableColumn) modelManager.getInsertModel(bindingModel); 1223 } 1224 TableColumn columnModel = new TableColumn(tableModel, column, columnIndex); 1225 modelManager.bindInsertModel(bindingModel, columnModel); 1226 return columnModel; 1227 } 1228 1229 public TableColumn createInsertTableColumn(Table tableModel, TConstant column, int columnIndex) { 1230 Pair<Table, TConstant> bindingModel = new Pair<Table, TConstant>(tableModel, column); 1231 1232 if (tableModel.isCreateTable()) { 1233 if (columnIndex < tableModel.getColumns().size()) { 1234 TableColumn columnModel = tableModel.getColumns().get(columnIndex); 1235 modelManager.bindInsertModel(bindingModel, columnModel); 1236 return columnModel; 1237 } else { 1238 return null; 1239 } 1240 } 1241 1242 if (modelManager.getInsertModel(bindingModel) instanceof TableColumn) { 1243 return (TableColumn) modelManager.getInsertModel(bindingModel); 1244 } 1245 TableColumn columnModel = new TableColumn(tableModel, column, columnIndex); 1246 modelManager.bindInsertModel(bindingModel, columnModel); 1247 return columnModel; 1248 } 1249 1250 public SelectSetResultSet createSelectSetResultSet(TSelectSqlStatement stmt) { 1251 if (modelManager.getModel(stmt) instanceof SelectSetResultSet) { 1252 return (SelectSetResultSet) modelManager.getModel(stmt); 1253 } 1254 SelectSetResultSet resultSet = new SelectSetResultSet(stmt, stmt.getParentStmt() == null); 1255 modelManager.bindModel(stmt, resultSet); 1256 return resultSet; 1257 } 1258 1259 public ResultColumn createStarResultColumn(SelectResultSet resultSet, 1260 Pair<TResultColumn, TObjectName> starColumnPair) { 1261 if (modelManager.getModel(starColumnPair) instanceof ResultColumn) { 1262 return (ResultColumn) modelManager.getModel(starColumnPair); 1263 } 1264 ResultColumn column = new ResultColumn(resultSet, starColumnPair); 1265 modelManager.bindModel(starColumnPair, column); 1266 return column; 1267 } 1268 1269 public Variable createCursor(TCursorDeclStmt stmt) { 1270 String variableName = stmt.getCursorName().toString(); 1271 String procedureName = DlineageUtil.getProcedureParentName(stmt); 1272 String variableString = variableName.toString(); 1273 if (variableString.startsWith(":")) { 1274 variableString = variableString.substring(variableString.indexOf(":") + 1); 1275 } 1276 // B3 identity-first pools: cursors join the per-overload pool too 1277 // (codex-B3-r1 finding 7). Guarded so LEGACY never even allocates 1278 // the candidate Cursor — an eager throwaway would advance model IDs 1279 // (codex-B3-r2 finding 13); stack empty in LEGACY by construction. 1280 if (modelManager.hasIdentityScope()) { 1281 Variable pooledCursor = identityScopedCursor(variableString, 1282 procedureName, new Cursor(stmt)); 1283 if (pooledCursor != null) { 1284 return pooledCursor; 1285 } 1286 } 1287 if (!SQLUtil.isEmpty(procedureName)) { 1288 variableString = DlineageUtil.getTableFullName(procedureName) + "." + SQLUtil.getIdentifierNormalTableName(variableString); 1289 } 1290 1291 if (modelManager 1292 .getTableByName(DlineageUtil.getTableFullName(variableString)) instanceof Variable) { 1293 return (Variable) modelManager.getTableByName(DlineageUtil.getTableFullName(variableString)); 1294 } 1295 Cursor tableModel = new Cursor(stmt); 1296 if (!SQLUtil.isEmpty(procedureName)) { 1297 tableModel.setParent(procedureName); 1298 } 1299 modelManager.bindTableByName(DlineageUtil.getTableFullName(variableString), tableModel); 1300 modelManager.bindModel(DlineageUtil.getTableFullName(variableString), tableModel); 1301 return tableModel; 1302 } 1303 1304 public Variable createCursor(TMssqlDeclare stmt) { 1305 String variableName = stmt.getCursorName().toString(); 1306 String procedureName = DlineageUtil.getProcedureParentName(stmt); 1307 String variableString = variableName.toString(); 1308 if (variableString.startsWith(":")) { 1309 variableString = variableString.substring(variableString.indexOf(":") + 1); 1310 } 1311 // B3 identity-first pools: cursors join the per-overload pool too 1312 // (codex-B3-r1 finding 7). Guarded so LEGACY never even allocates 1313 // the candidate Cursor — an eager throwaway would advance model IDs 1314 // (codex-B3-r2 finding 13); stack empty in LEGACY by construction. 1315 if (modelManager.hasIdentityScope()) { 1316 Variable pooledCursor = identityScopedCursor(variableString, 1317 procedureName, new Cursor(stmt)); 1318 if (pooledCursor != null) { 1319 return pooledCursor; 1320 } 1321 } 1322 if (!SQLUtil.isEmpty(procedureName)) { 1323 variableString = DlineageUtil.getTableFullName(procedureName) + "." + SQLUtil.getIdentifierNormalTableName(variableString); 1324 } 1325 1326 if (modelManager 1327 .getTableByName(DlineageUtil.getTableFullName(variableString)) instanceof Variable) { 1328 return (Variable) modelManager.getTableByName(DlineageUtil.getTableFullName(variableString)); 1329 } 1330 Cursor tableModel = new Cursor(stmt); 1331 if (!SQLUtil.isEmpty(procedureName)) { 1332 tableModel.setParent(procedureName); 1333 } 1334 modelManager.bindTableByName(DlineageUtil.getTableFullName(variableString), tableModel); 1335 modelManager.bindModel(DlineageUtil.getTableFullName(variableString), tableModel); 1336 return tableModel; 1337 } 1338 1339 public Variable createCursor(TLoopStmt stmt) { 1340 String variableName = stmt.getRecordName().toString(); 1341 String procedureName = DlineageUtil.getProcedureParentName(stmt); 1342 String variableString = variableName.toString(); 1343 if (variableString.startsWith(":")) { 1344 variableString = variableString.substring(variableString.indexOf(":") + 1); 1345 } 1346 // B3 identity-first pools: cursors join the per-overload pool too 1347 // (codex-B3-r1 finding 7). Guarded so LEGACY never even allocates 1348 // the candidate Cursor — an eager throwaway would advance model IDs 1349 // (codex-B3-r2 finding 13); stack empty in LEGACY by construction. 1350 if (modelManager.hasIdentityScope()) { 1351 Variable pooledCursor = identityScopedCursor(variableString, 1352 procedureName, new Cursor(stmt)); 1353 if (pooledCursor != null) { 1354 return pooledCursor; 1355 } 1356 } 1357 if (!SQLUtil.isEmpty(procedureName)) { 1358 variableString = DlineageUtil.getTableFullName(procedureName) + "." + SQLUtil.getIdentifierNormalTableName(variableString); 1359 } 1360 1361 if (modelManager 1362 .getTableByName(DlineageUtil.getTableFullName(variableString)) instanceof Variable) { 1363 return (Variable) modelManager.getTableByName(DlineageUtil.getTableFullName(variableString)); 1364 } 1365 Cursor tableModel = new Cursor(stmt); 1366 if (!SQLUtil.isEmpty(procedureName)) { 1367 tableModel.setParent(procedureName); 1368 } 1369 modelManager.bindTableByName(DlineageUtil.getTableFullName(variableString), tableModel); 1370 modelManager.bindModel(DlineageUtil.getTableFullName(variableString), tableModel); 1371 return tableModel; 1372 } 1373 1374 public Variable createCursor(TForStmt stmt) { 1375 String variableName = stmt.getLoopName().toString(); 1376 String procedureName = DlineageUtil.getProcedureParentName(stmt); 1377 String variableString = variableName.toString(); 1378 if (variableString.startsWith(":")) { 1379 variableString = variableString.substring(variableString.indexOf(":") + 1); 1380 } 1381 // B3 identity-first pools: cursors join the per-overload pool too 1382 // (codex-B3-r1 finding 7). Guarded so LEGACY never even allocates 1383 // the candidate Cursor — an eager throwaway would advance model IDs 1384 // (codex-B3-r2 finding 13); stack empty in LEGACY by construction. 1385 if (modelManager.hasIdentityScope()) { 1386 Variable pooledCursor = identityScopedCursor(variableString, 1387 procedureName, new Cursor(stmt)); 1388 if (pooledCursor != null) { 1389 return pooledCursor; 1390 } 1391 } 1392 if (!SQLUtil.isEmpty(procedureName)) { 1393 variableString = DlineageUtil.getTableFullName(procedureName) + "." + SQLUtil.getIdentifierNormalTableName(variableString); 1394 } 1395 1396 if (modelManager 1397 .getTableByName(DlineageUtil.getTableFullName(variableString)) instanceof Variable) { 1398 return (Variable) modelManager.getTableByName(DlineageUtil.getTableFullName(variableString)); 1399 } 1400 Cursor tableModel = new Cursor(stmt); 1401 if (!SQLUtil.isEmpty(procedureName)) { 1402 tableModel.setParent(procedureName); 1403 } 1404 modelManager.bindTableByName(DlineageUtil.getTableFullName(variableString), tableModel); 1405 modelManager.bindModel(DlineageUtil.getTableFullName(variableString), tableModel); 1406 return tableModel; 1407 } 1408 1409 public Variable createCursor(TOpenforStmt stmt) { 1410 String variableName = stmt.getCursorVariableName().toString(); 1411 String procedureName = DlineageUtil.getProcedureParentName(stmt); 1412 String variableString = variableName.toString(); 1413 if (variableString.startsWith(":")) { 1414 variableString = variableString.substring(variableString.indexOf(":") + 1); 1415 } 1416 // B3 identity-first pools: cursors join the per-overload pool too 1417 // (codex-B3-r1 finding 7). Guarded so LEGACY never even allocates 1418 // the candidate Cursor — an eager throwaway would advance model IDs 1419 // (codex-B3-r2 finding 13); stack empty in LEGACY by construction. 1420 if (modelManager.hasIdentityScope()) { 1421 Variable pooledCursor = identityScopedCursor(variableString, 1422 procedureName, new Cursor(stmt)); 1423 if (pooledCursor != null) { 1424 return pooledCursor; 1425 } 1426 } 1427 if (!SQLUtil.isEmpty(procedureName)) { 1428 variableString = DlineageUtil.getTableFullName(procedureName) + "." + SQLUtil.getIdentifierNormalTableName(variableString); 1429 } 1430 1431 if (modelManager.getTableByName( 1432 DlineageUtil.getTableFullName(variableString)) instanceof Variable) { 1433 return (Variable) modelManager 1434 .getTableByName(DlineageUtil.getTableFullName(variableString)); 1435 } 1436 Cursor tableModel = new Cursor(stmt); 1437 if (!SQLUtil.isEmpty(procedureName)) { 1438 tableModel.setParent(procedureName); 1439 } 1440 modelManager.bindTableByName(DlineageUtil.getTableFullName(variableString), 1441 tableModel); 1442 modelManager.bindModel(DlineageUtil.getTableFullName(variableString), tableModel); 1443 return tableModel; 1444 } 1445 1446 /** 1447 * B1 (routine-summary-scc-design §3): additionally index a declared 1448 * formal's Variable under its routine's overload-discriminating identity 1449 * scope key. Pure lookup-map addition — no model binding, no new model 1450 * objects — so LEGACY output is untouched by construction; the 1451 * identity-first lookups of SHADOW/ENHANCED (slice B3) are the consumers. 1452 */ 1453 public void bindVariableUnderIdentityScope(Procedure procedure, String variableName, 1454 Variable variable) { 1455 if (procedure == null || variable == null 1456 || SQLUtil.isEmpty(procedure.getIdentityScopeKey()) 1457 || SQLUtil.isEmpty(variableName)) { 1458 return; 1459 } 1460 String simple = variableName; 1461 if (simple.startsWith(":")) { 1462 simple = simple.substring(1); 1463 } 1464 String key = procedure.getIdentityScopeKey() + "." 1465 + SQLUtil.getIdentifierNormalTableName(simple); 1466 if (!(modelManager.getTableByName(key) instanceof Variable)) { 1467 modelManager.bindTableByName(key, variable); 1468 } 1469 } 1470 1471 /** 1472 * B3 (routine-summary-scc-design §3): object-level per-overload variable 1473 * pools. While a routine body is analyzed under the identity-first mode 1474 * ({@code Option.identityFirstVariablePools}), its overload-discriminating 1475 * identity scope key sits on this stack and {@code createVariable} keys 1476 * variables under it INSTEAD of the legacy shared scope — two same-named 1477 * overloads get DISTINCT formal/local pools. LIFO because routines nest 1478 * (package members, nested blocks). Empty in LEGACY mode by construction, 1479 * so every shipped path is untouched. 1480 */ 1481 /** Sticky per-analysis: set on first push; gates the callee-formal 1482 * identity-first lookup that runs OUTSIDE any body scope. The stack 1483 * itself lives on the {@link ModelBindingManager} so DIRECT 1484 * getTableByName reads resolve identity-first too (codex-B3-r2 1485 * finding 7). */ 1486 private boolean identityFirstPools = false; 1487 1488 public void pushIdentityScope(String identityScopeKey) { 1489 if (identityScopeKey != null) { 1490 modelManager.pushIdentityScope(identityScopeKey); 1491 identityFirstPools = true; 1492 } 1493 } 1494 1495 public void popIdentityScope() { 1496 modelManager.popIdentityScope(); 1497 } 1498 1499 /** Identity-pool LOOKUP for the active scope: the identity key ONLY. 1500 * Deliberately NO legacy-key fallback: the legacy composed key 1501 * ("scope.var") never unified across scopes in LEGACY either (each 1502 * routine scope composes its own key), while a fallback would hand a 1503 * same-named OVERLOAD's variable back and silently re-merge the pools 1504 * this mode exists to split. Null when no scope is active or on a miss. */ 1505 private Variable lookupInIdentityScope(String variableString, 1506 String procedureName) { 1507 if (!modelManager.hasIdentityScope()) { 1508 return null; 1509 } 1510 String identityKey = modelManager.peekIdentityScope() + "." 1511 + SQLUtil.getIdentifierNormalTableName(variableString); 1512 Object hit = modelManager.getTableByName(identityKey); 1513 if (hit instanceof Variable) { 1514 return (Variable) hit; 1515 } 1516 return null; 1517 } 1518 1519 /** Identity-pool BIND: always under the identity key, and ALSO under the 1520 * legacy key while that key is unoccupied — legacy-key consumers (direct 1521 * {@code getTableByName} reads outside createVariable) keep working for 1522 * the non-colliding common case, while a same-named overload finds the 1523 * legacy key taken and keeps its own pool (codex-B3-r1 finding 7). */ 1524 private void bindInIdentityScope(String variableString, String procedureName, 1525 Variable variable) { 1526 String identityKey = modelManager.peekIdentityScope() + "." 1527 + SQLUtil.getIdentifierNormalTableName(variableString); 1528 modelManager.bindTableByName(identityKey, variable); 1529 modelManager.bindModel(identityKey, variable); 1530 String legacyQualified = variableString; 1531 if (!SQLUtil.isEmpty(procedureName)) { 1532 legacyQualified = DlineageUtil.getTableFullName(procedureName) + "." 1533 + SQLUtil.getIdentifierNormalTableName(variableString); 1534 } 1535 String legacyKey = DlineageUtil.getTableFullName(legacyQualified); 1536 if (!(modelManager.getTableByName(legacyKey) instanceof Variable)) { 1537 modelManager.bindTableByName(legacyKey, variable); 1538 modelManager.bindModel(legacyKey, variable); 1539 } 1540 } 1541 1542 /** 1543 * Identity-pool variable resolution for the ACTIVE scope: lookup, then on 1544 * a full miss create a fresh pool member. Returns null when no scope is 1545 * active (caller continues legacy path) or when {@code create} is false 1546 * and nothing was found. 1547 */ 1548 private Variable identityScopedVariable(String variableString, 1549 TObjectName displayName, String procedureName, boolean create) { 1550 if (!modelManager.hasIdentityScope()) { 1551 return null; 1552 } 1553 Variable found = lookupInIdentityScope(variableString, procedureName); 1554 if (found != null) { 1555 return found; 1556 } 1557 if (!create) { 1558 return null; 1559 } 1560 Variable variable = displayName != null 1561 ? new Variable(displayName) : new Variable(variableString); 1562 if (!SQLUtil.isEmpty(procedureName)) { 1563 variable.setParent(procedureName); 1564 } 1565 bindInIdentityScope(variableString, procedureName, variable); 1566 return variable; 1567 } 1568 1569 /** Identity-pool branch shared by the five cursor creators: resolve in 1570 * the active scope or bind the freshly built cursor there. Null when no 1571 * scope is active (creator continues its legacy path). */ 1572 private Variable identityScopedCursor(String variableString, 1573 String procedureName, Cursor freshCursor) { 1574 if (!modelManager.hasIdentityScope()) { 1575 return null; 1576 } 1577 Variable found = lookupInIdentityScope(variableString, procedureName); 1578 if (found != null) { 1579 return found; 1580 } 1581 if (!SQLUtil.isEmpty(procedureName)) { 1582 freshCursor.setParent(procedureName); 1583 } 1584 bindInIdentityScope(variableString, procedureName, freshCursor); 1585 return freshCursor; 1586 } 1587 1588 public Variable createVariable(TObjectName variableName) { 1589 TCustomSqlStatement stmt = modelManager.getGlobalStmtStack().peek(); 1590 String procedureName = DlineageUtil.getProcedureParentName(stmt); 1591 String variableString = variableName.toString(); 1592 if (variableString.startsWith(":")) { 1593 variableString = variableString.substring(variableString.indexOf(":") + 1); 1594 } 1595 if (variableString.indexOf(".") != -1) { 1596 variableString = variableString.substring(0, variableString.indexOf(".")); 1597 } 1598 1599 // B3 identity-first pools: active only under the mode flag (stack 1600 // empty otherwise), so LEGACY behavior below is untouched. 1601 Variable pooled = identityScopedVariable(variableString, variableName, 1602 procedureName, true); 1603 if (pooled != null) { 1604 return pooled; 1605 } 1606 1607 if (!SQLUtil.isEmpty(procedureName)) { 1608 variableString = DlineageUtil.getTableFullName(procedureName) + "." + SQLUtil.getIdentifierNormalTableName(variableString); 1609 } 1610 1611 if (modelManager.getTableByName(DlineageUtil.getTableFullName(variableString)) instanceof Variable) { 1612 return (Variable) modelManager.getTableByName(DlineageUtil.getTableFullName(variableString)); 1613 } 1614 Variable variable = new Variable(variableName); 1615 if (!SQLUtil.isEmpty(procedureName)) { 1616 variable.setParent(procedureName); 1617 } 1618 modelManager.bindTableByName(DlineageUtil.getTableFullName(variableString), variable); 1619 modelManager.bindModel(DlineageUtil.getTableFullName(variableString), variable); 1620// modelManager.bindTableByName(DlineageUtil.getTableFullName(variableName.toString()), variable); 1621// modelManager.bindModel(DlineageUtil.getTableFullName(variableName.toString()), variable); 1622 return variable; 1623 } 1624 1625 public Variable createVariable(String variableName) { 1626 return createVariable(variableName, true); 1627 } 1628 1629 public Variable createVariable(String variableName, boolean create) { 1630 TCustomSqlStatement stmt = modelManager.getGlobalStmtStack().peek(); 1631 String procedureName = DlineageUtil.getProcedureParentName(stmt); 1632 String variableString = variableName.toString(); 1633 if (variableString.startsWith(":")) { 1634 variableString = variableString.substring(variableString.indexOf(":") + 1); 1635 } 1636 1637 // B3 identity-first pools: active only under the mode flag (stack 1638 // empty otherwise), so LEGACY behavior below is untouched. 1639 Variable pooled = identityScopedVariable(variableString, null, 1640 procedureName, create); 1641 if (pooled != null) { 1642 return pooled; 1643 } 1644 if (modelManager.hasIdentityScope() && !create) { 1645 return null; 1646 } 1647 1648 if (!SQLUtil.isEmpty(procedureName)) { 1649 variableString = DlineageUtil.getTableFullName(procedureName) + "." + SQLUtil.getIdentifierNormalTableName(variableString); 1650 } 1651 1652 if (modelManager.getTableByName(DlineageUtil.getTableFullName(variableString)) instanceof Variable) { 1653 return (Variable) modelManager.getTableByName(DlineageUtil.getTableFullName(variableString)); 1654 } 1655 1656 if (create) { 1657 Variable variable = new Variable(variableName); 1658 if (!SQLUtil.isEmpty(procedureName)) { 1659 variable.setParent(procedureName); 1660 } 1661 modelManager.bindTableByName(DlineageUtil.getTableFullName(variableString), variable); 1662 modelManager.bindModel(DlineageUtil.getTableFullName(variableString), variable); 1663// modelManager.bindTableByName(DlineageUtil.getTableFullName(variableName.toString()), variable); 1664// modelManager.bindModel(DlineageUtil.getTableFullName(variableName.toString()), variable); 1665 return variable; 1666 } 1667 else { 1668 return null; 1669 } 1670 } 1671 1672 public Variable createVariable(Procedure procedure, String variableName, boolean create) { 1673 // Two-stage lookup. Stage 1 is the historical key (display name plus 1674 // package prefix): whatever it finds — wildcard columns included — 1675 // is long-shipped behavior and returns untouched. Stage 2 is the 1676 // declaration-time variableScopeKey (package members register their 1677 // variables under DlineageUtil.getProcedureParentName; under a USE 1678 // database context body variables register under the 1679 // getTableFullName-composed scope), which recovers the bindings the 1680 // display-name key silently misses. Only this recovered path refuses 1681 // complex-typed formals (records/collections carry a single wildcard 1682 // column): binding at that granularity would emit the *-target 1683 // relationship noise testIBF4RL guards against, and field-level flow 1684 // through such formals is produced by the body-side machinery. 1685 String legacyScope = procedure.getName(); 1686 if (procedure.getParentPackage() != null) { 1687 legacyScope = procedure.getParentPackage().getName() + "." + legacyScope; 1688 } 1689 String variableString = variableName.toString(); 1690 if (variableString.startsWith(":")) { 1691 variableString = variableString.substring(variableString.indexOf(":") + 1); 1692 } 1693 // B3 identity-first pools (stage 0, mode-gated): the callee's formals 1694 // were keyed under ITS identity scope, so caller-side argument binding 1695 // must consult that pool first — this is what discriminates same-named 1696 // overloads. Mirrors stage 2's complex-typed refusal. 1697 if (identityFirstPools && procedure.getIdentityScopeKey() != null) { 1698 String identityKey = procedure.getIdentityScopeKey() + "." 1699 + SQLUtil.getIdentifierNormalTableName(variableString); 1700 Object identityHit = modelManager.getTableByName(identityKey); 1701 if (identityHit instanceof Variable) { 1702 Variable found = (Variable) identityHit; 1703 if (!found.getColumns().isEmpty() 1704 && "*".equals(found.getColumns().get(0).getName())) { 1705 return null; 1706 } 1707 return found; 1708 } 1709 } 1710 Variable legacyFound = lookupVariable(legacyScope, variableString); 1711 if (legacyFound != null) { 1712 return legacyFound; 1713 } 1714 String scopeKey = procedure.getVariableScopeKey(); 1715 if (scopeKey != null) { 1716 Variable found = lookupVariable(scopeKey, variableString); 1717 if (found != null) { 1718 if (!found.getColumns().isEmpty() 1719 && "*".equals(found.getColumns().get(0).getName())) { 1720 return null; 1721 } 1722 return found; 1723 } 1724 } 1725 1726 if (create) { 1727 String qualified = variableString; 1728 if (!SQLUtil.isEmpty(legacyScope)) { 1729 qualified = DlineageUtil.getTableFullName(legacyScope) + "." 1730 + SQLUtil.getIdentifierNormalTableName(variableString); 1731 } 1732 Variable variable = new Variable(variableName); 1733 if (!SQLUtil.isEmpty(legacyScope)) { 1734 variable.setParent(legacyScope); 1735 } 1736 modelManager.bindTableByName(DlineageUtil.getTableFullName(qualified), variable); 1737 modelManager.bindModel(DlineageUtil.getTableFullName(qualified), variable); 1738 return variable; 1739 } 1740 else { 1741 return null; 1742 } 1743 } 1744 1745 /** 1746 * The formal-argument variable of {@code procedure} named 1747 * {@code variableName}, WITHOUT stage 2's complex-typed refusal (#695). 1748 * The refusal exists because binding a whole record onto its single 1749 * wildcard column was noise; a caller that first materializes the formal's 1750 * fields from its declared type binds exactly, so it needs the variable 1751 * the refusal hides. Lookup only — never creates. 1752 */ 1753 public Variable findFormalVariable(Procedure procedure, String variableName) { 1754 String legacyScope = procedure.getName(); 1755 if (procedure.getParentPackage() != null) { 1756 legacyScope = procedure.getParentPackage().getName() + "." + legacyScope; 1757 } 1758 String variableString = variableName; 1759 if (variableString.startsWith(":")) { 1760 variableString = variableString.substring(variableString.indexOf(":") + 1); 1761 } 1762 if (procedure.getIdentityScopeKey() != null) { 1763 Object identityHit = modelManager.getTableByName(procedure.getIdentityScopeKey() + "." 1764 + SQLUtil.getIdentifierNormalTableName(variableString)); 1765 if (identityHit instanceof Variable) { 1766 return (Variable) identityHit; 1767 } 1768 } 1769 Variable legacyFound = lookupVariable(legacyScope, variableString); 1770 if (legacyFound != null) { 1771 return legacyFound; 1772 } 1773 if (procedure.getVariableScopeKey() != null) { 1774 return lookupVariable(procedure.getVariableScopeKey(), variableString); 1775 } 1776 return null; 1777 } 1778 1779 /** One scope-qualified variable lookup; null when absent or not a Variable. */ 1780 private Variable lookupVariable(String scope, String variableString) { 1781 String qualified = variableString; 1782 if (!SQLUtil.isEmpty(scope)) { 1783 qualified = DlineageUtil.getTableFullName(scope) + "." 1784 + SQLUtil.getIdentifierNormalTableName(variableString); 1785 } 1786 Object hit = modelManager.getTableByName(DlineageUtil.getTableFullName(qualified)); 1787 return hit instanceof Variable ? (Variable) hit : null; 1788 } 1789 1790 public Database createDatabase(TObjectName databaseName) { 1791 if (modelManager.getTableByName(DlineageUtil.getTableFullName(databaseName.toString())) instanceof Database) { 1792 return (Database) modelManager.getTableByName(DlineageUtil.getTableFullName(databaseName.toString())); 1793 } 1794 Database database = new Database(databaseName); 1795 modelManager.bindTableByName(DlineageUtil.getTableFullName(databaseName.toString()), database); 1796 modelManager.bindModel(DlineageUtil.getTableFullName(databaseName.toString()), database); 1797 return database; 1798 } 1799 1800 public Schema createSchema(TObjectName schemaName) { 1801 if (modelManager 1802 .getTableByName(DlineageUtil.getIdentifierNormalTableName(schemaName.toString())) instanceof Schema) { 1803 return (Schema) modelManager 1804 .getTableByName(DlineageUtil.getIdentifierNormalTableName(schemaName.toString())); 1805 } 1806 Schema schema = new Schema(schemaName); 1807 modelManager.bindTableByName(DlineageUtil.getIdentifierNormalTableName(schemaName.toString()), schema); 1808 modelManager.bindModel(DlineageUtil.getIdentifierNormalTableName(schemaName.toString()), schema); 1809 return schema; 1810 } 1811 1812 public PivotedTable createPivotdTable(TPivotClause pivotedTable) { 1813 if (modelManager.getModel(pivotedTable) instanceof PivotedTable) { 1814 return (PivotedTable) modelManager.getModel(pivotedTable); 1815 } 1816 PivotedTable resultSet = new PivotedTable(pivotedTable); 1817 modelManager.bindModel(pivotedTable, resultSet); 1818 if (pivotedTable.getPivotTable() != null) { 1819 modelManager.bindModel(pivotedTable.getPivotTable(), resultSet); 1820 } 1821 return resultSet; 1822 } 1823 1824 public Procedure createProcedure(TStoredProcedureSqlStatement stmt) { 1825 if (stmt == null || DlineageUtil.getProcedureOrFunctionName(stmt) == null) { 1826 return null; 1827 } 1828 String procedureNameWithArgs = DlineageUtil 1829 .getIdentifierNormalTableName(DlineageUtil.getProcedureNameWithArgs(stmt)); 1830 String procedureNameWithArgNum = DlineageUtil 1831 .getIdentifierNormalTableName(DlineageUtil.getProcedureNameWithArgNum(stmt)); 1832 String procedureNameWithInputArgNum = DlineageUtil 1833 .getIdentifierNormalTableName(DlineageUtil.getProcedureNameWithInputArgNum(stmt)); 1834 if (ModelBindingManager.getGlobalOraclePackage() != null) { 1835 procedureNameWithArgs = ModelBindingManager.getGlobalOraclePackage().getName() + "." 1836 + procedureNameWithArgs; 1837 procedureNameWithArgNum = ModelBindingManager.getGlobalOraclePackage().getName() + "." 1838 + procedureNameWithArgNum; 1839 procedureNameWithInputArgNum = ModelBindingManager.getGlobalOraclePackage().getName() + "." 1840 + procedureNameWithInputArgNum; 1841 } 1842 if (this.modelManager.getModel(stmt) instanceof Procedure) { 1843 return (Procedure) this.modelManager.getModel(stmt); 1844 } else if (this.modelManager.getProcedureByName(procedureNameWithArgs) != null) { 1845 return (Procedure) this.modelManager.getProcedureByName(procedureNameWithArgs); 1846 } else if (this.modelManager.getProcedureByName(procedureNameWithArgNum) != null) { 1847 return (Procedure) this.modelManager.getProcedureByName(procedureNameWithArgNum); 1848 } else if (this.modelManager.getProcedureByName(procedureNameWithInputArgNum) != null) { 1849 return (Procedure) this.modelManager.getProcedureByName(procedureNameWithInputArgNum); 1850 } else { 1851 Procedure procedure = new Procedure(stmt); 1852 this.modelManager.bindModel(stmt, procedure); 1853 this.modelManager.bindProcedureByName(procedureNameWithArgs, procedure); 1854 this.modelManager.bindProcedureByName(procedureNameWithArgNum, procedure); 1855 this.modelManager.bindProcedureByName(procedureNameWithInputArgNum, procedure); 1856 return procedure; 1857 } 1858 } 1859 1860 public OraclePackage createOraclePackage(TPlsqlCreatePackage stmt) { 1861 if (this.modelManager.getModel(stmt) instanceof OraclePackage) { 1862 return (OraclePackage) this.modelManager.getModel(stmt); 1863 } else { 1864 OraclePackage oraclePackage = new OraclePackage(stmt); 1865 this.modelManager.bindModel(stmt, oraclePackage); 1866 this.modelManager.bindOraclePackageByName( 1867 DlineageUtil.getIdentifierNormalTableName(DlineageUtil.getProcedureNameWithArgs(stmt)), 1868 oraclePackage); 1869 this.modelManager.bindOraclePackageByName( 1870 DlineageUtil.getIdentifierNormalTableName(DlineageUtil.getProcedureNameWithArgNum(stmt)), 1871 oraclePackage); 1872 this.modelManager.bindOraclePackageByName( 1873 DlineageUtil.getIdentifierNormalTableName(DlineageUtil.getProcedureNameWithInputArgNum(stmt)), 1874 oraclePackage); 1875 return oraclePackage; 1876 } 1877 } 1878 1879 public Procedure createProcedureFromFunctionCall(TFunctionCall function) { 1880 if (this.modelManager.getModel(function) instanceof Procedure) { 1881 return (Procedure) this.modelManager.getModel(function); 1882 } else { 1883 Procedure procedure = new Procedure(function); 1884 procedure.setType(ESqlStatementType.sstcreateprocedure); 1885 this.modelManager.bindModel(function, procedure); 1886 this.modelManager.bindProcedureByName(DlineageUtil.getIdentifierNormalTableName(procedure.getName()), 1887 procedure); 1888 return procedure; 1889 } 1890 } 1891 1892// public Procedure createProcedureByName(TObjectName procedureName) { 1893// if (this.modelManager.getModel(procedureName) instanceof Procedure) { 1894// return (Procedure) this.modelManager.getModel(procedureName); 1895// } 1896// else if (this.modelManager 1897// .getProcedureByName(DlineageUtil.getIdentifierNormalTableName(procedureName.toString())) != null) { 1898// return modelManager.getProcedureByName(DlineageUtil.getIdentifierNormalTableName(procedureName.toString())); 1899// } 1900// else { 1901// Procedure procedure = new Procedure(procedureName); 1902// procedure.setType(ESqlStatementType.sstcreateprocedure); 1903// this.modelManager.bindModel(procedureName, procedure); 1904// this.modelManager.bindProcedureByName(DlineageUtil.getIdentifierNormalTableName(procedure.getName()), 1905// procedure); 1906// return procedure; 1907// } 1908// } 1909 1910 public Procedure createProcedureByName(TObjectName procedureName, int argumentSize) { 1911 String procedureNameWithArgSize = procedureName.toString() + "(" + argumentSize + ")"; 1912 if (argumentSize <= 0 || !DlineageUtil.supportFunctionOverride(ModelBindingManager.getGlobalVendor())) { 1913 procedureNameWithArgSize = procedureName.toString(); 1914 } 1915 if (this.modelManager.getModel(procedureName) instanceof Procedure) { 1916 return (Procedure) this.modelManager.getModel(procedureName); 1917 } 1918 else if (this.modelManager 1919 .getProcedureByName(DlineageUtil.getIdentifierNormalTableName(procedureNameWithArgSize)) != null) { 1920 return modelManager.getProcedureByName(DlineageUtil.getIdentifierNormalTableName(procedureNameWithArgSize)); 1921 } 1922 else { 1923 Procedure procedure = new Procedure(procedureName); 1924 procedure.setType(ESqlStatementType.sstcreateprocedure); 1925 this.modelManager.bindModel(procedureName, procedure); 1926 this.modelManager.bindProcedureByName(DlineageUtil.getIdentifierNormalTableName(procedureNameWithArgSize), 1927 procedure); 1928 return procedure; 1929 } 1930 } 1931 1932 public Argument createProcedureArgument(Procedure procedure, TParameterDeclaration parameter, int index) { 1933 if (this.modelManager.getModel(parameter) instanceof Argument) { 1934 return (Argument) this.modelManager.getModel(parameter); 1935 } else { 1936 if (procedure.getArguments() != null) { 1937 for (Argument argument : procedure.getArguments()) { 1938 if (parameter.getParameterName() == null) { 1939 continue; 1940 } 1941 if (argument.getName().equals(parameter.getParameterName().toString())) { 1942 return argument; 1943 } 1944 } 1945 } 1946 Argument argumentModel = new Argument(procedure, parameter, index); 1947 this.modelManager.bindModel(parameter, argumentModel); 1948 this.modelManager.bindModel(procedure.getName() + ":" + argumentModel.getName(), argumentModel); 1949 return argumentModel; 1950 } 1951 } 1952 1953 public Argument createProcedureArgument(OraclePackage oraclePackage, TParameterDeclaration parameter, int index) { 1954 if (this.modelManager.getModel(parameter) instanceof Argument) { 1955 return (Argument) this.modelManager.getModel(parameter); 1956 } else { 1957 Argument argumentModel = new Argument(oraclePackage, parameter, index); 1958 this.modelManager.bindModel(parameter, argumentModel); 1959 return argumentModel; 1960 } 1961 } 1962 1963}