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
124 changes: 124 additions & 0 deletions src/sqlancer/yugabyte/ysql/YSQLErrors.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@ public static void addCommonFetchErrors(ExpectedErrors errors) {
errors.add("FULL JOIN is only supported with merge-joinable or hash-joinable join conditions");
errors.add("but it cannot be referenced from this part of the query");
errors.add("missing FROM-clause entry for table");
errors.add("set-returning functions are not allowed in JOIN conditions");
errors.add("set-returning functions are not allowed in WHERE");
errors.add("set-returning functions are not allowed in partition key expressions");
errors.add("set-returning functions are not allowed in VALUES");
errors.add("set-returning functions are not allowed in RETURNING");
errors.add("set-returning functions are not allowed in HAVING");
errors.add("argument of IN must not return a set");
errors.add("argument of NOT must not return a set");
errors.add("argument of AND must not return a set");
errors.add("argument of OR must not return a set");
errors.add("set-returning functions are not allowed in CASE");
errors.add("set-returning functions are not allowed in expressions");

errors.add("canceling statement due to statement timeout");
}
Expand All @@ -24,9 +36,45 @@ public static void addCommonTableErrors(ExpectedErrors errors) {
errors.add("PRIMARY KEY containing column of type 'INET' not yet supported");
errors.add("PRIMARY KEY containing column of type 'VARBIT' not yet supported");
errors.add("PRIMARY KEY containing column of type 'INT4RANGE' not yet supported");
errors.add("PRIMARY KEY containing column of type 'INT8RANGE' not yet supported");
errors.add("PRIMARY KEY containing column of type 'NUMRANGE' not yet supported");
errors.add("PRIMARY KEY containing column of type 'TSRANGE' not yet supported");
errors.add("PRIMARY KEY containing column of type 'TSTZRANGE' not yet supported");
errors.add("PRIMARY KEY containing column of type 'DATERANGE' not yet supported");
errors.add("PRIMARY KEY containing column of type 'JSON' not yet supported");
errors.add("PRIMARY KEY containing column of type 'JSONB' not yet supported");
errors.add("PRIMARY KEY containing column of type 'CIDR' not yet supported");
errors.add("PRIMARY KEY containing column of type 'MACADDR' not yet supported");
errors.add("PRIMARY KEY containing column of type 'POINT' not yet supported");
errors.add("PRIMARY KEY containing column of type 'LINE' not yet supported");
errors.add("PRIMARY KEY containing column of type 'LSEG' not yet supported");
errors.add("PRIMARY KEY containing column of type 'BOX' not yet supported");
errors.add("PRIMARY KEY containing column of type 'PATH' not yet supported");
errors.add("PRIMARY KEY containing column of type 'POLYGON' not yet supported");
errors.add("PRIMARY KEY containing column of type 'CIRCLE' not yet supported");
errors.add("INDEX on column of type 'INET' not yet supported");
errors.add("INDEX on column of type 'VARBIT' not yet supported");
errors.add("INDEX on column of type 'INT4RANGE' not yet supported");
errors.add("INDEX on column of type 'INT8RANGE' not yet supported");
errors.add("INDEX on column of type 'NUMRANGE' not yet supported");
errors.add("INDEX on column of type 'TSRANGE' not yet supported");
errors.add("INDEX on column of type 'TSTZRANGE' not yet supported");
errors.add("INDEX on column of type 'DATERANGE' not yet supported");
errors.add("INDEX on column of type 'JSON' not yet supported");
errors.add("INDEX on column of type 'JSONB' not yet supported");
errors.add("INDEX on column of type 'CIDR' not yet supported");
errors.add("INDEX on column of type 'MACADDR' not yet supported");
errors.add("INDEX on column of type 'POINT' not yet supported");
errors.add("INDEX on column of type 'LINE' not yet supported");
errors.add("INDEX on column of type 'LSEG' not yet supported");
errors.add("INDEX on column of type 'BOX' not yet supported");
errors.add("INDEX on column of type 'PATH' not yet supported");
errors.add("INDEX on column of type 'POLYGON' not yet supported");
errors.add("INDEX on column of type 'CIRCLE' not yet supported");
errors.add("INDEX on column of type 'INTERVAL' not yet supported");
errors.add("INDEX on column of type 'BOOLARRAY' not yet supported");
errors.add("INDEX on column of type 'INT4ARRAY' not yet supported");
errors.add("INDEX on column of type 'TEXTARRAY' not yet supported");
errors.add("cannot be changed");
errors.add("cannot split table that does not have primary key");
}
Expand All @@ -41,11 +89,41 @@ public static void addTransactionErrors(ExpectedErrors errors) {
errors.add("cannot insert a non-DEFAULT value into column");
errors.add("Operation failed. Try again");
errors.add("Value write after transaction start");
errors.add("no partition of relation");
// YugabyteDB Read-Committed specific errors
errors.add("Read Committed isolation level not supported");
errors.add("yb_enable_read_committed_isolation must be enabled");
errors.add("could not serialize access due to read/write dependencies among transactions");
errors.add("could not serialize access due to concurrent update");
errors.add("Transaction aborted");
errors.add("Transaction conflicted");
errors.add("current transaction is aborted, commands ignored until end of transaction block");
// Wait-on-Conflict errors
errors.add("Wait queue operation failed");
errors.add("yb_enable_wait_queues must be enabled");
errors.add("Wait-on-Conflict mode requires Read Committed isolation");
errors.add("Deadlock detected");
errors.add("Statement timeout while waiting for lock");
}

