From 1cb0b0a5c5bcdb9eeb1f66240f00611613b0d6e7 Mon Sep 17 00:00:00 2001 From: Juan Pablo Galeotti Date: Mon, 17 Nov 2025 20:27:51 -0300 Subject: [PATCH 01/33] introduces specific logic to handle SELECT queries that include a LIMIT clause. --- .../client/java/sql/QueryResult.java | 21 + .../heuristic/SqlHeuristicsCalculator.java | 109 +- .../java/sql/internal/SqlParserUtils.java | 13 + .../SqlHeuristicsCalculatorTest.java | 998 ++---------------- 4 files changed, 173 insertions(+), 968 deletions(-) diff --git a/client-java/sql/src/main/java/org/evomaster/client/java/sql/QueryResult.java b/client-java/sql/src/main/java/org/evomaster/client/java/sql/QueryResult.java index 4144c1492a..ce74280042 100644 --- a/client-java/sql/src/main/java/org/evomaster/client/java/sql/QueryResult.java +++ b/client-java/sql/src/main/java/org/evomaster/client/java/sql/QueryResult.java @@ -195,4 +195,25 @@ public String getTableName() { } return variableDescriptors.get(0).getTableName(); } + + /** + * Creates a new QueryResult containing only the first 'limit' rows + * of the current QueryResult. + * + * @param limit the maximum number of rows to include in the new QueryResult + * @return a new QueryResult with at most 'limit' rows + */ + public QueryResult limit(long limit) { + if (limit < 0) { + throw new IllegalArgumentException("Limit must be non-negative"); + } + if (limit >= rows.size()) { + return this; + } + QueryResult limitedResult = new QueryResult(this.variableDescriptors); + for (int i = 0; i < limit; i++) { + limitedResult.addRow(this.rows.get(i)); + } + return limitedResult; + } } diff --git a/client-java/sql/src/main/java/org/evomaster/client/java/sql/heuristic/SqlHeuristicsCalculator.java b/client-java/sql/src/main/java/org/evomaster/client/java/sql/heuristic/SqlHeuristicsCalculator.java index 07c51feda3..4676080e3c 100644 --- a/client-java/sql/src/main/java/org/evomaster/client/java/sql/heuristic/SqlHeuristicsCalculator.java +++ b/client-java/sql/src/main/java/org/evomaster/client/java/sql/heuristic/SqlHeuristicsCalculator.java @@ -406,36 +406,53 @@ private QueryResult createQueryResultLeftJoin(QueryResult leftQueryResult, Query SqlHeuristicResult computeHeuristic(Select select) { tableColumnResolver.enterStatementeContext(select); final SqlHeuristicResult heuristicResult; - if (select instanceof SetOperationList) { - SetOperationList unionQuery = (SetOperationList) select; - List subqueries = unionQuery.getSelects(); + heuristicResult = computeHeuristicUnion(subqueries, unionQuery.getLimit()); + } else if (select instanceof ParenthesedSelect) { + // Handle case of parenthesed SELECT + ParenthesedSelect parenthesedSelect = (ParenthesedSelect) select; + Select subquery = parenthesedSelect.getSelect(); + final SqlHeuristicResult subqueryHeuristicResult = computeHeuristic(subquery); + if (parenthesedSelect.getLimit() != null) { + long limitValue = getLimitValue(parenthesedSelect.getLimit()); + QueryResult queryResult = subqueryHeuristicResult.getQueryResult().limit(limitValue); + heuristicResult = new SqlHeuristicResult(subqueryHeuristicResult.getTruthness(), queryResult); + } else { + heuristicResult = subqueryHeuristicResult; + } + } else if (select instanceof PlainSelect) { + // Handle case of plain SELECT + PlainSelect plainSelect = (PlainSelect) select; + final FromItem fromItem = getFrom(plainSelect); + final List joins = getJoins(plainSelect); + final Expression whereClause = getWhere(plainSelect); + if (plainSelect.getGroupBy() != null) { + heuristicResult = computeHeuristicSelectGroupByHaving( + plainSelect.getSelectItems(), + fromItem, + joins, + whereClause, + plainSelect.getGroupBy().getGroupByExpressionList(), + plainSelect.getHaving(), + plainSelect.getLimit()); + } else { + heuristicResult = computeHeuristicSelect( + plainSelect.getSelectItems(), + fromItem, + joins, + whereClause, + plainSelect.getLimit()); + } } else { - heuristicResult = computeHeuristicSelect( - plainSelect.getSelectItems(), - fromItem, - joins, - whereClause); + throw new IllegalArgumentException("Cannot calculate heuristics for SQL command of type " + select.getClass().getName()); } - } else { - throw new IllegalArgumentException("Cannot calculate heuristics for SQL command of type " + select.getClass().getName()); } tableColumnResolver.exitCurrentStatementContext(); return heuristicResult; @@ -448,13 +465,31 @@ private SqlHeuristicResult computeHeuristicSelect(List> selectItem return heuristicResult; } + private SqlHeuristicResult computeHeuristicSelect(List> selectItems, + FromItem fromItem, + List joins, + Expression whereClause, + Limit limit) { + final SqlHeuristicResult intermediateHeuristicResult = computeHeuristic(fromItem, joins, whereClause); + QueryResult queryResult = createQueryResult(intermediateHeuristicResult.getQueryResult(), selectItems); + + if (limit != null) { + long limitValue = getLimitValue(limit); + queryResult = queryResult.limit(limitValue); + } + + final SqlHeuristicResult heuristicResult = new SqlHeuristicResult(intermediateHeuristicResult.getTruthness(), queryResult); + return heuristicResult; + } + private SqlHeuristicResult computeHeuristicSelectGroupByHaving( List> selectItems, FromItem fromItem, List joins, Expression whereClause, List groupByExpressions, - Expression having) { + Expression having, + Limit limit) { final SqlHeuristicResult intermediateHeuristicResult = computeHeuristic(fromItem, joins, whereClause); @@ -490,7 +525,7 @@ private SqlHeuristicResult computeHeuristicSelectGroupByHaving( } } final List variableDescriptors = createSelectVariableDescriptors(selectItems, sourceQueryResult.seeVariableDescriptors()); - final QueryResult queryResult = new QueryResult(variableDescriptors); + QueryResult queryResult = new QueryResult(variableDescriptors); for (DataRow groupByDataRow : groupByDataRows) { queryResult.addRow(groupByDataRow); } @@ -505,6 +540,11 @@ private SqlHeuristicResult computeHeuristicSelectGroupByHaving( intermediateHeuristicResult.getTruthness(), havingTruthness); + if (limit != null) { + long limitValue = getLimitValue(limit); + queryResult = queryResult.limit(limitValue); + } + return new SqlHeuristicResult(groupByHavingTruthness, queryResult); } @@ -728,7 +768,7 @@ && isAggregateFunction(((Function) selectItem.getExpression()).getName())) { return selectVariableDescriptors; } - private SqlHeuristicResult computeHeuristicUnion(List subqueries, Limit limit) { List subqueryResults = new ArrayList<>(); for (Select subquery : subqueries) { SqlHeuristicResult subqueryResult = computeHeuristic(subquery); @@ -742,7 +782,12 @@ private SqlHeuristicResult computeHeuristicUnion(List