Skip to content

Commit 0492650

Browse files
committed
Add an expected error class
This class introduces additional flexibility when dealing with expected errors. For now, it unifies the data structure used for handling expected errors. Future improvements could, for example, include support for regular expressions.
1 parent d722528 commit 0492650

File tree

109 files changed

+382
-389
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

109 files changed

+382
-389
lines changed

src/sqlancer/ComparatorHelper.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ static boolean equals(double a, double b) {
3131
return Math.abs(a - b) < 0.0001 * Math.max(Math.abs(a), Math.abs(b));
3232
}
3333

34-
public static List<String> getResultSetFirstColumnAsString(String queryString, Set<String> errors,
34+
public static List<String> getResultSetFirstColumnAsString(String queryString, ExpectedErrors errors,
3535
GlobalState<?, ?> state) throws SQLException {
3636
if (state.getOptions().logEachSelect()) {
3737
// TODO: refactor me
@@ -65,10 +65,8 @@ public static List<String> getResultSetFirstColumnAsString(String queryString, S
6565
if (e.getMessage() == null) {
6666
throw new AssertionError(queryString, e);
6767
}
68-
for (String error : errors) {
69-
if (e.getMessage().contains(error)) {
70-
throw new IgnoreMeException();
71-
}
68+
if (errors.errorIsExpected(e.getMessage())) {
69+
throw new IgnoreMeException();
7270
}
7371
throw new AssertionError(queryString, e);
7472
} finally {
@@ -114,7 +112,7 @@ public static void assumeResultSetsAreEqual(List<String> resultSet, List<String>
114112

115113
public static List<String> getCombinedResultSet(String firstQueryString, String secondQueryString,
116114
String thirdQueryString, List<String> combinedString, boolean asUnion, GlobalState<?, ?> state,
117-
Set<String> errors) throws SQLException {
115+
ExpectedErrors errors) throws SQLException {
118116
List<String> secondResultSet;
119117
if (asUnion) {
120118
String unionString = firstQueryString + " UNION ALL " + secondQueryString + " UNION ALL "
@@ -135,7 +133,7 @@ public static List<String> getCombinedResultSet(String firstQueryString, String
135133

136134
public static List<String> getCombinedResultSetNoDuplicates(String firstQueryString, String secondQueryString,
137135
String thirdQueryString, List<String> combinedString, boolean asUnion, GlobalState<?, ?> state,
138-
Set<String> errors) throws SQLException {
136+
ExpectedErrors errors) throws SQLException {
139137
String unionString;
140138
if (asUnion) {
141139
unionString = firstQueryString + " UNION " + secondQueryString + " UNION " + thirdQueryString;

src/sqlancer/ExpectedErrors.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package sqlancer;
2+
3+
import java.util.Collection;
4+
import java.util.HashSet;
5+
import java.util.Set;
6+
7+
/**
8+
* This class represents the errors that executing a statement might result in. For example, an INSERT statement might
9+
* result in an error "UNIQUE constraint violated" when it attempts to insert a duplicate value in a column declared as
10+
* UNIQUE.
11+
*/
12+
public class ExpectedErrors {
13+
14+
private final Set<String> errors = new HashSet<>();
15+
16+
public ExpectedErrors add(String error) {
17+
if (error == null) {
18+
throw new IllegalArgumentException();
19+
}
20+
errors.add(error);
21+
return this;
22+
}
23+
24+
/**
25+
* Checks whether the error message (e.g., returned by the DBMS under test) contains any of the added error
26+
* messages.
27+
*
28+
* @param error
29+
* the error message
30+
*
31+
* @return whether the error message contains any of the substrings specified as expected errors
32+
*/
33+
public boolean errorIsExpected(String error) {
34+
if (error == null) {
35+
throw new IllegalArgumentException();
36+
}
37+
for (String s : errors) {
38+
if (error.contains(s)) {
39+
return true;
40+
}
41+
}
42+
return false;
43+
}
44+
45+
public ExpectedErrors addAll(Collection<String> list) {
46+
errors.addAll(list);
47+
return this;
48+
}
49+
50+
public static ExpectedErrors from(String... errors) {
51+
ExpectedErrors expectedErrors = new ExpectedErrors();
52+
for (String error : errors) {
53+
expectedErrors.add(error);
54+
}
55+
return expectedErrors;
56+
}
57+
58+
}

src/sqlancer/NoRECBase.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
package sqlancer;
22

33
import java.sql.Connection;
4-
import java.util.HashSet;
5-
import java.util.Set;
64

75
import sqlancer.Main.StateLogger;
86

97
public abstract class NoRECBase<S extends GlobalState<?, ?>> implements TestOracle {
108

119
protected final S state;
12-
protected final Set<String> errors = new HashSet<>();
10+
protected final ExpectedErrors errors = new ExpectedErrors();
1311
protected final StateLogger logger;
1412
protected final MainOptions options;
1513
protected final Connection con;

src/sqlancer/Query.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package sqlancer;
22

33
import java.sql.SQLException;
4-
import java.util.Collection;
54

65
public abstract class Query {
76

@@ -24,7 +23,7 @@ public abstract class Query {
2423
*/
2524
public abstract boolean execute(GlobalState<?, ?> globalState, String... fills) throws SQLException;
2625

27-
public abstract Collection<String> getExpectedErrors();
26+
public abstract ExpectedErrors getExpectedErrors();
2827

2928
@Override
3029
public String toString() {

src/sqlancer/QueryAdapter.java

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,26 @@
44
import java.sql.ResultSet;
55
import java.sql.SQLException;
66
import java.sql.Statement;
7-
import java.util.ArrayList;
8-
import java.util.Collection;
97

108
public class QueryAdapter extends Query {
119

1210
private final String query;
13-
private final Collection<String> expectedErrors;
11+
private final ExpectedErrors expectedErrors;
1412
private final boolean couldAffectSchema;
1513

1614
public QueryAdapter(String query) {
17-
this(query, new ArrayList<>());
15+
this(query, new ExpectedErrors());
1816
}
1917

2018
public QueryAdapter(String query, boolean couldAffectSchema) {
21-
this(query, new ArrayList<>(), couldAffectSchema);
19+
this(query, new ExpectedErrors(), couldAffectSchema);
2220
}
2321

24-
public QueryAdapter(String query, Collection<String> expectedErrors) {
25-
this.query = canonicalizeString(query);
26-
this.expectedErrors = expectedErrors;
27-
this.couldAffectSchema = false;
28-
checkQueryString();
22+
public QueryAdapter(String query, ExpectedErrors expectedErrors) {
23+
this(query, expectedErrors, false);
2924
}
3025

31-
public QueryAdapter(String query, Collection<String> expectedErrors, boolean couldAffectSchema) {
26+
public QueryAdapter(String query, ExpectedErrors expectedErrors, boolean couldAffectSchema) {
3227
this.query = canonicalizeString(query);
3328
this.expectedErrors = expectedErrors;
3429
this.couldAffectSchema = couldAffectSchema;
@@ -84,14 +79,7 @@ public boolean execute(GlobalState<?, ?> globalState, String... fills) throws SQ
8479
}
8580

8681
public void checkException(Exception e) throws AssertionError {
87-
boolean isExcluded = false;
88-
for (String expectedError : expectedErrors) {
89-
if (e.getMessage().contains(expectedError)) {
90-
isExcluded = true;
91-
break;
92-
}
93-
}
94-
if (!isExcluded) {
82+
if (!expectedErrors.errorIsExpected(e.getMessage())) {
9583
throw new AssertionError(query, e);
9684
}
9785
}
@@ -133,7 +121,7 @@ public boolean couldAffectSchema() {
133121
}
134122

135123
@Override
136-
public Collection<String> getExpectedErrors() {
124+
public ExpectedErrors getExpectedErrors() {
137125
return expectedErrors;
138126
}
139127

src/sqlancer/TernaryLogicPartitioningOracleBase.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
package sqlancer;
22

3-
import java.util.HashSet;
4-
import java.util.Set;
5-
63
import sqlancer.gen.ExpressionGenerator;
74

85
/**
@@ -20,7 +17,7 @@ public abstract class TernaryLogicPartitioningOracleBase<E, S> implements TestOr
2017
protected E isNullPredicate;
2118

2219
protected final S state;
23-
protected final Set<String> errors = new HashSet<>();
20+
protected final ExpectedErrors errors = new ExpectedErrors();
2421

2522
protected TernaryLogicPartitioningOracleBase(S state) {
2623
this.state = state;

src/sqlancer/citus/CitusProvider.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,12 @@
88
import java.util.ArrayList;
99
import java.util.Arrays;
1010
import java.util.HashMap;
11-
import java.util.HashSet;
1211
import java.util.List;
13-
import java.util.Set;
1412
import java.util.stream.Collectors;
1513

1614
import sqlancer.AbstractAction;
1715
import sqlancer.CompositeTestOracle;
16+
import sqlancer.ExpectedErrors;
1817
import sqlancer.IgnoreMeException;
1918
import sqlancer.Query;
2019
import sqlancer.QueryAdapter;
@@ -452,8 +451,8 @@ public String getDBMSName() {
452451
return "citus";
453452
}
454453

455-
private static Set<String> getCitusErrors() {
456-
Set<String> errors = new HashSet<>();
454+
private static ExpectedErrors getCitusErrors() {
455+
ExpectedErrors errors = new ExpectedErrors();
457456
CitusCommon.addCitusErrors(errors);
458457
return errors;
459458
}

src/sqlancer/citus/gen/CitusAlterTableGenerator.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package sqlancer.citus.gen;
22

33
import java.util.List;
4-
import java.util.Set;
54

5+
import sqlancer.ExpectedErrors;
66
import sqlancer.IgnoreMeException;
77
import sqlancer.Query;
88
import sqlancer.postgres.PostgresGlobalState;
@@ -21,7 +21,7 @@ public static Query create(PostgresTable randomTable, PostgresGlobalState global
2121
}
2222

2323
@Override
24-
public List<Action> getActions(Set<String> errors) {
24+
public List<Action> getActions(ExpectedErrors errors) {
2525
List<Action> action = super.getActions(errors);
2626
CitusCommon.addCitusErrors(errors);
2727
action.remove(Action.ALTER_COLUMN_SET_STATISTICS);

src/sqlancer/citus/gen/CitusCommon.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package sqlancer.citus.gen;
22

3-
import java.util.Collection;
4-
import java.util.Set;
5-
3+
import sqlancer.ExpectedErrors;
64
import sqlancer.postgres.PostgresGlobalState;
75
import sqlancer.postgres.PostgresSchema.PostgresTable;
86
import sqlancer.postgres.gen.PostgresCommon;
@@ -12,7 +10,7 @@ public final class CitusCommon {
1210
private CitusCommon() {
1311
}
1412

15-
public static void addCitusErrors(Collection<String> errors) {
13+
public static void addCitusErrors(ExpectedErrors errors) {
1614
errors.add("recursive CTEs are not supported in distributed queries");
1715
errors.add("could not run distributed query with GROUPING SETS, CUBE, or ROLLUP");
1816
errors.add("Subqueries in HAVING cannot refer to outer query");
@@ -68,7 +66,7 @@ public static void addCitusErrors(Collection<String> errors) {
6866
}
6967

7068
public static void addTableConstraint(StringBuilder sb, PostgresTable table, PostgresGlobalState globalState,
71-
Set<String> errors) {
69+
ExpectedErrors errors) {
7270
PostgresCommon.addTableConstraint(sb, table, globalState, errors);
7371
CitusCommon.addCitusErrors(errors);
7472
}

src/sqlancer/citus/gen/CitusDeleteGenerator.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package sqlancer.citus.gen;
22

3-
import java.util.Set;
4-
3+
import sqlancer.ExpectedErrors;
54
import sqlancer.Query;
65
import sqlancer.postgres.PostgresGlobalState;
76
import sqlancer.postgres.gen.PostgresDeleteGenerator;
@@ -13,7 +12,7 @@ private CitusDeleteGenerator() {
1312

1413
public static Query create(PostgresGlobalState globalState) {
1514
Query deleteQuery = PostgresDeleteGenerator.create(globalState);
16-
Set<String> errors = (Set<String>) deleteQuery.getExpectedErrors();
15+
ExpectedErrors errors = deleteQuery.getExpectedErrors();
1716
CitusCommon.addCitusErrors(errors);
1817
return deleteQuery;
1918
}

0 commit comments

Comments
 (0)