public static void addCommonExpressionErrors(ExpectedErrors errors) {
errors.add("non-integer constant in");
errors.add("must appear in the GROUP BY clause or be used in an aggregate function");
// JSONB specific errors
errors.add("cannot extract elements from a scalar");
errors.add("cannot extract field from a non-object");
errors.add("cannot delete from scalar");
errors.add("path element at position");
errors.add("cannot index");
errors.add("jsonb array must have even number of elements");
errors.add("argument of json_build_object must be a string");
errors.add("argument list must have even number of elements");
errors.add("could not determine data type of parameter");
errors.add("cannot call jsonb_");
errors.add("jsonb path is not an array");
errors.add("invalid input syntax for type json");
errors.add("token");
errors.add("JSON");
errors.add("GROUP BY position");
errors.add("must not be");
errors.add("must be");
Expand All @@ -61,10 +139,20 @@ public static void addCommonExpressionErrors(ExpectedErrors errors) {
errors.add("is not a table");
errors.add("cannot change materialized view");
errors.add("syntax error at or near \"(\"");
errors.add("syntax error at or near \"WITH\"");
errors.add("syntax error at or near \"RENAME\"");
errors.add("syntax error at or near \",\"");
errors.add("syntax error at or near \"ATTACH\"");
errors.add("syntax error at or near \"SCHEMA\"");
errors.add("syntax error at or near \"USER\"");
errors.add("syntax error at or near \"ALL\"");
errors.add("syntax error at or near");
errors.add("encoding conversion from");
errors.add("does not exist");
errors.add("is not unique");
errors.add("is not supported");
errors.add("This statement not supported yet");
errors.add("not supported yet");
errors.add("cannot be changed");
errors.add("invalid reference to FROM-clause entry for table");

Expand All @@ -88,11 +176,46 @@ public static void addCommonExpressionErrors(ExpectedErrors errors) {
errors.add("division by zero");
errors.add("invalid input syntax for type money");
errors.add("invalid input syntax for type");
errors.add("time zone");
errors.add("not recognized");
errors.add("cannot cast type");
errors.add("cannot cast jsonb array to type");
errors.add("cannot cast jsonb object to type boolean");
errors.add("cannot cast jsonb object to type integer");
errors.add("cannot cast jsonb string to type integer");
errors.add("cannot cast jsonb string to type boolean");
errors.add("CASE types");
errors.add("value overflows numeric format");
errors.add("is out of range for type");
errors.add("numeric field overflow");
errors.add("is of type boolean but expression is of type text");
errors.add("but default expression is of type");
errors.add("but expression is of type");
errors.add("but default expression is of type");
errors.add("is of type numrange but default expression is of type int4range");
errors.add("is of type int8range but default expression is of type int4range");
errors.add("CASE types text and bytea cannot be matched");
errors.add("a negative number raised to a non-integer power yields a complex result");
errors.add("could not determine polymorphic type because input has type unknown");
errors.add("input of anonymous composite types is not implemented");

// Ordering errors for types that don't have natural ordering
errors.add("could not identify an ordering operator for type circle");
errors.add("could not identify an ordering operator for type");
errors.add("could not identify an equality operator for type json");
errors.add("could not identify an equality operator for type point");
errors.add("could not identify an equality operator for type circle");
errors.add("could not identify an equality operator for type box");
errors.add("could not identify an equality operator for type polygon");
errors.add("could not identify an equality operator for type lseg");
errors.add("could not identify an equality operator for type line");
errors.add("could not identify an equality operator for type path");
errors.add("cannot cast jsonb numeric to type boolean");
errors.add("cannot set path in scalar");
errors.add("cannot delete path in scalar");
errors.add("aggregate function calls cannot contain set-returning function calls");
errors.add("single boolean result is expected");
errors.add("cannot deconstruct a scalar");

addToCharFunctionErrors(errors);
addBitStringOperationErrors(errors);
Expand Down Expand Up @@ -138,6 +261,7 @@ public static void addFunctionErrors(ExpectedErrors errors) {

public static void addCommonRegexExpressionErrors(ExpectedErrors errors) {
errors.add("is not a valid hexadecimal digit");
errors.add("malformed array literal");
}

public static void addCommonRangeExpressionErrors(ExpectedErrors errors) {
Expand Down
35 changes: 35 additions & 0 deletions src/sqlancer/yugabyte/ysql/YSQLExpectedValueVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
import sqlancer.yugabyte.ysql.ast.YSQLAggregate;
import sqlancer.yugabyte.ysql.ast.YSQLBetweenOperation;
import sqlancer.yugabyte.ysql.ast.YSQLBinaryLogicalOperation;
import sqlancer.yugabyte.ysql.ast.YSQLCaseExpression;
import sqlancer.yugabyte.ysql.ast.YSQLCastOperation;
import sqlancer.yugabyte.ysql.ast.YSQLJSONBOperation;
import sqlancer.yugabyte.ysql.ast.YSQLJSONBFunction;
import sqlancer.yugabyte.ysql.ast.YSQLColumnValue;
import sqlancer.yugabyte.ysql.ast.YSQLConstant;
import sqlancer.yugabyte.ysql.ast.YSQLExpression;
Expand Down Expand Up @@ -144,6 +147,38 @@ public void visit(YSQLBinaryLogicalOperation op) {
visit(op.getLeft());
visit(op.getRight());
}

@Override
public void visit(YSQLJSONBOperation op) {
print(op);
visit(op.getLeft());
visit(op.getRight());
}

@Override
public void visit(YSQLJSONBFunction op) {
print(op);
for (YSQLExpression arg : op.getArguments()) {
visit(arg);
}
}

@Override
public void visit(YSQLCaseExpression op) {
print(op);
if (op.getSwitchCondition() != null) {
visit(op.getSwitchCondition());
}
for (YSQLExpression condition : op.getConditions()) {
visit(condition);
}
for (YSQLExpression result : op.getResults()) {
visit(result);
}
if (op.getElseResult() != null) {
visit(op.getElseResult());
}
}

public String get() {
return sb.toString();
Expand Down
48 changes: 40 additions & 8 deletions src/sqlancer/yugabyte/ysql/YSQLProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,18 @@
import sqlancer.common.DBMSCommon;
import sqlancer.common.query.SQLQueryAdapter;
import sqlancer.common.query.SQLQueryProvider;
import sqlancer.common.query.SQLancerResultSet;
// import sqlancer.common.query.SQLancerResultSet;
import sqlancer.common.query.ExpectedErrors;
import sqlancer.yugabyte.ysql.gen.*;
// import sqlancer.yugabyte.ysql.gen.YSQLMergeGenerator; // Commented out - MERGE not supported

import java.net.URI;
import java.net.URISyntaxException;
import java.sql.Connection;
import java.util.Arrays;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;

import static sqlancer.yugabyte.ysql.YSQLOptions.YSQLOracleFactory.CATALOG;

Expand Down Expand Up @@ -55,7 +57,13 @@ public static int mapActions(YSQLGlobalState globalState, Action a) {
nrPerformed = r.getInteger(0, 5);
break;
case COMMIT:
nrPerformed = r.getInteger(0, 0);
nrPerformed = r.getInteger(0, 3);
break;
case SET_TRANSACTION:
nrPerformed = r.getInteger(0, 2);
break;
case PARALLEL_QUERY_TEST:
nrPerformed = r.getInteger(0, 1);
break;
case ALTER_TABLE:
nrPerformed = r.getInteger(0, 5);
Expand All @@ -79,6 +87,9 @@ public static int mapActions(YSQLGlobalState globalState, Action a) {
case TRUNCATE:
nrPerformed = r.getInteger(0, 15);
break;
// case MERGE:
// nrPerformed = r.getInteger(0, 10);
// break;
case CREATE_VIEW:
nrPerformed = r.getInteger(0, 5);
break;
Expand Down Expand Up @@ -228,13 +239,16 @@ private Connection createConnectionSafely(String entryURL, String user, String p
}

protected void readFunctions(YSQLGlobalState globalState) throws SQLException {
// Commented out to avoid set-returning functions causing errors
/*
SQLQueryAdapter query = new SQLQueryAdapter("SELECT proname, provolatile FROM pg_proc;");
SQLancerResultSet rs = query.executeAndGet(globalState);
while (rs.next()) {
String functionName = rs.getString(1);
Character functionType = rs.getString(2).charAt(0);
globalState.addFunctionAndType(functionName, functionType);
}
*/
}

protected void createTables(YSQLGlobalState globalState, int numTables) throws Exception {
Expand All @@ -259,7 +273,12 @@ private void exceptionLessSleep(long timeout) {
}

protected void prepareTables(YSQLGlobalState globalState) throws Exception {
StatementExecutor<YSQLGlobalState, Action> se = new StatementExecutor<>(globalState, Action.values(),
// Filter out unsupported actions like MERGE
Action[] supportedActions = Arrays.stream(Action.values())
.filter(action -> !action.name().equals("MERGE"))
.toArray(Action[]::new);

StatementExecutor<YSQLGlobalState, Action> se = new StatementExecutor<>(globalState, supportedActions,
YSQLProvider::mapActions, (q) -> {
if (globalState.getSchema().getDatabaseTables().isEmpty()) {
throw new IgnoreMeException();
Expand Down Expand Up @@ -345,11 +364,22 @@ public enum Action implements AbstractAction<YSQLGlobalState> {
SET(YSQLSetGenerator::create), // TODO insert yugabyte sets
SET_CONSTRAINTS((g) -> {
String sb = "SET CONSTRAINTS ALL " + Randomly.fromOptions("DEFERRED", "IMMEDIATE");
return new SQLQueryAdapter(sb);
return new SQLQueryAdapter(sb, ExpectedErrors.from(
"SET CONSTRAINTS is not supported yet",
"result of range union would not be contiguous",
"current transaction is aborted",
"there is no unique or exclusion constraint"
));
}), //
RESET_ROLE((g) -> new SQLQueryAdapter("RESET ROLE")), //
SET_TRANSACTION(YSQLTransactionGenerator::setTransactionMode), //
RESET_ROLE((g) -> new SQLQueryAdapter("RESET ROLE", ExpectedErrors.from(
"This statement not supported yet",
"current transaction is aborted"
))), //
COMMENT_ON(YSQLCommentGenerator::generate), //
RESET((g) -> new SQLQueryAdapter("RESET ALL") /*
RESET((g) -> new SQLQueryAdapter("RESET ALL", ExpectedErrors.from(
"current transaction is aborted, commands ignored until end of transaction block",
"RESET ALL cannot run inside a transaction block")) /*
* https://www.postgres.org/docs/devel/sql-reset.html TODO: also
* configuration parameter
*/), //
Expand All @@ -358,7 +388,9 @@ public enum Action implements AbstractAction<YSQLGlobalState> {
// UNLISTEN((g) -> YSQLNotifyGenerator.createUnlisten()), //
CREATE_SEQUENCE(YSQLSequenceGenerator::createSequence), //
CREATE_VIEW(YSQLViewGenerator::create),
REFRESH_VIEW(YSQLMaterializedViewRefresh::create);
REFRESH_VIEW(YSQLMaterializedViewRefresh::create),
PARALLEL_QUERY_TEST(YSQLParallelQueryGenerator::generateParallelQueryTest);
// MERGE(YSQLMergeGenerator::create); // Disabled - YugabyteDB doesn't support MERGE yet

private final SQLQueryProvider<YSQLGlobalState> sqlQueryProvider;

Expand Down
Loading
Loading