Skip to content

Commit f14743d

Browse files
2010YOUY01malwaregarrymriggerqoegarobins
authored
Sync with upstream (#18)
* Add TLPWhereGenerator interface * Add generic TLPWhere oracle * Implement TLPWhereGenerator interfaces for SQLite3 * Use generic TLPWhere oracle for SQLite3 * [Databend] Refactor tests * [Databend] Update to v1.2.542 * Remove duplicated logs in NoREC oracle (#953) * [ClickHouse] Added pattern for changed error message (#955) * [ClickHouse] Added pattern for changed error message https://fiddle.clickhouse.com/a3a95024-4da7-4275-baff-86f116014744 ``` Received exception from server (version 24.2.3): Code: 403. DB::Exception: Received from localhost:9000. DB::Exception: Cannot get JOIN keys from JOIN ON section: '476505718 = `_--right_2.c0`', found keys: [Left keys: [] Right keys [] Condition columns: '', 'equals(476505718, _--right_2.c0)']. (INVALID_JOIN_ON_EXPRESSION) (query: SELECT SUM(check <> 0) FROM ((SELECT right_0.c0 AS `check` FROM t0 AS left FULL OUTER JOIN t0 AS right_0 ON ((left.c0)=(right_0.c0)) LEFT OUTER JOIN t0 AS right_1 ON ((left.c0)=(right_1.c0)) LEFT ANTI JOIN t0 AS right_2 ON ((476505718)=(right_2.c0)))) as res;) ``` * formatter * Avoid storage parameters during CREATE TABLE for partitioned tables (#956) CREATE TABLE WITH() allows storage parameters, but partitioned tables emit an error (given below) if attempted. This is because partitioned non-leaf tables are virutal tables [1] and don't accept storage parameters. Sample Error: "ERROR: cannot specify storage parameters for a partitioned table" This patch skips storage parameter generation for partitioned tables. Ref: 1. https://www.postgresql.org/docs/current/ddl-partitioning.html * Review feedback * Ensure INHERITS() only uses tables (not views) In Postgres, CREATE TABLE INHERITS () throws an error when VIEWs are provided, sample given below. ERROR: inherited relation "pg_buffercache" is not a table or foreign table Ref: 1. https://www.postgresql.org/docs/current/ddl-inherit.html * Revert "Ensure INHERITS() only uses tables (not views)" This reverts commit 0316c1c. * Ensure INHERITS() only uses tables (not views) In Postgres, CREATE TABLE INHERITS () throws an error when VIEWs are provided, sample given below. ERROR: inherited relation "pg_buffercache" is not a table or foreign table Ref: 1. https://www.postgresql.org/docs/current/ddl-inherit.html * Another fix --------- Co-authored-by: malwaregarry <[email protected]> Co-authored-by: ming wei <[email protected]> Co-authored-by: Manuel Rigger <[email protected]> Co-authored-by: Ilya Yatsishin <[email protected]> Co-authored-by: Robins <[email protected]>
1 parent 6681b41 commit f14743d

18 files changed

+299
-174
lines changed

src/sqlancer/clickhouse/ClickHouseErrors.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ public static List<String> getExpectedExpressionErrors() {
4545
"Positional argument numeric constant expression is not representable as",
4646
"Positional argument must be constant with numeric type", " is out of bounds. Expected in range",
4747
"with constants is not supported. (INVALID_JOIN_ON_EXPRESSION)",
48-
"Unexpected inf or nan to integer conversion", "Unsigned type must not contain",
48+
"Cannot get JOIN keys from JOIN ON section", "Unexpected inf or nan to integer conversion",
49+
"Cannot determine join keys in", "Unsigned type must not contain",
4950
"Unexpected inf or nan to integer conversion",
5051

5152
// The way we generate JOINs we can have ambiguous left table column without
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package sqlancer.common.gen;
2+
3+
import sqlancer.common.ast.newast.Expression;
4+
import sqlancer.common.schema.AbstractTableColumn;
5+
6+
public interface PartitionGenerator<E extends Expression<C>, C extends AbstractTableColumn<?, ?>> {
7+
8+
/**
9+
* Negates a predicate (i.e., uses a NOT operator).
10+
*
11+
* @param predicate
12+
* the boolean predicate.
13+
*
14+
* @return the negated predicate.
15+
*/
16+
E negatePredicate(E predicate);
17+
18+
/**
19+
* Checks if an expression evaluates to NULL (i.e., implements the IS NULL operator).
20+
*
21+
* @param expr
22+
* the expression
23+
*
24+
* @return an expression that checks whether the expression evaluates to NULL.
25+
*/
26+
E isNull(E expr);
27+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package sqlancer.common.gen;
2+
3+
import java.util.List;
4+
5+
import sqlancer.common.ast.newast.Expression;
6+
import sqlancer.common.ast.newast.Join;
7+
import sqlancer.common.ast.newast.Select;
8+
import sqlancer.common.schema.AbstractTable;
9+
import sqlancer.common.schema.AbstractTableColumn;
10+
import sqlancer.common.schema.AbstractTables;
11+
12+
public interface TLPWhereGenerator<S extends Select<J, E, T, C>, J extends Join<E, T, C>, E extends Expression<C>, T extends AbstractTable<C, ?, ?>, C extends AbstractTableColumn<?, ?>>
13+
extends PartitionGenerator<E, C> {
14+
15+
TLPWhereGenerator<S, J, E, T, C> setTablesAndColumns(AbstractTables<T, C> tables);
16+
17+
E generateBooleanExpression();
18+
19+
S generateSelect();
20+
21+
List<J> getRandomJoinClauses();
22+
23+
List<E> getTableRefs();
24+
25+
List<E> generateFetchColumns(boolean shouldCreateDummy);
26+
27+
List<E> generateOrderBys();
28+
}

src/sqlancer/common/oracle/NoRECOracle.java

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,6 @@ public Reproducer<G> getLastReproducer() {
123123
private int countRows(String queryString, ExpectedErrors errors, SQLGlobalState<?, ?> state) {
124124
SQLQueryAdapter q = new SQLQueryAdapter(queryString, errors);
125125

126-
if (state.getOptions().logEachSelect()) {
127-
state.getLogger().writeCurrent(queryString);
128-
}
129-
130126
int count = 0;
131127
try (SQLancerResultSet rs = q.executeAndGet(state)) {
132128
if (rs == null) {
@@ -151,10 +147,6 @@ private int countRows(String queryString, ExpectedErrors errors, SQLGlobalState<
151147

152148
private int extractCounts(String queryString, ExpectedErrors errors, SQLGlobalState<?, ?> state) {
153149
SQLQueryAdapter q = new SQLQueryAdapter(queryString, errors);
154-
if (state.getOptions().logEachSelect()) {
155-
state.getLogger().writeCurrent(queryString);
156-
}
157-
158150
int count = 0;
159151
try (SQLancerResultSet rs = q.executeAndGet(state)) {
160152
if (rs == null) {
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package sqlancer.common.oracle;
2+
3+
import java.sql.SQLException;
4+
import java.util.ArrayList;
5+
import java.util.List;
6+
7+
import sqlancer.ComparatorHelper;
8+
import sqlancer.Randomly;
9+
import sqlancer.SQLGlobalState;
10+
import sqlancer.common.ast.newast.Expression;
11+
import sqlancer.common.ast.newast.Join;
12+
import sqlancer.common.ast.newast.Select;
13+
import sqlancer.common.gen.TLPWhereGenerator;
14+
import sqlancer.common.query.ExpectedErrors;
15+
import sqlancer.common.schema.AbstractSchema;
16+
import sqlancer.common.schema.AbstractTable;
17+
import sqlancer.common.schema.AbstractTableColumn;
18+
import sqlancer.common.schema.AbstractTables;
19+
20+
public class TLPWhereOracle<Z extends Select<J, E, T, C>, J extends Join<E, T, C>, E extends Expression<C>, S extends AbstractSchema<?, T>, T extends AbstractTable<C, ?, ?>, C extends AbstractTableColumn<?, ?>, G extends SQLGlobalState<?, S>>
21+
implements TestOracle<G> {
22+
23+
private final G state;
24+
25+
private TLPWhereGenerator<Z, J, E, T, C> gen;
26+
private final ExpectedErrors errors;
27+
28+
private String generatedQueryString;
29+
30+
public TLPWhereOracle(G state, TLPWhereGenerator<Z, J, E, T, C> gen, ExpectedErrors expectedErrors) {
31+
if (state == null || gen == null || expectedErrors == null) {
32+
throw new IllegalArgumentException("Null variables used to initialize test oracle.");
33+
}
34+
this.state = state;
35+
this.gen = gen;
36+
this.errors = expectedErrors;
37+
}
38+
39+
@Override
40+
public void check() throws SQLException {
41+
S s = state.getSchema();
42+
AbstractTables<T, C> targetTables = TestOracleUtils.getRandomTableNonEmptyTables(s);
43+
gen = gen.setTablesAndColumns(targetTables);
44+
45+
Select<J, E, T, C> select = gen.generateSelect();
46+
47+
boolean shouldCreateDummy = true;
48+
select.setFetchColumns(gen.generateFetchColumns(shouldCreateDummy));
49+
select.setJoinClauses(gen.getRandomJoinClauses());
50+
select.setFromList(gen.getTableRefs());
51+
select.setWhereClause(null);
52+
53+
String originalQueryString = select.asString();
54+
generatedQueryString = originalQueryString;
55+
List<String> firstResultSet = ComparatorHelper.getResultSetFirstColumnAsString(originalQueryString, errors,
56+
state);
57+
58+
boolean orderBy = Randomly.getBooleanWithSmallProbability();
59+
if (orderBy) {
60+
select.setOrderByClauses(gen.generateOrderBys());
61+
}
62+
63+
TestOracleUtils.PredicateVariants<E, C> predicates = TestOracleUtils.initializeTernaryPredicateVariants(gen,
64+
gen.generateBooleanExpression());
65+
select.setWhereClause(predicates.predicate);
66+
String firstQueryString = select.asString();
67+
select.setWhereClause(predicates.negatedPredicate);
68+
String secondQueryString = select.asString();
69+
select.setWhereClause(predicates.isNullPredicate);
70+
String thirdQueryString = select.asString();
71+
72+
List<String> combinedString = new ArrayList<>();
73+
List<String> secondResultSet = ComparatorHelper.getCombinedResultSet(firstQueryString, secondQueryString,
74+
thirdQueryString, combinedString, !orderBy, state, errors);
75+
76+
ComparatorHelper.assumeResultSetsAreEqual(firstResultSet, secondResultSet, originalQueryString, combinedString,
77+
state);
78+
}
79+
80+
@Override
81+
public String getLastQueryString() {
82+
return generatedQueryString;
83+
}
84+
}

src/sqlancer/common/oracle/TestOracleUtils.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import sqlancer.IgnoreMeException;
44
import sqlancer.Randomly;
5+
import sqlancer.common.ast.newast.Expression;
6+
import sqlancer.common.gen.PartitionGenerator;
57
import sqlancer.common.schema.AbstractSchema;
68
import sqlancer.common.schema.AbstractTable;
79
import sqlancer.common.schema.AbstractTableColumn;
@@ -12,11 +14,42 @@ public final class TestOracleUtils {
1214
private TestOracleUtils() {
1315
}
1416

17+
public static final class PredicateVariants<E extends Expression<C>, C extends AbstractTableColumn<?, ?>> {
18+
public E predicate;
19+
public E negatedPredicate;
20+
public E isNullPredicate;
21+
22+
PredicateVariants(E predicate, E negatedPredicate, E isNullPredicate) {
23+
this.predicate = predicate;
24+
this.negatedPredicate = negatedPredicate;
25+
this.isNullPredicate = isNullPredicate;
26+
}
27+
}
28+
1529
public static <T extends AbstractTable<C, ?, ?>, C extends AbstractTableColumn<?, ?>> AbstractTables<T, C> getRandomTableNonEmptyTables(
1630
AbstractSchema<?, T> schema) {
1731
if (schema.getDatabaseTables().isEmpty()) {
1832
throw new IgnoreMeException();
1933
}
2034
return new AbstractTables<>(Randomly.nonEmptySubset(schema.getDatabaseTables()));
2135
}
36+
37+
public static <E extends Expression<C>, T extends AbstractTable<C, ?, ?>, C extends AbstractTableColumn<?, ?>> PredicateVariants<E, C> initializeTernaryPredicateVariants(
38+
PartitionGenerator<E, C> gen, E predicate) {
39+
if (gen == null) {
40+
throw new IllegalStateException();
41+
}
42+
if (predicate == null) {
43+
throw new IllegalStateException();
44+
}
45+
E negatedPredicate = gen.negatePredicate(predicate);
46+
if (negatedPredicate == null) {
47+
throw new IllegalStateException();
48+
}
49+
E isNullPredicate = gen.isNull(predicate);
50+
if (isNullPredicate == null) {
51+
throw new IllegalStateException();
52+
}
53+
return new PredicateVariants<>(predicate, negatedPredicate, isNullPredicate);
54+
}
2255
}

src/sqlancer/datafusion/DataFusionProvider.java

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

3-
import static java.lang.System.exit;
43
import static sqlancer.datafusion.DataFusionUtil.DataFusionLogger.DataFusionLogType.DML;
4+
import static sqlancer.datafusion.DataFusionUtil.dfAssert;
55
import static sqlancer.datafusion.DataFusionUtil.displayTables;
66

77
import java.sql.Connection;
@@ -52,13 +52,12 @@ public void generateDatabase(DataFusionGlobalState globalState) throws Exception
5252
List<DataFusionTable> allTables = globalState.getSchema().getDatabaseTables();
5353
List<String> allTablesName = allTables.stream().map(t -> t.getName()).collect(Collectors.toList());
5454
if (allTablesName.isEmpty()) {
55-
System.out.println("Generate database failed");
56-
exit(1);
55+
dfAssert(false, "Generate Database failed.");
5756
}
5857

5958
// Randomly insert some data into existing tables
6059
for (DataFusionTable table : allTables) {
61-
int nInsertQuery = globalState.getRandomly().getInteger(0, 8); // [0, 10)
60+
int nInsertQuery = globalState.getRandomly().getInteger(0, globalState.getOptions().getMaxNumberInserts());
6261

6362
for (int i = 0; i < nInsertQuery; i++) {
6463
SQLQueryAdapter insertQuery = null;

src/sqlancer/datafusion/DataFusionUtil.java

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package sqlancer.datafusion;
22

3-
import static java.lang.System.exit;
4-
53
import java.io.BufferedReader;
64
import java.io.File;
75
import java.io.FileReader;
@@ -66,11 +64,15 @@ public static String displayTables(DataFusionGlobalState state, List<String> fro
6664
return resultStringBuilder.toString();
6765
}
6866

67+
// During development, you might want to manually let this function call exit(1) to fail fast
6968
public static void dfAssert(boolean condition, String message) {
7069
if (!condition) {
71-
String methodName = Thread.currentThread().getStackTrace()[2].getMethodName();
72-
System.err.println("DataFusion assertion failed in function '" + methodName + "': " + message);
73-
exit(1);
70+
// // Development mode assertion failure
71+
// String methodName = Thread.currentThread().getStackTrace()[2]// .getMethodName();
72+
// System.err.println("DataFusion assertion failed in function '" + methodName + "': " + message);
73+
// exit(1);
74+
75+
throw new AssertionError(message);
7476
}
7577
}
7678

@@ -149,9 +151,7 @@ public void appendToLog(DataFusionLogType logType, String logContent) {
149151
try {
150152
logFileWriter = new FileWriter(errorLogFile, true);
151153
} catch (IOException e) {
152-
System.out.println("Failed to create FileWriter for errorLogFIle");
153-
e.printStackTrace();
154-
exit(1);
154+
dfAssert(false, "Failed to create FileWriter for errorLogFIle");
155155
}
156156
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
157157
String formattedDateTime = LocalDateTime.now().format(formatter);
@@ -175,14 +175,11 @@ public void appendToLog(DataFusionLogType logType, String logContent) {
175175
logFileWriter.write(logContent);
176176
logFileWriter.flush();
177177
} catch (IOException e) {
178-
System.out.println("Failed to write to " + logType + " log: " + e.getMessage());
179-
e.printStackTrace();
180-
exit(1);
178+
String err = "Failed to write to " + logType + " log: " + e.getMessage();
179+
dfAssert(false, err);
181180
}
182181
} else {
183-
System.out.println("appending to log failed");
184-
Thread.currentThread().getStackTrace();
185-
exit(1);
182+
dfAssert(false, "appending to log failed");
186183
}
187184
}
188185

src/sqlancer/datafusion/server/datafusion_server/Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@ async-trait = "0.1.73"
1818
bytes = "1.4"
1919
chrono = { version = "0.4.34", default-features = false }
2020
dashmap = "5.5.0"
21+
# This version is for SQLancer CI run
2122
datafusion = { version = "40.0.0" }
22-
# datafusion = { git = "https://github.com/apache/datafusion.git", branch = "main"}
23-
datafusion_dev = { package = "datafusion", git = "https://github.com/apache/datafusion.git", branch = "main", optional = true }
23+
# Use following line if you want to test against the latest main branch of DataFusion
24+
# datafusion = { git = "https://github.com/apache/datafusion.git", branch = "main" }
2425
env_logger = "0.11"
2526
futures = "0.3"
2627
half = { version = "2.2.1", default-features = false }

src/sqlancer/postgres/gen/PostgresTableGenerator.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,9 @@ private void createStandard() throws AssertionError {
113113
generateInherits();
114114
generatePartitionBy();
115115
generateUsing();
116-
PostgresCommon.generateWith(sb, globalState, errors);
116+
if (!isPartitionedTable) {
117+
PostgresCommon.generateWith(sb, globalState, errors);
118+
}
117119
if (Randomly.getBoolean() && isTemporaryTable) {
118120
sb.append(" ON COMMIT ");
119121
sb.append(Randomly.fromOptions("PRESERVE ROWS", "DELETE ROWS", "DROP"));
@@ -205,7 +207,7 @@ private void generateUsing() {
205207
}
206208

207209
private void generateInherits() {
208-
if (Randomly.getBoolean() && !newSchema.getDatabaseTables().isEmpty()) {
210+
if (Randomly.getBoolean() && !newSchema.getDatabaseTablesWithoutViews().isEmpty()) {
209211
sb.append(" INHERITS(");
210212
sb.append(newSchema.getDatabaseTablesRandomSubsetNotEmpty().stream().map(t -> t.getName())
211213
.collect(Collectors.joining(", ")));

src/sqlancer/sqlite3/gen/SQLite3ExpressionGenerator.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import sqlancer.Randomly;
1010
import sqlancer.common.gen.ExpressionGenerator;
1111
import sqlancer.common.gen.NoRECGenerator;
12+
import sqlancer.common.gen.TLPWhereGenerator;
1213
import sqlancer.common.schema.AbstractTables;
1314
import sqlancer.sqlite3.SQLite3GlobalState;
1415
import sqlancer.sqlite3.ast.SQLite3Aggregate;
@@ -50,7 +51,8 @@
5051
import sqlancer.sqlite3.schema.SQLite3Schema.SQLite3Table;
5152

5253
public class SQLite3ExpressionGenerator implements ExpressionGenerator<SQLite3Expression>,
53-
NoRECGenerator<SQLite3Select, Join, SQLite3Expression, SQLite3Table, SQLite3Column> {
54+
NoRECGenerator<SQLite3Select, Join, SQLite3Expression, SQLite3Table, SQLite3Column>,
55+
TLPWhereGenerator<SQLite3Select, Join, SQLite3Expression, SQLite3Table, SQLite3Column> {
5456

5557
private SQLite3RowValue rw;
5658
private final SQLite3GlobalState globalState;
@@ -133,6 +135,7 @@ public static SQLite3Expression getRandomLiteralValue(SQLite3GlobalState globalS
133135
return new SQLite3ExpressionGenerator(globalState).getRandomLiteralValueInternal(globalState.getRandomly());
134136
}
135137

138+
@Override
136139
public List<SQLite3Expression> generateOrderBys() {
137140
List<SQLite3Expression> expressions = new ArrayList<>();
138141
for (int i = 0; i < Randomly.smallNumber() + 1; i++) {
@@ -747,6 +750,18 @@ public List<SQLite3Expression> getTableRefs() {
747750
return tableRefs;
748751
}
749752

753+
@Override
754+
public List<SQLite3Expression> generateFetchColumns(boolean shouldCreateDummy) {
755+
List<SQLite3Expression> columns = new ArrayList<>();
756+
if (shouldCreateDummy && Randomly.getBoolean()) {
757+
columns.add(new SQLite3ColumnName(SQLite3Column.createDummy("*"), null));
758+
} else {
759+
columns = Randomly.nonEmptySubset(this.columns).stream().map(c -> new SQLite3ColumnName(c, null))
760+
.collect(Collectors.toList());
761+
}
762+
return columns;
763+
}
764+
750765
@Override
751766
public String generateOptimizedQueryString(SQLite3Select select, SQLite3Expression whereCondition,
752767
boolean shouldUseAggregate) {

0 commit comments

Comments
 (0)