001package gudusoft.gsqlparser.dlineage.util;
002
003import java.io.File;
004import java.util.ArrayList;
005import java.util.Arrays;
006import java.util.LinkedHashSet;
007import java.util.List;
008import java.util.Map;
009import java.util.Set;
010
011import gudusoft.gsqlparser.EDbVendor;
012import gudusoft.gsqlparser.EParameterMode;
013import gudusoft.gsqlparser.TCustomSqlStatement;
014import gudusoft.gsqlparser.dlineage.dataflow.model.AnalyzeMode;
015import gudusoft.gsqlparser.dlineage.dataflow.model.ModelBindingManager;
016import gudusoft.gsqlparser.dlineage.dataflow.model.Option;
017import gudusoft.gsqlparser.dlineage.dataflow.model.SqlInfo;
018import gudusoft.gsqlparser.dlineage.dataflow.model.SubType;
019import gudusoft.gsqlparser.dlineage.dataflow.model.Table;
020import gudusoft.gsqlparser.dlineage.dataflow.model.xml.*;
021import gudusoft.gsqlparser.nodes.TFunctionCall;
022import gudusoft.gsqlparser.nodes.TObjectName;
023import gudusoft.gsqlparser.nodes.TParameterDeclaration;
024import gudusoft.gsqlparser.nodes.TParameterDeclarationList;
025import gudusoft.gsqlparser.sqlenv.ESQLDataObjectType;
026import gudusoft.gsqlparser.sqlenv.TSQLEnv;
027import gudusoft.gsqlparser.stmt.TCommonBlock;
028import gudusoft.gsqlparser.stmt.TSelectSqlStatement;
029import gudusoft.gsqlparser.stmt.TStoredProcedureSqlStatement;
030import gudusoft.gsqlparser.stmt.oracle.TPlsqlCreatePackage;
031import gudusoft.gsqlparser.TBaseType;
032import gudusoft.gsqlparser.util.SQLUtil;
033import gudusoft.gsqlparser.stmt.teradata.TTeradataCreateProcedure;
034import gudusoft.gsqlparser.util.SQLUtil;
035import gudusoft.gsqlparser.util.functionChecker;
036import gudusoft.gsqlparser.util.keywordChecker;
037import gudusoft.gsqlparser.util.json.JSON;
038
039public class DlineageUtil {
040
041    public static boolean compareIdentifier(String source, String target, ESQLDataObjectType sqlDataObjectType) {
042        return SQLUtil.compareIdentifier(ModelBindingManager.getGlobalVendor(), sqlDataObjectType, source, target);
043    }
044
045    public static boolean compareColumnIdentifier(String source, String target) {
046        return SQLUtil.compareIdentifier(ModelBindingManager.getGlobalVendor(), ESQLDataObjectType.dotColumn, source,
047                target);
048    }
049
050    public static boolean compareTableIdentifier(String source, String target) {
051        return SQLUtil.compareIdentifier(ModelBindingManager.getGlobalVendor(), ESQLDataObjectType.dotTable, source,
052                target);
053    }
054
055        public static String getIdentifierNormalColumnName(String name) {
056                EDbVendor dbVendor = ModelBindingManager.getGlobalVendor();
057                return SQLUtil.getIdentifierNormalName(dbVendor, name, ESQLDataObjectType.dotColumn);
058        }
059
060        public static String getIdentifierNormalColumnName(String name, EDbVendor dbVendor) {
061                return SQLUtil.getIdentifierNormalName(dbVendor, name, ESQLDataObjectType.dotColumn);
062        }
063
064    public static String normalizeColumnName(String name) {
065        return SQLUtil.normalizeIdentifier(ModelBindingManager.getGlobalVendor(),  ESQLDataObjectType.dotColumn, name);
066    }
067    
068    public static String normalizeColumnName(String name, EDbVendor dbVendor) {
069        return SQLUtil.normalizeIdentifier(dbVendor,  ESQLDataObjectType.dotColumn, name);
070    }
071
072    
073    public static String getIdentifierNormalTableName(String name) {
074                if (name == null) {
075                        return null;
076                }
077                if (ModelBindingManager.get() != null && ModelBindingManager.get().isDblinkTable(name)) {
078                        int index = name.lastIndexOf("@");
079                        if (index > 0) {
080                                return SQLUtil.getIdentifierNormalName(ModelBindingManager.getGlobalVendor(), name.substring(0, index),
081                                                ESQLDataObjectType.dotTable) + name.substring(index);
082                        } else {
083                                return name;
084                        }
085                }
086                if (name.endsWith(")") && name.indexOf("(") != -1) {
087                        return SQLUtil.getIdentifierNormalName(ModelBindingManager.getGlobalVendor(),
088                                        name.substring(0, name.lastIndexOf("(")), ESQLDataObjectType.dotTable)
089                                        + name.substring(name.lastIndexOf("("));
090                }
091        return SQLUtil.getIdentifierNormalName(ModelBindingManager.getGlobalVendor(), name,
092                ESQLDataObjectType.dotTable);
093    }
094
095    public static String getIdentifierNormalFunctionName(String name) {
096        return SQLUtil.getIdentifierNormalName(ModelBindingManager.getGlobalVendor(), name,
097                ESQLDataObjectType.dotFunction);
098    }
099
100    public static String getIdentifierNormalName(String name, ESQLDataObjectType sqlDataObjectType) {
101        return SQLUtil.getIdentifierNormalName(ModelBindingManager.getGlobalVendor(), name, sqlDataObjectType);
102    }
103
104    public static String getColumnName(TObjectName column) {
105        if (column == null || column.toString() == null) {
106            return null;
107        }
108        String name = column.getColumnNameOnly();
109        if (name == null || "".equals(name.trim())) {
110            return getIdentifierNormalColumnName(column.toString().trim());
111        } else
112            return getIdentifierNormalColumnName(name.trim());
113    }
114    
115    public static String getColumnName(String column) {
116                if (column == null) {
117                        return null;
118                }
119                String name = column.substring(column.lastIndexOf(".") + 1);
120                if (name == null || "".equals(name.trim())) {
121                        return DlineageUtil.getIdentifierNormalColumnName(column.toString().trim());
122                } else
123                        return DlineageUtil.getIdentifierNormalColumnName(name.trim());
124        }
125
126    public static boolean isTempTable(Table tableModel, EDbVendor vendor) {
127                if (SubType.temp_table == tableModel.getSubType()) {
128                        return true;
129                }
130        switch (vendor) {
131            case dbvmssql:
132            case dbvazuresql:
133                return tableModel.getName().startsWith("#") && !tableModel.getName().startsWith("##");
134            default:
135                return false;
136        }
137    }
138
139    public static String getTableFullName(String tableName) {
140                if (ModelBindingManager.get() != null && ModelBindingManager.get().isDblinkTable(tableName)) {
141                        return tableName;
142                }
143
144        if(tableName == null){
145            return null;
146        }
147
148        if (tableName.startsWith("`") && tableName.endsWith("`") && tableName.indexOf(".") != -1
149                                && ModelBindingManager.getGlobalOption().getVendor() == EDbVendor.dbvbigquery) {
150                        tableName = SQLUtil.trimColumnStringQuote(tableName);
151                }
152        List<String> segments = SQLUtil.parseNames(tableName);
153        if (segments.size() == 1) {
154            StringBuffer buffer = new StringBuffer();
155            if (ModelBindingManager.getGlobalDatabase() != null) {
156                buffer.append(ModelBindingManager.getGlobalDatabase()).append(".");
157            }
158            if (ModelBindingManager.getGlobalSchema() != null) {
159                buffer.append(ModelBindingManager.getGlobalSchema()).append(".");
160            }
161            buffer.append(tableName);
162            return getIdentifierNormalTableName(buffer.toString());
163        } else if (segments.size() == 2) {
164            if (ModelBindingManager.getGlobalDatabase() != null) {
165                return getIdentifierNormalTableName(ModelBindingManager.getGlobalDatabase() + "." + tableName);
166            } else {
167                return getIdentifierNormalTableName(tableName);
168            }
169        } else {
170            if ((ModelBindingManager.getGlobalVendor() == EDbVendor.dbvmssql
171                    || ModelBindingManager.getGlobalVendor() == EDbVendor.dbvazuresql) && tableName.indexOf("..") != -1) {
172                if (ModelBindingManager.getGlobalSchema() != null) {
173                    return getIdentifierNormalTableName(
174                            tableName.replace("..", "." + ModelBindingManager.getGlobalSchema() + "."));
175                } else if (ModelBindingManager.getGlobalVendor() == EDbVendor.dbvmssql
176                        || ModelBindingManager.getGlobalVendor() == EDbVendor.dbvazuresql) {
177                    return getIdentifierNormalTableName(tableName.replace("..", ".dbo."));
178                } else {
179                    return getIdentifierNormalTableName(tableName);
180                }
181            } else {
182                return getIdentifierNormalTableName(tableName);
183            }
184        }
185    }
186
187
188    
189    public static String getSimpleTableName(String tableName) {
190        if (tableName.startsWith("`") && tableName.endsWith("`") && tableName.indexOf(".") != -1
191                                && ModelBindingManager.getGlobalOption().getVendor() == EDbVendor.dbvbigquery) {
192                        tableName = SQLUtil.trimColumnStringQuote(tableName);
193                }
194        List<String> segments = SQLUtil.parseNames(tableName);
195        return segments.get(segments.size()-1);
196    }
197    
198    public static String getColumnNameOnly(String columnName) {
199        if (columnName.startsWith("`") && columnName.endsWith("`") && columnName.indexOf(".") != -1
200                                && ModelBindingManager.getGlobalOption().getVendor() == EDbVendor.dbvbigquery) {
201                columnName = SQLUtil.trimColumnStringQuote(columnName);
202                }
203        List<String> segments = SQLUtil.parseNames(columnName);
204        return segments.get(segments.size()-1);
205    }
206
207    public static String getTableSchema(String tableName) {
208        EDbVendor vendor = ModelBindingManager.getGlobalOption().getVendor();
209        boolean supportSchema = TSQLEnv.supportSchema(vendor);
210
211        if (tableName.startsWith("`") && tableName.endsWith("`") && tableName.indexOf(".") != -1
212                && ModelBindingManager.getGlobalOption().getVendor() == EDbVendor.dbvbigquery) {
213            tableName = SQLUtil.trimColumnStringQuote(tableName);
214        }
215        List<String> segments = SQLUtil.parseNames(tableName);
216        if (segments.size() == 1) {
217            if (supportSchema && ModelBindingManager.getGlobalSchema() != null) {
218                return ModelBindingManager.getGlobalSchema();
219            }
220        } else if (segments.size() == 2) {
221            if(supportSchema) {
222                return segments.get(0);
223            }
224        } else {
225            if (ModelBindingManager.getGlobalVendor() == EDbVendor.dbvmssql && tableName.indexOf("..") != -1) {
226                if (ModelBindingManager.getGlobalSchema() != null) {
227                    return ModelBindingManager.getGlobalSchema();
228                } else if (ModelBindingManager.getGlobalVendor() == EDbVendor.dbvmssql) {
229                    return "dbo";
230                }
231            } else {
232                if(supportSchema) {
233                    return segments.get(segments.size() - 2);
234                }
235            }
236        }
237        return null;
238    }
239
240    public static String getTableServer(String tableName) {
241        EDbVendor vendor = ModelBindingManager.getGlobalOption().getVendor();
242        boolean supportCatalog = TSQLEnv.supportCatalog(vendor);
243        boolean supportSchema = TSQLEnv.supportSchema(vendor);
244
245        if (tableName.startsWith("`") && tableName.endsWith("`") && tableName.indexOf(".") != -1
246                && ModelBindingManager.getGlobalOption().getVendor() == EDbVendor.dbvbigquery) {
247            tableName = SQLUtil.trimColumnStringQuote(tableName);
248        }
249        List<String> segments = SQLUtil.parseNames(tableName);
250        if (segments.size() <= 2) {
251            return ModelBindingManager.getGlobalServer();
252        } else if (segments.size() == 3) {
253            if(supportCatalog && supportSchema) {
254                return ModelBindingManager.getGlobalServer();
255            } else {
256                return segments.get(0);
257            }
258        } else {
259            if(supportCatalog && supportSchema) {
260                    return segments.get(segments.size() - 4);
261            } else {
262                return segments.get(segments.size() - 3);
263            }
264        }
265    }
266
267    public static String getTableDatabase(String tableName) {
268        EDbVendor vendor = ModelBindingManager.getGlobalOption().getVendor();
269        boolean supportCatalog = TSQLEnv.supportCatalog(vendor);
270        boolean supportSchema = TSQLEnv.supportSchema(vendor);
271
272        if (tableName.startsWith("`") && tableName.endsWith("`") && tableName.indexOf(".") != -1
273                                && ModelBindingManager.getGlobalOption().getVendor() == EDbVendor.dbvbigquery) {
274                        tableName = SQLUtil.trimColumnStringQuote(tableName);
275                }
276        List<String> segments = SQLUtil.parseNames(tableName);
277        if (segments.size() == 1) {
278            if (supportCatalog && ModelBindingManager.getGlobalDatabase() != null) {
279                return ModelBindingManager.getGlobalDatabase();
280            }
281        } else if (segments.size() == 2) {
282            if(supportCatalog && supportSchema) {
283                if (ModelBindingManager.getGlobalDatabase() != null) {
284                    return ModelBindingManager.getGlobalDatabase();
285                }
286            } else {
287                if (supportCatalog) {
288                    return segments.get(0);
289                }
290            }
291        } else {
292            if (ModelBindingManager.getGlobalVendor() == EDbVendor.dbvmssql && tableName.indexOf("..") != -1) {
293                String fullName = tableName;
294                if (ModelBindingManager.getGlobalSchema() != null) {
295                    fullName = getIdentifierNormalTableName(
296                            tableName.replace("..", "." + ModelBindingManager.getGlobalSchema() + "."));
297                } else if (ModelBindingManager.getGlobalVendor() == EDbVendor.dbvmssql) {
298                    fullName = getIdentifierNormalTableName(tableName.replace("..", ".dbo."));
299                } else {
300                    fullName = getIdentifierNormalTableName(tableName);
301                }
302                return getTableDatabase(fullName);
303            } else {
304                if(supportCatalog && supportSchema) {
305                    return segments.get(segments.size() - 3);
306                }
307                else if(supportCatalog){
308                    return segments.get(segments.size() - 2);
309                }
310            }
311        }
312        return null;
313    }
314
315    public static String getTableFullNameWithDefaultSchema(String tableName) {
316        EDbVendor vendor = ModelBindingManager.getGlobalOption().getVendor();
317        boolean supportCatalog = TSQLEnv.supportCatalog(vendor);
318        boolean supportSchema = TSQLEnv.supportSchema(vendor);
319
320        if (tableName.startsWith("`") && tableName.endsWith("`") && tableName.indexOf(".") != -1
321                                && ModelBindingManager.getGlobalOption().getVendor() == EDbVendor.dbvbigquery) {
322                        tableName = SQLUtil.trimColumnStringQuote(tableName);
323                }
324        List<String> segments = SQLUtil.parseNames(tableName);
325        if (segments.size() == 1) {
326            StringBuffer buffer = new StringBuffer();
327            if (supportCatalog && ModelBindingManager.getGlobalDatabase() != null) {
328                buffer.append(ModelBindingManager.getGlobalDatabase()).append(".");
329            }
330            if (supportSchema && ModelBindingManager.getGlobalSchema() != null) {
331                buffer.append(ModelBindingManager.getGlobalSchema()).append(".");
332            } else if (ModelBindingManager.getGlobalVendor() == EDbVendor.dbvmssql) {
333                buffer.append("dbo").append(".");
334            }
335            buffer.append(tableName);
336            return getIdentifierNormalTableName(buffer.toString());
337        } else if (segments.size() == 2) {
338            if (supportCatalog && supportSchema && ModelBindingManager.getGlobalDatabase() != null) {
339                return getIdentifierNormalTableName(ModelBindingManager.getGlobalDatabase() + "." + tableName);
340            } else {
341                return getIdentifierNormalTableName(tableName);
342            }
343        } else {
344            if (ModelBindingManager.getGlobalVendor() == EDbVendor.dbvmssql && tableName.indexOf("..") != -1) {
345                if (ModelBindingManager.getGlobalSchema() != null) {
346                    return getIdentifierNormalTableName(
347                            tableName.replace("..", "." + ModelBindingManager.getGlobalSchema() + "."));
348                } else if (ModelBindingManager.getGlobalVendor() == EDbVendor.dbvmssql) {
349                    return getIdentifierNormalTableName(tableName.replace("..", ".dbo."));
350                } else {
351                    return getIdentifierNormalTableName(tableName);
352                }
353            } else {
354                return getIdentifierNormalTableName(tableName);
355            }
356        }
357    }
358
359    @SuppressWarnings("rawtypes")
360    public static SqlInfo[] convertSQL(File file, String json) {
361        List<SqlInfo> sqlInfos = new ArrayList<SqlInfo>();
362        try {
363            List sqlContents = (List) JSON.parseObject(json);
364            for (int j = 0; j < sqlContents.size(); j++) {
365                Map sqlContent = (Map) sqlContents.get(j);
366                String sql = (String) sqlContent.get("sql");
367                String fileName = (String) sqlContent.get("fileName");
368                String filePath = (String) sqlContent.get("filePath");
369                if (sql != null && sql.trim().startsWith("{")) {
370                    Map queryObject = (Map) JSON.parseObject(sql);
371                    List querys = (List) queryObject.get("queries");
372                    if (querys != null) {
373                        for (int i = 0; i < querys.size(); i++) {
374                            Map object = (Map) querys.get(i);
375                            SqlInfo info = new SqlInfo();
376                            info.setSql(JSON.toJSONString(object));
377                            info.setFileName(fileName);
378                            info.setFilePath(filePath);
379                            info.setOriginIndex(i);
380                            sqlInfos.add(info);
381                        }
382                    } else {
383                        SqlInfo info = new SqlInfo();
384                        info.setSql(JSON.toJSONString(queryObject));
385                        info.setFileName(fileName);
386                        info.setFilePath(filePath);
387                        info.setOriginIndex(0);
388                        sqlInfos.add(info);
389                    }
390                } else if (sql != null) {
391                    SqlInfo info = new SqlInfo();
392                    info.setSql(sql);
393                    info.setFileName(fileName);
394                    info.setFilePath(filePath);
395                    info.setOriginIndex(0);
396                    sqlInfos.add(info);
397                }
398            }
399        } catch (Exception e) {
400            try {
401                Map queryObject = (Map) JSON.parseObject(json);
402                List querys = (List) queryObject.get("queries");
403                if (querys != null) {
404                    for (int i = 0; i < querys.size(); i++) {
405                        Map object = (Map) querys.get(i);
406                        SqlInfo info = new SqlInfo();
407                        info.setSql(JSON.toJSONString(object));
408                        if (file != null) {
409                            info.setFileName(file.getName());
410                            info.setFilePath(file.getAbsolutePath());
411                        }
412                        info.setOriginIndex(i);
413                        sqlInfos.add(info);
414                    }
415                } else {
416                    SqlInfo info = new SqlInfo();
417                    info.setSql(JSON.toJSONString(queryObject));
418                    if (file != null) {
419                        info.setFileName(file.getName());
420                        info.setFilePath(file.getAbsolutePath());
421                    }
422                    info.setOriginIndex(0);
423                    sqlInfos.add(info);
424                }
425            } catch (Exception e1) {
426                SqlInfo info = new SqlInfo();
427                info.setSql(json);
428                if (file != null) {
429                    info.setFileName(file.getName());
430                    info.setFilePath(file.getAbsolutePath());
431                }
432                info.setOriginIndex(0);
433                sqlInfos.add(info);
434            }
435        }
436        return sqlInfos.toArray(new SqlInfo[0]);
437    }
438
439    
440        public static String getQualifiedTableName(table table) {
441                boolean supportCatalog = TSQLEnv.supportCatalog(ModelBindingManager.getGlobalVendor());
442                boolean supportSchema = TSQLEnv.supportSchema(ModelBindingManager.getGlobalVendor());
443                StringBuilder buffer = new StringBuilder();
444                if (supportCatalog && supportSchema) {
445                        if (!SQLUtil.isEmpty(table.getDatabase())) {
446                                if (ModelBindingManager.getGlobalVendor() == EDbVendor.dbvoracle
447                                                && SubType.dblink.name().equals(table.getSubType())) {
448                                        //dblink doesn't set database
449                                } else {
450                                        buffer.append(table.getDatabase());
451                                }
452                        }
453                        if (!SQLUtil.isEmpty(table.getSchema())) {
454                                if (buffer.length() > 0) {
455                                        buffer.append(".");
456                                }
457                                buffer.append(table.getSchema());
458                        } else {
459                                if (buffer.length() > 0) {
460                                        buffer.append(".");
461                                        if (ModelBindingManager.getGlobalVendor() == EDbVendor.dbvmssql) {
462                                                buffer.append("dbo");
463                                        } else {
464                                                buffer.append(TSQLEnv.DEFAULT_SCHEMA_NAME);
465                                        }
466                                }
467                        }
468                        if (buffer.length() > 0) {
469                                buffer.append(".");
470                        }
471                        buffer.append(table.getTableNameOnly());
472                }
473                else if(supportCatalog) {
474                        if (!SQLUtil.isEmpty(table.getDatabase())) {
475                                buffer.append(table.getDatabase());
476                        }
477                        if (buffer.length() > 0) {
478                                buffer.append(".");
479                        }
480                        buffer.append(table.getTableNameOnly());
481                }
482                else if(supportSchema) {
483                        if (!SQLUtil.isEmpty(table.getSchema())) {
484                                buffer.append(table.getSchema());
485                        }
486                        if (buffer.length() > 0) {
487                                buffer.append(".");
488                        }
489                        buffer.append(table.getTableNameOnly());
490                }
491                if (SubType.dblink.name().equals(table.getSubType())) {
492                        buffer.append("@").append(table.getDatabase());
493                }
494                return buffer.toString();
495        }
496
497    public static TCustomSqlStatement getTopStmt(TCustomSqlStatement stmt) {
498        if (ModelBindingManager.getGlobalOption() != null && ModelBindingManager.getGlobalOption().getAnalyzeMode() == AnalyzeMode.crud) {
499            TCustomSqlStatement parent = stmt.getParentStmt();
500            if (parent == null || parent instanceof TPlsqlCreatePackage
501                    || parent instanceof TStoredProcedureSqlStatement || parent instanceof TCommonBlock)
502                return stmt;
503            return getTopStmt(parent);
504        } else {
505            TCustomSqlStatement parent = stmt.getParentStmt();
506            if (parent == null || parent instanceof TPlsqlCreatePackage)
507                return stmt;
508            return getTopStmt(parent);
509        }
510    }
511
512    public static boolean isQuote(String column) {
513        return (column.startsWith("\"") && column.endsWith("\"")) || (column.startsWith("'") && column.endsWith("'"))
514                || (column.startsWith("[") && column.endsWith("]")) || (column.startsWith("`") && column.endsWith("`"));
515    }
516
517    public static String getProcedureNameWithArgs(TStoredProcedureSqlStatement stmt) {
518                StringBuilder buffer = new StringBuilder();
519                if (stmt.getStoredProcedureName() == null) {
520                        return null;
521                }
522                buffer.append(stmt.getStoredProcedureName().toString());
523                if (stmt.getParameterDeclarations() != null && DlineageUtil.supportFunctionOverride(ModelBindingManager.getGlobalVendor())) {
524                        buffer.append("(");
525                        TParameterDeclarationList parameters = stmt.getParameterDeclarations();
526                        for (int i = 0; i < parameters.size(); ++i) {
527                                TParameterDeclaration parameter = parameters.getParameterDeclarationItem(i);
528                                if(parameter.getDataType()!=null) {
529                                        buffer.append(parameter.getDataType().getDataTypeName());
530                                }
531                                if(i<parameters.size()-1) {
532                                        buffer.append(",");
533                                }
534                        }
535                        buffer.append(")");
536                }
537                return buffer.toString();
538        }
539
540    public static String getIdentifierProcedureNameWithArgNum(procedure procedure) {
541        StringBuilder buffer = new StringBuilder();
542        buffer.append(SQLUtil.trimColumnStringQuote(procedure.getName()));
543        if (procedure.getArguments() != null && procedure.getArguments().size() > 0 && DlineageUtil.supportFunctionOverride(ModelBindingManager.getGlobalVendor())) {
544            buffer.append("(");
545            buffer.append(procedure.getArguments().size());
546            buffer.append(")");
547        }
548        return buffer.toString().toUpperCase();
549    }
550
551    public static String getIdentifierOraclePackageNameWithArgNum(oraclePackage pkg) {
552        StringBuilder buffer = new StringBuilder();
553        buffer.append(SQLUtil.trimColumnStringQuote(pkg.getName()));
554        if (pkg.getArguments() != null && pkg.getArguments().size() > 0 && DlineageUtil.supportFunctionOverride(ModelBindingManager.getGlobalVendor())) {
555            buffer.append("(");
556            buffer.append(pkg.getArguments().size());
557            buffer.append(")");
558        }
559        return buffer.toString().toUpperCase();
560    }
561
562    public static String getIdentifierFunctionName(table function) {
563        StringBuilder buffer = new StringBuilder();
564        buffer.append(SQLUtil.trimColumnStringQuote(function.getName()));
565        return buffer.toString().toUpperCase();
566    }
567
568    public static String getProcedureNameWithArgNum(TStoredProcedureSqlStatement stmt) {
569                StringBuilder buffer = new StringBuilder();
570                if (stmt.getStoredProcedureName() == null) {
571                        return null;
572                }
573                buffer.append(stmt.getStoredProcedureName().toString());
574                if (stmt.getParameterDeclarations() != null && DlineageUtil.supportFunctionOverride(ModelBindingManager.getGlobalVendor())) {
575                        buffer.append("(");
576                        buffer.append(stmt.getParameterDeclarations().size());
577                        buffer.append(")");
578                }
579                return buffer.toString();
580        }
581    
582        public static String getProcedureNameWithInputArgNum(TStoredProcedureSqlStatement stmt) {
583                StringBuilder buffer = new StringBuilder();
584                if (stmt.getStoredProcedureName() == null) {
585                        return null;
586                }
587                buffer.append(stmt.getStoredProcedureName().toString());
588                if (stmt.getParameterDeclarations() != null && DlineageUtil.supportFunctionOverride(ModelBindingManager.getGlobalVendor())) {
589                        buffer.append("(");
590                        int count = 0;
591                        for (int i = 0; i < stmt.getParameterDeclarations().size(); i++) {
592                                if (stmt.getParameterDeclarations().getParameterDeclarationItem(i)
593                                                .getParameterMode() == EParameterMode.in) {
594                                        count++;
595                                }
596                        }
597                        if (count == 0) {
598                                count = stmt.getParameterDeclarations().size();
599                        }
600                        buffer.append(count);
601                        buffer.append(")");
602                }
603                return buffer.toString();
604        }
605
606        public static String getFunctionNameWithArgNum(TFunctionCall function) {
607                StringBuilder buffer = new StringBuilder();
608                buffer.append(function.getFunctionName().toString());
609                if (function.getArgs() != null && DlineageUtil.supportFunctionOverride(ModelBindingManager.getGlobalVendor())) {
610                        buffer.append("(");
611                        buffer.append(function.getArgs().size());
612                        buffer.append(")");
613                }
614                return buffer.toString();
615        }
616
617        public static String getTableSchema(Table tableModel) {
618                StringBuilder buffer = new StringBuilder();
619                if(tableModel.getDatabase()!=null) {
620                        buffer.append(tableModel.getDatabase());
621                }
622                else {
623                        buffer.append(TSQLEnv.DEFAULT_DB_NAME);
624                }
625                buffer.append(".");
626                if(tableModel.getSchema()!=null) {
627                        buffer.append(tableModel.getSchema());
628                }
629                else {
630                        buffer.append(TSQLEnv.DEFAULT_SCHEMA_NAME);
631                }
632                return buffer.toString();
633        }
634        
635        public static String getTableSQLEnvKey(Table tableModel) {
636                StringBuilder buffer = new StringBuilder();
637                if(tableModel.getDatabase()!=null) {
638                        buffer.append(tableModel.getDatabase());
639                }
640                else {
641                        buffer.append(TSQLEnv.DEFAULT_DB_NAME);
642                }
643                buffer.append(".");
644                if(tableModel.getSchema()!=null) {
645                        buffer.append(tableModel.getSchema());
646                }
647                else {
648                        buffer.append(TSQLEnv.DEFAULT_SCHEMA_NAME);
649                }
650                buffer.append(".");
651                buffer.append(DlineageUtil.getSimpleTableName(tableModel.getName()));
652                return buffer.toString();
653        }
654        
655        public static String getProcedureParentName(TCustomSqlStatement stmt) {
656                if (stmt instanceof TStoredProcedureSqlStatement) {
657                        if (((TStoredProcedureSqlStatement) stmt).getStoredProcedureName() != null) {
658                                return getOraclePackageName() + ((TStoredProcedureSqlStatement) stmt).getStoredProcedureName().toString();
659                        }
660                }
661                stmt = stmt.getParentStmt();
662                if (stmt == null)
663                        return null;
664
665        if (stmt instanceof TCommonBlock) {
666                        if(((TCommonBlock) stmt).getBlockBody().getParentObjectName() instanceof TStoredProcedureSqlStatement) {
667                                stmt = (TStoredProcedureSqlStatement)((TCommonBlock) stmt).getBlockBody().getParentObjectName();
668                        }
669                }
670        
671                if (stmt instanceof TStoredProcedureSqlStatement) {
672                        if (((TStoredProcedureSqlStatement) stmt).getStoredProcedureName() != null) {
673                                String procedureName = getOraclePackageName() + ((TStoredProcedureSqlStatement) stmt).getStoredProcedureName().toString();
674                return getTableFullName(procedureName);
675                        }
676                }
677                if (stmt instanceof TTeradataCreateProcedure) {
678                        if (((TTeradataCreateProcedure) stmt).getProcedureName() != null) {
679                                String procedureName =  ((TTeradataCreateProcedure) stmt).getProcedureName().toString();
680                return getTableFullName(procedureName);
681                        }
682                }
683
684                return getProcedureParentName(stmt);
685        }
686
687        private static String getOraclePackageName() {
688                if (ModelBindingManager.getGlobalOraclePackage() != null) {
689                        return ModelBindingManager.getGlobalOraclePackage().getName() + ".";
690                }
691                return "";
692        }
693
694        public static sourceColumn copySourceColumn(sourceColumn oldSourceName) {
695                sourceColumn newSourceColumn = new sourceColumn();
696                newSourceColumn.setClauseType(oldSourceName.getClauseType());
697                newSourceColumn.setColumn(oldSourceName.getColumn());
698                newSourceColumn.setColumn_type(oldSourceName.getColumn_type());
699                newSourceColumn.setCoordinate(oldSourceName.getCoordinate());
700                newSourceColumn.setId(oldSourceName.getId());
701                newSourceColumn.setName(oldSourceName.getName());
702                newSourceColumn.setParent_alias(oldSourceName.getParent_alias());
703                newSourceColumn.setParent_id(oldSourceName.getParent_id());
704                newSourceColumn.setParent_name(oldSourceName.getParent_name());
705                newSourceColumn.setSource(oldSourceName.getSource());
706                newSourceColumn.setSource_id(oldSourceName.getSource_id());
707                newSourceColumn.setSource_name(oldSourceName.getSource_name());
708                newSourceColumn.setStruct(oldSourceName.isStruct());
709                newSourceColumn.setType(oldSourceName.getType());
710                newSourceColumn.setValue(oldSourceName.getValue());
711                if(oldSourceName.getTransforms()!=null) {
712                        newSourceColumn.setTransforms(new LinkedHashSet<transform>());
713                        for(transform transform: oldSourceName.getTransforms()) {
714                                newSourceColumn.getTransforms().add(transform);
715                        }
716                }
717                if(oldSourceName.getCandidateParents()!=null) {
718                        newSourceColumn.setCandidateParents(new LinkedHashSet<candidateTable>());
719                        for(candidateTable candidateTable: oldSourceName.getCandidateParents()) {
720                                newSourceColumn.getCandidateParents().add(candidateTable);
721                        }
722                }
723                return newSourceColumn;
724        }
725
726        public static boolean supportFunctionOverride(EDbVendor vendor) {
727                switch (vendor) {
728                case dbvpostgresql:
729                case dbvoracle:
730                case dbvdb2:
731                case dbvmysql:
732                case dbvsnowflake:
733                case dbvhana:
734                case dbvgreenplum:
735                case dbvgaussdb:
736                case dbvedb:
737                case dbvdameng:
738                        return true;
739                default:
740                        return false;
741                }
742        }
743        
744        private static final List<String> TERADATA_BUILTIN_FUNCTIONS = Arrays
745                        .asList(new String[] { "ACCOUNT", "CURRENT_DATE", "CURRENT_ROLE", "CURRENT_TIME", "CURRENT_TIMESTAMP",
746                                        "CURRENT_USER", "DATABASE", "DATE", "PROFILE", "ROLE", "SESSION", "TIME", "USER", "SYSDATE", });
747        
748        public static boolean isBuiltInFunctionName(String functionName) {
749                if (functionName == null)
750                        return false;
751                try {
752                        EDbVendor vendor = ModelBindingManager.getGlobalOption().getVendor();
753                        if (vendor == EDbVendor.dbvteradata) {
754                                boolean result = TERADATA_BUILTIN_FUNCTIONS.contains(functionName.toUpperCase());
755                                if (result) {
756                                        return true;
757                                }
758                        }
759
760                        List<String> versions = functionChecker.getAvailableDbVersions(vendor);
761                        if (versions != null && versions.size() > 0) {
762                                for (int i = 0; i < versions.size(); i++) {
763                                        boolean result = functionChecker.isBuiltInFunction(functionName.toUpperCase(),
764                                                        vendor, versions.get(i));
765                                        if (result) {
766                                                return result;
767                                        }
768                                }
769
770                                // boolean result =
771                                // TERADATA_BUILTIN_FUNCTIONS.contains(object.toString());
772                                // if (result) {
773                                // return true;
774                                // }
775                        }
776                } catch (Exception e) {
777                }
778
779                return false;
780        }
781        
782        public static boolean isKeyword(String objectName) {
783                if (objectName == null)
784                        return false;
785                try {
786                        EDbVendor vendor = ModelBindingManager.getGlobalOption().getVendor();
787
788                        List<String> versions = keywordChecker.getAvailableDbVersions(vendor);
789                        if (versions != null && versions.size() > 0) {
790                                for (int i = 0; i < versions.size(); i++) {
791                                        List<String> segments = SQLUtil.parseNames(objectName);
792                                        boolean result = keywordChecker.isKeyword(segments.get(segments.size() - 1),
793                                                        vendor, versions.get(i), false);
794                                        if (result) {
795                                                return result;
796                                        }
797                                }
798                        }
799                } catch (Exception e) {
800                }
801
802                return false;
803        }
804
805        public static TSelectSqlStatement getLeftStmt(TSelectSqlStatement stmt) {
806                TSelectSqlStatement current = stmt.getLeftStmt();
807                if (current == null) return null;
808                while (current.getLeftStmt() != null) {
809                        current = current.getLeftStmt();
810                }
811                return current;
812        }
813
814        public static String stripQuotesFromQualifiedName(String qualifiedName) {
815                if (SQLUtil.isEmpty(qualifiedName)) {
816                        return qualifiedName;
817                }
818
819                List<String> segments = SQLUtil.parseNames(qualifiedName);
820                StringBuilder sb = new StringBuilder();
821                for (int i = 0; i < segments.size(); i++) {
822                        if (i > 0) {
823                                sb.append('.');
824                        }
825                        String seg = segments.get(i);
826                        sb.append(TBaseType.getTextWithoutQuoted(seg));
827                }
828                return sb.toString();
829        }
830
831        public static boolean isProcedureExcluded(String fullName) {
832                if (SQLUtil.isEmpty(fullName)) {
833                        return false;
834                }
835
836                Option option = ModelBindingManager.getGlobalOption();
837                if (option == null) {
838                        return false;
839                }
840
841                Set<String> excludedNames = option.getExcludedProcedureNames();
842                Set<String> excludedPatterns = option.getExcludedProcedurePatterns();
843
844                if ((excludedNames == null || excludedNames.isEmpty()) &&
845                        (excludedPatterns == null || excludedPatterns.isEmpty())) {
846                        return false;
847                }
848
849        if (excludedNames != null) {
850            for (String excludedName : excludedNames) {
851                if (DlineageUtil.compareIdentifier(fullName, excludedName, ESQLDataObjectType.dotFunction)) {
852                    return true;
853                }
854            }
855        }
856
857        if (excludedPatterns != null && !excludedPatterns.isEmpty()) {
858            // Generate the qualified-name and all of its trailing segment-suffixes so a
859            // schema-qualified pattern can match a more-qualified name. e.g. the pattern
860            // "SCHEM.*" matches the Snowflake procedure "DB.SCHEM.PROC" through the suffix
861            // "SCHEM.PROC", and "PUBLIC.*" matches "COVID19.PUBLIC.INSERT_CDC_DATA".
862            // Segments are parsed with quote-awareness so dots inside a quoted identifier
863            // (e.g. "SCHEMA"."PROC.WITH.DOTS") are not split.
864            List<String> candidates = buildQualifiedNameSuffixes(fullName);
865            for (String pattern : excludedPatterns) {
866                if (SQLUtil.isEmpty(pattern)) {
867                        continue;
868                }
869                String normalizedPattern = stripQuotesFromQualifiedName(pattern);
870                StringBuilder regexBuilder = new StringBuilder();
871                for (char c : normalizedPattern.toCharArray()) {
872                    switch (c) {
873                        case '.':
874                            regexBuilder.append("\\.");
875                            break;
876                        case '*':
877                            regexBuilder.append(".*");
878                            break;
879                        case '?':
880                            regexBuilder.append(".");
881                            break;
882                        case '(': case ')': case '[': case ']': case '{': case '}':
883                        case '|': case '^': case '$': case '+': case '\\':
884                            regexBuilder.append("\\").append(c);
885                            break;
886                        default:
887                            regexBuilder.append(c);
888                    }
889                }
890                String regex = "(?i)^" + regexBuilder.toString() + "$";
891                for (String candidate : candidates) {
892                    if (candidate.matches(regex)) {
893                        return true;
894                    }
895                }
896            }
897        }
898
899                return false;
900        }
901
902        /**
903         * Builds the quote-stripped qualified name and each of its trailing segment-suffixes,
904         * longest first. For {@code "DB"."SCHEM"."PROC"} this yields
905         * {@code [DB.SCHEM.PROC, SCHEM.PROC, PROC]}. Used by procedure-exclusion pattern
906         * matching so a schema-level pattern matches a database-qualified name.
907         */
908        private static List<String> buildQualifiedNameSuffixes(String fullName) {
909                List<String> suffixes = new ArrayList<String>();
910                List<String> segments = SQLUtil.parseNames(fullName);
911                if (segments == null || segments.isEmpty()) {
912                        suffixes.add(stripQuotesFromQualifiedName(fullName));
913                        return suffixes;
914                }
915                List<String> stripped = new ArrayList<String>(segments.size());
916                for (String seg : segments) {
917                        stripped.add(TBaseType.getTextWithoutQuoted(seg));
918                }
919                for (int i = 0; i < stripped.size(); i++) {
920                        StringBuilder sb = new StringBuilder();
921                        for (int j = i; j < stripped.size(); j++) {
922                                if (j > i) {
923                                        sb.append('.');
924                                }
925                                sb.append(stripped.get(j));
926                        }
927                        suffixes.add(sb.toString());
928                }
929                return suffixes;
930        }
931}