001 002package gudusoft.gsqlparser.dlineage.dataflow.model; 003 004import gudusoft.gsqlparser.EDbVendor; 005import gudusoft.gsqlparser.EExpressionType; 006import gudusoft.gsqlparser.ESetOperatorType; 007import gudusoft.gsqlparser.TCustomSqlStatement; 008import gudusoft.gsqlparser.dlineage.util.DlineageUtil; 009import gudusoft.gsqlparser.dlineage.util.Pair; 010import gudusoft.gsqlparser.dlineage.util.Pair3; 011import gudusoft.gsqlparser.dlineage.util.SHA256; 012import gudusoft.gsqlparser.nodes.*; 013import gudusoft.gsqlparser.sqlenv.ESQLDataObjectType; 014import gudusoft.gsqlparser.sqlenv.TSQLEnv; 015import gudusoft.gsqlparser.stmt.*; 016import gudusoft.gsqlparser.stmt.mssql.TMssqlDeclare; 017import gudusoft.gsqlparser.util.IndexedLinkedHashMap; 018import gudusoft.gsqlparser.util.Logger; 019import gudusoft.gsqlparser.util.LoggerFactory; 020import gudusoft.gsqlparser.util.SQLUtil; 021 022import java.util.*; 023 024@SuppressWarnings({ "unchecked", "rawtypes" }) 025public class ModelBindingManager { 026 027 private static final Logger logger = LoggerFactory.getLogger(ModelBindingManager.class); 028 029 private final Map modelBindingMap = new LinkedHashMap(); 030 private final Map processModelBindingMap = new LinkedHashMap(); 031 private final Map viewModelBindingMap = new LinkedHashMap(); 032 private final Map insertModelBindingMap = new LinkedHashMap(); 033 private final Map createModelBindingMap = new LinkedHashMap(); 034 private final Map createModelQuickBindingMap = new LinkedHashMap(); 035 private final Map mergeModelBindingMap = new LinkedHashMap(); 036 private final Map updateModelBindingMap = new LinkedHashMap(); 037 private final Map cursorModelBindingMap = new LinkedHashMap(); 038 private final Map functionTableMap = new LinkedHashMap<>(); 039 private final Map tableNamesMap = new LinkedHashMap(); 040 private final Set<Table> dropTables = new HashSet<Table>(); 041 private final Map procedureNamesMap = new LinkedHashMap(); 042 private final Map oraclePackageNamesMap = new LinkedHashMap(); 043 private final Set<Relationship> relationHolder = Collections.synchronizedSet(new LinkedHashSet<Relationship>()); 044 private final Map<String, TTable> tableAliasMap = new LinkedHashMap(); 045 private final Map<TCustomSqlStatement, String> tableHashMap = new LinkedHashMap(); 046 private final Map<TCustomSqlStatement, String> topStmtHashMap = new HashMap(); 047 private final Map hashSQLMap = new HashMap(); 048 private final Map dynamicSQLMap = new HashMap(); 049 private final Set tableSet = new LinkedHashSet(); 050 private final Set resultSetSet = new LinkedHashSet(); 051 private final Set<String> dblinkTableSet = new LinkedHashSet(); 052 053 // Pipelined function stitching state 054 private final Map<String, List<String>> objectTypeIndex = new LinkedHashMap<>(); 055 private final Map<String, String> collectionToElementTypeIndex = new LinkedHashMap<>(); 056 private final Map<String, List<PipelinedFunctionSignature>> pipelinedSignatures = new LinkedHashMap<>(); 057 private final List<PendingPipelinedCallSite> pendingPipelinedCallSites = new ArrayList<>(); 058 private final Set<String> resolvingPipelinedFunctions = new HashSet<>(); 059 060 public Map<String, Long> DISPLAY_ID = new LinkedHashMap<String, Long>(); 061 public Map<Long, String> DISPLAY_NAME = new LinkedHashMap<Long, String>(); 062 public Map<String, String> virtualTableNames = new LinkedHashMap<String, String>(); 063 064 public long TABLE_COLUMN_ID = 0; 065 public long RELATION_ID = 0; 066 public int virtualTableIndex = -1; 067 068 private final static ThreadLocal localManager = new ThreadLocal(); 069 private final static ThreadLocal globalDatabase = new ThreadLocal(); 070 private final static ThreadLocal globalSchema = new ThreadLocal(); 071 private final static ThreadLocal schemaUnsetStatements = new ThreadLocal(); 072 private final static ThreadLocal globalVendor = new ThreadLocal(); 073 private final static ThreadLocal globalSQLEnv = new ThreadLocal(); 074 private final static ThreadLocal globalHash = new ThreadLocal(); 075 private final static ThreadLocal globalStmtStack = new ThreadLocal(); 076 private final static ThreadLocal globalSqlInfo = new ThreadLocal(); 077 private final static ThreadLocal globalOption = new ThreadLocal(); 078 private final static ThreadLocal globalOraclePackage = new ThreadLocal(); 079 private final static ThreadLocal globalProcedure = new ThreadLocal(); 080 081 public static void set(ModelBindingManager modelManager) { 082 if (modelManager != null) { 083 localManager.set(modelManager); 084 } 085 } 086 087 public static ModelBindingManager get() { 088 return (ModelBindingManager) localManager.get(); 089 } 090 091 public static void setGlobalDatabase(String database) { 092 if (database != null) { 093 globalDatabase.set(database); 094 } 095 } 096 097 public static String getGlobalDatabase() { 098 return (String) globalDatabase.get(); 099 } 100 101 public static void removeGlobalDatabase() { 102 globalDatabase.remove(); 103 } 104 105 public static void setGlobalSchema(String schema) { 106 if (schema != null) { 107 globalSchema.set(schema); 108 } 109 } 110 111 public static void removeGlobalSchema() { 112 globalSchema.remove(); 113 } 114 115 public static String getGlobalSchema() { 116 return (String) globalSchema.get(); 117 } 118 119 /** 120 * The statements that a Snowflake {@code USE <database>} left with NO current 121 * schema, i.e. everything after such a switch up to the next schema switch. 122 * 123 * <p>Recorded as a set of statements rather than as a running flag on 124 * purpose. The analyzer walks the statement list several times - one pass for 125 * CREATE TABLE, another for views, another for procedures - replaying the 126 * {@code USE} statements in each. A running flag set during one pass is still 127 * set when a LATER pass reaches a statement that precedes the switch, so it 128 * would apply the clearing backwards and strip an already-exact qualification 129 * off a statement that ran while the old schema was still current. Keyed by 130 * statement, the answer is the same no matter which pass asks. 131 * 132 * <p>See GitHub #715 / MantisBT 4677. 133 */ 134 public static void setSchemaUnsetStatements(Set<TCustomSqlStatement> statements) { 135 if (statements == null || statements.isEmpty()) { 136 schemaUnsetStatements.remove(); 137 } else { 138 schemaUnsetStatements.set(statements); 139 } 140 } 141 142 public static void removeSchemaUnsetStatements() { 143 schemaUnsetStatements.remove(); 144 } 145 146 /** 147 * Whether the statement being analyzed right now has no current schema 148 * because a Snowflake {@code USE <database>} unset it. 149 * 150 * @see #setSchemaUnsetStatements(Set) 151 */ 152 @SuppressWarnings("unchecked") 153 public static boolean isGlobalSchemaUnset() { 154 Set<TCustomSqlStatement> unset = (Set<TCustomSqlStatement>) schemaUnsetStatements.get(); 155 if (unset == null || unset.isEmpty()) { 156 return false; 157 } 158 Stack<TCustomSqlStatement> stack = getGlobalStmtStack(); 159 if (stack == null || stack.isEmpty()) { 160 return false; 161 } 162 return unset.contains(DlineageUtil.getTopStmt(stack.peek())); 163 } 164 165 public static void setGlobalHash(String hash) { 166 if (hash != null) { 167 globalHash.set(hash); 168 } 169 } 170 171 public static void removeGlobalHash() { 172 globalHash.remove(); 173 } 174 175 public static String getGlobalHash() { 176 return (String) globalHash.get(); 177 } 178 179 public static void setGlobalOraclePackage(OraclePackage currentOraclePackage) { 180 if (currentOraclePackage != null) { 181 globalOraclePackage.set(currentOraclePackage); 182 } 183 } 184 185 public static void removeGlobalOraclePackage() { 186 globalOraclePackage.remove(); 187 } 188 189 public static OraclePackage getGlobalOraclePackage() { 190 return (OraclePackage) globalOraclePackage.get(); 191 } 192 193 public static void setGlobalProcedure(TStoredProcedureSqlStatement procedureSqlStatement) { 194 if (procedureSqlStatement != null) { 195 globalProcedure.set(procedureSqlStatement); 196 } 197 } 198 199 public static void removeGlobalProcedure() { 200 globalProcedure.remove(); 201 ModelBindingManager.get().cleanTempTable(); 202 } 203 204 public static TStoredProcedureSqlStatement getGlobalProcedure() { 205 return (TStoredProcedureSqlStatement) globalProcedure.get(); 206 } 207 208 public static void setGlobalVendor(EDbVendor vendor) { 209 if (vendor != null) { 210 globalVendor.set(vendor); 211 } 212 } 213 214 public static void removeGlobalVendor() { 215 globalVendor.remove(); 216 } 217 218 public static EDbVendor getGlobalVendor() { 219 return (EDbVendor) globalVendor.get(); 220 } 221 222 public static void setGlobalSQLEnv(TSQLEnv sqlenv) { 223 if (sqlenv != null) { 224 globalSQLEnv.set(sqlenv); 225 } 226 } 227 228 public static void removeGlobalSQLEnv() { 229 globalSQLEnv.remove(); 230 } 231 232 public static TSQLEnv getGlobalSQLEnv() { 233 return (TSQLEnv) globalSQLEnv.get(); 234 } 235 236 public static String getGlobalServer() { 237 TSQLEnv sqlEnv = getGlobalSQLEnv(); 238 if (sqlEnv != null) 239 return TSQLEnv.DEFAULT_SERVER_NAME.equals(sqlEnv.getDefaultServerName()) ? null : sqlEnv.getDefaultServerName(); 240 return null; 241 } 242 243 /** 244 * Resolve the effective default database (catalog) used to qualify 245 * unqualified / partial object names, with a three-tier precedence: 246 * 247 * <ol> 248 * <li>the active global database — an in-script {@code USE database}, or the 249 * per-group database set by {@code DataFlowAnalyzer};</li> 250 * <li>the per-analysis {@code Option.getDefaultDatabase()};</li> 251 * <li>the attached {@code TSQLEnv} default catalog;</li> 252 * <li>{@code TSQLEnv.DEFAULT_DB_NAME}.</li> 253 * </ol> 254 * 255 * Each lower tier is consulted only when the higher tier is null/empty. This 256 * lets a shared multi-catalog {@code TSQLEnv} be reused across analyses with 257 * different per-analysis default databases (tier 2) without mutating the env, 258 * while still honoring an in-script {@code USE database} (tier 1). 259 */ 260 public static String getEffectiveDefaultDatabase() { 261 // tier 1: active global database (USE database / per-group database) 262 String database = getGlobalDatabase(); 263 if (!SQLUtil.isEmpty(database)) { 264 return database; 265 } 266 // tier 2: per-analysis Option default database 267 Option option = getGlobalOption(); 268 if (option != null) { 269 String optionDatabase = option.getDefaultDatabase(); 270 if (!SQLUtil.isEmpty(optionDatabase) && !TSQLEnv.DEFAULT_DB_NAME.equals(optionDatabase)) { 271 return optionDatabase; 272 } 273 } 274 // tier 3: attached TSQLEnv default catalog 275 TSQLEnv sqlenv = getGlobalSQLEnv(); 276 if (sqlenv != null && !SQLUtil.isEmpty(sqlenv.getDefaultCatalogName())) { 277 return sqlenv.getDefaultCatalogName(); 278 } 279 // tier 4: fallback 280 return TSQLEnv.DEFAULT_DB_NAME; 281 } 282 283 /** 284 * The schema an unqualified name defaults to right now. 285 * 286 * <p>Six model classes used to carry an identical copy of this fallback; it 287 * lives here so the {@link #isGlobalSchemaUnset() unset} rule cannot be 288 * applied to some of them and forgotten on the others. Returns 289 * {@link TSQLEnv#DEFAULT_SCHEMA_NAME} when there is no schema to default to. 290 * 291 * @see #getEffectiveDefaultDatabase() 292 */ 293 public static String getEffectiveDefaultSchema() { 294 // A Snowflake USE <database> unset the current schema for this statement. 295 // The attached env's default schema is batch-global -- TUseSchema writes 296 // it while PARSING, so it holds the LAST USE SCHEMA of the whole script -- 297 // and falling back to it here would re-attach the previous database's 298 // schema to names that follow the switch. See GitHub #715. 299 if (isGlobalSchemaUnset()) { 300 // Unset, unless the attached catalog PROVES what the switch landed 301 // in. Snowflake makes PUBLIC current when the new database has one; 302 // when the catalog shows it does, that is a fact rather than an 303 // assumption, and discarding it would lose an exact resolution. 304 String afterSwitch = null; 305 if (getGlobalSQLEnv() != null) { 306 afterSwitch = getGlobalSQLEnv().findSchemaAfterDatabaseSwitch(getEffectiveDefaultDatabase()); 307 } 308 return SQLUtil.isEmpty(afterSwitch) ? TSQLEnv.DEFAULT_SCHEMA_NAME : afterSwitch; 309 } 310 String defaultSchema = null; 311 if (getGlobalSQLEnv() != null) { 312 defaultSchema = getGlobalSQLEnv().getDefaultSchemaName(); 313 } 314 if (!SQLUtil.isEmpty(defaultSchema)) { 315 return defaultSchema; 316 } 317 return TSQLEnv.DEFAULT_SCHEMA_NAME; 318 } 319 320 public static void setGlobalStmtStack(Stack<TCustomSqlStatement> stack) { 321 if (stack != null) { 322 globalStmtStack.set(stack); 323 } 324 } 325 326 public static void removeGlobalStmtStack() { 327 globalStmtStack.remove(); 328 } 329 330 public static void setGlobalSqlInfo(IndexedLinkedHashMap<String, List<SqlInfo>> sqlInfoMap) { 331 if (sqlInfoMap != null) { 332 globalSqlInfo.set(sqlInfoMap); 333 } 334 } 335 336 public static void removeGlobalSqlInfo() { 337 globalSqlInfo.remove(); 338 } 339 340 public static IndexedLinkedHashMap<String, List<SqlInfo>> getGlobalSqlInfo() { 341 return (IndexedLinkedHashMap<String, List<SqlInfo>>) globalSqlInfo.get(); 342 } 343 344 public static void setGlobalOption(Option option) { 345 if (option != null) { 346 globalOption.set(option); 347 } 348 } 349 350 public static Option getGlobalOption() { 351 return (Option) globalOption.get(); 352 } 353 354 public static void removeGlobalOption() { 355 globalOption.remove(); 356 } 357 358 public static Stack<TCustomSqlStatement> getGlobalStmtStack() { 359 return (Stack<TCustomSqlStatement>) globalStmtStack.get(); 360 } 361 362 public static void remove() { 363 localManager.remove(); 364 globalDatabase.remove(); 365 globalSchema.remove(); 366 schemaUnsetStatements.remove(); 367 globalVendor.remove(); 368 globalSQLEnv.remove(); 369 globalHash.remove(); 370 globalStmtStack.remove(); 371 globalOption.remove(); 372 globalSqlInfo.remove(); 373 } 374 375 public void bindModel(Object gspModel, Object relationModel) { 376 if(gspModel == null) { 377 return; 378 } 379 modelBindingMap.put(gspModel, relationModel); 380 381 TTable table = null; 382 if (gspModel instanceof TTable && !(gspModel instanceof TCTE)) { 383 table = ((TTable) gspModel); 384 } else if (gspModel instanceof Table) { 385 table = ((Table) gspModel).getTableObject(); 386 } else if (gspModel instanceof QueryTable) { 387 table = ((QueryTable) gspModel).getTableObject(); 388 } else if (gspModel instanceof TCTE) { 389 TTableList tables = ((TCTE) gspModel).getPreparableStmt().tables; 390 for (int j = 0; j < tables.size(); j++) { 391 TTable item = tables.getTable(j); 392 if (item != null && !SQLUtil.isEmpty(item.getAliasName())) { 393 TCustomSqlStatement stmt = ((TCTE) gspModel).getPreparableStmt(); 394 if (tableHashMap.containsKey(stmt)) { 395 tableAliasMap.put( 396 tableHashMap.get(stmt) + ":" + DlineageUtil.getIdentifierNormalTableName(item.getAliasName()), 397 item); 398 } else { 399 String sql = stmt.toString(); 400 if(sql == null){ 401 System.err.println("Current statement toString() returns null."); 402 continue; 403 } 404 String hash = SHA256.getMd5(sql); 405 tableHashMap.put(stmt, hash); 406 tableAliasMap.put(hash + ":" + DlineageUtil.getIdentifierNormalTableName(item.getAliasName()), item); 407 } 408 } 409 410 if (item != null) { 411 tableSet.add(item); 412 } 413 } 414 } else if (gspModel instanceof Pair && ((Pair) gspModel).first instanceof Table) { 415 table = ((Table) ((Pair) gspModel).first).getTableObject(); 416 } 417 418 if (table == null && relationModel instanceof QueryTable) { 419 table = ((QueryTable) relationModel).getTableObject(); 420 } 421 422 updateTableAliasMap(table); 423 424 if (table != null) { 425 tableSet.add(table); 426 } 427 428 if(relationModel instanceof ResultSet) { 429 resultSetSet.add(relationModel); 430 } 431 } 432 433 protected void updateTableAliasMap(TTable table) { 434 if (table != null && !SQLUtil.isEmpty(table.getAliasName())) { 435 TCustomSqlStatement stmt = ModelBindingManager.getGlobalStmtStack().peek(); 436 if (tableHashMap.containsKey(stmt)) { 437 tableAliasMap.put(tableHashMap.get(stmt) + ":" + DlineageUtil.getIdentifierNormalTableName(table.getAliasName()), 438 table); 439 } else { 440 String sql = stmt.toString(); 441 if(sql == null){ 442 System.err.println("Current statement toString() returns null."); 443 } 444 else { 445 String hash = SHA256.getMd5(sql); 446 tableHashMap.put(stmt, hash); 447 tableAliasMap.put(hash + ":" + DlineageUtil.getIdentifierNormalTableName(table.getAliasName()), 448 table); 449 } 450 } 451 } 452 } 453 454 public Object getModel(Object gspModel) { 455 if (gspModel == null) { 456 return null; 457 } 458 459 if (gspModel instanceof TTable && !(gspModel instanceof TCTE)) { 460 TTable table = (TTable) gspModel; 461 if (table.getCTE() != null) { 462 Object result = modelBindingMap.get(table.getCTE()); 463 if (result != null) { 464 return result; 465 } 466 } 467 if (table.getAliasClause() != null && table.getAliasClause().getColumns() != null) { 468 Object result = modelBindingMap.get(table.getAliasClause().getColumns()); 469 if (result != null) { 470 return result; 471 } 472 } 473 if (table.getSubquery() != null && !table.getSubquery().isCombinedQuery()) { 474 Object result = modelBindingMap.get(table.getSubquery().getResultColumnList()); 475 if (result != null) { 476 return result; 477 } 478 } 479 } 480 if (gspModel instanceof TSelectSqlStatement) { 481 TSelectSqlStatement select = (TSelectSqlStatement) gspModel; 482 if (!select.isCombinedQuery()) { 483 if (select.getResultColumnList() != null) { 484 Object result = modelBindingMap.get(select.getResultColumnList()); 485 if (result != null) { 486 return result; 487 } 488 } 489 else if (select.getTransformClause() != null) { 490 Object result = modelBindingMap.get(select.getTransformClause()); 491 if (result != null) { 492 return result; 493 } 494 } 495 } 496 } 497 Object result = modelBindingMap.get(gspModel); 498 if (result == null) { 499 result = createModelBindingMap.get(gspModel); 500 } 501 if (result == null) { 502 result = insertModelBindingMap.get(gspModel); 503 } 504 if (result == null) { 505 result = updateModelBindingMap.get(gspModel); 506 } 507 if (result == null) { 508 result = mergeModelBindingMap.get(gspModel); 509 } 510 if (result == null) { 511 result = viewModelBindingMap.get(gspModel); 512 } 513 if (result == null) { 514 result = cursorModelBindingMap.get(gspModel); 515 } 516 517 if (result == null && gspModel instanceof TTable) { 518 result = getCreateTable((TTable) gspModel); 519 } 520 521 if (result == null && gspModel instanceof TTable) { 522 result = (Table) getCreateModel((TTable) gspModel); 523 } 524 525 if (result == null && gspModel instanceof TTable) { 526 TTable table = (TTable) gspModel; 527 if (table.getLinkTable() != null) { 528 result = (Table) getTableByName( 529 DlineageUtil.getTableFullName(table.getLinkTable().getTableName().toString())); 530 if (result == null) { 531 result = (Table) getTableByName( 532 DlineageUtil.getTableFullNameWithDefaultSchema(table.getLinkTable().getTableName().toString())); 533 } 534 } else { 535 result = (Table) getTableByName( 536 DlineageUtil.getTableFullName(((TTable) gspModel).getTableName().toString())); 537 if (result == null) { 538 result = (Table) getTableByName( 539 DlineageUtil.getTableFullNameWithDefaultSchema(((TTable) gspModel).getTableName().toString())); 540 } 541 } 542 } 543 544 if (result == null && gspModel instanceof TTable) { 545 TTable table = (TTable) gspModel; 546 if(table.getFuncCall()!=null) { 547 result = getModel(table.getFuncCall()); 548 } 549 } 550 551 if (result == null && gspModel instanceof TTable) { 552 TTable table = (TTable) gspModel; 553 Table tableModel = new Table(table); 554 result = (Table) getTableByName(DlineageUtil.getTableFullName(tableModel.getName())); 555 } 556 557 return result; 558 } 559 560 public List<Procedure> getProcedureModels(){ 561 List<Procedure> procedures = new ArrayList<Procedure>(); 562 for (Object obj : modelBindingMap.values()) { 563 if(obj instanceof Procedure && !procedures.contains(obj)){ 564 procedures.add((Procedure)obj); 565 } 566 } 567 return procedures; 568 } 569 570 public List<OraclePackage> getOraclePackageModels(){ 571 List<OraclePackage> oraclePackages = new ArrayList<OraclePackage>(); 572 for (Object obj : modelBindingMap.values()) { 573 if(obj instanceof OraclePackage && !oraclePackages.contains(obj)){ 574 oraclePackages.add((OraclePackage)obj); 575 } 576 } 577 return oraclePackages; 578 } 579 580 public List<Process> getProcessModels(){ 581 List<Process> processes = new ArrayList<Process>(); 582 for (Object obj : processModelBindingMap.values()) { 583 if(obj instanceof Process && !processes.contains(obj)){ 584 processes.add((Process)obj); 585 } 586 } 587 return processes; 588 } 589 590 public void bindProcessModel(TParseTreeNode gspModel, Object relationModel) { 591 processModelBindingMap.put(gspModel, relationModel); 592 } 593 594 public void unbindProcessModel(TParseTreeNode gspModel) { 595 processModelBindingMap.remove(gspModel); 596 } 597 598 public Process getProcessModel(TParseTreeNode gspModel) { 599 return (Process)processModelBindingMap.get(gspModel); 600 } 601 602 public void bindViewModel(Object gspModel, Object relationModel) { 603 viewModelBindingMap.put(gspModel, relationModel); 604 } 605 606 public Object getViewModel(Object gspModel) { 607 return viewModelBindingMap.get(gspModel); 608 } 609 610 public void bindUpdateModel(Object gspModel, Object relationModel) { 611 updateModelBindingMap.put(gspModel, relationModel); 612 } 613 614 public Object getUpdateModel(Object gspModel) { 615 return updateModelBindingMap.get(gspModel); 616 } 617 618 public void bindMergeModel(Object gspModel, Object relationModel) { 619 mergeModelBindingMap.put(gspModel, relationModel); 620 } 621 622 public Object getMergeModel(Object gspModel) { 623 return mergeModelBindingMap.get(gspModel); 624 } 625 626 public void bindInsertModel(Object gspModel, Object relationModel) { 627 insertModelBindingMap.put(gspModel, relationModel); 628 } 629 630 public Object getInsertModel(Object gspModel) { 631 return insertModelBindingMap.get(gspModel); 632 } 633 634 public void bindTableFunction(Object gspModel, Object functionTable) { 635 if (functionTableMap.containsKey(gspModel)) { 636 ((Set) functionTableMap.get(gspModel)).add(functionTable); 637 } else { 638 Set tableSet = new LinkedHashSet(); 639 tableSet.add(functionTable); 640 functionTableMap.put(gspModel, tableSet); 641 } 642 } 643 644 public Set<Object> getFunctionTable(Object gspModel) { 645 Set<Object> result = (Set<Object>)functionTableMap.get(gspModel); 646 if (result == null && gspModel instanceof String) { 647 for (Object key : functionTableMap.keySet()) { 648 if(!(key instanceof String)) { 649 continue; 650 } 651 String keyString = (String) key; 652 String modelString = (String) gspModel; 653 654 if (keyString.indexOf(".") != -1 && modelString.indexOf(".") == -1) { 655 keyString = keyString.substring(keyString.lastIndexOf(".") + 1); 656 if (DlineageUtil.sameName(ESQLDataObjectType.dotTable, keyString, modelString)) { 657 return (Set<Object>)functionTableMap.get(key); 658 } 659 } 660 if (keyString.indexOf(".") == -1 && modelString.indexOf(".") != -1) { 661 modelString = modelString.substring(modelString.lastIndexOf(".") + 1); 662 if (DlineageUtil.sameName(ESQLDataObjectType.dotTable, keyString, modelString)) { 663 return (Set<Object>)functionTableMap.get(key); 664 } 665 } 666 667 } 668 } 669 return result; 670 } 671 672 public Table getCreateTable(TTable table) { 673 if (table != null && table.getFullName() != null) { 674 return (Table) createModelQuickBindingMap.get(DlineageUtil.getTableFullName(table.getTableName().toString())); 675 } 676 if(modelBindingMap.get(table) instanceof Table) { 677 return (Table)modelBindingMap.get(table); 678 } 679 return null; 680 } 681 682 public Table getCreateModel(TTable table) { 683 return (Table) createModelBindingMap.get(table); 684 } 685 686 public void bindCreateModel(TTable table, Table tableModel) { 687 createModelBindingMap.put(table, tableModel); 688 if (!createModelQuickBindingMap.containsKey(DlineageUtil.getTableFullName(table.getTableName().toString()))) { 689 createModelQuickBindingMap.put(DlineageUtil.getTableFullName(table.getTableName().toString()), tableModel); 690 } 691 } 692 693 public void bindCreateModel(TObjectName tableName, Table tableModel) { 694 if (!createModelQuickBindingMap.containsKey(DlineageUtil.getTableFullName(tableName.toString()))) { 695 createModelQuickBindingMap.put(DlineageUtil.getTableFullName(tableName.toString()), tableModel); 696 } 697 } 698 699 public void bindCreateModel(String tableName, Table tableModel) { 700 if (!createModelQuickBindingMap.containsKey(DlineageUtil.getTableFullName(tableName))) { 701 createModelQuickBindingMap.put(DlineageUtil.getTableFullName(tableName), tableModel); 702 } 703 } 704 705 public TObjectName[] getTableColumns(TTable table) { 706 Table createTable = getCreateTable(table); 707 if (createTable != null) { 708 List<TableColumn> columnList = createTable.getColumns(); 709 TObjectName[] columns = new TObjectName[columnList.size()]; 710 for (int i = 0; i < columns.length; i++) { 711 columns[i] = columnList.get(i).getColumnObject(); 712 } 713 Arrays.sort(columns, new Comparator<TObjectName>() { 714 715 @Override 716 public int compare(TObjectName o1, TObjectName o2) { 717 if (o1 == null) { 718 return -1; 719 } 720 if (o2 == null) { 721 return 1; 722 } 723 return o1.getStartToken().posinlist - o2.getStartToken().posinlist; 724 } 725 }); 726 return columns; 727 } 728 else if(modelBindingMap.get(table) instanceof QueryTable) { 729 QueryTable queryTable = (QueryTable)modelBindingMap.get(table); 730 List<TObjectName> columns = new ArrayList<TObjectName>(); 731 for (ResultColumn resultColumn : queryTable.getColumns()) { 732 if(resultColumn.hasStarLinkColumn()) { 733 for(TObjectName column: resultColumn.getStarLinkColumnList()) { 734 columns.add(column); 735 } 736 } 737 else if (resultColumn.getColumnObject() instanceof TResultColumn) { 738 TResultColumn columnObject = ((TResultColumn) resultColumn.getColumnObject()); 739 TAliasClause alias = columnObject.getAliasClause(); 740 if (alias != null && alias.getAliasName() != null) { 741 if(resultColumn.isStruct() && resultColumn.getName().endsWith("*")) { 742 TObjectName structColumn = new TObjectName(); 743 structColumn.setString("*"); 744 columns.add(structColumn); 745 } 746 else { 747 columns.add(alias.getAliasName()); 748 } 749 } else { 750 if (columnObject.getFieldAttr() != null) { 751 columns.add(columnObject.getFieldAttr()); 752 } else { 753 TObjectName column = new TObjectName(); 754 if (columnObject.getExpr().getExpressionType() == EExpressionType.typecast_t) { 755 column.setString(columnObject.getExpr().getLeftOperand().toString()); 756 } else { 757 column.setString(columnObject.toString()); 758 } 759 columns.add(column); 760 } 761 } 762 } else if (resultColumn.getColumnObject() instanceof TObjectName) { 763 columns.add((TObjectName) resultColumn.getColumnObject()); 764 } 765 } 766 return columns.toArray(new TObjectName[0]); 767 } 768 769 TObjectNameList list = table.getLinkedColumns(); 770 List<TObjectName> columns = new ArrayList<TObjectName>(); 771 772 if (table.getCTE() != null) { 773 ResultSet resultSet = (ResultSet) getModel(table.getCTE()); 774 if (resultSet != null) { 775 List<ResultColumn> columnList = resultSet.getColumns(); 776 for (int i = 0; i < columnList.size(); i++) { 777 ResultColumn resultColumn = columnList.get(i); 778 if (resultColumn.getColumnObject() instanceof TResultColumn) { 779 TResultColumn columnObject = ((TResultColumn) resultColumn.getColumnObject()); 780 TAliasClause alias = columnObject.getAliasClause(); 781 if (alias != null && alias.getAliasName() != null) { 782 columns.add(alias.getAliasName()); 783 } else { 784 if (columnObject.getFieldAttr() != null) { 785 columns.add(columnObject.getFieldAttr()); 786 } else { 787 continue; 788 } 789 } 790 } else if (resultColumn.getColumnObject() instanceof TObjectName) { 791 columns.add((TObjectName) resultColumn.getColumnObject()); 792 } 793 } 794 } 795 } else if (list.size() == 1 && list.toString().indexOf("*") != -1 && table.getSubquery() != null) { 796 addSubqueryColumns(table, columns); 797 } else { 798 for (int i = 0; i < list.size(); i++) { 799 TObjectName object = list.getObjectName(i); 800 if (object.toString().indexOf("*") != -1 && table.getSubquery() != null) { 801 addSubqueryColumns(table, columns); 802 } 803 else 804 columns.add(object); 805 } 806 } 807 Collections.sort(columns, new Comparator<TObjectName>() { 808 809 @Override 810 public int compare(TObjectName o1, TObjectName o2) { 811 return o1.getStartToken().posinlist - o2.getStartToken().posinlist; 812 } 813 }); 814 return columns.toArray(new TObjectName[0]); 815 } 816 817 private void addSubqueryColumns(TTable table, List<TObjectName> columns) { 818 ResultSet resultSet = (ResultSet) getModel(table.getSubquery()); 819 if (resultSet != null) { 820 List<ResultColumn> columnList = resultSet.getColumns(); 821 for (int i = 0; i < columnList.size(); i++) { 822 ResultColumn resultColumn = columnList.get(i); 823 if (resultColumn.getColumnObject() instanceof TResultColumn) { 824 TResultColumn columnObject = ((TResultColumn) resultColumn.getColumnObject()); 825 TAliasClause alias = columnObject.getAliasClause(); 826 if (alias != null && alias.getAliasName() != null) { 827 columns.add(alias.getAliasName()); 828 } else { 829 if (columnObject.getFieldAttr() != null) { 830 columns.add(columnObject.getFieldAttr()); 831 } else { 832 TObjectName column = new TObjectName(); 833 if (columnObject.getExpr().getExpressionType() == EExpressionType.typecast_t) { 834 column.setString(columnObject.getExpr().getLeftOperand().toString()); 835 } else { 836 column.setString(columnObject.toString()); 837 } 838 columns.add(column); 839 } 840 } 841 } else if (resultColumn.getColumnObject() instanceof TObjectName) { 842 columns.add((TObjectName) resultColumn.getColumnObject()); 843 } 844 } 845 } 846 } 847 848 public TTable getTableFromColumn(TObjectName column) { 849 if (column.getSourceTable() != null) { 850 return column.getSourceTable(); 851 } 852 853 if (column.getTableString() != null && column.getTableString().trim().length() > 0) { 854 TCustomSqlStatement peekStmt = ModelBindingManager.getGlobalStmtStack().peek(); 855 while (peekStmt != null) { 856 TTable table = null; 857 if (tableHashMap.containsKey(peekStmt)) { 858 table = tableAliasMap.get(tableHashMap.get(peekStmt) + ":" 859 + DlineageUtil.getIdentifierNormalTableName(column.getTableString())); 860 } 861 if (table != null) { 862 return table; 863 } else { 864 peekStmt = peekStmt.getParentStmt(); 865 } 866 } 867 } 868 return null; 869 } 870 871 public TTable getTable(TCustomSqlStatement stmt, TObjectName column) { 872 if (column.getSourceTable() != null) { 873 return column.getSourceTable(); 874 } 875 876 if (column.getTableString() != null && column.getTableString().trim().length() > 0) { 877 TCustomSqlStatement peekStmt = ModelBindingManager.getGlobalStmtStack().peek(); 878 while (peekStmt != null) { 879 TTable table = null; 880 if (tableHashMap.containsKey(peekStmt)) { 881 table = tableAliasMap.get(tableHashMap.get(peekStmt) + ":" 882 + DlineageUtil.getIdentifierNormalTableName(column.getTableString())); 883 } 884 if (table != null && table.getSubquery() != stmt) 885 return table; 886 887 if (peekStmt.getTables() != null) { 888 for (TTable tableItem : peekStmt.getTables()) { 889 if (DlineageUtil.getIdentifierNormalTableName(tableItem.getTableName().toString()) 890 .equals(DlineageUtil.getIdentifierNormalTableName(column.getTableString()))) { 891 return tableItem; 892 } 893 } 894 } 895 896 peekStmt = peekStmt.getParentStmt(); 897 } 898 } 899 900 if (stmt.getTables() != null) { 901 for (int j = 0; j < stmt.getTables().size(); j++) { 902 TTable table = (TTable) stmt.getTables().getTable(j); 903 if (table.getSubquery() == stmt) 904 continue; 905 906 TObjectName[] columns = getTableColumns(table); 907 for (int i = 0; i < columns.length; i++) { 908 TObjectName columnName = columns[i]; 909 if (columnName == null || "*".equals(columnName.getColumnNameOnly())) 910 continue; 911 if (DlineageUtil.getIdentifierNormalColumnName(columnName.toString()) 912 .equals(DlineageUtil.getIdentifierNormalColumnName(column.toString()))) { 913 if (columnName.getSourceTable() == null || columnName.getSourceTable() == table) { 914 return table; 915 } 916 } 917 if (!SQLUtil.isEmpty(columnName.getColumnNameOnly()) 918 && DlineageUtil.getIdentifierNormalColumnName(columnName.getColumnNameOnly()) 919 .equals(DlineageUtil.getIdentifierNormalColumnName(column.getColumnNameOnly()))) { 920 if (columnName.getSourceTable() == null || columnName.getSourceTable() == table) { 921 return table; 922 } 923 } 924 } 925 } 926 } 927 928 // Iterator iter = tableSet.iterator(); 929 // while (iter.hasNext()) { 930 // TTable table = (TTable) iter.next(); 931 // 932 // if (table.getSubquery() == stmt) 933 // continue; 934 // 935 // if (table.getSubquery() != null) { 936 // int start = table.getSubquery().getStartToken().posinlist; 937 // int end = table.getSubquery().getEndToken().posinlist; 938 // if (start <= stmt.getStartToken().posinlist && end >= 939 // stmt.getEndToken().posinlist) { 940 // continue; 941 // } 942 // } 943 // 944 // TObjectName[] columns = getTableColumns(table); 945 // for (int i = 0; i < columns.length; i++) { 946 // TObjectName columnName = columns[i]; 947 // if (columnName == null || "*".equals(columnName.getColumnNameOnly())) 948 // continue; 949 // if 950 // (DlineageUtil.getIdentifierNormalName(columnName.toString()).equals(DlineageUtil.getIdentifierNormalName(column.toString()))) 951 // { 952 // if (columnName.getSourceTable() == null 953 // || columnName.getSourceTable() == table) { 954 // return table; 955 // } 956 // } 957 // if (columnName.getColumnNameOnly()!=null && 958 // DlineageUtil.getIdentifierNormalName(columnName.getColumnNameOnly()).equals(DlineageUtil.getIdentifierNormalName(column.getColumnNameOnly()))) 959 // { 960 // if (columnName.getSourceTable() == null 961 // || columnName.getSourceTable() == table) { 962 // return table; 963 // } 964 // } 965 // } 966 // } 967 return null; 968 } 969 970 public TTable guessTable(TCustomSqlStatement stmt, TObjectName column) { 971 if (column.getTableString() != null && column.getTableString().trim().length() > 0) { 972 TCustomSqlStatement peekStmt = ModelBindingManager.getGlobalStmtStack().peek(); 973 TTable table = null; 974 if (tableHashMap.containsKey(peekStmt)) { 975 table = tableAliasMap.get( 976 tableHashMap.get(peekStmt) + ":" + DlineageUtil.getIdentifierNormalTableName(column.getTableString())); 977 } 978 if (table != null && table.getSubquery() != stmt) 979 return table; 980 } 981 982 Iterator iter = tableSet.iterator(); 983 while (iter.hasNext()) { 984 TTable table = (TTable) iter.next(); 985 986 if (table.getSubquery() == stmt) 987 continue; 988 989 TObjectName[] columns = getTableColumns(table); 990 for (int i = 0; i < columns.length; i++) { 991 TObjectName columnName = columns[i]; 992 if ("*".equals(columnName.getColumnNameOnly())) 993 continue; 994 if (DlineageUtil.sameQualifiedName(ESQLDataObjectType.dotColumn, columnName.toString(), column.toString())) { 995 if (columnName.getSourceTable() == null || columnName.getSourceTable() == table) { 996 return table; 997 } 998 } 999 } 1000 } 1001 return null; 1002 } 1003 1004 public List<Table> getTablesByName() { 1005 List<Table> tables = new ArrayList<Table>(); 1006 Iterator iter = tableNamesMap.values().iterator(); 1007 while (iter.hasNext()) { 1008 tables.add((Table) iter.next()); 1009 } 1010 return tables; 1011 } 1012 1013 public List<TTable> getBaseTables() { 1014 List<TTable> tables = new ArrayList<TTable>(); 1015 1016 Iterator iter = modelBindingMap.keySet().iterator(); 1017 while (iter.hasNext()) { 1018 Object key = iter.next(); 1019 if (!(key instanceof TTable)) { 1020 continue; 1021 } 1022 TTable table = (TTable) key; 1023 if (table.getSubquery() == null) { 1024 tables.add(table); 1025 } 1026 } 1027 1028 iter = createModelBindingMap.keySet().iterator(); 1029 while (iter.hasNext()) { 1030 Object key = iter.next(); 1031 if (!(key instanceof TTable)) { 1032 continue; 1033 } 1034 TTable table = (TTable) key; 1035 tables.add(table); 1036 } 1037 1038 iter = insertModelBindingMap.keySet().iterator(); 1039 while (iter.hasNext()) { 1040 Object key = iter.next(); 1041 if (!(key instanceof TTable)) { 1042 continue; 1043 } 1044 TTable table = (TTable) key; 1045 tables.add(table); 1046 } 1047 1048 iter = mergeModelBindingMap.keySet().iterator(); 1049 while (iter.hasNext()) { 1050 Object key = iter.next(); 1051 if (!(key instanceof TTable)) { 1052 continue; 1053 } 1054 TTable table = (TTable) key; 1055 tables.add(table); 1056 } 1057 1058 iter = updateModelBindingMap.keySet().iterator(); 1059 while (iter.hasNext()) { 1060 Object key = iter.next(); 1061 if (!(key instanceof TTable)) { 1062 continue; 1063 } 1064 TTable table = (TTable) key; 1065 if (!tables.contains(table)) { 1066 tables.add(table); 1067 } 1068 } 1069 1070 return tables; 1071 } 1072 1073 public List<TCustomSqlStatement> getViews() { 1074 List<TCustomSqlStatement> views = new ArrayList<TCustomSqlStatement>(); 1075 1076 Iterator iter = viewModelBindingMap.keySet().iterator(); 1077 while (iter.hasNext()) { 1078 Object key = iter.next(); 1079 if (!(key instanceof TCreateViewSqlStatement) && !(key instanceof TCreateMaterializedSqlStatement)) { 1080 continue; 1081 } 1082 TCustomSqlStatement view = (TCustomSqlStatement) key; 1083 if (!views.contains(view)) { 1084 views.add(view); 1085 } 1086 } 1087 return views; 1088 } 1089 1090 public List<TResultColumnList> getSelectResultSets() { 1091 List<TResultColumnList> resultSets = new ArrayList<TResultColumnList>(); 1092 1093 Iterator iter = modelBindingMap.keySet().iterator(); 1094 while (iter.hasNext()) { 1095 Object key = iter.next(); 1096 if (!(key instanceof TResultColumnList)) { 1097 continue; 1098 } 1099 TResultColumnList resultset = (TResultColumnList) key; 1100 resultSets.add(resultset); 1101 } 1102 return resultSets; 1103 } 1104 1105 public List<TObjectNameList> getQueryAliasTables() { 1106 List<TObjectNameList> resultSets = new ArrayList<TObjectNameList>(); 1107 1108 Iterator iter = modelBindingMap.keySet().iterator(); 1109 while (iter.hasNext()) { 1110 Object key = iter.next(); 1111 if (!(key instanceof TObjectNameList)) { 1112 continue; 1113 } 1114 TObjectNameList resultset = (TObjectNameList) key; 1115 resultSets.add(resultset); 1116 } 1117 return resultSets; 1118 } 1119 1120 public List<TSelectSqlStatement> getSelectSetResultSets() { 1121 List<TSelectSqlStatement> resultSets = new ArrayList<TSelectSqlStatement>(); 1122 1123 Iterator iter = modelBindingMap.keySet().iterator(); 1124 while (iter.hasNext()) { 1125 Object key = iter.next(); 1126 if (!(key instanceof TSelectSqlStatement)) { 1127 continue; 1128 } 1129 1130 TSelectSqlStatement stmt = (TSelectSqlStatement) key; 1131 if (stmt.getSetOperatorType() == ESetOperatorType.none) 1132 continue; 1133 1134 resultSets.add(stmt); 1135 } 1136 return resultSets; 1137 } 1138 1139 public List<TCTE> getCTEs() { 1140 List<TCTE> resultSets = new ArrayList<TCTE>(); 1141 1142 Iterator iter = modelBindingMap.keySet().iterator(); 1143 while (iter.hasNext()) { 1144 Object key = iter.next(); 1145 if (!(key instanceof TCTE)) { 1146 continue; 1147 } 1148 1149 TCTE cte = (TCTE) key; 1150 resultSets.add(cte); 1151 } 1152 return resultSets; 1153 } 1154 1155 public List<TTable> getTableWithSelectSetResultSets() { 1156 List<TTable> resultSets = new ArrayList<TTable>(); 1157 1158 Iterator iter = modelBindingMap.keySet().iterator(); 1159 while (iter.hasNext()) { 1160 Object key = iter.next(); 1161 if (!(key instanceof TTable)) { 1162 continue; 1163 } 1164 1165 if (((TTable) key).getSubquery() == null) 1166 continue; 1167 TSelectSqlStatement stmt = ((TTable) key).getSubquery(); 1168 if (stmt.getSetOperatorType() == ESetOperatorType.none) 1169 continue; 1170 1171 resultSets.add((TTable) key); 1172 } 1173 return resultSets; 1174 } 1175 1176 public List<TParseTreeNode> getMergeResultSets() { 1177 List<TParseTreeNode> resultSets = new ArrayList<TParseTreeNode>(); 1178 1179 Iterator iter = modelBindingMap.keySet().iterator(); 1180 while (iter.hasNext()) { 1181 Object key = iter.next(); 1182 if (!(key instanceof TMergeUpdateClause) && !(key instanceof TMergeInsertClause)) { 1183 continue; 1184 } 1185 TParseTreeNode resultset = (TParseTreeNode) key; 1186 resultSets.add(resultset); 1187 } 1188 return resultSets; 1189 } 1190 1191 public List<TParseTreeNode> getOutputResultSets() { 1192 List<TParseTreeNode> resultSets = new ArrayList<TParseTreeNode>(); 1193 1194 Iterator iter = modelBindingMap.keySet().iterator(); 1195 while (iter.hasNext()) { 1196 Object key = iter.next(); 1197 if (!(key instanceof TOutputClause)) { 1198 continue; 1199 } 1200 TParseTreeNode resultset = (TParseTreeNode) key; 1201 resultSets.add(resultset); 1202 } 1203 return resultSets; 1204 } 1205 1206 public List<TParseTreeNode> getUpdateResultSets() { 1207 List<TParseTreeNode> resultSets = new ArrayList<TParseTreeNode>(); 1208 1209 Iterator iter = modelBindingMap.keySet().iterator(); 1210 while (iter.hasNext()) { 1211 Object key = iter.next(); 1212 if (!(key instanceof TUpdateSqlStatement)) { 1213 continue; 1214 } 1215 TParseTreeNode resultset = (TParseTreeNode) key; 1216 resultSets.add(resultset); 1217 } 1218 return resultSets; 1219 } 1220 1221 public List<TParseTreeNode> getFunctoinCalls() { 1222 List<TParseTreeNode> resultSets = new ArrayList<TParseTreeNode>(); 1223 1224 Iterator iter = modelBindingMap.keySet().iterator(); 1225 while (iter.hasNext()) { 1226 Object key = iter.next(); 1227 if (!(key instanceof TFunctionCall) && !(key instanceof TCaseExpression)) { 1228 continue; 1229 } 1230 TParseTreeNode resultset = (TParseTreeNode) key; 1231 resultSets.add(resultset); 1232 } 1233 return resultSets; 1234 } 1235 1236 public List<TParseTreeNode> getAliases() { 1237 List<TParseTreeNode> resultSets = new ArrayList<TParseTreeNode>(); 1238 1239 Iterator iter = modelBindingMap.keySet().iterator(); 1240 while (iter.hasNext()) { 1241 Object key = iter.next(); 1242 if (!(key instanceof TAliasClause)) { 1243 continue; 1244 } 1245 TParseTreeNode resultset = (TParseTreeNode) key; 1246 resultSets.add(resultset); 1247 } 1248 return resultSets; 1249 } 1250 1251 public List<TParseTreeNode> getCursors() { 1252 List<TParseTreeNode> resultSets = new ArrayList<TParseTreeNode>(); 1253 1254 Iterator iter = modelBindingMap.keySet().iterator(); 1255 while (iter.hasNext()) { 1256 Object key = iter.next(); 1257 if (!(key instanceof TCursorDeclStmt) && !(key instanceof TOpenforStmt)) { 1258 continue; 1259 } 1260 TParseTreeNode resultset = (TParseTreeNode) key; 1261 resultSets.add(resultset); 1262 } 1263 return resultSets; 1264 } 1265 1266 public List<TParseTreeNode> getPivotdTables() { 1267 List<TParseTreeNode> resultSets = new ArrayList<TParseTreeNode>(); 1268 1269 Iterator iter = modelBindingMap.keySet().iterator(); 1270 while (iter.hasNext()) { 1271 Object key = iter.next(); 1272 if (!(key instanceof TPivotClause)) { 1273 continue; 1274 } 1275 TParseTreeNode resultset = (TParseTreeNode) key; 1276 resultSets.add(resultset); 1277 } 1278 return resultSets; 1279 } 1280 1281 public void addRelation(Relationship relation) { 1282 if (relation != null && !relationHolder.contains(relation)) { 1283 relationHolder.add(relation); 1284 } 1285 } 1286 1287 public void removeRelation(ImpactRelationship relation) { 1288 if (relation != null) { 1289 relationHolder.remove(relation); 1290 } 1291 } 1292 1293 public Relationship[] getRelations() { 1294 return relationHolder.toArray(new Relationship[0]); 1295 } 1296 1297 public void reset() { 1298 modelBindingMap.clear(); 1299 processModelBindingMap.clear(); 1300 viewModelBindingMap.clear(); 1301 insertModelBindingMap.clear(); 1302 createModelBindingMap.clear(); 1303 createModelQuickBindingMap.clear(); 1304 mergeModelBindingMap.clear(); 1305 updateModelBindingMap.clear(); 1306 cursorModelBindingMap.clear(); 1307 functionTableMap.clear(); 1308 tableNamesMap.clear(); 1309 dropTables.clear(); 1310 procedureNamesMap.clear(); 1311 oraclePackageNamesMap.clear(); 1312 relationHolder.clear(); 1313 tableAliasMap.clear(); 1314 tableHashMap.clear(); 1315 topStmtHashMap.clear(); 1316 hashSQLMap.clear(); 1317 dynamicSQLMap.clear(); 1318 tableSet.clear(); 1319 resultSetSet.clear(); 1320 dblinkTableSet.clear(); 1321 objectTypeIndex.clear(); 1322 collectionToElementTypeIndex.clear(); 1323 pipelinedSignatures.clear(); 1324 pendingPipelinedCallSites.clear(); 1325 resolvingPipelinedFunctions.clear(); 1326 DISPLAY_ID.clear(); 1327 DISPLAY_NAME.clear(); 1328 virtualTableNames.clear(); 1329 } 1330 1331 public void bindCursorModel(TCursorDeclStmt stmt, Variable resultSet) { 1332 String procedureName = DlineageUtil.getProcedureParentName(stmt); 1333 String variableString = stmt.getCursorName().toString(); 1334 if (variableString.startsWith(":")) { 1335 variableString = variableString.substring(variableString.indexOf(":") + 1); 1336 } 1337 if (!SQLUtil.isEmpty(procedureName)) { 1338 variableString = DlineageUtil.getTableFullName(procedureName) + "." + SQLUtil.getIdentifierNormalTableName(variableString); 1339 } 1340 createModelBindingMap.put(DlineageUtil.getTableFullName(variableString), resultSet); 1341 } 1342 1343 public void bindCursorModel(TMssqlDeclare stmt, Variable resultSet) { 1344 String procedureName = DlineageUtil.getProcedureParentName(stmt); 1345 String variableString = stmt.getCursorName().toString(); 1346 if (variableString.startsWith(":")) { 1347 variableString = variableString.substring(variableString.indexOf(":") + 1); 1348 } 1349 if (!SQLUtil.isEmpty(procedureName)) { 1350 variableString = DlineageUtil.getTableFullName(procedureName) + "." + SQLUtil.getIdentifierNormalTableName(variableString); 1351 } 1352 createModelBindingMap.put(DlineageUtil.getTableFullName(variableString), resultSet); 1353 } 1354 1355 public void bindCursorModel(TOpenforStmt stmt, Variable resultSet) { 1356 String procedureName = DlineageUtil.getProcedureParentName(stmt); 1357 String variableString = stmt.getCursorVariableName().toString(); 1358 if (variableString.startsWith(":")) { 1359 variableString = variableString.substring(variableString.indexOf(":") + 1); 1360 } 1361 if (!SQLUtil.isEmpty(procedureName)) { 1362 variableString = DlineageUtil.getTableFullName(procedureName) + "." + SQLUtil.getIdentifierNormalTableName(variableString); 1363 } 1364 createModelBindingMap.put(DlineageUtil.getTableFullName(variableString), resultSet); 1365 } 1366 1367 public void bindCursorModel(TForStmt stmt, Variable resultSet) { 1368 String procedureName = DlineageUtil.getProcedureParentName(stmt); 1369 String variableString = stmt.getCursorName().toString(); 1370 if (variableString.startsWith(":")) { 1371 variableString = variableString.substring(variableString.indexOf(":") + 1); 1372 } 1373 if (!SQLUtil.isEmpty(procedureName)) { 1374 variableString = DlineageUtil.getTableFullName(procedureName) + "." + SQLUtil.getIdentifierNormalTableName(variableString); 1375 } 1376 createModelBindingMap.put(DlineageUtil.getTableFullName(variableString), resultSet); 1377 } 1378 1379 public void bindCursorModel(TLoopStmt stmt, Variable resultSet) { 1380 String procedureName = DlineageUtil.getProcedureParentName(stmt); 1381 String variableString = stmt.getRecordName().toString(); 1382 if (variableString.startsWith(":")) { 1383 variableString = variableString.substring(variableString.indexOf(":") + 1); 1384 } 1385 if (!SQLUtil.isEmpty(procedureName)) { 1386 variableString = DlineageUtil.getTableFullName(procedureName) + "." + SQLUtil.getIdentifierNormalTableName(variableString); 1387 } 1388 createModelBindingMap.put(DlineageUtil.getTableFullName(variableString), resultSet); 1389 } 1390 1391 public void bindCursorIndex(TObjectName indexName, TObjectName cursorName) { 1392 TCustomSqlStatement stmt = getGlobalStmtStack().peek(); 1393 String procedureName = DlineageUtil.getProcedureParentName(stmt); 1394 String variableString = cursorName.toString(); 1395 if (variableString.startsWith(":")) { 1396 variableString = variableString.substring(variableString.indexOf(":") + 1); 1397 } 1398 if (!SQLUtil.isEmpty(procedureName)) { 1399 variableString = DlineageUtil.getTableFullName(procedureName) + "." + SQLUtil.getIdentifierNormalTableName(variableString); 1400 } 1401 1402 Variable cursor = ((Variable) createModelBindingMap 1403 .get(DlineageUtil.getTableFullName(variableString))); 1404 if (cursor != null) { 1405 String indexNameString = indexName.toString(); 1406 if (!SQLUtil.isEmpty(procedureName)) { 1407 indexNameString = DlineageUtil.getTableFullName(procedureName) + "." + SQLUtil.getIdentifierNormalTableName(indexNameString); 1408 } 1409 if (cursor instanceof Cursor) { 1410 bindModel(DlineageUtil.getTableFullName(indexNameString), 1411 modelBindingMap.get(((Cursor)cursor).getResultColumnObject())); 1412 } 1413 bindTableByName(DlineageUtil.getTableFullName(indexNameString), 1414 cursor); 1415 } 1416 } 1417 1418 public List<TStoredProcedureSqlStatement> getProcedures() { 1419 List<TStoredProcedureSqlStatement> procedures = new ArrayList(); 1420 Iterator iter = this.modelBindingMap.keySet().iterator(); 1421 1422 while (iter.hasNext()) { 1423 Object key = iter.next(); 1424 if (key instanceof TStoredProcedureSqlStatement) { 1425 TStoredProcedureSqlStatement procedure = (TStoredProcedureSqlStatement) key; 1426 procedures.add(procedure); 1427 } 1428 } 1429 1430 return procedures; 1431 } 1432 1433 // public void bindTableByName(TObjectName tableName, Table tableModel) { 1434 // tableNamesMap.put(tableName, tableModel); 1435 // 1436 // } 1437 // 1438 public void bindTableByName(String tableName, Table tableModel) { 1439 tableNamesMap.put(tableName, tableModel); 1440 1441 } 1442 1443 // public Table getTableByName(TObjectName tableName) { 1444 // return (Table)tableNamesMap.get(tableName); 1445 // } 1446 1447 /** 1448 * B3 (routine-summary-scc-design §3): the overload-discriminating scope 1449 * of the routine whose body is being analyzed, active ONLY under 1450 * {@code Option.identityFirstVariablePools}. Held here (not just in the 1451 * factory) because DIRECT name lookups all funnel through 1452 * {@link #getTableByName(String)} — without this, a same-named 1453 * overload's reads fall back to the SHARED procedure-composed key and 1454 * cross-contaminate the pools (codex-B3-r2 finding 7). Empty in LEGACY 1455 * by construction. 1456 */ 1457 private final java.util.ArrayDeque<String> identityScopeStack = 1458 new java.util.ArrayDeque<String>(); 1459 public void pushIdentityScope(String identityScopeKey) { 1460 if (identityScopeKey != null) { 1461 identityScopeStack.push(identityScopeKey); 1462 } 1463 } 1464 1465 public void popIdentityScope() { 1466 if (!identityScopeStack.isEmpty()) { 1467 identityScopeStack.pop(); 1468 } 1469 } 1470 1471 public boolean hasIdentityScope() { 1472 return !identityScopeStack.isEmpty(); 1473 } 1474 1475 public String peekIdentityScope() { 1476 return identityScopeStack.peek(); 1477 } 1478 1479 public Table getTableByName(String tableName) { 1480 if (tableName == null) { 1481 return null; 1482 } 1483 Table table = (Table) tableNamesMap.get(tableName); 1484 // A direct hit that is a VARIABLE may be the legacy shared-key 1485 // binding of a same-named overload (cursor-fetch readers pass the 1486 // shared qualified key) — under an active identity scope the pool 1487 // binding wins (codex-B3-r3 finding 2a). Non-variable hits (real 1488 // tables) keep winning unchanged; stack is empty in LEGACY. 1489 // An identity-scoped request (\u0002-prefixed) is already 1490 // pool-precise: redirecting it to the ACTIVE scope would hand an 1491 // explicit callee-formal lookup the CALLER's same-named variable 1492 // (codex-B3-r4 finding 1). 1493 if (table instanceof Variable && !identityScopeStack.isEmpty() 1494 && !tableName.startsWith("\u0002")) { 1495 java.util.List<String> segments = SQLUtil.parseNames(tableName); 1496 String simple = segments.isEmpty() 1497 ? tableName : segments.get(segments.size() - 1); 1498 Object pooled = tableNamesMap.get(identityScopeStack.peek() + "." 1499 + SQLUtil.getIdentifierNormalTableName(simple)); 1500 if (pooled instanceof Variable) { 1501 return (Table) pooled; 1502 } 1503 } 1504 if (table == null) { 1505 Stack<TCustomSqlStatement> stmtStack = getGlobalStmtStack(); 1506 if (stmtStack.isEmpty()) { 1507 return (Table) tableNamesMap.get(DlineageUtil.getTableFullName(tableName.toString())); 1508 } 1509 TCustomSqlStatement stmt = stmtStack.peek(); 1510 String procedureName = DlineageUtil.getProcedureParentName(stmt); 1511 String variableString = tableName.toString(); 1512 // Identity-first pool resolution (mode-gated: stack empty in 1513 // LEGACY). Only VARIABLE hits short-circuit — a real table that 1514 // resolved above already won, exactly as before. 1515 if (!identityScopeStack.isEmpty() 1516 && !tableName.startsWith("\u0002")) { // never re-scope an identity key 1517 Object pooled = tableNamesMap.get(identityScopeStack.peek() + "." 1518 + SQLUtil.getIdentifierNormalTableName(variableString)); 1519 if (pooled instanceof Variable) { 1520 return (Table) pooled; 1521 } 1522 } 1523 if (!SQLUtil.isEmpty(procedureName) && !tableName.startsWith("\u0002")) { 1524 java.util.List<String> segments = SQLUtil.parseNames(variableString); 1525 String simpleName = segments.isEmpty() ? variableString : segments.get(segments.size() - 1); 1526 String variableWithProcedure = DlineageUtil.getTableFullName(procedureName) + "." + SQLUtil.getIdentifierNormalTableName(simpleName); 1527 if(tableNamesMap.containsKey(DlineageUtil.getTableFullName(variableWithProcedure))) { 1528 return (Table) tableNamesMap.get(DlineageUtil.getTableFullName(variableWithProcedure)); 1529 } 1530 } 1531 return (Table) tableNamesMap.get(DlineageUtil.getTableFullName(variableString)); 1532 } else { 1533 return table; 1534 } 1535 } 1536 1537 1538 public void bindProcedureByName(String procedureName, Procedure procedureModel) { 1539 procedureNamesMap.put(procedureName, procedureModel); 1540 1541 } 1542 1543 public Procedure getProcedureByName(String procedureName) { 1544 if(procedureName == null){ 1545 return null; 1546 } 1547 1548 if (ModelBindingManager.getGlobalOraclePackage() != null 1549 && !procedureName.startsWith(ModelBindingManager.getGlobalOraclePackage().getName())) { 1550 procedureName = ModelBindingManager.getGlobalOraclePackage().getName() + "." + procedureName; 1551 } 1552 Procedure procedure = (Procedure) procedureNamesMap.get(procedureName); 1553 if (procedure == null) { 1554 if (procedureName.indexOf("(") == -1) { 1555 for (Object name : procedureNamesMap.keySet()) { 1556 String fuctionName = name.toString(); 1557 if (fuctionName.startsWith(procedureName + "(")) { 1558 return (Procedure) procedureNamesMap.get(name); 1559 } 1560 if (fuctionName.indexOf(".") != -1 && procedureName.indexOf(".") == -1) { 1561 fuctionName = fuctionName.substring(fuctionName.lastIndexOf(".") + 1); 1562 if (fuctionName.startsWith(procedureName + "(")) { 1563 return (Procedure) procedureNamesMap.get(name); 1564 } 1565 } 1566 if (fuctionName.indexOf(".") == -1 && procedureName.indexOf(".") != -1) { 1567 String procedureNameSubstring = procedureName.substring(procedureName.lastIndexOf(".") + 1); 1568 if (fuctionName.startsWith(procedureNameSubstring + "(")) { 1569 return (Procedure) procedureNamesMap.get(name); 1570 } 1571 } 1572 } 1573 } 1574 else { 1575 for (Object name : procedureNamesMap.keySet()) { 1576 String fuctionName = name.toString(); 1577 if (fuctionName.startsWith(procedureName)) { 1578 return (Procedure) procedureNamesMap.get(name); 1579 } 1580 if (fuctionName.indexOf(".") != -1 && procedureName.indexOf(".") == -1) { 1581 fuctionName = fuctionName.substring(fuctionName.lastIndexOf(".") + 1); 1582 if (DlineageUtil.sameName(ESQLDataObjectType.dotProcedure, fuctionName, procedureName)) { 1583 return (Procedure) procedureNamesMap.get(name); 1584 } 1585 } 1586 if (fuctionName.indexOf(".") == -1 && procedureName.indexOf(".") != -1) { 1587 String procedureNameSubstring = procedureName.substring(procedureName.lastIndexOf(".") + 1); 1588 if (DlineageUtil.sameName(ESQLDataObjectType.dotProcedure, fuctionName, procedureNameSubstring)) { 1589 return (Procedure) procedureNamesMap.get(name); 1590 } 1591 } 1592 } 1593 } 1594 } 1595 return procedure; 1596 } 1597 1598 public void bindOraclePackageByName(String oraclePackageName, OraclePackage oraclePackageModel) { 1599 oraclePackageNamesMap.put(oraclePackageName, oraclePackageModel); 1600 1601 } 1602 1603 public OraclePackage getOraclePackageByName(String oraclePackageName) { 1604 return (OraclePackage) oraclePackageNamesMap.get(oraclePackageName); 1605 } 1606 1607 1608 public String getSqlHash(TCustomSqlStatement stmt) { 1609 return topStmtHashMap.get(stmt); 1610 } 1611 1612 public Map getHashSQLMap() { 1613 return hashSQLMap; 1614 } 1615 1616 public Map getDynamicSQLMap() { 1617 return dynamicSQLMap; 1618 } 1619 1620 public void collectSqlHash(TCustomSqlStatement stmt) { 1621 if (getGlobalOption().getAnalyzeMode() == AnalyzeMode.crud) { 1622 String sql = stmt.toString(); 1623 if (sql != null) { 1624 sql = stmt.getStartToken().lineNo + ":" + sql; 1625 String hash = SQLUtil.stringToMD5(sql); 1626 topStmtHashMap.put(stmt, hash); 1627 hashSQLMap.put(hash, new Pair3<Long, Long, String>(stmt.getStartToken().lineNo, stmt.getEndToken().lineNo, ModelBindingManager.getGlobalHash())); 1628 } 1629 } else { 1630 try { 1631 String sql = stmt.asCanonical(); 1632 if (sql != null) { 1633 String hash = SQLUtil.stringToMD5(sql); 1634 topStmtHashMap.put(stmt, hash); 1635 hashSQLMap.put(hash, sql); 1636 } 1637 } catch (Exception e) { 1638 logger.error("collectSqlHash error: " + e.getMessage(), e); 1639 } 1640 } 1641 } 1642 1643 public void collectDynamicSqlHash(TCustomSqlStatement stmt) { 1644 if (getGlobalOption().getAnalyzeMode() == AnalyzeMode.dynamic) { 1645 String sql = stmt.toString(); 1646 if (sql != null) { 1647 sql = stmt.getStartToken().lineNo + ":" + sql; 1648 String hash = SQLUtil.stringToMD5(sql); 1649 dynamicSQLMap.put(hash, new Pair3<Long, Long, String>(stmt.getStartToken().lineNo, stmt.getEndToken().lineNo, ModelBindingManager.getGlobalHash())); 1650 } 1651 } 1652 } 1653 1654 public void appendDblinkTable(String name) { 1655 if (!SQLUtil.isEmpty(name)) { 1656 dblinkTableSet.add(name); 1657 } 1658 } 1659 1660 public boolean isDblinkTable(String name) { 1661 return dblinkTableSet.contains(name); 1662 } 1663 1664 public Set<ResultSet> getResultSets() { 1665 return resultSetSet; 1666 } 1667 1668 public void dropTable(Table table) { 1669 List tableNames = new ArrayList(tableNamesMap.keySet()); 1670 for (Object tableName : tableNames) { 1671 if(tableNamesMap.get(tableName) == table) { 1672 tableNamesMap.remove(tableName); 1673 dropTables.add(table); 1674 } 1675 } 1676 } 1677 1678 public void cleanTempTable() { 1679 Iterator<String> iter = tableNamesMap.keySet().iterator(); 1680 while(iter.hasNext()) { 1681 String tableName = iter.next(); 1682 if(DlineageUtil.isTempTable((Table)tableNamesMap.get(tableName), getGlobalVendor())) { 1683 dropTables.add((Table)tableNamesMap.get(tableName)); 1684 iter.remove(); 1685 } 1686 } 1687 } 1688 1689 public Set<Table> getDropTables() { 1690 return dropTables; 1691 } 1692 1693 // --- Pipelined function stitching methods --- 1694 1695 public void indexObjectType(String normalizedName, List<String> fieldNames) { 1696 objectTypeIndex.put(normalizedName, fieldNames); 1697 } 1698 1699 public List<String> getObjectTypeFields(String normalizedName) { 1700 return objectTypeIndex.get(normalizedName); 1701 } 1702 1703 public void indexCollectionType(String collectionName, String elementTypeName) { 1704 collectionToElementTypeIndex.put(collectionName, elementTypeName); 1705 } 1706 1707 public String getElementTypeName(String collectionName) { 1708 return collectionToElementTypeIndex.get(collectionName); 1709 } 1710 1711 public void addPipelinedSignature(PipelinedFunctionSignature sig) { 1712 pipelinedSignatures.computeIfAbsent(sig.getFunctionKey(), k -> new ArrayList<>()).add(sig); 1713 if (sig.getNakedKey() != null && !sig.getNakedKey().equals(sig.getFunctionKey())) { 1714 pipelinedSignatures.computeIfAbsent(sig.getNakedKey(), k -> new ArrayList<>()).add(sig); 1715 } 1716 } 1717 1718 public PipelinedFunctionSignature findPipelinedSignature(List<String> candidates, int argCount) { 1719 for (String key : candidates) { 1720 List<PipelinedFunctionSignature> sigs = pipelinedSignatures.get(key); 1721 if (sigs != null) { 1722 PipelinedFunctionSignature match = null; 1723 for (PipelinedFunctionSignature sig : sigs) { 1724 if (sig.getArgCount() == argCount || argCount < 0) { 1725 if (match != null) { 1726 return null; // ambiguous 1727 } 1728 match = sig; 1729 } 1730 } 1731 if (match != null) { 1732 return match; 1733 } 1734 } 1735 } 1736 return null; 1737 } 1738 1739 public PipelinedFunctionSignature findPipelinedSignatureAny(List<String> candidates) { 1740 for (String key : candidates) { 1741 List<PipelinedFunctionSignature> sigs = pipelinedSignatures.get(key); 1742 if (sigs != null && !sigs.isEmpty()) { 1743 if (sigs.size() == 1) { 1744 return sigs.get(0); 1745 } 1746 } 1747 } 1748 return null; 1749 } 1750 1751 public void addPendingPipelinedCallSite(PendingPipelinedCallSite callSite) { 1752 pendingPipelinedCallSites.add(callSite); 1753 } 1754 1755 public List<PendingPipelinedCallSite> getPendingPipelinedCallSites() { 1756 return pendingPipelinedCallSites; 1757 } 1758 1759 public Set<String> getResolvingPipelinedFunctions() { 1760 return resolvingPipelinedFunctions; 1761 } 1762 1763 public Map<String, List<PipelinedFunctionSignature>> getPipelinedSignatures() { 1764 return pipelinedSignatures; 1765 } 1766 1767}