Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 8 additions & 0 deletions docs/DEVELOPMENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Development


## Options

SQLancer uses [JCommander](https://jcommander.org/) for handling options. The `MainOptions` class contains options that are expected to be supported by all DBMS-testing implementations. Furthermore, each `*Provider` class provides a method to return an additional set of supported options.

An option can include lowercase alphanumeric characters, and hyphens. The format of the options is checked by a unit test.
24 changes: 15 additions & 9 deletions src/sqlancer/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -274,15 +274,7 @@ public static void main(String[] args) {
}

public static int executeMain(String[] args) throws AssertionError {
List<DatabaseProvider<?, ?>> providers = new ArrayList<>();
providers.add(new SQLite3Provider());
providers.add(new CockroachDBProvider());
providers.add(new MySQLProvider());
providers.add(new MariaDBProvider());
providers.add(new TiDBProvider());
providers.add(new PostgresProvider());
providers.add(new ClickhouseProvider());
providers.add(new DuckDBProvider());
List<DatabaseProvider<?, ?>> providers = getDBMSProviders();
Map<String, DatabaseProvider<?, ?>> nameToProvider = new HashMap<>();
Map<String, Object> nameToOptions = new HashMap<>();
MainOptions options = new MainOptions();
Expand All @@ -302,6 +294,7 @@ public static int executeMain(String[] args) throws AssertionError {
}
JCommander jc = commandBuilder.programName("SQLancer").build();
jc.parse(args);

if (jc.getParsedCommand() == null) {
jc.usage();
return options.getErrorExitCode();
Expand Down Expand Up @@ -411,6 +404,19 @@ private void runThread(final String databaseName) {
return threadsShutdown == 0 ? 0 : options.getErrorExitCode();
}

static List<DatabaseProvider<?, ?>> getDBMSProviders() {
List<DatabaseProvider<?, ?>> providers = new ArrayList<>();
providers.add(new SQLite3Provider());
providers.add(new CockroachDBProvider());
providers.add(new MySQLProvider());
providers.add(new MariaDBProvider());
providers.add(new TiDBProvider());
providers.add(new PostgresProvider());
providers.add(new ClickhouseProvider());
providers.add(new DuckDBProvider());
return providers;
}

private static void startProgressMonitor() {
final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(new Runnable() {
Expand Down
12 changes: 6 additions & 6 deletions src/sqlancer/MainOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,25 @@
public class MainOptions {

@Parameter(names = {
"--num_threads" }, description = "How many threads should run concurrently to test separate databases")
"--num-threads" }, description = "How many threads should run concurrently to test separate databases")
private int nrConcurrentThreads = 16;

@Parameter(names = { "--num_tries" }, description = "Specifies after how many found errors to stop testing")
@Parameter(names = { "--num-tries" }, description = "Specifies after how many found errors to stop testing")
private int totalNumberTries = 100;

@Parameter(names = { "--max_num_inserts" }, description = "Specifies how many INSERT statements should be issued")
@Parameter(names = { "--max-num-inserts" }, description = "Specifies how many INSERT statements should be issued")
private int maxNumberInserts = 30;

@Parameter(names = {
"--max_expression_depth" }, description = "Specifies the maximum depth of randomly-generated expressions")
"--max-expression-depth" }, description = "Specifies the maximum depth of randomly-generated expressions")
private int maxExpressionDepth = 3;

@Parameter(names = {
"--num_queries" }, description = "Specifies the number of queries to be issued to a database before creating a new database")
"--num-queries" }, description = "Specifies the number of queries to be issued to a database before creating a new database")
private int nrQueries = 100000;

@Parameter(names = {
"--num_statement_kind_retries" }, description = "Specifies the number of times a specific statement kind (e.g., INSERT) should be retried when the DBMS indicates that it failed")
"--num-statement-kind-retries" }, description = "Specifies the number of times a specific statement kind (e.g., INSERT) should be retried when the DBMS indicates that it failed")
private int nrStatementRetryCount = 1000;

@Parameter(names = "--log-each-select", description = "Logs every statement issued", arity = 1)
Expand Down
8 changes: 4 additions & 4 deletions src/sqlancer/cockroachdb/CockroachDBOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,14 @@ public TestOracle create(CockroachDBGlobalState globalState) throws SQLException
}

@Parameter(names = {
"--test_hash_indexes" }, description = "Test the USING HASH WITH BUCKET_COUNT=n_buckets option in CREATE INDEX")
"--test-hash-indexes" }, description = "Test the USING HASH WITH BUCKET_COUNT=n_buckets option in CREATE INDEX")
public boolean testHashIndexes = true;

@Parameter(names = { "--test_temp_tables" }, description = "Test TEMPORARY tables")
@Parameter(names = { "--test-temp-tables" }, description = "Test TEMPORARY tables")
public boolean testTempTables = true;

@Parameter(names = { "--increased_vectorization",
"Generate VECTORIZE=on with a higher probability (which found a number of bugs in the past)" })
@Parameter(names = {
"--increased-vectorization" }, description = "Generate VECTORIZE=on with a higher probability (which found a number of bugs in the past)")
public boolean makeVectorizationMoreLikely = true;

}
44 changes: 44 additions & 0 deletions test/sqlancer/TestParameterFormat.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package sqlancer;

import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

import org.junit.jupiter.api.Test;

import com.beust.jcommander.JCommander;
import com.beust.jcommander.JCommander.Builder;
import com.beust.jcommander.ParameterDescription;

/**
* Check that consistent option names are used (those that are displayed when launcing SQLancer without options).
*/
public class TestParameterFormat {

private final static String OPTION_REGEX = "--[a-z0-9-]*";

@Test
public void testOptionFormat() {
List<DatabaseProvider<?, ?>> providers = Main.getDBMSProviders();
MainOptions options = new MainOptions();
Builder commandBuilder = JCommander.newBuilder().addObject(options);
List<ParameterDescription> parameterDescriptions = new ArrayList<>();
for (int i = 0; i < providers.size(); i++) {
commandBuilder = commandBuilder.addCommand(String.format("db%d", i), providers.get(i).getCommand());
}
JCommander jc = commandBuilder.programName("SQLancer").build();
jc.parse(new String[0]);

parameterDescriptions.addAll(jc.getParameters());
for (String commandName : jc.getCommands().keySet()) {
JCommander command = jc.getCommands().get(commandName);
parameterDescriptions.addAll(command.getParameters());
}
for (ParameterDescription parameter : parameterDescriptions) {
assertTrue(Pattern.matches(OPTION_REGEX, parameter.getNames()), parameter.getNames());
}
}

}