Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
1cb0b0a
introduces specific logic to handle SELECT queries that include a LIM…
jgaleotti Nov 17, 2025
6b7c3cc
support for SQL COALESCE() function, enhancing of SQL TIME() function…
jgaleotti Nov 18, 2025
de4806d
support for ORDER BY (ascending and descending)
jgaleotti Nov 18, 2025
ea6e025
replace size()>0 with !isEmpty()
jgaleotti Nov 18, 2025
44573bc
initial implementation of DateTrunc
jgaleotti Nov 19, 2025
a7e7f64
support for SQL NOW() as canonical value / DATE_TRUNC() supports both…
jgaleotti Nov 19, 2025
057b062
ORDER BY expressions are evaluated as any other expressions in SqlHeu…
jgaleotti Nov 19, 2025
2d0dde5
test `testDeleteFromWithSubquery` validates the detection of tables …
jgaleotti Nov 26, 2025
e84be1b
Merge branch 'master' into advanced-sql-missing-features
jgaleotti Nov 26, 2025
c61b154
support for SQL LOWER() function / test cases for both lower() and up…
jgaleotti Nov 26, 2025
f72d733
support for Common Table Expressions (CTE)
jgaleotti Nov 26, 2025
7ffd2e7
add support for Common Table Expressions (CTE) with aliases in SQL he…
jgaleotti Nov 27, 2025
01494f2
handle parenthesized select items in SQL heuristics and add correspon…
jgaleotti Nov 28, 2025
dc4a956
use nullSafeEndsWithIgnoreCase when retrieving DataRow values to hand…
jgaleotti Dec 1, 2025
a3e0530
Merge remote-tracking branch 'origin/master' into advanced-sql-missin…
jgaleotti Dec 1, 2025
c1fe77f
Add multi-schema support in SQL table and column resolution
jgaleotti Dec 2, 2025
a93816d
Refactor SQL table and column resolution
jgaleotti Dec 2, 2025
b8de407
Add support for catalog and schema names when querying data from the …
jgaleotti Dec 2, 2025
dcc1e68
support for catalog/schema/table name
jgaleotti Dec 3, 2025
e87b94a
Merge remote-tracking branch 'origin/master' into advanced-sql-missin…
jgaleotti Dec 3, 2025
1031b00
Merge remote-tracking branch 'origin/master' into advanced-sql-missin…
jgaleotti Dec 3, 2025
610d800
support for SELECT DISTINCT and SELECT DISTINCT ON
jgaleotti Dec 3, 2025
fbbb362
If an SQL aggregation returns multiple rows, SQL picks the first one …
jgaleotti Dec 4, 2025
e572dbc
Fixing bug in TablesNameFinder by adding missing implementation for I…
jgaleotti Dec 4, 2025
f2ac00e
SQL DATE() function
jgaleotti Dec 4, 2025
69b82a8
SQL UUID comparisons
jgaleotti Dec 4, 2025
fc49ad0
bugfix: invalid database names
jgaleotti Dec 5, 2025
36f0506
bugfix: handle MYSQL select queries with both database and schema.
jgaleotti Dec 5, 2025
79cf4fd
Merge remote-tracking branch 'origin/master' into advanced-sql-missin…
jgaleotti Dec 9, 2025
f544aa5
Merge remote-tracking branch 'origin/master' into advanced-sql-missin…
jgaleotti Dec 15, 2025
bafec04
Merge remote-tracking branch 'origin/master' into advanced-sql-missin…
jgaleotti Dec 17, 2025
e25a404
Merge remote-tracking branch 'origin/master' into advanced-sql-missin…
jgaleotti Dec 30, 2025
e6b1bbf
Merge remote-tracking branch 'origin/master' into advanced-sql-missin…
jgaleotti Jan 9, 2026
c69573a
Add some explanantion and tests for CoalesceFunction
jgaleotti Jan 9, 2026
3767698
fixed error message plus added test cases for empty arguments and mor…
jgaleotti Jan 9, 2026
89e46d5
added number of arguments to message errors / improved message error …
jgaleotti Jan 9, 2026
71cae15
Refactored `TableAliasResolver` by extracting `TableAliasContext` int…
jgaleotti Jan 9, 2026
b48b596
added TODO comments to TableNameMatcher.matches()
jgaleotti Jan 9, 2026
1653850
added logic to detect illegal catalog and schema names
jgaleotti Jan 12, 2026
fc40c87
added some comment to sqlTableId constructor
jgaleotti Jan 12, 2026
8971efb
Updated `SqlTableId` and `SqlTableIdParser` to support `DatabaseType`…
jgaleotti Jan 14, 2026
feee946
Merge remote-tracking branch 'origin/master' into advanced-sql-missin…
jgaleotti Jan 14, 2026
300ccf5
testfix: adding database type to schema
jgaleotti Jan 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@
import java.time.chrono.ChronoLocalDateTime;
import java.util.Date;
import java.util.Objects;
import java.util.UUID;

