Skip to content

Commit 49afc88

Browse files
author
Jinsheng Ba
authored
TiDB DQP (sqlancer#920)
1 parent d01c4a5 commit 49afc88

8 files changed

Lines changed: 182 additions & 7 deletions

File tree

src/sqlancer/tidb/TiDBBugs.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,21 @@ public final class TiDBBugs {
1717
// https://github.com/pingcap/tidb/issues/44747
1818
public static boolean bug44747 = true;
1919

20+
// https://github.com/pingcap/tidb/issues/46556
21+
public static boolean bug46556 = true;
22+
23+
// https://github.com/pingcap/tidb/issues/46591
24+
public static boolean bug46591 = true;
25+
26+
// https://github.com/pingcap/tidb/issues/46598
27+
public static boolean bug46598 = true;
28+
29+
// https://github.com/pingcap/tidb/issues/47346
30+
public static boolean bug47346 = true;
31+
32+
// https://github.com/pingcap/tidb/issues/47348
33+
public static boolean bug47348 = true;
34+
2035
private TiDBBugs() {
2136
}
2237

src/sqlancer/tidb/TiDBErrors.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,12 @@ public static void addExpressionErrors(ExpectedErrors errors) {
2525
errors.add("is not valid for CHARACTER SET");
2626
errors.add("DOUBLE value is out of range");
2727

28-
errors.add("Data truncation: %s value is out of range in '%s'");
28+
errors.add("Data truncat");
2929
errors.add("Truncated incorrect FLOAT value");
3030
errors.add("Bad Number");
31+
errors.add("strconv.Atoi: parsing");
32+
errors.add("expected integer");
33+
errors.add("Duplicate entry");
3134

3235
// regex
3336
errors.add("error parsing regexp");

src/sqlancer/tidb/TiDBOptions.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import sqlancer.tidb.TiDBOptions.TiDBOracleFactory;
1616
import sqlancer.tidb.TiDBProvider.TiDBGlobalState;
1717
import sqlancer.tidb.oracle.TiDBCERTOracle;
18+
import sqlancer.tidb.oracle.TiDBDQPOracle;
1819
import sqlancer.tidb.oracle.TiDBTLPHavingOracle;
1920
import sqlancer.tidb.oracle.TiDBTLPWhereOracle;
2021

@@ -71,6 +72,12 @@ public TestOracle<TiDBGlobalState> create(TiDBGlobalState globalState) throws SQ
7172
public boolean requiresAllTablesToContainRows() {
7273
return true;
7374
}
75+
},
76+
DQP {
77+
@Override
78+
public TestOracle<TiDBGlobalState> create(TiDBGlobalState globalState) throws SQLException {
79+
return new TiDBDQPOracle(globalState);
80+
}
7481
};
7582

7683
}

src/sqlancer/tidb/gen/TiDBAlterTableGenerator.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public static SQLQueryAdapter getQuery(TiDBGlobalState globalState) {
3232
errors.add("can't drop");
3333
errors.add("A PRIMARY must include all columns in the table's partitioning function");
3434
errors.add("key was too long");
35+
errors.add("Duplicate entry");
3536
StringBuilder sb = new StringBuilder("ALTER TABLE ");
3637
TiDBTable table = globalState.getSchema().getRandomTable(t -> !t.isView());
3738
TiDBColumn column = table.getRandomColumn();

src/sqlancer/tidb/gen/TiDBHintGenerator.java

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

3+
import java.util.ArrayList;
4+
import java.util.Arrays;
35
import java.util.List;
46
import java.util.stream.Collectors;
57

@@ -22,12 +24,13 @@ enum IndexHint {
2224
INL_HASH_JOIN, //
2325
INL_MERGE_JOIN, //
2426
HASH_JOIN, //
27+
READ_FROM_TIKV, //
28+
READ_FROM_TIFLASH, //
2529
HASH_AGG, //
2630
STREAM_AGG, //
2731
USE_INDEX, //
2832
IGNORE_INDEX, //
2933
AGG_TO_COP, //
30-
// READ_FROM_STORAGE
3134
USE_INDEX_MERGE, //
3235
NO_INDEX_MERGE, //
3336
USE_TOJA, //
@@ -46,13 +49,40 @@ public TiDBHintGenerator(TiDBSelect select, List<TiDBTable> tables) {
4649
}
4750

4851
public static void generateHints(TiDBSelect select, List<TiDBTable> tables) {
49-
new TiDBHintGenerator(select, tables).generate();
52+
new TiDBHintGenerator(select, tables).randomHint();
53+
}
5054

55+
public static List<TiDBText> generateAllHints(TiDBSelect select, List<TiDBTable> tables) {
56+
TiDBHintGenerator generator = new TiDBHintGenerator(select, tables);
57+
return generator.allHints();
5158
}
5259

53-
private void generate() {
60+
private void randomHint() {
5461
TiDBTable table = Randomly.fromList(tables);
55-
switch (Randomly.fromOptions(IndexHint.values())) {
62+
IndexHint chosenhint = Randomly.fromOptions(IndexHint.values());
63+
generate(table, chosenhint);
64+
}
65+
66+
private List<TiDBText> allHints() {
67+
List<TiDBText> results = new ArrayList<>();
68+
IndexHint[] values = IndexHint.values();
69+
List<IndexHint> availableHints = new ArrayList<>(Arrays.asList(values));
70+
71+
for (IndexHint hint : availableHints) {
72+
try {
73+
TiDBText generatedHint = generate(Randomly.fromList(tables), hint);
74+
results.add(generatedHint);
75+
} catch (IgnoreMeException e) {
76+
continue;
77+
}
78+
}
79+
return results;
80+
}
81+
82+
private TiDBText generate(TiDBTable table, IndexHint chosenhint) {
83+
sb.setLength(0);
84+
85+
switch (chosenhint) {
5686
case MERGE_JOIN:
5787
tablesHint("MERGE_JOIN");
5888
break;
@@ -68,6 +98,12 @@ private void generate() {
6898
case HASH_JOIN:
6999
tablesHint("HASH_JOIN");
70100
break;
101+
case READ_FROM_TIKV:
102+
storageHint("READ_FROM_STORAGE(TIKV");
103+
break;
104+
case READ_FROM_TIFLASH:
105+
storageHint("READ_FROM_STORAGE(TIFLASH");
106+
break;
71107
case HASH_AGG:
72108
sb.append("HASH_AGG()");
73109
break;
@@ -126,7 +162,9 @@ private void generate() {
126162
default:
127163
throw new AssertionError();
128164
}
129-
select.setHint(new TiDBText(sb.toString()));
165+
TiDBText hint = new TiDBText(sb.toString());
166+
select.setHint(hint);
167+
return hint;
130168
}
131169

132170
private void indexesHint(String string) {
@@ -152,6 +190,13 @@ private void tablesHint(String string) {
152190
sb.append(")");
153191
}
154192

193+
private void storageHint(String string) {
194+
sb.append(string);
195+
sb.append("[");
196+
appendTables();
197+
sb.append("])");
198+
}
199+
155200
private void twoTablesHint(String string, TiDBTable table) {
156201
if (table.hasIndexes()) {
157202
sb.append(string);

src/sqlancer/tidb/gen/TiDBSetGenerator.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ private enum Action {
4343

4444
TIDB_ENABLE_WINDOW_FUNCTION("tidb_enable_window_function", (r) -> Randomly.fromOptions(0, 1)),
4545

46-
TIDB_ENABLE_FAST_ANALYZE("tidb_enable_fast_analyze", (r) -> Randomly.fromOptions(0, 1)), //
46+
// TIDB_ENABLE_FAST_ANALYZE("tidb_enable_fast_analyze", (r) -> Randomly.fromOptions(0, 1)), //
47+
// java.sql.SQLException: Fast analyze hasn't reached General Availability and only support analyze version 1
48+
// currently
4749
TIDB_WAIT_SPLIT_REGION_FINISH("tidb_wait_split_region_finish", (r) -> Randomly.fromOptions(0, 1)),
4850
TIDB_SCATTER_REGION("global.tidb_scatter_region", (r) -> Randomly.fromOptions(0, 1)),
4951
TIDB_ENABLE_STMT_SUMMARY("global.tidb_enable_stmt_summary", (r) -> Randomly.fromOptions(0, 1)), //
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package sqlancer.tidb.oracle;
2+
3+
import java.sql.SQLException;
4+
import java.util.ArrayList;
5+
import java.util.List;
6+
import java.util.stream.Collectors;
7+
8+
import sqlancer.ComparatorHelper;
9+
import sqlancer.Randomly;
10+
import sqlancer.common.oracle.TestOracle;
11+
import sqlancer.common.query.ExpectedErrors;
12+
import sqlancer.tidb.TiDBErrors;
13+
import sqlancer.tidb.TiDBExpressionGenerator;
14+
import sqlancer.tidb.TiDBProvider.TiDBGlobalState;
15+
import sqlancer.tidb.TiDBSchema.TiDBTables;
16+
import sqlancer.tidb.ast.TiDBColumnReference;
17+
import sqlancer.tidb.ast.TiDBExpression;
18+
import sqlancer.tidb.ast.TiDBJoin;
19+
import sqlancer.tidb.ast.TiDBSelect;
20+
import sqlancer.tidb.ast.TiDBTableReference;
21+
import sqlancer.tidb.ast.TiDBText;
22+
import sqlancer.tidb.gen.TiDBHintGenerator;
23+
import sqlancer.tidb.visitor.TiDBVisitor;
24+
25+
public class TiDBDQPOracle implements TestOracle<TiDBGlobalState> {
26+
private TiDBExpressionGenerator gen;
27+
private final TiDBGlobalState state;
28+
private TiDBSelect select;
29+
private final ExpectedErrors errors = new ExpectedErrors();
30+
31+
public TiDBDQPOracle(TiDBGlobalState globalState) {
32+
state = globalState;
33+
TiDBErrors.addExpressionErrors(errors);
34+
}
35+
36+
@Override
37+
public void check() throws SQLException {
38+
// Randomly generate a query
39+
TiDBTables tables = state.getSchema().getRandomTableNonEmptyTables();
40+
gen = new TiDBExpressionGenerator(state).setColumns(tables.getColumns());
41+
select = new TiDBSelect();
42+
43+
List<TiDBExpression> fetchColumns = new ArrayList<>();
44+
fetchColumns.addAll(Randomly.nonEmptySubset(tables.getColumns()).stream().map(c -> new TiDBColumnReference(c))
45+
.collect(Collectors.toList()));
46+
select.setFetchColumns(fetchColumns);
47+
48+
List<TiDBExpression> tableList = tables.getTables().stream().map(t -> new TiDBTableReference(t))
49+
.collect(Collectors.toList());
50+
List<TiDBExpression> joins = TiDBJoin.getJoins(tableList, state);
51+
select.setJoinList(joins);
52+
select.setFromList(tableList);
53+
if (Randomly.getBoolean()) {
54+
select.setWhereClause(gen.generateExpression());
55+
}
56+
if (Randomly.getBooleanWithRatherLowProbability()) {
57+
select.setOrderByExpressions(gen.generateOrderBys());
58+
}
59+
if (Randomly.getBoolean()) {
60+
select.setLimitClause(gen.generateExpression());
61+
}
62+
if (Randomly.getBoolean()) {
63+
select.setOffsetClause(gen.generateExpression());
64+
}
65+
66+
String originalQueryString = TiDBVisitor.asString(select);
67+
List<String> originalResult = ComparatorHelper.getResultSetFirstColumnAsString(originalQueryString, errors,
68+
state);
69+
70+
List<TiDBText> hintList = TiDBHintGenerator.generateAllHints(select, tables.getTables());
71+
for (TiDBText hint : hintList) {
72+
select.setHint(hint);
73+
String queryString = TiDBVisitor.asString(select);
74+
List<String> result = ComparatorHelper.getResultSetFirstColumnAsString(queryString, errors, state);
75+
ComparatorHelper.assumeResultSetsAreEqual(originalResult, result, originalQueryString, List.of(queryString),
76+
state);
77+
}
78+
}
79+
80+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package sqlancer.dqp.tidb;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assumptions.assumeTrue;
5+
6+
import org.junit.jupiter.api.Test;
7+
8+
import sqlancer.Main;
9+
import sqlancer.dbms.TestConfig;
10+
11+
public class TestTiDBDQP {
12+
13+
@Test
14+
public void testTiDBQPG() {
15+
String tiDB = System.getenv("TIDB_AVAILABLE");
16+
boolean tiDBIsAvailable = tiDB != null && tiDB.equalsIgnoreCase("true");
17+
assumeTrue(tiDBIsAvailable);
18+
assertEquals(0, Main.executeMain(new String[] { "--random-seed", "0", "--timeout-seconds", TestConfig.SECONDS,
19+
"--num-threads", "1", "--num-queries", TestConfig.NUM_QUERIES, "tidb", "--oracle", "DQP" }));
20+
}
21+
22+
}

0 commit comments

Comments
 (0)