Skip to content

Commit 7b372ed

Browse files
committed
Add Provider and Schema for QuestDB
1 parent 2b2829c commit 7b372ed

12 files changed

+617
-2
lines changed

pom.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,11 @@
347347
<artifactId>arangodb-java-driver</artifactId>
348348
<version>6.9.0</version>
349349
</dependency>
350+
<dependency>
351+
<groupId>org.questdb</groupId>
352+
<artifactId>questdb</artifactId>
353+
<version>6.5.3</version>
354+
</dependency>
350355
</dependencies>
351356
<reporting>
352357
<plugins>
@@ -446,4 +451,4 @@
446451
</build>
447452
</profile>
448453
</profiles>
449-
</project>
454+
</project>

src/sqlancer/GlobalState.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ public S getSchema() {
131131
try {
132132
updateSchema();
133133
} catch (Exception e) {
134-
throw new AssertionError();
134+
throw new AssertionError(e.getMessage());
135135
}
136136
}
137137
return schema;
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package sqlancer.questdb;
2+
3+
public class QuestDBErrors {
4+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package sqlancer.questdb;
2+
3+
import java.sql.SQLException;
4+
import java.util.Arrays;
5+
import java.util.List;
6+
7+
import com.beust.jcommander.Parameter;
8+
import com.beust.jcommander.Parameters;
9+
10+
import sqlancer.DBMSSpecificOptions;
11+
import sqlancer.OracleFactory;
12+
import sqlancer.common.oracle.TestOracle;
13+
import sqlancer.questdb.QuestDBOptions.QuestDBOracleFactory;
14+
import sqlancer.questdb.QuestDBProvider.QuestDBGlobalState;
15+
16+
@Parameters(separators = "=", commandDescription = "QuestDB (default port: " + QuestDBOptions.DEFAULT_PORT
17+
+ " default host: " + QuestDBOptions.DEFAULT_HOST + ")")
18+
public class QuestDBOptions implements DBMSSpecificOptions<QuestDBOracleFactory> {
19+
public static final String DEFAULT_HOST = "localhost";
20+
public static final int DEFAULT_PORT = 8812;
21+
22+
@Parameter(names = "--oracle")
23+
public QuestDBOracleFactory oracle = QuestDBOracleFactory.WHERE;
24+
25+
public enum QuestDBOracleFactory implements OracleFactory<QuestDBGlobalState> {
26+
// TODO: implement test oracles
27+
WHERE {
28+
@Override
29+
public TestOracle create(QuestDBGlobalState globalState) throws SQLException {
30+
return null;
31+
}
32+
};
33+
34+
}
35+
36+
@Parameter(names = "--username", description = "The user name used to log into QuestDB")
37+
private String userName = "admin"; // NOPMD
38+
39+
@Parameter(names = "--password", description = "The password used to log into QuestDB")
40+
private String password = "quest"; // NOPMD
41+
42+
@Override
43+
public List<QuestDBOracleFactory> getTestOracleFactory() {
44+
return Arrays.asList(oracle);
45+
}
46+
47+
public String getUserName() {
48+
return userName;
49+
}
50+
51+
public String getPassword() {
52+
return password;
53+
}
54+
55+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package sqlancer.questdb;
2+
3+
import java.sql.Connection;
4+
import java.sql.DriverManager;
5+
import java.sql.SQLException;
6+
import java.sql.Statement;
7+
import java.util.Properties;
8+
9+
import com.google.auto.service.AutoService;
10+
11+
import sqlancer.AbstractAction;
12+
import sqlancer.DatabaseProvider;
13+
import sqlancer.SQLConnection;
14+
import sqlancer.SQLGlobalState;
15+
import sqlancer.SQLProviderAdapter;
16+
import sqlancer.common.query.SQLQueryAdapter;
17+
import sqlancer.common.query.SQLQueryProvider;
18+
import sqlancer.questdb.QuestDBProvider.QuestDBGlobalState;
19+
import sqlancer.questdb.gen.QuestDBDeleteGenerator;
20+
import sqlancer.questdb.gen.QuestDBIndexGenerator;
21+
import sqlancer.questdb.gen.QuestDBInsertGenerator;
22+
import sqlancer.questdb.gen.QuestDBTableGenerator;
23+
24+
@AutoService(DatabaseProvider.class)
25+
public class QuestDBProvider extends SQLProviderAdapter<QuestDBGlobalState, QuestDBOptions> {
26+
public QuestDBProvider() {
27+
super(QuestDBGlobalState.class, QuestDBOptions.class);
28+
}
29+
30+
public enum Action implements AbstractAction<QuestDBGlobalState> {
31+
INSERT(QuestDBInsertGenerator::getQuery), //
32+
CREATE_INDEX(QuestDBIndexGenerator::getQuery), //
33+
DELETE(QuestDBDeleteGenerator::generate); //
34+
// TODO: maybe implement these later
35+
// UPDATE(QuestDBUpdateGenerator::getQuery), //
36+
// CREATE_VIEW(QuestDBViewGenerator::generate), //
37+
38+
private final SQLQueryProvider<QuestDBGlobalState> sqlQueryProvider;
39+
40+
Action(SQLQueryProvider<QuestDBGlobalState> sqlQueryProvider) {
41+
this.sqlQueryProvider = sqlQueryProvider;
42+
}
43+
44+
@Override
45+
public SQLQueryAdapter getQuery(QuestDBGlobalState state) throws Exception {
46+
return sqlQueryProvider.getQuery(state);
47+
}
48+
}
49+
50+
public static class QuestDBGlobalState extends SQLGlobalState<QuestDBOptions, QuestDBSchema> {
51+
52+
@Override
53+
protected QuestDBSchema readSchema() throws SQLException {
54+
return QuestDBSchema.fromConnection(getConnection(), getDatabaseName());
55+
}
56+
57+
}
58+
59+
@Override
60+
public void generateDatabase(QuestDBGlobalState globalState) throws Exception {
61+
// TODO: should follow duckdb or cockrachdb? what's the difference between generate and create db?
62+
}
63+
64+
@Override
65+
public SQLConnection createDatabase(QuestDBGlobalState globalState) throws Exception {
66+
String host = globalState.getOptions().getHost();
67+
int port = globalState.getOptions().getPort();
68+
if (host == null) {
69+
host = QuestDBOptions.DEFAULT_HOST;
70+
}
71+
if (port == sqlancer.MainOptions.NO_SET_PORT) {
72+
port = QuestDBOptions.DEFAULT_PORT;
73+
}
74+
// TODO(anxing): maybe not hardcode here...
75+
String databaseName = "qdb";
76+
String tableName = "test";
77+
String url = String.format("jdbc:postgresql://%s:%d/%s", host, port, databaseName);
78+
// use QuestDB default username & password for Postgres JDBC
79+
Properties properties = new Properties();
80+
properties.setProperty("user", globalState.getDbmsSpecificOptions().getUserName());
81+
properties.setProperty("password", globalState.getDbmsSpecificOptions().getPassword());
82+
properties.setProperty("sslmode", "disable");
83+
84+
Connection con = DriverManager.getConnection(url, properties);
85+
// QuestDB cannot create or drop `DATABASE`, can only create or drop `TABLE`
86+
globalState.getState().logStatement("DROP TABLE IF EXISTS " + tableName + " CASCADE");
87+
SQLQueryAdapter createTableCommand = new QuestDBTableGenerator().getQuery(globalState);
88+
globalState.getState().logStatement(createTableCommand);
89+
90+
try (Statement s = con.createStatement()) {
91+
s.execute("DROP TABLE IF EXISTS " + tableName);
92+
}
93+
try (Statement s = con.createStatement()) {
94+
s.execute(createTableCommand.getQueryString());
95+
}
96+
con.close();
97+
con = DriverManager.getConnection(url, properties);
98+
return new SQLConnection(con);
99+
}
100+
101+
@Override
102+
public String getDBMSName() {
103+
return "questdb";
104+
}
105+
106+
}

0 commit comments

Comments
 (0)