diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/QueryMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/QueryMapper.java index 93e7e01e277e50e6ddeff58e5d5397ab5927f647..9a9ee424fd315bfbe1c8e994ae073d78b445dea3 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/QueryMapper.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/QueryMapper.java @@ -694,13 +694,12 @@ public interface QueryMapper { final List<SelectItem> clauses = ps.getSelectItems(); log.trace("columns referenced in the from-clause: {}", clauses); /* Parse all tables */ - final List<FromItem> tablesOrViews = new ArrayList<>(); - tablesOrViews.add(ps.getFromItem()); - if (ps.getJoins() != null && ps.getJoins().size() > 0) { + final List<FromItem> fromItems = new ArrayList<>(fromItemToFromItems(ps.getFromItem())); + if (ps.getJoins() != null && !ps.getJoins().isEmpty()) { log.trace("query contains join items: {}", ps.getJoins()); for (net.sf.jsqlparser.statement.select.Join j : ps.getJoins()) { if (j.getRightItem() != null) { - tablesOrViews.add(j.getRightItem()); + fromItems.add(j.getRightItem()); } } } @@ -711,30 +710,30 @@ public interface QueryMapper { .toList(); log.trace("columns referenced in the from-clause and join-clause(s): {}", clauses); /* Checking if all tables or views exist */ - log.trace("table(s) or view(s) referenced in the statement: {}", tablesOrViews.stream().map(t -> ((net.sf.jsqlparser.schema.Table) t).getName()).collect(Collectors.toList())); + log.trace("table/view/join referenced in the statement: {}", fromItems.stream().map(this::fromItemToFromItems).flatMap(List::stream).collect(Collectors.toList())); /* Checking if all columns exist */ for (SelectItem clause : clauses) { final SelectExpressionItem item = (SelectExpressionItem) clause; final Column column = (Column) item.getExpression(); - final Optional<net.sf.jsqlparser.schema.Table> optionalTableOrView = tablesOrViews.stream() + final Optional<net.sf.jsqlparser.schema.Table> optional = fromItems.stream() .map(t -> (net.sf.jsqlparser.schema.Table) t) .filter(t -> { if (column.getTable() == null) { /* column does not reference a specific table, so there is only one table */ - final String tableName = ((net.sf.jsqlparser.schema.Table) tablesOrViews.get(0)).getName().replace("`", ""); - return tableOptionalAliasMatches(t, tableName); + final String tableName = ((net.sf.jsqlparser.schema.Table) fromItems.get(0)).getName().replace("`", ""); + return tableMatches(t, tableName); } final String tableName = column.getTable().getName().replace("`", ""); - return tableOptionalAliasMatches(t, tableName); + return tableMatches(t, tableName); }) .findFirst(); - if (optionalTableOrView.isEmpty()) { - log.error("Failed to find table or view with alias {}", column.getTable().getAlias()); - throw new JSQLParserException("Failed to find table or view with alias " + column.getTable().getAlias()); + if (optional.isEmpty()) { + log.error("Failed to find table/view {} (with designator {})", column.getTable().getName(), column.getTable().getAlias()); + throw new JSQLParserException("Failed to find table/view " + column.getTable().getName() + " (with alias " + column.getTable().getAlias() + ")"); } final Optional<TableColumn> optionalColumn = allColumns.stream() .filter(c -> c.getInternalName().equals(column.getColumnName().replace("`", ""))) - .filter(c -> columnMatches(c, optionalTableOrView.get().getName().replace("`", ""))) + .filter(c -> columnMatches(c, optional.get().getName().replace("`", ""))) .findFirst(); if (optionalColumn.isEmpty()) { log.error("Failed to find column with name {} in {}", column.getColumnName(), allColumns.stream().map(TableColumn::getInternalName).toList()); @@ -750,22 +749,45 @@ public interface QueryMapper { return columns; } - default boolean tableOptionalAliasMatches(net.sf.jsqlparser.schema.Table table, String tableName) { + default List<FromItem> fromItemToFromItems(FromItem data) { + return fromItemToFromItems(data, 0); + } + + default List<FromItem> fromItemToFromItems(FromItem data, Integer level) { + final List<FromItem> fromItems = new LinkedList<>(); + if (data instanceof net.sf.jsqlparser.schema.Table table) { + fromItems.add(data); + log.trace("from-item {} is of type table: level ~> {}", table.getName(), level); + return fromItems; + } + if (data instanceof SubJoin subJoin) { + log.trace("from-item is of type sub-join: level ~> {}", level); + for (Join join : subJoin.getJoinList()) { + fromItems.addAll(fromItemToFromItems(join.getRightItem(), level + 1)); + } + fromItems.addAll(fromItemToFromItems(((SubJoin) data).getLeft(), level + 1)); + return fromItems; + } + log.warn("unknown from-item {}", data); + return null; + } + + default boolean tableMatches(net.sf.jsqlparser.schema.Table table, String otherTableName) { + final String tableName = table.getName() + .trim() + .replace("`", ""); if (table.getAlias() == null) { - /* table is non-aliased */ - final String otherTableName = table.getName() - .trim() - .replace("`", ""); - log.trace("table {} has no alias", otherTableName); - return otherTableName.equals(tableName); + /* table does not have designator */ + log.trace("table {} has no designator", tableName); + return tableName.equals(otherTableName); } - /* has alias */ - final String alias = table.getAlias() + /* has designator */ + final String designator = table.getAlias() .getName() .trim() .replace("`", ""); - log.trace("table {} has alias {}", table.getName(), alias); - return alias.equals(tableName); + log.trace("table {} has designator {}", tableName, designator); + return designator.equals(otherTableName); } @Transactional(readOnly = true) diff --git a/dbrepo-metadata-service/rest-service/src/main/resources/application-local.yml b/dbrepo-metadata-service/rest-service/src/main/resources/application-local.yml index 1ae0d498b22b598e1d1306fdb48cf681cc778b64..d759af61d3e67ffa18c7fe332fa7f5dd286b1209 100644 --- a/dbrepo-metadata-service/rest-service/src/main/resources/application-local.yml +++ b/dbrepo-metadata-service/rest-service/src/main/resources/application-local.yml @@ -40,7 +40,7 @@ spring: loadbalancer.ribbon.enabled: false management.endpoints.web.exposure.include: health,info,prometheus server: - port: 19099 + port: 9099 logging: pattern.console: "%d %highlight(%-5level) %msg%n" level: