package sqlancer.sqlite3.gen;
import java.util.ArrayList;
import java.util.List;
import sqlancer.Randomly;
import sqlancer.common.DBMSCommon;
import sqlancer.sqlite3.SQLite3GlobalState;
import sqlancer.sqlite3.SQLite3Visitor;
import sqlancer.sqlite3.ast.SQLite3Expression;
import sqlancer.sqlite3.ast.SQLite3Expression.SQLite3TableReference;
import sqlancer.sqlite3.schema.SQLite3DataType;
import sqlancer.sqlite3.schema.SQLite3Schema;
import sqlancer.sqlite3.schema.SQLite3Schema.SQLite3Column;
import sqlancer.sqlite3.schema.SQLite3Schema.SQLite3Table;
public final class SQLite3Common {
private SQLite3Common() {
}
public static String getRandomCollate() {
return Randomly.fromOptions(" COLLATE BINARY", " COLLATE RTRIM", " COLLATE NOCASE"/* , " COLLATE UINT" */);
}
public static String getCheckConstraint(SQLite3GlobalState globalState, List columns) {
SQLite3Expression expression = new SQLite3ExpressionGenerator(globalState).setColumns(columns)
.generateExpression();
return " CHECK ( " + SQLite3Visitor.asString(expression) + ")";
}
// TODO: refactor others to use this method
// https://www.sqlite.org/syntax/ordering-term.html
public static String getOrderingTerm(List columns, SQLite3GlobalState globalState) {
SQLite3Expression randExpr = new SQLite3ExpressionGenerator(globalState).setColumns(columns)
.generateExpression();
StringBuilder sb = new StringBuilder(SQLite3Visitor.asString(randExpr));
sb.append(" ");
if (Randomly.getBoolean()) {
sb.append(SQLite3Common.getRandomCollate());
}
if (Randomly.getBoolean()) {
if (Randomly.getBoolean()) {
sb.append(" ASC");
} else {
sb.append(" DESC");
}
}
return sb.toString();
}
public static String getIndexedClause(String indexName) {
StringBuilder sb = new StringBuilder();
if (Randomly.getBoolean()) {
sb.append("INDEXED BY ");
sb.append(indexName);
} else {
sb.append("NOT INDEXED");
}
return sb.toString();
}
public static String getFreeTableName(SQLite3Schema s) {
int nr = 0;
String[] name = new String[1];
do {
name[0] = DBMSCommon.createTableName(nr++);
} while (s.getDatabaseTables().stream().anyMatch(tab -> tab.getName().contentEquals(name[0])));
return name[0];
}
public static String getFreeViewName(SQLite3Schema s) {
int nr = 0;
String[] name = new String[1];
do {
name[0] = "v" + nr++;
} while (s.getDatabaseTables().stream().anyMatch(tab -> tab.getName().contentEquals(name[0])));
return name[0];
}
public static String getFreeIndexName(SQLite3Schema s) {
List indexNames = s.getIndexNames();
String candidateName;
do {
candidateName = DBMSCommon.createIndexName((int) Randomly.getNotCachedInteger(0, 100));
} while (indexNames.contains(candidateName));
return candidateName;
}
public static String getFreeColumnName(SQLite3Table t) {
List indexNames = t.getColumns();
final String[] candidateName = new String[1];
do {
candidateName[0] = DBMSCommon.createColumnName((int) Randomly.getNotCachedInteger(0, 100));
} while (indexNames.stream().anyMatch(c -> c.getName().contentEquals(candidateName[0])));
return candidateName[0];
}
public static String getOrderByAsString(List columns, SQLite3GlobalState globalState) {
StringBuilder sb = new StringBuilder();
SQLite3ExpressionGenerator gen = new SQLite3ExpressionGenerator(globalState).setColumns(columns);
sb.append(" ORDER BY ");
for (int i = 0; i < Randomly.smallNumber() + 1; i++) {
if (i != 0) {
sb.append(", ");
}
sb.append(SQLite3Visitor.asString(gen.generateOrderingTerm()));
}
return sb.toString();
}
public static List getOrderBy(List columns, SQLite3GlobalState globalState) {
SQLite3ExpressionGenerator gen = new SQLite3ExpressionGenerator(globalState).setColumns(columns);
List list = new ArrayList<>();
for (int i = 0; i < 1 + Randomly.smallNumber(); i++) {
list.add(gen.generateOrderingTerm());
}
return list;
}
public static SQLite3Column createColumn(int i) {
return new SQLite3Column(DBMSCommon.createColumnName(i), SQLite3DataType.NONE, false, false, null);
}
public static List getTableRefs(List tables, SQLite3Schema s) {
List tableRefs = new ArrayList<>();
for (SQLite3Table t : tables) {
SQLite3TableReference tableRef;
if (Randomly.getBooleanWithSmallProbability() && !s.getIndexNames().isEmpty()) {
tableRef = new SQLite3TableReference(s.getRandomIndexOrBailout(), t);
} else {
tableRef = new SQLite3TableReference(t);
}
tableRefs.add(tableRef);
}
return tableRefs;
}
}