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