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