001package gudusoft.gsqlparser.dlineage.dataflow.metadata.sqlenv;
002
003import gudusoft.gsqlparser.EDbVendor;
004import gudusoft.gsqlparser.dlineage.dataflow.metadata.MetadataAnalyzer;
005import gudusoft.gsqlparser.dlineage.dataflow.model.ModelBindingManager;
006import gudusoft.gsqlparser.dlineage.dataflow.model.xml.*;
007import gudusoft.gsqlparser.dlineage.util.DlineageUtil;
008import gudusoft.gsqlparser.dlineage.util.Pair3;
009import gudusoft.gsqlparser.sqlenv.*;
010import gudusoft.gsqlparser.util.SQLUtil;
011
012import java.util.*;
013
014public class SQLEnvMetadataAnalyzer implements MetadataAnalyzer<TSQLEnv> {
015
016    private Map<String, procedure> procedureMap = new LinkedHashMap<String, procedure>();
017    private Map<String, table> tableMap = new LinkedHashMap<String, table>();
018    private Map<String, oraclePackage> oraclePackageMap = new LinkedHashMap<String, oraclePackage>();
019    private Map<String, column> columnMap = new LinkedHashMap<String, column>();
020    private EDbVendor vendor;
021    private boolean lower = false;
022
023    public SQLEnvMetadataAnalyzer(boolean lower) {
024        this.lower = lower;
025    }
026
027    @Override
028    public synchronized dataflow analyzeMetadata(EDbVendor metadataVendor, TSQLEnv sqlenv) {
029        init(vendor);
030        dataflow dataflow = new dataflow();
031
032        String serverName = sqlenv.getDefaultServerName();
033        EDbVendor vendor = metadataVendor;
034        if (sqlenv.getDBVendor() != null) {
035            vendor = sqlenv.getDBVendor();
036        }
037
038        boolean supportsCatalogs = TSQLEnv.supportCatalog(vendor);
039        boolean supportsSchemas = TSQLEnv.supportSchema(vendor);
040
041        List<TSQLCatalog> databases = sqlenv.getCatalogList();
042        if (databases != null) {
043            for (int i = 0; i < databases.size(); i++) {
044                TSQLCatalog catalog = databases.get(i);
045                String databaseName = catalog.getName();
046                if (SQLUtil.parseNames(databaseName).size() > 1) {
047                    databaseName = "\"" + databaseName + "\"";
048                }
049                List<TSQLSchema> schemas = catalog.getSchemaList();
050                if (schemas == null) {
051                    continue;
052                }
053                for (int j = 0; j < schemas.size(); j++) {
054                    TSQLSchema jsonSchema = schemas.get(j);
055                    String schemaName = (String) jsonSchema.getName();
056                    if (SQLUtil.parseNames(schemaName).size() > 1) {
057                        schemaName = "\"" + schemaName + "\"";
058                    }
059                    List<TSQLSchemaObject> dbObjs = jsonSchema.getSchemaObjectList();
060                    if (dbObjs == null) {
061                        continue;
062                    }
063                    for (int k = 0; k < dbObjs.size(); k++) {
064                        TSQLSchemaObject jsonTable = dbObjs.get(k);
065                        if (jsonTable instanceof TSQLTable) {
066                            TSQLTable table = (TSQLTable) jsonTable;
067                            String tableName = table.getName();
068                            boolean isView = table.isView();
069                            List<TSQLColumn> columns = table.getColumnList();
070                            if (columns == null) {
071                                continue;
072                            }
073                            for (int l = 0; l < columns.size(); l++) {
074                                TSQLColumn jsonColumn = columns.get(l);
075                                String columnName = jsonColumn.getName();
076                                if (SQLUtil.isEmpty(columnName)) {
077                                    continue;
078                                }
079                                appendTable(vendor, supportsCatalogs, supportsSchemas, dataflow, serverName, databaseName, schemaName, tableName, isView, columnName);
080                            }
081                        }
082                        if (jsonTable instanceof TSQLOraclePackage) {
083                            TSQLOraclePackage sqlOraclePackage = (TSQLOraclePackage) jsonTable;
084                            oraclePackage oraclePackage = appendOraclePackage(vendor, supportsCatalogs, supportsSchemas, dataflow, serverName, databaseName, schemaName, sqlOraclePackage);
085                            if (sqlOraclePackage.getSchemaObjectList() != null) {
086                                for (TSQLSchemaObject sqlProcedure : sqlOraclePackage.getSchemaObjectList()) {
087                                    appendProcedure(vendor, supportsCatalogs, supportsSchemas, dataflow, serverName, databaseName, schemaName, (TSQLSchemaObject) sqlProcedure, oraclePackage);
088                                }
089                            }
090                        }
091                        if(jsonTable instanceof TSQLProcedure){
092                            appendProcedure(vendor, supportsCatalogs, supportsSchemas, dataflow, serverName, databaseName, schemaName, (TSQLSchemaObject)jsonTable, null);
093                        }
094                    }
095                }
096            }
097        }
098        sortTableColumns(dataflow);
099        return dataflow;
100    }
101
102    private void appendProcedure(EDbVendor vendor, boolean supportsCatalogs, boolean supportsSchemas, dataflow dataflow, String serverName, String databaseName, String schemaName, TSQLSchemaObject sqlProcedure, oraclePackage oraclePackage) {
103        String qualifiedName = sqlProcedure.getQualifiedName();
104        if (DlineageUtil.isProcedureExcluded(qualifiedName)) {
105            return;
106        }
107        String procedureName = sqlProcedure.getName();
108        String procedureKey = getFullName(serverName, databaseName, schemaName, procedureName);
109        if (!procedureMap.containsKey(procedureKey)) {
110            procedure procedure = new procedure();
111            if (serverName != null && !TSQLEnv.DEFAULT_SERVER_NAME.equalsIgnoreCase(serverName)) {
112                procedure.setServer(serverName);
113            }
114            if(supportsCatalogs && supportsSchemas){
115                if(databaseName != null && !TSQLEnv.DEFAULT_DB_NAME.equalsIgnoreCase(databaseName)) {
116                    if (lower) {
117                        procedure.setDatabase(SQLUtil.trimColumnStringQuote(databaseName).toLowerCase());
118                    } else {
119                        procedure.setDatabase(databaseName);
120                    }
121                }
122                if(schemaName != null && !TSQLEnv.DEFAULT_SCHEMA_NAME.equalsIgnoreCase(schemaName)) {
123                    if (lower) {
124                        procedure.setSchema(SQLUtil.trimColumnStringQuote(schemaName).toLowerCase());
125                    } else {
126                        procedure.setSchema(schemaName);
127                    }
128                }
129            }
130            else if(supportsCatalogs){
131                if(databaseName != null && !TSQLEnv.DEFAULT_DB_NAME.equalsIgnoreCase(databaseName)) {
132                    if (lower) {
133                        procedure.setDatabase(SQLUtil.trimColumnStringQuote(databaseName).toLowerCase());
134                    } else {
135                        procedure.setDatabase(databaseName);
136                    }
137                }
138            }
139            else if(supportsSchemas){
140                if(schemaName != null && !TSQLEnv.DEFAULT_SCHEMA_NAME.equalsIgnoreCase(schemaName)) {
141                    if (lower) {
142                        procedure.setSchema(SQLUtil.trimColumnStringQuote(schemaName).toLowerCase());
143                    } else {
144                        procedure.setSchema(schemaName);
145                    }
146                }
147            }
148
149            if (lower) {
150                procedure.setName(SQLUtil.trimColumnStringQuote(procedureName).toLowerCase());
151            } else {
152                procedure.setName(procedureName);
153            }
154            if (supportsSchemas && !SQLUtil.isEmpty(procedure.getSchema()) && !TSQLEnv.DEFAULT_SCHEMA_NAME.equalsIgnoreCase(procedure.getSchema())) {
155                procedure.setName(procedure.getSchema() + "." + procedure.getName());
156            }
157            if (supportsCatalogs && !SQLUtil.isEmpty(procedure.getDatabase()) && !TSQLEnv.DEFAULT_DB_NAME.equalsIgnoreCase(procedure.getDatabase())) {
158                procedure.setName(procedure.getDatabase() + "." + procedure.getName());
159            }
160            procedure.setId(String.valueOf(++ModelBindingManager.get().TABLE_COLUMN_ID));
161            if (ModelBindingManager.getGlobalSqlInfo() != null) {
162                procedure.setCoordinate(new Pair3<Long, Long, Integer>(-1L, -1L,
163                        ModelBindingManager.getGlobalSqlInfo().getIndexOf(ModelBindingManager.getGlobalHash())) + ","
164                        + new Pair3<Long, Long, Integer>(-1L, -1L,
165                        ModelBindingManager.getGlobalSqlInfo().getIndexOf(ModelBindingManager.getGlobalHash())));
166            }
167            procedure.setType(sqlProcedure.getDataObjectType().name().replace("dot","").toLowerCase());
168            if(oraclePackage!=null) {
169                oraclePackage.getProcedures().add(procedure);
170            }
171            else{
172                dataflow.getProcedures().add(procedure);
173            }
174            procedureMap.put(procedureKey, procedure);
175        }
176    }
177
178    private oraclePackage appendOraclePackage(EDbVendor vendor, boolean supportsCatalogs, boolean supportsSchemas, dataflow dataflow, String serverName, String databaseName, String schemaName, TSQLOraclePackage sqlOraclePackage) {
179        String oraclePackageName = sqlOraclePackage.getName();
180        String oraclePackageKey = getFullName(serverName, databaseName, schemaName, oraclePackageName);
181        if (!oraclePackageMap.containsKey(oraclePackageKey)) {
182            oraclePackage oraclePackage = new oraclePackage();
183            if (serverName != null && !TSQLEnv.DEFAULT_SERVER_NAME.equalsIgnoreCase(serverName)) {
184                oraclePackage.setServer(serverName);
185            }
186            if(supportsCatalogs && supportsSchemas){
187                if(databaseName != null && !TSQLEnv.DEFAULT_DB_NAME.equalsIgnoreCase(databaseName)) {
188                    if (lower) {
189                        oraclePackage.setDatabase(SQLUtil.trimColumnStringQuote(databaseName).toLowerCase());
190                    } else {
191                        oraclePackage.setDatabase(databaseName);
192                    }
193                }
194                if(schemaName != null && !TSQLEnv.DEFAULT_SCHEMA_NAME.equalsIgnoreCase(schemaName)) {
195                    if (lower) {
196                        oraclePackage.setSchema(SQLUtil.trimColumnStringQuote(schemaName).toLowerCase());
197                    } else {
198                        oraclePackage.setSchema(schemaName);
199                    }
200                }
201            }
202            else if(supportsCatalogs){
203                if(databaseName != null && !TSQLEnv.DEFAULT_DB_NAME.equalsIgnoreCase(databaseName)) {
204                    if (lower) {
205                        oraclePackage.setDatabase(SQLUtil.trimColumnStringQuote(databaseName).toLowerCase());
206                    } else {
207                        oraclePackage.setDatabase(databaseName);
208                    }
209                }
210            }
211            else if(supportsSchemas){
212                if(schemaName != null && !TSQLEnv.DEFAULT_SCHEMA_NAME.equalsIgnoreCase(schemaName)) {
213                    if (lower) {
214                        oraclePackage.setSchema(SQLUtil.trimColumnStringQuote(schemaName).toLowerCase());
215                    } else {
216                        oraclePackage.setSchema(schemaName);
217                    }
218                }
219            }
220
221            if (lower) {
222                oraclePackage.setName(SQLUtil.trimColumnStringQuote(oraclePackageName).toLowerCase());
223            } else {
224                oraclePackage.setName(oraclePackageName);
225            }
226            if (supportsSchemas && !SQLUtil.isEmpty(oraclePackage.getSchema()) && !TSQLEnv.DEFAULT_SCHEMA_NAME.equalsIgnoreCase(oraclePackage.getSchema())) {
227                oraclePackage.setName(oraclePackage.getSchema() + "." + oraclePackage.getName());
228            }
229            if (supportsCatalogs && !SQLUtil.isEmpty(oraclePackage.getDatabase()) && !TSQLEnv.DEFAULT_DB_NAME.equalsIgnoreCase(oraclePackage.getDatabase())) {
230                oraclePackage.setName(oraclePackage.getDatabase() + "." + oraclePackage.getName());
231            }
232            oraclePackage.setId(String.valueOf(++ModelBindingManager.get().TABLE_COLUMN_ID));
233            if (ModelBindingManager.getGlobalSqlInfo() != null) {
234                oraclePackage.setCoordinate(new Pair3<Long, Long, Integer>(-1L, -1L,
235                        ModelBindingManager.getGlobalSqlInfo().getIndexOf(ModelBindingManager.getGlobalHash())) + ","
236                        + new Pair3<Long, Long, Integer>(-1L, -1L,
237                        ModelBindingManager.getGlobalSqlInfo().getIndexOf(ModelBindingManager.getGlobalHash())));
238            }
239            dataflow.getPackages().add(oraclePackage);
240            oraclePackageMap.put(oraclePackageKey, oraclePackage);
241        }
242        return oraclePackageMap.get(oraclePackageKey);
243    }
244
245    private void init(EDbVendor vendor) {
246        this.vendor = vendor;
247        procedureMap.clear();
248        tableMap.clear();
249        columnMap.clear();
250        if (ModelBindingManager.get() == null) {
251            ModelBindingManager.set(new ModelBindingManager());
252        }
253    }
254
255    private void sortTableColumns(dataflow dataflow) {
256        if (dataflow.getTables() != null) {
257            for (table table : dataflow.getTables()) {
258                Collections.sort(table.getColumns(), new Comparator<column>() {
259                    public int compare(column t1, column t2) {
260                        if (t1.getName().equalsIgnoreCase("RelationRows"))
261                            return 1;
262                        if (t2.getName().equalsIgnoreCase("RelationRows"))
263                            return -1;
264                        return 0;
265                    }
266                });
267            }
268        }
269
270        if (dataflow.getResultsets() != null) {
271            for (table table : dataflow.getResultsets()) {
272                Collections.sort(table.getColumns(), new Comparator<column>() {
273                    public int compare(column t1, column t2) {
274                        if (t1.getName().equalsIgnoreCase("RelationRows"))
275                            return 1;
276                        if (t2.getName().equalsIgnoreCase("RelationRows"))
277                            return -1;
278                        return 0;
279                    }
280                });
281            }
282        }
283    }
284
285    private void appendTable(EDbVendor vendor, boolean supportsCatalogs, boolean supportsSchemas, dataflow dataflow, String serverName, String databaseName, String schemaName, String tableName,
286                             boolean isView, String columnName) {
287        String tableKey = getFullName(serverName, databaseName, schemaName, tableName);
288        if (!tableMap.containsKey(tableKey)) {
289            table table = new table();
290            if (serverName != null && !TSQLEnv.DEFAULT_SERVER_NAME.equalsIgnoreCase(serverName)) {
291                table.setServer(serverName);
292            }
293            if(supportsCatalogs && supportsSchemas){
294                if(databaseName != null && !TSQLEnv.DEFAULT_DB_NAME.equalsIgnoreCase(databaseName)) {
295                    if (lower) {
296                        table.setDatabase(SQLUtil.trimColumnStringQuote(databaseName).toLowerCase());
297                    } else {
298                        table.setDatabase(databaseName);
299                    }
300                }
301                if(schemaName != null && !TSQLEnv.DEFAULT_SCHEMA_NAME.equalsIgnoreCase(schemaName)) {
302                    if (lower) {
303                        table.setSchema(SQLUtil.trimColumnStringQuote(schemaName).toLowerCase());
304                    } else {
305                        table.setSchema(schemaName);
306                    }
307                }
308            }
309            else if(supportsCatalogs){
310                if(databaseName != null && !TSQLEnv.DEFAULT_DB_NAME.equalsIgnoreCase(databaseName)) {
311                    if (lower) {
312                        table.setDatabase(SQLUtil.trimColumnStringQuote(databaseName).toLowerCase());
313                    } else {
314                        table.setDatabase(databaseName);
315                    }
316                }
317            }
318            else if(supportsSchemas){
319                if(schemaName != null && !TSQLEnv.DEFAULT_SCHEMA_NAME.equalsIgnoreCase(schemaName)) {
320                    if (lower) {
321                        table.setSchema(SQLUtil.trimColumnStringQuote(schemaName).toLowerCase());
322                    } else {
323                        table.setSchema(schemaName);
324                    }
325                }
326            }
327
328            if (lower) {
329                table.setName(SQLUtil.trimColumnStringQuote(tableName).toLowerCase());
330            } else {
331                table.setName(tableName);
332            }
333            if (supportsSchemas && !SQLUtil.isEmpty(table.getSchema()) && !TSQLEnv.DEFAULT_SCHEMA_NAME.equalsIgnoreCase(table.getSchema())) {
334                table.setName(table.getSchema() + "." + table.getName());
335            }
336            if (supportsCatalogs && !SQLUtil.isEmpty(table.getDatabase()) && !TSQLEnv.DEFAULT_DB_NAME.equalsIgnoreCase(table.getDatabase())) {
337                table.setName(table.getDatabase() + "." + table.getName());
338            }
339            table.setId(String.valueOf(++ModelBindingManager.get().TABLE_COLUMN_ID));
340            if (ModelBindingManager.getGlobalSqlInfo() != null) {
341                table.setCoordinate(new Pair3<Long, Long, Integer>(-1L, -1L,
342                        ModelBindingManager.getGlobalSqlInfo().getIndexOf(ModelBindingManager.getGlobalHash())) + ","
343                        + new Pair3<Long, Long, Integer>(-1L, -1L,
344                        ModelBindingManager.getGlobalSqlInfo().getIndexOf(ModelBindingManager.getGlobalHash())));
345            }
346            if (isView) {
347                table.setType("view");
348                dataflow.getViews().add(table);
349            } else {
350                table.setType("table");
351                dataflow.getTables().add(table);
352            }
353            tableMap.put(tableKey, table);
354        }
355
356        table table = tableMap.get(tableKey);
357        String sourceColumnKey = getFullName(serverName, databaseName, schemaName, tableName, columnName);
358        if (!columnMap.containsKey(sourceColumnKey)) {
359            column column = new column();
360            column.setId(String.valueOf(++ModelBindingManager.get().TABLE_COLUMN_ID));
361            column.setName(columnName);
362            if ("RelationRows".equalsIgnoreCase(columnName)) {
363                column.setSource("system");
364            }
365            if (ModelBindingManager.getGlobalSqlInfo() != null) {
366                column.setCoordinate(new Pair3<Long, Long, Integer>(-1L, -1L,
367                        ModelBindingManager.getGlobalSqlInfo().getIndexOf(ModelBindingManager.getGlobalHash())) + ","
368                        + new Pair3<Long, Long, Integer>(-1L, -1L,
369                        ModelBindingManager.getGlobalSqlInfo().getIndexOf(ModelBindingManager.getGlobalHash())));
370            }
371            table.getColumns().add(column);
372            columnMap.put(sourceColumnKey, column);
373        }
374    }
375
376    private String getFullName(String... segments) {
377        StringBuilder builder = new StringBuilder();
378        for (int i = 0; i < segments.length; i++) {
379            builder.append(segments[i]);
380            if (i < segments.length - 1) {
381                builder.append(".");
382            }
383        }
384        return builder.toString();
385    }
386}