package sqlancer; import java.util.Objects; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; import sqlancer.Randomly.StringGenerationStrategy; @Parameters(separators = "=", commandDescription = "Options applicable to all DBMS") public class MainOptions { public static final int NO_SET_PORT = -1; public static final int NO_REDUCE_LIMIT = -1; public static final MainOptions DEFAULT_OPTIONS = new MainOptions(); @Parameter(names = { "--help", "-h" }, description = "Lists all supported options and commands", help = true) private boolean help; // NOPMD @Parameter(names = { "--num-threads" }, description = "How many threads should run concurrently to test separate databases") private int nrConcurrentThreads = 16; // NOPMD @Parameter(names = { "--random-seed" }, description = "A seed value != -1 that can be set to make the query and database generation deterministic") private long randomSeed = -1; // NOPMD @Parameter(names = { "--num-tries" }, description = "Specifies after how many found errors to stop testing") private int totalNumberTries = 100; // NOPMD @Parameter(names = { "--max-num-inserts" }, description = "Specifies how many INSERT statements should be issued") private int maxNumberInserts = 30; // NOPMD @Parameter(names = { "--max-expression-depth" }, description = "Specifies the maximum depth of randomly-generated expressions") private int maxExpressionDepth = 3; // NOPMD @Parameter(names = { "--num-queries" }, description = "Specifies the number of queries to be issued to a database before creating a new database") private int nrQueries = 100000; // NOPMD @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") private int nrStatementRetryCount = 1000; // NOPMD @Parameter(names = "--log-each-select", description = "Logs every statement issued", arity = 1) private boolean logEachSelect = true; // NOPMD @Parameter(names = "--log-execution-time", description = "Logs the execution time of each statement (requires --log-each-select to be enabled)", arity = 1) private boolean logExecutionTime = true; // NOPMD @Parameter(names = "--print-failed", description = "Logs failed insert, create and other statements without results", arity = 1) private boolean loggerPrintFailed = true; // NOPMD @Parameter(names = "--qpg-enable", description = "Enable the experimental feature Query Plan Guidance (QPG)", arity = 1) private boolean enableQPG; @Parameter(names = "--qpg-log-query-plan", description = "Logs the query plans of each query (requires --qpg-enable)", arity = 1) private boolean logQueryPlan; @Parameter(names = "--qpg-max-interval", description = "The maximum number of iterations to mutate tables if no new query plans (requires --qpg-enable)") private static int qpgMaxInterval = 1000; @Parameter(names = "--qpg-reward-weight", description = "The weight (0-1) of last reward when updating weighted average reward. A higher value denotes average reward is more affected by the last reward (requires --qpg-enable)") private static double qpgk = 0.25; @Parameter(names = "--qpg-selection-probability", description = "The probability (0-1) of the random selection of mutators. A higher value (>0.5) favors exploration over exploitation. (requires --qpg-enable)") private static double qpgProbability = 0.7; @Parameter(names = "--username", description = "The user name used to log into the DBMS") private String userName = "sqlancer"; // NOPMD @Parameter(names = "--password", description = "The password used to log into the DBMS") private String password = "sqlancer"; // NOPMD @Parameter(names = "--host", description = "The host used to log into the DBMS") private String host = null; // NOPMD @Parameter(names = "--port", description = "The port used to log into the DBMS") private int port = MainOptions.NO_SET_PORT; // NOPMD @Parameter(names = "--print-progress-information", description = "Whether to print progress information such as the number of databases generated or queries issued", arity = 1) private boolean printProgressInformation = true; // NOPMD @Parameter(names = "--print-progress-summary", description = "Whether to print an execution summary when exiting SQLancer", arity = 1) private boolean printProgressSummary; // NOPMD @Parameter(names = "--timeout-seconds", description = "The timeout in seconds") private int timeoutSeconds = -1; // NOPMD @Parameter(names = "--max-generated-databases", description = "The maximum number of databases that are generated by each thread") private int maxGeneratedDatabases = -1; // NOPMD @Parameter(names = "--exit-code-error", description = "The exit code that should be returned when an error is encountered (or a bug is found)") private int errorExitCode = -1; // NOPMD @Parameter(names = "--print-statements", description = "Print all statements to stdout, before they are sent to the DBMS (not yet implemented for all oracles)", arity = 1) private boolean printStatements; // NOPMD @Parameter(names = "--print-succeeding-statements", description = "Print statements that are successfully processed by the DBMS to stdout (not yet implemented for all oracles)", arity = 1) private boolean printSucceedingStatements; // NOPMD @Parameter(names = "--test-only-nonempty-tables", description = "Test only databases each of whose tables contain at least a single row", arity = 1) private boolean testOnlyWithMoreThanZeroRows; // NOPMD @Parameter(names = "--pqs-test-aggregates", description = "Partially test aggregate functions when all tables contain only a single row.", arity = 1) private boolean testAggregateFunctions; // NOPMD @Parameter(names = "--random-string-generation", description = "Select the random-string eneration approach") private StringGenerationStrategy randomStringGenerationStrategy = StringGenerationStrategy.SOPHISTICATED; // NOPMD @Parameter(names = "--string-constant-max-length", description = "Specify the maximum-length of generated string constants") private int maxStringConstantLength = 10; // NOPMD @Parameter(names = "--use-constant-caching", description = "Specifies whether constants should be cached and re-used with a certain probability", arity = 1) private boolean useConstantCaching = true; // NOPMD @Parameter(names = "--use-connection-test", description = "Test whether the DBMS is accessible before trying to connect using multiple threads", arity = 1) private boolean useConnectionTest = true; // NOPMD @Parameter(names = "--constant-cache-size", description = "Specifies the size of the constant cache. This option only takes effect when constant caching is enabled") private int constantCacheSize = 100; // NOPMD @Parameter(names = "--database-prefix", description = "The prefix used for each database created") private String databasePrefix = "database"; // NOPMD @Parameter(names = "--serialize-reproduce-state", description = "Serialize the state to reproduce") private boolean serializeReproduceState = false; // NOPMD @Parameter(names = "--use-reducer", description = "EXPERIMENTAL Attempt to reduce queries using a simple reducer") private boolean useReducer = false; // NOPMD @Parameter(names = "--reduce-ast", description = "EXPERIMENTAL perform AST reduction after statement reduction") private boolean reduceAST = false; // NOPMD @Parameter(names = "--statement-reducer-max-steps", description = "EXPERIMENTAL Maximum steps the statement reducer will do") private long maxStatementReduceSteps = NO_REDUCE_LIMIT; // NOPMD @Parameter(names = "--statement-reducer-max-time", description = "EXPERIMENTAL Maximum time duration (secs) the AST-based reducer will do") private long maxASTReduceTime = NO_REDUCE_LIMIT; // NOPMD @Parameter(names = "--ast-reducer-max-steps", description = "EXPERIMENTAL Maximum steps the AST-based reducer will do") private long maxASTReduceSteps = NO_REDUCE_LIMIT; // NOPMD @Parameter(names = "--ast-reducer-max-time", description = "EXPERIMENTAL Maximum time duration (secs) the statement reducer will do") private long maxStatementReduceTime = NO_REDUCE_LIMIT; // NOPMD @Parameter(names = "--validate-result-size-only", description = "Should validate result size only and skip comparing content of the result set ", arity = 1) private boolean validateResultSizeOnly = false; // NOPMD @Parameter(names = "--canonicalize-sql-strings", description = "Should canonicalize query string (add ';' at the end", arity = 1) private boolean canonicalizeSqlString = true; // NOPMD public int getMaxExpressionDepth() { return maxExpressionDepth; } public int getTotalNumberTries() { return totalNumberTries; } public int getNumberConcurrentThreads() { return nrConcurrentThreads; } public boolean logEachSelect() { return logEachSelect; } public boolean printAllStatements() { if (printSucceedingStatements && printStatements) { throw new AssertionError(); } return printStatements; } public boolean printSucceedingStatements() { if (printStatements && printSucceedingStatements) { throw new AssertionError(); } return printSucceedingStatements; } public boolean logExecutionTime() { if (!logEachSelect) { throw new AssertionError(); } return logExecutionTime; } public boolean loggerPrintFailed() { return loggerPrintFailed; } public boolean logQueryPlan() { return logQueryPlan; } public boolean enableQPG() { return enableQPG; } public int getQPGMaxMutationInterval() { return qpgMaxInterval; } public double getQPGk() { return qpgk; } public double getQPGProbability() { return qpgProbability; } public int getNrQueries() { return nrQueries; } public int getMaxNumberInserts() { return maxNumberInserts; } public int getNrStatementRetryCount() { return nrStatementRetryCount; } public String getUserName() { return userName; } public String getPassword() { return password; } public String getHost() { return host; } public int getPort() { return port; } public boolean printProgressInformation() { return printProgressInformation; } public boolean printProgressSummary() { return printProgressSummary; } public int getTimeoutSeconds() { return timeoutSeconds; } public int getMaxGeneratedDatabases() { return maxGeneratedDatabases; } public int getErrorExitCode() { return errorExitCode; } public long getRandomSeed() { return randomSeed; } public boolean testAggregateFunctionsPQS() { return testAggregateFunctions; } public boolean testOnlyWithMoreThanZeroRows() { return testOnlyWithMoreThanZeroRows; } public StringGenerationStrategy getRandomStringGenerationStrategy() { return randomStringGenerationStrategy; } public int getMaxStringConstantLength() { return maxStringConstantLength; } public boolean useConstantCaching() { return useConstantCaching; } public int getConstantCacheSize() { return constantCacheSize; } public boolean isHelp() { return help; } public boolean isDefaultPassword() { return Objects.equals(password, DEFAULT_OPTIONS.password); } public boolean isDefaultUsername() { return Objects.equals(userName, DEFAULT_OPTIONS.userName); } public String getDatabasePrefix() { return databasePrefix; } public boolean performConnectionTest() { return useConnectionTest; } public boolean serializeReproduceState() { return serializeReproduceState; } public boolean useReducer() { return useReducer; } public boolean reduceAST() { return reduceAST; } public long getMaxStatementReduceSteps() { return maxStatementReduceSteps; } public long getMaxStatementReduceTime() { return maxStatementReduceTime; } public long getMaxASTReduceSteps() { return maxASTReduceSteps; } public long getMaxASTReduceTime() { return maxASTReduceTime; } public boolean validateResultSizeOnly() { return validateResultSizeOnly; } public boolean canonicalizeSqlString() { return canonicalizeSqlString; } }