/**
* All generic distance functions on JVM types should be defined here.
* Recall the distinction between "distance" and "heuristic" terms in EvoMaster:
*
* <p>
* - distance: a value between 0 and MAX. If 0, constraint is solved.
* - heuristic: a value between 0 and 1. If 0, constraint is NOT solved. If solved, value is 1.
*
* <p>
* The "distance"s are what usually used in literature.
* However, in EvoMaster we need [0,1] "heuristic"s (due to the handling of Many Objective Optimization).
*/
Expand Down Expand Up @@ -44,23 +45,23 @@ public class DistanceHelper {
* @param delta
* @return
*/
public static double increasedDistance(double distance, double delta){
public static double increasedDistance(double distance, double delta) {

if(distance < 0){
if (distance < 0) {
throw new IllegalArgumentException("Negative distance: " + distance);
}
if(delta < 0){
if (delta < 0) {
throw new IllegalArgumentException("Invalid negative delta: " + delta);
}
if(delta == 0){
if (delta == 0) {
throw new IllegalArgumentException("Meaningless 0 delta");
}

if(Double.isInfinite(distance) || distance == Double.MAX_VALUE){
if (Double.isInfinite(distance) || distance == Double.MAX_VALUE) {
return distance;
}

if(distance > (Double.MAX_VALUE - delta)){
if (distance > (Double.MAX_VALUE - delta)) {
return Double.MAX_VALUE;
}

Expand All @@ -75,10 +76,10 @@ public static double increasedDistance(double distance, double delta){
* @return
*/
public static double addDistances(double a, double b) {
if(a < 0){
if (a < 0) {
throw new IllegalArgumentException("Negative distance: " + a);
}
if(b < 0){
if (b < 0) {
throw new IllegalArgumentException("Negative distance: " + b);
}
double sum = a + b;
Expand All @@ -92,36 +93,37 @@ public static double addDistances(double a, double b) {

/**
* Return a h=[0,1] heuristics from a scaled distance, taking into account a starting base
*
* @param base
* @param distance
* @return
*/
public static double heuristicFromScaledDistanceWithBase(double base, double distance){
public static double heuristicFromScaledDistanceWithBase(double base, double distance) {

if(base < 0 || base >= 1){
if (base < 0 || base >= 1) {
throw new IllegalArgumentException("Invalid base: " + base);
}
if(distance < 0){
if (distance < 0) {
throw new IllegalArgumentException("Negative distance: " + distance);
}

if(Double.isInfinite(distance) || distance == Double.MAX_VALUE){
if (Double.isInfinite(distance) || distance == Double.MAX_VALUE) {
return base;
}

return base + ((1 - base) / (distance + 1));
return base + ((1 - base) / (distance + 1));
}

public static double scaleHeuristicWithBase(double heuristic, double base){
public static double scaleHeuristicWithBase(double heuristic, double base) {

if(heuristic < 0 || heuristic >= 1){
if (heuristic < 0 || heuristic >= 1) {
throw new IllegalArgumentException("Invalid heuristic: " + base);
}
if(base < 0 || base >= 1){
if (base < 0 || base >= 1) {
throw new IllegalArgumentException("Invalid base: " + base);
}

return base + ((1-base)*heuristic);
return base + ((1 - base) * heuristic);
}

public static int distanceToDigit(char c) {
Expand All @@ -144,7 +146,7 @@ public static int distanceToRange(int c, int minInclusive, int maxInclusive) {

//1 of 2 will be necessarily a 0
long dist = Math.max(diffAfter, 0) + Math.max(diffBefore, 0);
if(dist > Integer.MAX_VALUE){
if (dist > Integer.MAX_VALUE) {
return Integer.MAX_VALUE;
}
assert (dist >= 0);
Expand All @@ -166,7 +168,7 @@ public static long getLeftAlignmentDistance(String a, String b) {
dist += Math.abs(a.charAt(i) - b.charAt(i));
}

if(dist < 0){
if (dist < 0) {
dist = Long.MAX_VALUE; // overflow
}

Expand Down Expand Up @@ -242,10 +244,10 @@ public static double getDistanceToEquality(LocalTime a, LocalTime b) {

public static double getDistance(Object left, Object right) {

if(left == null && right == null){
if (left == null && right == null) {
return 0;
}
if(left == null || right == null){
if (left == null || right == null) {
return Double.MAX_VALUE;
}

Expand Down Expand Up @@ -330,4 +332,19 @@ public static double getDistance(Object left, Object right) {

return distance;
}

/**
* Computes the Hamming distance between two UUIDs. The Hamming distance is determined by
* counting the number of differing bits between the most and least significant bits
* of the two UUIDs.
*
* @param left the first UUID
* @param right the second UUID
* @return the Hamming distance between the two UUIDs
*/
public static int getDistance(UUID left, UUID right) {
long diff1 = left.getMostSignificantBits() ^ right.getMostSignificantBits();
long diff2 = left.getLeastSignificantBits() ^ right.getLeastSignificantBits();
return Long.bitCount(diff1) + Long.bitCount(diff2);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.Arrays;
import java.util.Objects;
import java.util.UUID;

public class TruthnessUtils {

Expand Down Expand Up @@ -132,6 +133,7 @@ public static Truthness getEqualityTruthness(double a, double b) {

/**
* Returns a truthness value for comparing how close a length was to 0.
*
* @param len a positive value for a length
* @return a Truthness instance
*/
Expand Down Expand Up @@ -190,13 +192,13 @@ public static Truthness buildOrAggregationTruthness(Truthness... truthnesses) {
* <p>
* This method returns XOR(a,b) as (a AND NOT b) OR (NOT a AND b).
*
* @param left the first Truthness instance
* @param left the first Truthness instance
* @param right the second Truthness instance
* @return a new Truthness instance representing the XOR aggregation of the input Truthness instances
*/
public static Truthness buildXorAggregationTruthness(Truthness left, Truthness right) {
Truthness leftAndNotRight = buildAndAggregationTruthness(left,right.invert());
Truthness notLeftAndRight = buildAndAggregationTruthness(left.invert(),right);
Truthness leftAndNotRight = buildAndAggregationTruthness(left, right.invert());
Truthness notLeftAndRight = buildAndAggregationTruthness(left.invert(), right);
Truthness orAggregation = buildOrAggregationTruthness(leftAndNotRight, notLeftAndRight);
return orAggregation;
}
Expand Down Expand Up @@ -294,7 +296,7 @@ private static double trueOrAverageTrue(Truthness... truthnesses) {
* and creates a Truthness instance where the `ofTrue` field is the scaled value and
* the `ofFalse` field is set to 1.0.
*
* @param base the base value used for scaling
* @param base the base value used for scaling
* @param ofTrueToScale the value to be scaled
* @return a new Truthness instance with the scaled `ofTrue` value and `ofFalse` set to 1.0
*/
Expand All @@ -305,5 +307,16 @@ public static Truthness buildScaledTruthness(double base, double ofTrueToScale)
}


public static Truthness getEqualityTruthness(UUID left, UUID right) {
Objects.requireNonNull(left);
Objects.requireNonNull(right);

double distance = DistanceHelper.getDistance(left, right);
double normalizedDistance = normalizeValue(distance);
return new Truthness(
1d - normalizedDistance,
!left.equals(right) ? 1d : 0d
);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import org.junit.jupiter.api.Test;

import java.util.UUID;

import static org.evomaster.client.java.distance.heuristics.DistanceHelper.*;
import static org.junit.jupiter.api.Assertions.*;

Expand Down Expand Up @@ -68,9 +70,33 @@ public void testDoubleOverflowsDistance() {

@Test
public void testDoubleMaxDistance() {
double upperBound = Double.MAX_VALUE /2;
double upperBound = Double.MAX_VALUE / 2;
double lowerBound = -upperBound;
double distance = getDistanceToEquality(lowerBound, upperBound);
assertEquals(Double.MAX_VALUE, distance);
}
}

@Test
public void testDistanceUUIDEquals() {
UUID left = UUID.fromString("123e4567-e89b-12d3-a456-426614174000");
UUID right = UUID.fromString("123e4567-e89b-12d3-a456-426614174000");
double distance = getDistance(left, right);
assertEquals(0, distance);
}

@Test
public void testDistanceUUIDNotEquals() {
UUID left = UUID.fromString("123e4567-e89b-12d3-a456-426614174001");
UUID right = UUID.fromString("123e4567-e89b-12d3-a456-426614174000");
double distance = getDistance(left, right);
assertEquals(1, distance);
}

@Test
public void testDistanceUUIDNotEqualsThree() {
UUID left = UUID.fromString("123e4567-e89b-12d3-a456-426614174003");
UUID right = UUID.fromString("123e4567-e89b-12d3-a456-426614174000");
double distance = getDistance(left, right);
assertEquals(2, distance);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.evomaster.client.java.distance.heuristics;

import org.junit.jupiter.api.Test;

import java.util.UUID;

import static org.evomaster.client.java.distance.heuristics.TruthnessUtils.normalizeValue;
import static org.junit.jupiter.api.Assertions.*;

class TruthnessUtilsTest {

@Test
public void testGetEqualityTruthnessEqualsUUID() {
UUID left = UUID.fromString("123e4567-e89b-12d3-a456-426614174000");
UUID right = UUID.fromString("123e4567-e89b-12d3-a456-426614174000");
Truthness t = TruthnessUtils.getEqualityTruthness(left, right);
assertTrue(t.isTrue());
assertEquals(1.0, t.getOfTrue());
assertEquals(0.0, t.getOfFalse());
}

@Test
public void testGetEqualityTruthnessNotEqualsUUID() {
UUID left = UUID.fromString("123e4567-e89b-12d3-a456-426614174000");
UUID right = UUID.fromString("123e4567-e89b-12d3-a456-426614174001");
Truthness t = TruthnessUtils.getEqualityTruthness(left, right);
assertFalse(t.isTrue());
assertEquals(1.0 - normalizeValue(1), t.getOfTrue());
assertEquals(1.0, t.getOfFalse());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.util.*;
import java.util.stream.Collectors;

import static org.evomaster.client.java.sql.heuristic.SqlStringUtils.nullSafeEndsWithIgnoreCase;
import static org.evomaster.client.java.sql.heuristic.SqlStringUtils.nullSafeEqualsIgnoreCase;

/**
Expand Down Expand Up @@ -102,10 +103,10 @@ public Object getValueByName(String name, String table) {
* since 'y','n','on','off', 'yes' and 'no'
* are also considered boolean literals.
*/
if (n!=null && n.equalsIgnoreCase("true")) {
if (n != null && n.equalsIgnoreCase("true")) {
return true;
}
if (n!= null && n.equalsIgnoreCase("false")) {
if (n != null && n.equalsIgnoreCase("false")) {
return false;
}

Expand All @@ -128,11 +129,11 @@ public Object getValueByName(String name, String table) {
boolean matchColumnName = nullSafeEqualsIgnoreCase(n, desc.getColumnName())
|| nullSafeEqualsIgnoreCase(n, desc.getAliasColumnName());

if (!matchColumnName){
if (!matchColumnName) {
continue;
}
//no defined table, or exact match
if(t == null || t.isEmpty() || nullSafeEqualsIgnoreCase(t, desc.getTableName()) ){
if (t == null || t.isEmpty() || nullSafeEqualsIgnoreCase(t, desc.getTableName())) {
return getValue(i);
}
/*
Expand All @@ -141,20 +142,20 @@ there can be many unnamed tables (eg results of sub-selects)
with same column names. At this moment, we would not
be able to distinguish them
*/
if(nullSafeEqualsIgnoreCase(t, SqlNameContext.UNNAMED_TABLE)){
if (nullSafeEqualsIgnoreCase(t, SqlNameContext.UNNAMED_TABLE)) {
candidates.add(i);
}

if(!t.contains(".") && desc.getTableName().toLowerCase().endsWith("."+t.toLowerCase())){
if (!t.contains(".") && nullSafeEndsWithIgnoreCase(desc.getTableName(), "." + t)) {
candidates.add(i);
}
}

if(candidates.size() > 1){
if (candidates.size() > 1) {
SimpleLogger.uniqueWarn("More than one table candidate for: " + t);
}

if(candidates.size() >= 1){
if (candidates.size() >= 1) {
return getValue(candidates.get(0));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.evomaster.client.java.sql;

import net.sf.jsqlparser.statement.select.OrderByElement;
import org.evomaster.client.java.controller.api.dto.database.operations.QueryResultDto;

import java.lang.reflect.Method;
Expand Down Expand Up @@ -195,4 +196,26 @@ 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;
}

}
Loading