Skip to content

Commit

Permalink
Merge pull request #1145 from WebFuzzing/sql_heuristics_for_subqueries
Browse files Browse the repository at this point in the history
handling of join queries without WHERE/ON clauses
  • Loading branch information
arcuri82 authored Dec 23, 2024
2 parents 8a3a375 + f7ef3d3 commit b23d0da
Show file tree
Hide file tree
Showing 8 changed files with 1,184 additions and 37 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.evomaster.client.java.distance.heuristics;

import java.util.Arrays;

public class TruthnessUtils {

/**
Expand All @@ -13,7 +15,7 @@ public static double normalizeValue(double v) {
throw new IllegalArgumentException("Negative value: " + v);
}

if(Double.isInfinite(v) || v == Double.MAX_VALUE){
if (Double.isInfinite(v) || v == Double.MAX_VALUE) {
return 1d;
}

Expand All @@ -26,7 +28,6 @@ public static double normalizeValue(double v) {
}



public static Truthness getEqualityTruthness(int a, int b) {
double distance = DistanceHelper.getDistanceToEquality(a, b);
double normalizedDistance = normalizeValue(distance);
Expand All @@ -45,6 +46,15 @@ public static Truthness getEqualityTruthness(long a, long b) {
);
}


public static Truthness getLessThanTruthness(double a, double b) {
double distance = DistanceHelper.getDistanceToEquality(a, b);
return new Truthness(
a < b ? 1d : 1d / (1.1d + distance),
a >= b ? 1d : 1d / (1.1d + distance)
);
}

public static Truthness getLessThanTruthness(long a, long b) {
double distance = DistanceHelper.getDistanceToEquality(a, b);
return new Truthness(
Expand Down Expand Up @@ -79,4 +89,58 @@ public static Truthness getTruthnessToEmpty(int len) {
}
return t;
}

public static Truthness buildAndAggregationTruthness(Truthness... truthnesses) {
double averageOfTrue = averageOfTrue(truthnesses);
double falseOrAverageFalse = falseOrAverageFalse(truthnesses);
return new Truthness(averageOfTrue, falseOrAverageFalse);
}

private static double averageOfTrue(Truthness... truthnesses) {
checkValidTruthnesses(truthnesses);
double[] getOfTrueValues = Arrays.stream(truthnesses).mapToDouble(Truthness::getOfTrue)
.toArray();
return average(getOfTrueValues);
}

private static void checkValidTruthnesses(Truthness[] truthnesses) {
if (truthnesses == null || truthnesses.length == 0 || Arrays.stream(truthnesses).anyMatch(e -> e == null)) {
throw new IllegalArgumentException("null or empty Truthness instance");
}
}

private static double average(double... values) {
if (values == null || values.length == 0) {
throw new IllegalArgumentException("null or empty values");
}
double total = 0.0;
for (double v : values) {
total += v;
}
return total / values.length;
}

private static double averageOfFalse(Truthness... truthnesses) {
checkValidTruthnesses(truthnesses);
double[] getOfFalseValues = Arrays.stream(truthnesses).mapToDouble(Truthness::getOfFalse)
.toArray();
return average(getOfFalseValues);
}

private static double falseOrAverageFalse(Truthness... truthnesses) {
checkValidTruthnesses(truthnesses);
if (Arrays.stream(truthnesses).anyMatch(t -> t.isFalse())) {
return 1.0d;
} else {
return averageOfFalse(truthnesses);
}
}

public static Truthness buildScaledTruthness(double base, double ofTrueToScale) {
final double scaledOfTrue = DistanceHelper.scaleHeuristicWithBase(ofTrueToScale, base);
final double ofFalse = 1.0d;
return new Truthness(scaledOfTrue, ofFalse);
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ public QueryResult(List<VariableDescriptor> variableDescriptorList) {
variableDescriptors.addAll(variableDescriptorList);
}



/**
* WARNING: Constructor only needed for testing
*
Expand Down Expand Up @@ -173,4 +175,17 @@ public QueryResultDto toDto(){

return dto;
}

/**
* Retrieves the table name of this queryResult.
*
* @return the table name of the first {@code VariableDescriptor} in the {@code variableDescriptors} list.
* @throws IllegalStateException if the {@code variableDescriptors} list is empty.
*/
public String getTableName() {
if (variableDescriptors.isEmpty()) {
throw new IllegalStateException("No variable descriptors found");
}
return variableDescriptors.get(0).getTableName();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package org.evomaster.client.java.sql;

import java.util.Map;
import java.util.TreeMap;

/**
* Represents a collection of query results mapped to table names,
* with support for both named and virtual tables.
*
* This class allows case-sensitive or case-insensitive handling of table names
* and provides mechanisms to add, retrieve, and manage query results.
*
*/
public class QueryResultSet {

/**
* A map storing query results associated with table names.
* The keys are table names, and the values are {@link QueryResult} objects.
*/
private final Map<String, QueryResult> queryResults;

/**
* Indicates whether table name comparisons are case-sensitive.
*/
private final boolean isCaseSensitive;

/**
* Stores the query result for a virtual table, if any.
*/
private QueryResult queryResultForVirtualTable;

public QueryResultSet() {
this(true);
}

/**
* Creates a new {@code QueryResultSet}.
*
* @param isCaseSensitive whether table name comparisons should be case-sensitive
*/
public QueryResultSet(boolean isCaseSensitive) {
queryResults = new TreeMap<>(isCaseSensitive ? null : String.CASE_INSENSITIVE_ORDER);
this.isCaseSensitive = isCaseSensitive;
}

/**
* Returns whether table name comparisons are case-sensitive.
*
* @return {@code true} if comparisons are case-sensitive, {@code false} otherwise
*/
public boolean isCaseSensitive() {
return isCaseSensitive;
}

/**
* Adds a query result to the result set.
* <p>
* If the query result corresponds to a named table, it is stored in the map.
* If it corresponds to a virtual table, it is stored separately.
* Throws an exception if a duplicate table (named or virtual) is added.
* </p>
*
* @param queryResult the query result to add
* @throws IllegalArgumentException if the table name already exists in the set
*/
public void addQueryResult(QueryResult queryResult) {
String tableName = queryResult.seeVariableDescriptors()
.stream()
.findFirst()
.map(VariableDescriptor::getTableName)
.orElse(null);

if (tableName == null) {
handleVirtualTable(queryResult);
} else {
handleNamedTable(tableName, queryResult);
}
}

private void handleNamedTable(String tableName, QueryResult queryResult) {
if (queryResults.containsKey(tableName)) {
throw new IllegalArgumentException("Duplicate table in QueryResultSet: " + tableName);
}
queryResults.put(tableName, queryResult);
}

private void handleVirtualTable(QueryResult queryResult) {
if (queryResultForVirtualTable != null) {
throw new IllegalArgumentException("Duplicate values for virtual table");
}
queryResultForVirtualTable = queryResult;
}

/**
* Retrieves the query result associated with a named table.
*
* @param tableName the name of the table
* @return the query result for the table, or {@code null} if no result exists
*/
public QueryResult getQueryResultForNamedTable(String tableName) {
return queryResults.get(tableName);
}

/**
* Retrieves the query result for a virtual table.
*
* @return the query result for the virtual table, or {@code null} if none exists
*/
public QueryResult getQueryResultForVirtualTable() {
return queryResultForVirtualTable;
}

}
Loading

0 comments on commit b23d0da

Please sign in to comment.