From 24b2d497feeb21df482b50439e02aafb340e5f4c Mon Sep 17 00:00:00 2001 From: zhenglinli <1125806272@qq.com> Date: Fri, 30 Jun 2023 14:20:00 +0800 Subject: [PATCH 01/23] fix: Tianmu engine does not support fulltext index. --- src/sqlancer/stonedb/gen/StoneDBIndexCreateGenerator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sqlancer/stonedb/gen/StoneDBIndexCreateGenerator.java b/src/sqlancer/stonedb/gen/StoneDBIndexCreateGenerator.java index b50f07a6a..82eab3413 100644 --- a/src/sqlancer/stonedb/gen/StoneDBIndexCreateGenerator.java +++ b/src/sqlancer/stonedb/gen/StoneDBIndexCreateGenerator.java @@ -28,7 +28,8 @@ public static SQLQueryAdapter generate(StoneDBGlobalState globalState) { private SQLQueryAdapter getQuery() { sb.append("CREATE "); - sb.append(Randomly.fromOptions("UNIQUE", "FULLTEXT", "SPATIAL")); + // Tianmu engine does not support fulltext index. + sb.append(Randomly.fromOptions("UNIQUE" /* "FULLTEXT" */, "SPATIAL")); sb.append(" INDEX "); sb.append(globalState.getSchema().getFreeIndexName()); if (Randomly.getBoolean()) { From 653c88833c2c627dce98f43f3e07fe1c44c7a28c Mon Sep 17 00:00:00 2001 From: zhenglinli <1125806272@qq.com> Date: Mon, 3 Jul 2023 18:15:36 +0800 Subject: [PATCH 02/23] feat: add expectedErrors for all generator --- src/sqlancer/stonedb/gen/StoneDBIndexDropGenerator.java | 4 ++++ src/sqlancer/stonedb/gen/StoneDBTableUpdateGenerator.java | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/sqlancer/stonedb/gen/StoneDBIndexDropGenerator.java b/src/sqlancer/stonedb/gen/StoneDBIndexDropGenerator.java index dda72c735..4155ef6e5 100644 --- a/src/sqlancer/stonedb/gen/StoneDBIndexDropGenerator.java +++ b/src/sqlancer/stonedb/gen/StoneDBIndexDropGenerator.java @@ -29,9 +29,13 @@ private SQLQueryAdapter getQuery() { sb.append(" ON "); sb.append(table.getName()); appendAlgoOrLockOption(); + addExpectedErrors(); return new SQLQueryAdapter(sb.toString(), errors); } + private void addExpectedErrors() { + } + private void appendAlgoOrLockOption() { if (Randomly.getBoolean()) { return; diff --git a/src/sqlancer/stonedb/gen/StoneDBTableUpdateGenerator.java b/src/sqlancer/stonedb/gen/StoneDBTableUpdateGenerator.java index 4812a6ee3..bb100a211 100644 --- a/src/sqlancer/stonedb/gen/StoneDBTableUpdateGenerator.java +++ b/src/sqlancer/stonedb/gen/StoneDBTableUpdateGenerator.java @@ -39,9 +39,13 @@ public SQLQueryAdapter getQuery() { if (Randomly.getBoolean()) { appendLimit(); } + addExpectedErrors(); return new SQLQueryAdapter(sb.toString(), errors); } + private void addExpectedErrors() { + } + public void appendAssignmentList() { for (int i = 0; i < new Randomly().getInteger(1, table.getColumns().size()); i++) { if (i != 0) { From dccbd331c0621079e893cbd01e2672ba884e2566 Mon Sep 17 00:00:00 2001 From: zhenglinli <1125806272@qq.com> Date: Tue, 4 Jul 2023 09:28:27 +0800 Subject: [PATCH 03/23] refactor: remove unused expected errors --- src/sqlancer/stonedb/gen/StoneDBIndexDropGenerator.java | 4 ---- src/sqlancer/stonedb/gen/StoneDBTableUpdateGenerator.java | 4 ---- 2 files changed, 8 deletions(-) diff --git a/src/sqlancer/stonedb/gen/StoneDBIndexDropGenerator.java b/src/sqlancer/stonedb/gen/StoneDBIndexDropGenerator.java index 4155ef6e5..dda72c735 100644 --- a/src/sqlancer/stonedb/gen/StoneDBIndexDropGenerator.java +++ b/src/sqlancer/stonedb/gen/StoneDBIndexDropGenerator.java @@ -29,13 +29,9 @@ private SQLQueryAdapter getQuery() { sb.append(" ON "); sb.append(table.getName()); appendAlgoOrLockOption(); - addExpectedErrors(); return new SQLQueryAdapter(sb.toString(), errors); } - private void addExpectedErrors() { - } - private void appendAlgoOrLockOption() { if (Randomly.getBoolean()) { return; diff --git a/src/sqlancer/stonedb/gen/StoneDBTableUpdateGenerator.java b/src/sqlancer/stonedb/gen/StoneDBTableUpdateGenerator.java index bb100a211..4812a6ee3 100644 --- a/src/sqlancer/stonedb/gen/StoneDBTableUpdateGenerator.java +++ b/src/sqlancer/stonedb/gen/StoneDBTableUpdateGenerator.java @@ -39,13 +39,9 @@ public SQLQueryAdapter getQuery() { if (Randomly.getBoolean()) { appendLimit(); } - addExpectedErrors(); return new SQLQueryAdapter(sb.toString(), errors); } - private void addExpectedErrors() { - } - public void appendAssignmentList() { for (int i = 0; i < new Randomly().getInteger(1, table.getColumns().size()); i++) { if (i != 0) { From 5980460e5447f2993c6dc46cfe55e3c821376106 Mon Sep 17 00:00:00 2001 From: zhenglinli <1125806272@qq.com> Date: Mon, 3 Jul 2023 18:15:36 +0800 Subject: [PATCH 04/23] feat: add expectedErrors for all generator --- src/sqlancer/stonedb/gen/StoneDBIndexDropGenerator.java | 4 ++++ src/sqlancer/stonedb/gen/StoneDBTableUpdateGenerator.java | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/sqlancer/stonedb/gen/StoneDBIndexDropGenerator.java b/src/sqlancer/stonedb/gen/StoneDBIndexDropGenerator.java index dda72c735..4155ef6e5 100644 --- a/src/sqlancer/stonedb/gen/StoneDBIndexDropGenerator.java +++ b/src/sqlancer/stonedb/gen/StoneDBIndexDropGenerator.java @@ -29,9 +29,13 @@ private SQLQueryAdapter getQuery() { sb.append(" ON "); sb.append(table.getName()); appendAlgoOrLockOption(); + addExpectedErrors(); return new SQLQueryAdapter(sb.toString(), errors); } + private void addExpectedErrors() { + } + private void appendAlgoOrLockOption() { if (Randomly.getBoolean()) { return; diff --git a/src/sqlancer/stonedb/gen/StoneDBTableUpdateGenerator.java b/src/sqlancer/stonedb/gen/StoneDBTableUpdateGenerator.java index 4812a6ee3..bb100a211 100644 --- a/src/sqlancer/stonedb/gen/StoneDBTableUpdateGenerator.java +++ b/src/sqlancer/stonedb/gen/StoneDBTableUpdateGenerator.java @@ -39,9 +39,13 @@ public SQLQueryAdapter getQuery() { if (Randomly.getBoolean()) { appendLimit(); } + addExpectedErrors(); return new SQLQueryAdapter(sb.toString(), errors); } + private void addExpectedErrors() { + } + public void appendAssignmentList() { for (int i = 0; i < new Randomly().getInteger(1, table.getColumns().size()); i++) { if (i != 0) { From c93e0d6c550b8d7fec77b5bad5848b30907128d2 Mon Sep 17 00:00:00 2001 From: zhenglinli <1125806272@qq.com> Date: Tue, 4 Jul 2023 09:28:27 +0800 Subject: [PATCH 05/23] refactor: remove unused expected errors --- src/sqlancer/stonedb/gen/StoneDBIndexDropGenerator.java | 4 ---- src/sqlancer/stonedb/gen/StoneDBTableUpdateGenerator.java | 4 ---- 2 files changed, 8 deletions(-) diff --git a/src/sqlancer/stonedb/gen/StoneDBIndexDropGenerator.java b/src/sqlancer/stonedb/gen/StoneDBIndexDropGenerator.java index 4155ef6e5..dda72c735 100644 --- a/src/sqlancer/stonedb/gen/StoneDBIndexDropGenerator.java +++ b/src/sqlancer/stonedb/gen/StoneDBIndexDropGenerator.java @@ -29,13 +29,9 @@ private SQLQueryAdapter getQuery() { sb.append(" ON "); sb.append(table.getName()); appendAlgoOrLockOption(); - addExpectedErrors(); return new SQLQueryAdapter(sb.toString(), errors); } - private void addExpectedErrors() { - } - private void appendAlgoOrLockOption() { if (Randomly.getBoolean()) { return; diff --git a/src/sqlancer/stonedb/gen/StoneDBTableUpdateGenerator.java b/src/sqlancer/stonedb/gen/StoneDBTableUpdateGenerator.java index bb100a211..4812a6ee3 100644 --- a/src/sqlancer/stonedb/gen/StoneDBTableUpdateGenerator.java +++ b/src/sqlancer/stonedb/gen/StoneDBTableUpdateGenerator.java @@ -39,13 +39,9 @@ public SQLQueryAdapter getQuery() { if (Randomly.getBoolean()) { appendLimit(); } - addExpectedErrors(); return new SQLQueryAdapter(sb.toString(), errors); } - private void addExpectedErrors() { - } - public void appendAssignmentList() { for (int i = 0; i < new Randomly().getInteger(1, table.getColumns().size()); i++) { if (i != 0) { From cc89deb945bdf08cfb201249e2f7f2223c6de5a7 Mon Sep 17 00:00:00 2001 From: zhenglinli <1125806272@qq.com> Date: Tue, 11 Jul 2023 14:11:29 +0800 Subject: [PATCH 06/23] feat: init support of TLP for StoneDB --- src/sqlancer/stonedb/StoneDBOptions.java | 57 +++++- .../gen/StoneDBExpressionGenerator.java | 13 +- ...oneDBQueryPartitioningAggregateTester.java | 168 ++++++++++++++++++ .../oracle/StoneDBQueryPartitioningBase.java | 71 ++++++++ ...toneDBQueryPartitioningDistinctTester.java | 42 +++++ ...StoneDBQueryPartitioningGroupByTester.java | 50 ++++++ .../StoneDBQueryPartitioningHavingTester.java | 46 +++++ .../StoneDBQueryPartitioningWhereTester.java | 42 +++++ .../stonedb/oracle/StoneDBTLPOracle.java | 16 -- 9 files changed, 482 insertions(+), 23 deletions(-) create mode 100644 src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningAggregateTester.java create mode 100644 src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningBase.java create mode 100644 src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningDistinctTester.java create mode 100644 src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningGroupByTester.java create mode 100644 src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningHavingTester.java create mode 100644 src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningWhereTester.java delete mode 100644 src/sqlancer/stonedb/oracle/StoneDBTLPOracle.java diff --git a/src/sqlancer/stonedb/StoneDBOptions.java b/src/sqlancer/stonedb/StoneDBOptions.java index 928bcfa39..280193e79 100644 --- a/src/sqlancer/stonedb/StoneDBOptions.java +++ b/src/sqlancer/stonedb/StoneDBOptions.java @@ -1,6 +1,7 @@ package sqlancer.stonedb; import java.sql.SQLException; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -9,11 +10,16 @@ import sqlancer.DBMSSpecificOptions; import sqlancer.OracleFactory; +import sqlancer.common.oracle.CompositeTestOracle; import sqlancer.common.oracle.TestOracle; import sqlancer.stonedb.StoneDBOptions.StoneDBOracleFactory; import sqlancer.stonedb.StoneDBProvider.StoneDBGlobalState; import sqlancer.stonedb.oracle.StoneDBNoRECOracle; -import sqlancer.stonedb.oracle.StoneDBTLPOracle; +import sqlancer.stonedb.oracle.StoneDBQueryPartitioningAggregateTester; +import sqlancer.stonedb.oracle.StoneDBQueryPartitioningDistinctTester; +import sqlancer.stonedb.oracle.StoneDBQueryPartitioningGroupByTester; +import sqlancer.stonedb.oracle.StoneDBQueryPartitioningHavingTester; +import sqlancer.stonedb.oracle.StoneDBQueryPartitioningWhereTester; @Parameters(separators = "=", commandDescription = "StoneDB (default host: " + StoneDBOptions.DEFAULT_HOST + ", default port: " + StoneDBOptions.DEFAULT_PORT + ")") @@ -22,7 +28,7 @@ public class StoneDBOptions implements DBMSSpecificOptions public static final int DEFAULT_PORT = 3306; @Parameter(names = "--oracle") - public List oracles = Arrays.asList(StoneDBOracleFactory.NOREC); + public List oracles = List.of(StoneDBOracleFactory.NOREC); public enum StoneDBOracleFactory implements OracleFactory { NOREC { @@ -31,12 +37,51 @@ public TestOracle create(StoneDBGlobalState globalState) thr return new StoneDBNoRECOracle(globalState); } }, - TLP { + + HAVING { + @Override + public TestOracle create(StoneDBGlobalState globalState) throws SQLException { + return new StoneDBQueryPartitioningHavingTester(globalState); + } + }, + WHERE { + @Override + public TestOracle create(StoneDBGlobalState globalState) throws SQLException { + return new StoneDBQueryPartitioningWhereTester(globalState); + } + }, + GROUP_BY { + @Override + public TestOracle create(StoneDBGlobalState globalState) throws SQLException { + return new StoneDBQueryPartitioningGroupByTester(globalState); + } + }, + AGGREGATE { + + @Override + public TestOracle create(StoneDBGlobalState globalState) throws SQLException { + return new StoneDBQueryPartitioningAggregateTester(globalState); + } + + }, + DISTINCT { + @Override + public TestOracle create(StoneDBGlobalState globalState) throws SQLException { + return new StoneDBQueryPartitioningDistinctTester(globalState); + } + }, + QUERY_PARTITIONING { @Override - public TestOracle create(StoneDBGlobalState globalState) throws Exception { - return new StoneDBTLPOracle(globalState); + public TestOracle create(StoneDBGlobalState globalState) throws SQLException { + List> oracles = new ArrayList<>(); + oracles.add(new StoneDBQueryPartitioningWhereTester(globalState)); + oracles.add(new StoneDBQueryPartitioningHavingTester(globalState)); + oracles.add(new StoneDBQueryPartitioningAggregateTester(globalState)); + oracles.add(new StoneDBQueryPartitioningDistinctTester(globalState)); + oracles.add(new StoneDBQueryPartitioningGroupByTester(globalState)); + return new CompositeTestOracle<>(oracles, globalState); } - } + }; } @Override diff --git a/src/sqlancer/stonedb/gen/StoneDBExpressionGenerator.java b/src/sqlancer/stonedb/gen/StoneDBExpressionGenerator.java index 87876c5cc..c3ba5d2e8 100644 --- a/src/sqlancer/stonedb/gen/StoneDBExpressionGenerator.java +++ b/src/sqlancer/stonedb/gen/StoneDBExpressionGenerator.java @@ -166,8 +166,9 @@ protected List> generateColumns() { return new ArrayList<>(set); } + // https://stonedb.io/docs/SQL-reference/functions/aggregate-functions/ public enum StoneDBAggregateFunction { - MAX(1), MIN(1), AVG(1), COUNT(1), FIRST(1), SUM(1); + MAX(1), MIN(1), AVG(1), COUNT(1), SUM(1); private int nrArgs; @@ -317,4 +318,14 @@ public String getTextRepresentation() { } } + + public NewFunctionNode generateAggregateAndArgs( + StoneDBAggregateFunction aggregateFunction) { + return new NewFunctionNode<>(generateExpressions(aggregateFunction.getNrArgs()), aggregateFunction); + } + + public Node generateAggregate() { + StoneDBAggregateFunction aggrFunc = StoneDBAggregateFunction.getRandom(); + return generateAggregateAndArgs(aggrFunc); + } } diff --git a/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningAggregateTester.java b/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningAggregateTester.java new file mode 100644 index 000000000..1e17540b4 --- /dev/null +++ b/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningAggregateTester.java @@ -0,0 +1,168 @@ +package sqlancer.stonedb.oracle; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import sqlancer.ComparatorHelper; +import sqlancer.IgnoreMeException; +import sqlancer.Randomly; +import sqlancer.common.ast.newast.NewAliasNode; +import sqlancer.common.ast.newast.NewFunctionNode; +import sqlancer.common.ast.newast.NewUnaryPostfixOperatorNode; +import sqlancer.common.ast.newast.NewUnaryPrefixOperatorNode; +import sqlancer.common.ast.newast.Node; +import sqlancer.common.query.SQLQueryAdapter; +import sqlancer.common.query.SQLancerResultSet; +import sqlancer.stonedb.StoneDBProvider.StoneDBGlobalState; +import sqlancer.stonedb.StoneDBSchema.StoneDBCompositeDataType; +import sqlancer.stonedb.StoneDBSchema.StoneDBDataType; +import sqlancer.stonedb.StoneDBToStringVisitor; +import sqlancer.stonedb.ast.StoneDBExpression; +import sqlancer.stonedb.ast.StoneDBSelect; +import sqlancer.stonedb.gen.StoneDBExpressionGenerator.StoneDBAggregateFunction; +import sqlancer.stonedb.gen.StoneDBExpressionGenerator.StoneDBCastOperation; +import sqlancer.stonedb.gen.StoneDBExpressionGenerator.StoneDBUnaryPostfixOperator; +import sqlancer.stonedb.gen.StoneDBExpressionGenerator.StoneDBUnaryPrefixOperator; + +public class StoneDBQueryPartitioningAggregateTester extends StoneDBQueryPartitioningBase { + + public StoneDBQueryPartitioningAggregateTester(StoneDBGlobalState state) { + super(state); + } + + @Override + public void check() throws Exception { + super.check(); + + StoneDBAggregateFunction aggregateFunction = Randomly.fromOptions(StoneDBAggregateFunction.values()); + NewFunctionNode aggregate = gen + .generateAggregateAndArgs(aggregateFunction); + + List> fetchColumns = new ArrayList<>(); + fetchColumns.add(aggregate); + select.setFetchColumns(fetchColumns); + + if (Randomly.getBooleanWithRatherLowProbability()) { + select.setOrderByExpressions(gen.generateOrderBys()); + } + + String originalQuery = StoneDBToStringVisitor.asString(select); + String originalResult = getAggregateResult(originalQuery); + + String metamorphicQuery = createMetamorphicUnionQuery(select, aggregate, select.getFromList()); + String metamorphicResult = getAggregateResult(metamorphicQuery); + + String line1 = "--" + originalQuery + ";"; + String line2 = "--" + originalResult + ";"; + String line3 = "--" + originalResult + ";"; + String line4 = "--" + metamorphicResult + ";"; + String output = String.join(System.lineSeparator(), line1, line2, line3, line4); + state.getState().getLocalState().log(output); + + if (originalResult == null && metamorphicResult != null + || originalResult != null && (!originalResult.contentEquals(metamorphicResult) + && !ComparatorHelper.isEqualDouble(originalResult, metamorphicResult))) { + throw new AssertionError("aggregate result mismatch!" + System.lineSeparator() + output); + } + } + + private String createMetamorphicUnionQuery(StoneDBSelect select, + NewFunctionNode aggregate, + List> from) { + String metamorphicQuery; + Node whereClause = gen.generateExpression(); + ; + Node negatedClause = new NewUnaryPrefixOperatorNode<>(whereClause, + StoneDBUnaryPrefixOperator.NOT); + Node notNullClause = new NewUnaryPostfixOperatorNode<>(whereClause, + StoneDBUnaryPostfixOperator.IS_NULL); + List> mappedAggregate = mapped(aggregate); + StoneDBSelect leftSelect = getSelect(mappedAggregate, from, whereClause, select.getJoinList()); + StoneDBSelect middleSelect = getSelect(mappedAggregate, from, negatedClause, select.getJoinList()); + StoneDBSelect rightSelect = getSelect(mappedAggregate, from, notNullClause, select.getJoinList()); + metamorphicQuery = "SELECT " + getOuterAggregateFunction(aggregate) + " FROM ("; + metamorphicQuery += StoneDBToStringVisitor.asString(leftSelect) + " UNION ALL " + + StoneDBToStringVisitor.asString(middleSelect) + " UNION ALL " + + StoneDBToStringVisitor.asString(rightSelect); + metamorphicQuery += ") as result"; + return metamorphicQuery; + } + + private String getAggregateResult(String queryString) throws SQLException { + String resultString; + SQLQueryAdapter q = new SQLQueryAdapter(queryString, errors); + try (SQLancerResultSet result = q.executeAndGet(state)) { + if (result == null) { + throw new IgnoreMeException(); + } + if (!result.next()) { + resultString = null; + } else { + resultString = result.getString(1); + } + return resultString; + } catch (SQLException e) { + if (!e.getMessage().contains("Not implemented type")) { + throw new AssertionError(queryString, e); + } else { + throw new IgnoreMeException(); + } + } + } + + private List> mapped( + NewFunctionNode aggregate) { + + StoneDBCastOperation count; + switch (aggregate.getFunc()) { + case COUNT: + case MAX: + case MIN: + case SUM: + return aliasArgs(List.of(aggregate)); + case AVG: + NewFunctionNode sum = new NewFunctionNode<>( + aggregate.getArgs(), StoneDBAggregateFunction.SUM); + count = new StoneDBCastOperation(new NewFunctionNode<>(aggregate.getArgs(), StoneDBAggregateFunction.COUNT), + new StoneDBCompositeDataType(StoneDBDataType.FLOAT, 8).getPrimitiveDataType()); + return aliasArgs(Arrays.asList(sum, count)); + default: + throw new AssertionError(aggregate.getFunc()); + } + } + + private List> aliasArgs(List> originalAggregateArgs) { + List> args = new ArrayList<>(); + int i = 0; + for (Node expr : originalAggregateArgs) { + args.add(new NewAliasNode(expr, "agg" + i++)); + } + return args; + } + + private String getOuterAggregateFunction(NewFunctionNode aggregate) { + switch (aggregate.getFunc()) { + case AVG: + return "SUM(agg0)/SUM(agg1)"; + case COUNT: + return StoneDBAggregateFunction.SUM + "(agg0)"; + default: + return aggregate.getFunc().toString() + "(agg0)"; + } + } + + private StoneDBSelect getSelect(List> aggregates, List> fromList, + Node whereClause, List> joinList) { + StoneDBSelect select = new StoneDBSelect(); + select.setFetchColumns(aggregates); + select.setFromList(fromList); + select.setWhereClause(whereClause); + select.setJoinList(joinList); + if (Randomly.getBooleanWithSmallProbability()) { + select.setGroupByExpressions(gen.generateExpressions(Randomly.smallNumber() + 1)); + } + return select; + } +} diff --git a/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningBase.java b/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningBase.java new file mode 100644 index 000000000..654faf6e3 --- /dev/null +++ b/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningBase.java @@ -0,0 +1,71 @@ +package sqlancer.stonedb.oracle; + +import sqlancer.Randomly; +import sqlancer.common.ast.newast.ColumnReferenceNode; +import sqlancer.common.ast.newast.Node; +import sqlancer.common.ast.newast.TableReferenceNode; +import sqlancer.common.gen.ExpressionGenerator; +import sqlancer.common.oracle.TernaryLogicPartitioningOracleBase; +import sqlancer.common.oracle.TestOracle; +import sqlancer.stonedb.StoneDBProvider.StoneDBGlobalState; +import sqlancer.stonedb.StoneDBSchema; +import sqlancer.stonedb.StoneDBSchema.StoneDBColumn; +import sqlancer.stonedb.StoneDBSchema.StoneDBTable; +import sqlancer.stonedb.StoneDBSchema.StoneDBTables; +import sqlancer.stonedb.ast.StoneDBExpression; +import sqlancer.stonedb.ast.StoneDBJoin; +import sqlancer.stonedb.ast.StoneDBSelect; +import sqlancer.stonedb.gen.StoneDBExpressionGenerator; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class StoneDBQueryPartitioningBase + extends TernaryLogicPartitioningOracleBase, StoneDBGlobalState> + implements TestOracle { + + StoneDBSchema schema; + StoneDBTables targetTables; + StoneDBExpressionGenerator gen; + StoneDBSelect select; + + public StoneDBQueryPartitioningBase(StoneDBGlobalState state) { + super(state); + } + + @Override + public void check() throws Exception { + schema = state.getSchema(); + targetTables = schema.getRandomTableNonEmptyTables(); + gen = new StoneDBExpressionGenerator(state).setColumns(targetTables.getColumns()); + initializeTernaryPredicateVariants(); + + select = new StoneDBSelect(); + select.setFetchColumns(generateFetchColumns()); + List tables = targetTables.getTables(); + List> tableReferenceNodeList = tables.stream() + .map(t -> new TableReferenceNode(t)).collect(Collectors.toList()); + List> joins = StoneDBJoin.getJoins(tableReferenceNodeList, state); + select.setJoinList(new ArrayList<>(joins)); + select.setFromList(new ArrayList<>(tableReferenceNodeList)); + select.setWhereClause(null); + } + + List> generateFetchColumns() { + List> columns = new ArrayList<>(); + if (Randomly.getBoolean()) { + columns.add(new ColumnReferenceNode<>(new StoneDBColumn("*", null, false, false, 0))); + } else { + columns = Randomly.nonEmptySubset(targetTables.getColumns()).stream() + .map(c -> new ColumnReferenceNode(c)) + .collect(Collectors.toList()); + } + return columns; + } + + @Override + protected ExpressionGenerator> getGen() { + return gen; + } +} diff --git a/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningDistinctTester.java b/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningDistinctTester.java new file mode 100644 index 000000000..cba8290b4 --- /dev/null +++ b/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningDistinctTester.java @@ -0,0 +1,42 @@ +package sqlancer.stonedb.oracle; + +import java.util.ArrayList; +import java.util.List; + +import sqlancer.ComparatorHelper; +import sqlancer.Randomly; +import sqlancer.stonedb.StoneDBProvider.StoneDBGlobalState; +import sqlancer.stonedb.StoneDBToStringVisitor; + +public class StoneDBQueryPartitioningDistinctTester extends StoneDBQueryPartitioningBase { + public StoneDBQueryPartitioningDistinctTester(StoneDBGlobalState state) { + super(state); + } + + @Override + public void check() throws Exception { + super.check(); + + select.setDistinct(true); + select.setWhereClause(null); + String originalQueryString = StoneDBToStringVisitor.asString(select); + List resultSet = ComparatorHelper.getResultSetFirstColumnAsString(originalQueryString, errors, state); + + if (Randomly.getBoolean()) { + select.setDistinct(false); + } + + select.setWhereClause(predicate); + String firstQueryString = StoneDBToStringVisitor.asString(select); + select.setWhereClause(negatedPredicate); + String secondQueryString = StoneDBToStringVisitor.asString(select); + select.setWhereClause(isNullPredicate); + String thirdQueryString = StoneDBToStringVisitor.asString(select); + List combinedString = new ArrayList<>(); + List secondResultSet = ComparatorHelper.getCombinedResultSetNoDuplicates(firstQueryString, + secondQueryString, thirdQueryString, combinedString, true, state, errors); + + ComparatorHelper.assumeResultSetsAreEqual(resultSet, secondResultSet, originalQueryString, combinedString, + state, ComparatorHelper::canonicalizeResultValue); + } +} diff --git a/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningGroupByTester.java b/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningGroupByTester.java new file mode 100644 index 000000000..49caa2a2f --- /dev/null +++ b/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningGroupByTester.java @@ -0,0 +1,50 @@ +package sqlancer.stonedb.oracle; + +import sqlancer.ComparatorHelper; +import sqlancer.Randomly; +import sqlancer.common.ast.newast.ColumnReferenceNode; +import sqlancer.common.ast.newast.Node; +import sqlancer.stonedb.StoneDBProvider.StoneDBGlobalState; +import sqlancer.stonedb.StoneDBSchema.StoneDBColumn; +import sqlancer.stonedb.StoneDBToStringVisitor; +import sqlancer.stonedb.ast.StoneDBExpression; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class StoneDBQueryPartitioningGroupByTester extends StoneDBQueryPartitioningBase { + public StoneDBQueryPartitioningGroupByTester(StoneDBGlobalState state) { + super(state); + } + + @Override + public void check() throws Exception { + super.check(); + // common to both original and combined query string + select.setGroupByExpressions(select.getFetchColumns()); + // specific to original query string + select.setWhereClause(null); + String originalQueryString = StoneDBToStringVisitor.asString(select); + List resultSet = ComparatorHelper.getResultSetFirstColumnAsString(originalQueryString, errors, state); + // specific to combined query string, will produce the same result as original query string in logic + select.setWhereClause(predicate); + String firstQueryString = StoneDBToStringVisitor.asString(select); + select.setWhereClause(negatedPredicate); + String secondQueryString = StoneDBToStringVisitor.asString(select); + select.setWhereClause(isNullPredicate); + String thirdQueryString = StoneDBToStringVisitor.asString(select); + List combinedString = new ArrayList<>(); + List secondResultSet = ComparatorHelper.getCombinedResultSetNoDuplicates(firstQueryString, + secondQueryString, thirdQueryString, combinedString, true, state, errors); + // compare the result + ComparatorHelper.assumeResultSetsAreEqual(resultSet, secondResultSet, originalQueryString, combinedString, + state, ComparatorHelper::canonicalizeResultValue); + } + + @Override + List> generateFetchColumns() { + return Randomly.nonEmptySubset(targetTables.getColumns()).stream() + .map(c -> new ColumnReferenceNode(c)).collect(Collectors.toList()); + } +} diff --git a/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningHavingTester.java b/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningHavingTester.java new file mode 100644 index 000000000..27a75db1d --- /dev/null +++ b/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningHavingTester.java @@ -0,0 +1,46 @@ +package sqlancer.stonedb.oracle; + +import sqlancer.ComparatorHelper; +import sqlancer.Randomly; +import sqlancer.stonedb.StoneDBToStringVisitor; +import sqlancer.stonedb.StoneDBProvider.StoneDBGlobalState; + +import java.util.ArrayList; +import java.util.List; + +public class StoneDBQueryPartitioningHavingTester extends StoneDBQueryPartitioningBase { + public StoneDBQueryPartitioningHavingTester(StoneDBGlobalState state) { + super(state); + } + + @Override + public void check() throws Exception { + super.check(); + // common to both original and combined query string + if (Randomly.getBoolean()) { + select.setWhereClause(gen.generateExpression()); + } + boolean orderBy = Randomly.getBoolean(); + if (orderBy) { + select.setOrderByExpressions(gen.generateOrderBys()); + } + select.setGroupByExpressions(gen.generateExpressions(Randomly.smallNumber() + 1)); + // specific to original query string + select.setHavingClause(null); + String originalQueryString = StoneDBToStringVisitor.asString(select); + List resultSet = ComparatorHelper.getResultSetFirstColumnAsString(originalQueryString, errors, state); + // specific to combined query string, will produce the same result as original query string in logic + select.setHavingClause(predicate); + String firstQueryString = StoneDBToStringVisitor.asString(select); + select.setHavingClause(negatedPredicate); + String secondQueryString = StoneDBToStringVisitor.asString(select); + select.setHavingClause(isNullPredicate); + String thirdQueryString = StoneDBToStringVisitor.asString(select); + List combinedString = new ArrayList<>(); + List secondResultSet = ComparatorHelper.getCombinedResultSet(firstQueryString, secondQueryString, + thirdQueryString, combinedString, !orderBy, state, errors); + // compare the result + ComparatorHelper.assumeResultSetsAreEqual(resultSet, secondResultSet, originalQueryString, combinedString, + state, ComparatorHelper::canonicalizeResultValue); + } +} diff --git a/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningWhereTester.java b/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningWhereTester.java new file mode 100644 index 000000000..c05780945 --- /dev/null +++ b/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningWhereTester.java @@ -0,0 +1,42 @@ +package sqlancer.stonedb.oracle; + +import sqlancer.ComparatorHelper; +import sqlancer.Randomly; +import sqlancer.stonedb.StoneDBProvider.StoneDBGlobalState; +import sqlancer.stonedb.StoneDBToStringVisitor; + +import java.util.ArrayList; +import java.util.List; + +public class StoneDBQueryPartitioningWhereTester extends StoneDBQueryPartitioningBase { + public StoneDBQueryPartitioningWhereTester(StoneDBGlobalState state) { + super(state); + } + + @Override + public void check() throws Exception { + super.check(); + + select.setWhereClause(null); + String originalQueryString = StoneDBToStringVisitor.asString(select); + List resultSet = ComparatorHelper.getResultSetFirstColumnAsString(originalQueryString, errors, state); + + boolean orderBy = Randomly.getBooleanWithRatherLowProbability(); + if (orderBy) { + select.setOrderByExpressions(gen.generateOrderBys()); + } + select.setWhereClause(predicate); + String firstQueryString = StoneDBToStringVisitor.asString(select); + select.setWhereClause(negatedPredicate); + String secondQueryString = StoneDBToStringVisitor.asString(select); + select.setWhereClause(isNullPredicate); + String thirdQueryString = StoneDBToStringVisitor.asString(select); + + List combinedString = new ArrayList<>(); + List secondResultSet = ComparatorHelper.getCombinedResultSet(firstQueryString, secondQueryString, + thirdQueryString, combinedString, !orderBy, state, errors); + // compare the result + ComparatorHelper.assumeResultSetsAreEqual(resultSet, secondResultSet, originalQueryString, combinedString, + state, ComparatorHelper::canonicalizeResultValue); + } +} diff --git a/src/sqlancer/stonedb/oracle/StoneDBTLPOracle.java b/src/sqlancer/stonedb/oracle/StoneDBTLPOracle.java deleted file mode 100644 index 96deda89e..000000000 --- a/src/sqlancer/stonedb/oracle/StoneDBTLPOracle.java +++ /dev/null @@ -1,16 +0,0 @@ -package sqlancer.stonedb.oracle; - -import sqlancer.common.oracle.NoRECBase; -import sqlancer.common.oracle.TestOracle; -import sqlancer.stonedb.StoneDBProvider.StoneDBGlobalState; - -public class StoneDBTLPOracle extends NoRECBase implements TestOracle { - public StoneDBTLPOracle(StoneDBGlobalState state) { - super(state); - } - - @Override - public void check() throws Exception { - - } -} From 4a8601c8efc1f0eb39bcfe0574d8ce7791fbbdff Mon Sep 17 00:00:00 2001 From: zhenglinli <1125806272@qq.com> Date: Tue, 11 Jul 2023 14:30:48 +0800 Subject: [PATCH 07/23] fix: mvn test errors --- src/sqlancer/stonedb/StoneDBOptions.java | 1 - ...oneDBQueryPartitioningAggregateTester.java | 48 +++++++++---------- .../oracle/StoneDBQueryPartitioningBase.java | 8 ++-- ...StoneDBQueryPartitioningGroupByTester.java | 8 ++-- .../StoneDBQueryPartitioningHavingTester.java | 8 ++-- .../StoneDBQueryPartitioningWhereTester.java | 6 +-- 6 files changed, 39 insertions(+), 40 deletions(-) diff --git a/src/sqlancer/stonedb/StoneDBOptions.java b/src/sqlancer/stonedb/StoneDBOptions.java index 280193e79..647864849 100644 --- a/src/sqlancer/stonedb/StoneDBOptions.java +++ b/src/sqlancer/stonedb/StoneDBOptions.java @@ -2,7 +2,6 @@ import java.sql.SQLException; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import com.beust.jcommander.Parameter; diff --git a/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningAggregateTester.java b/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningAggregateTester.java index 1e17540b4..7322411ce 100644 --- a/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningAggregateTester.java +++ b/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningAggregateTester.java @@ -63,17 +63,17 @@ public void check() throws Exception { if (originalResult == null && metamorphicResult != null || originalResult != null && (!originalResult.contentEquals(metamorphicResult) - && !ComparatorHelper.isEqualDouble(originalResult, metamorphicResult))) { + && !ComparatorHelper.isEqualDouble(originalResult, metamorphicResult))) { throw new AssertionError("aggregate result mismatch!" + System.lineSeparator() + output); } } private String createMetamorphicUnionQuery(StoneDBSelect select, - NewFunctionNode aggregate, - List> from) { + NewFunctionNode aggregate, + List> from) { String metamorphicQuery; Node whereClause = gen.generateExpression(); - ; + Node negatedClause = new NewUnaryPrefixOperatorNode<>(whereClause, StoneDBUnaryPrefixOperator.NOT); Node notNullClause = new NewUnaryPostfixOperatorNode<>(whereClause, @@ -117,19 +117,19 @@ private List> mapped( StoneDBCastOperation count; switch (aggregate.getFunc()) { - case COUNT: - case MAX: - case MIN: - case SUM: - return aliasArgs(List.of(aggregate)); - case AVG: - NewFunctionNode sum = new NewFunctionNode<>( - aggregate.getArgs(), StoneDBAggregateFunction.SUM); - count = new StoneDBCastOperation(new NewFunctionNode<>(aggregate.getArgs(), StoneDBAggregateFunction.COUNT), - new StoneDBCompositeDataType(StoneDBDataType.FLOAT, 8).getPrimitiveDataType()); - return aliasArgs(Arrays.asList(sum, count)); - default: - throw new AssertionError(aggregate.getFunc()); + case COUNT: + case MAX: + case MIN: + case SUM: + return aliasArgs(List.of(aggregate)); + case AVG: + NewFunctionNode sum = new NewFunctionNode<>( + aggregate.getArgs(), StoneDBAggregateFunction.SUM); + count = new StoneDBCastOperation(new NewFunctionNode<>(aggregate.getArgs(), StoneDBAggregateFunction.COUNT), + new StoneDBCompositeDataType(StoneDBDataType.FLOAT, 8).getPrimitiveDataType()); + return aliasArgs(Arrays.asList(sum, count)); + default: + throw new AssertionError(aggregate.getFunc()); } } @@ -144,17 +144,17 @@ private List> aliasArgs(List> or private String getOuterAggregateFunction(NewFunctionNode aggregate) { switch (aggregate.getFunc()) { - case AVG: - return "SUM(agg0)/SUM(agg1)"; - case COUNT: - return StoneDBAggregateFunction.SUM + "(agg0)"; - default: - return aggregate.getFunc().toString() + "(agg0)"; + case AVG: + return "SUM(agg0)/SUM(agg1)"; + case COUNT: + return StoneDBAggregateFunction.SUM + "(agg0)"; + default: + return aggregate.getFunc().toString() + "(agg0)"; } } private StoneDBSelect getSelect(List> aggregates, List> fromList, - Node whereClause, List> joinList) { + Node whereClause, List> joinList) { StoneDBSelect select = new StoneDBSelect(); select.setFetchColumns(aggregates); select.setFromList(fromList); diff --git a/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningBase.java b/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningBase.java index 654faf6e3..84d9f794f 100644 --- a/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningBase.java +++ b/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningBase.java @@ -1,5 +1,9 @@ package sqlancer.stonedb.oracle; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + import sqlancer.Randomly; import sqlancer.common.ast.newast.ColumnReferenceNode; import sqlancer.common.ast.newast.Node; @@ -17,10 +21,6 @@ import sqlancer.stonedb.ast.StoneDBSelect; import sqlancer.stonedb.gen.StoneDBExpressionGenerator; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - public class StoneDBQueryPartitioningBase extends TernaryLogicPartitioningOracleBase, StoneDBGlobalState> implements TestOracle { diff --git a/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningGroupByTester.java b/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningGroupByTester.java index 49caa2a2f..d7674a71c 100644 --- a/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningGroupByTester.java +++ b/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningGroupByTester.java @@ -1,5 +1,9 @@ package sqlancer.stonedb.oracle; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + import sqlancer.ComparatorHelper; import sqlancer.Randomly; import sqlancer.common.ast.newast.ColumnReferenceNode; @@ -9,10 +13,6 @@ import sqlancer.stonedb.StoneDBToStringVisitor; import sqlancer.stonedb.ast.StoneDBExpression; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - public class StoneDBQueryPartitioningGroupByTester extends StoneDBQueryPartitioningBase { public StoneDBQueryPartitioningGroupByTester(StoneDBGlobalState state) { super(state); diff --git a/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningHavingTester.java b/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningHavingTester.java index 27a75db1d..ea611241b 100644 --- a/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningHavingTester.java +++ b/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningHavingTester.java @@ -1,12 +1,12 @@ package sqlancer.stonedb.oracle; +import java.util.ArrayList; +import java.util.List; + import sqlancer.ComparatorHelper; import sqlancer.Randomly; -import sqlancer.stonedb.StoneDBToStringVisitor; import sqlancer.stonedb.StoneDBProvider.StoneDBGlobalState; - -import java.util.ArrayList; -import java.util.List; +import sqlancer.stonedb.StoneDBToStringVisitor; public class StoneDBQueryPartitioningHavingTester extends StoneDBQueryPartitioningBase { public StoneDBQueryPartitioningHavingTester(StoneDBGlobalState state) { diff --git a/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningWhereTester.java b/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningWhereTester.java index c05780945..2a8f2b4d4 100644 --- a/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningWhereTester.java +++ b/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningWhereTester.java @@ -1,13 +1,13 @@ package sqlancer.stonedb.oracle; +import java.util.ArrayList; +import java.util.List; + import sqlancer.ComparatorHelper; import sqlancer.Randomly; import sqlancer.stonedb.StoneDBProvider.StoneDBGlobalState; import sqlancer.stonedb.StoneDBToStringVisitor; -import java.util.ArrayList; -import java.util.List; - public class StoneDBQueryPartitioningWhereTester extends StoneDBQueryPartitioningBase { public StoneDBQueryPartitioningWhereTester(StoneDBGlobalState state) { super(state); From e8faa7759ea2651e2b359d56222b320c69c244da Mon Sep 17 00:00:00 2001 From: zhenglinli <1125806272@qq.com> Date: Thu, 13 Jul 2023 19:32:58 +0800 Subject: [PATCH 08/23] feat: add CI --- src/sqlancer/stonedb/StoneDBOptions.java | 27 +++++++++---------- ...TestStoneDB.java => TestStoneDBNoRec.java} | 2 +- 2 files changed, 14 insertions(+), 15 deletions(-) rename test/sqlancer/dbms/{TestStoneDB.java => TestStoneDBNoRec.java} (95%) diff --git a/src/sqlancer/stonedb/StoneDBOptions.java b/src/sqlancer/stonedb/StoneDBOptions.java index 647864849..3bb71eff8 100644 --- a/src/sqlancer/stonedb/StoneDBOptions.java +++ b/src/sqlancer/stonedb/StoneDBOptions.java @@ -36,7 +36,18 @@ public TestOracle create(StoneDBGlobalState globalState) thr return new StoneDBNoRECOracle(globalState); } }, - + QUERY_PARTITIONING { + @Override + public TestOracle create(StoneDBGlobalState globalState) throws SQLException { + List> oracles = new ArrayList<>(); + oracles.add(new StoneDBQueryPartitioningWhereTester(globalState)); + oracles.add(new StoneDBQueryPartitioningHavingTester(globalState)); + oracles.add(new StoneDBQueryPartitioningAggregateTester(globalState)); + oracles.add(new StoneDBQueryPartitioningDistinctTester(globalState)); + oracles.add(new StoneDBQueryPartitioningGroupByTester(globalState)); + return new CompositeTestOracle<>(oracles, globalState); + } + }, HAVING { @Override public TestOracle create(StoneDBGlobalState globalState) throws SQLException { @@ -68,19 +79,7 @@ public TestOracle create(StoneDBGlobalState globalState) thr public TestOracle create(StoneDBGlobalState globalState) throws SQLException { return new StoneDBQueryPartitioningDistinctTester(globalState); } - }, - QUERY_PARTITIONING { - @Override - public TestOracle create(StoneDBGlobalState globalState) throws SQLException { - List> oracles = new ArrayList<>(); - oracles.add(new StoneDBQueryPartitioningWhereTester(globalState)); - oracles.add(new StoneDBQueryPartitioningHavingTester(globalState)); - oracles.add(new StoneDBQueryPartitioningAggregateTester(globalState)); - oracles.add(new StoneDBQueryPartitioningDistinctTester(globalState)); - oracles.add(new StoneDBQueryPartitioningGroupByTester(globalState)); - return new CompositeTestOracle<>(oracles, globalState); - } - }; + } } @Override diff --git a/test/sqlancer/dbms/TestStoneDB.java b/test/sqlancer/dbms/TestStoneDBNoRec.java similarity index 95% rename from test/sqlancer/dbms/TestStoneDB.java rename to test/sqlancer/dbms/TestStoneDBNoRec.java index 14de121be..4b158f372 100644 --- a/test/sqlancer/dbms/TestStoneDB.java +++ b/test/sqlancer/dbms/TestStoneDBNoRec.java @@ -7,7 +7,7 @@ import sqlancer.Main; -public class TestStoneDB { +public class TestStoneDBNoRec { String stoneDBAvailable = System.getenv("STONEDB_AVAILABLE"); boolean stoneDBIsAvailable = stoneDBAvailable != null && stoneDBAvailable.equalsIgnoreCase("true"); From b781cbf9cf674c669b3964e31fffe71a78430a8a Mon Sep 17 00:00:00 2001 From: zhenglinli <1125806272@qq.com> Date: Thu, 13 Jul 2023 19:33:07 +0800 Subject: [PATCH 09/23] feat: add CI --- test/sqlancer/dbms/TestStoneDBTLP.java | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 test/sqlancer/dbms/TestStoneDBTLP.java diff --git a/test/sqlancer/dbms/TestStoneDBTLP.java b/test/sqlancer/dbms/TestStoneDBTLP.java new file mode 100644 index 000000000..d5db5b9ab --- /dev/null +++ b/test/sqlancer/dbms/TestStoneDBTLP.java @@ -0,0 +1,21 @@ +package sqlancer.dbms; + +import org.junit.jupiter.api.Test; +import sqlancer.Main; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + +public class TestStoneDBTLP { + + String stoneDBAvailable = System.getenv("STONEDB_AVAILABLE"); + boolean stoneDBIsAvailable = stoneDBAvailable != null && stoneDBAvailable.equalsIgnoreCase("true"); + + @Test + public void testStoneDB() { + assumeTrue(stoneDBIsAvailable); + assertEquals(0, Main.executeMain("--random-seed", "0", "--timeout-seconds", TestConfig.SECONDS, "--num-threads", + "1", "--num-queries", TestConfig.NUM_QUERIES, "stonedb", "--oracle", "QUERY_PARTITIONING")); + } + +} From 497dcc09365e4b65ca873bbba37b01e3f8bdd368 Mon Sep 17 00:00:00 2001 From: zhenglinli <1125806272@qq.com> Date: Thu, 13 Jul 2023 19:42:20 +0800 Subject: [PATCH 10/23] feat: add CI --- .github/workflows/main.yml | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 990543c0d..8a469004a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -375,8 +375,8 @@ jobs: run: | mvn -Dtest=TestSQLiteQPG test - stonedb: - name: DBMS Tests (StoneDB) + stonedb-norec: + name: DBMS Tests (StoneDB NoRec) runs-on: ubuntu-latest steps: @@ -400,7 +400,34 @@ jobs: run: mvn -B package -DskipTests=true - name: StoneDB Tests run: | - STONEDB_AVAILABLE=true mvn test -Dtest=TestStoneDB + STONEDB_AVAILABLE=true mvn test -Dtest=TestStoneDBNoRec + + stonedb-tlp: + name: DBMS Tests (StoneDB TLP) + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Set up StoneDB + run: | + docker pull stoneatom/stonedb:v1.0.3 + docker run -p 3306:3306 -itd -e MYSQL_ROOT_PASSWORD='123456' stoneatom/stonedb:v1.0.3 + docker ps + ContainerID=$(docker ps --filter ancestor=stoneatom/stonedb:v1.0.3 --format "{{.ID}}") + docker exec $ContainerID bash + sleep 180s + docker exec $ContainerID /opt/stonedb57/install/bin/mysql -uroot -p123456 -e "CREATE USER 'sqlancer'@'%' IDENTIFIED WITH mysql_native_password BY 'sqlancer'; GRANT ALL PRIVILEGES ON *.* TO 'sqlancer'@'%' WITH GRANT OPTION; FLUSH PRIVILEGES;" + - name: Set up JDK 11 + uses: actions/setup-java@v1.4.4 + with: + java-version: 11 + - name: Build + run: mvn -B package -DskipTests=true + - name: StoneDB Tests + run: | + STONEDB_AVAILABLE=true mvn test -Dtest=TestStoneDBTLP tidb: name: DBMS Tests (TiDB) From a68ecf03b809d7b852d2f484c8ab5b4c9f33e3fb Mon Sep 17 00:00:00 2001 From: zhenglinli <1125806272@qq.com> Date: Thu, 13 Jul 2023 19:47:53 +0800 Subject: [PATCH 11/23] fix: remove unsupported operator --- src/sqlancer/stonedb/gen/StoneDBExpressionGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sqlancer/stonedb/gen/StoneDBExpressionGenerator.java b/src/sqlancer/stonedb/gen/StoneDBExpressionGenerator.java index c3ba5d2e8..6c9057911 100644 --- a/src/sqlancer/stonedb/gen/StoneDBExpressionGenerator.java +++ b/src/sqlancer/stonedb/gen/StoneDBExpressionGenerator.java @@ -300,7 +300,7 @@ public String getTextRepresentation() { * Bitwise operators supported by StoneDB: https://stonedb.io/docs/SQL-reference/operators/bitwise-operators */ public enum StoneDBBinaryBitwiseOperator implements Operator { - AND("&"), OR("|"), XOR("^"), LEFTSHIFT("<<"), RIGHTSHIFT(">>"); + AND("&"), OR("|"), LEFTSHIFT("<<"), RIGHTSHIFT(">>"); private final String textRepr; From f35b6e973fc7affeecf7427a1a3b495a6c918ec3 Mon Sep 17 00:00:00 2001 From: zhenglinli <1125806272@qq.com> Date: Thu, 13 Jul 2023 20:59:46 +0800 Subject: [PATCH 12/23] fix: change string generator strategy --- src/sqlancer/stonedb/StoneDBErrors.java | 7 +++++++ src/sqlancer/stonedb/StoneDBSchema.java | 5 ++++- src/sqlancer/stonedb/gen/StoneDBExpressionGenerator.java | 5 ++++- src/sqlancer/stonedb/gen/StoneDBTableAlterGenerator.java | 3 +++ src/sqlancer/stonedb/gen/StoneDBTableDeleteGenerator.java | 6 ++++++ src/sqlancer/stonedb/oracle/StoneDBNoRECOracle.java | 2 ++ 6 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/sqlancer/stonedb/StoneDBErrors.java b/src/sqlancer/stonedb/StoneDBErrors.java index 54fd28ad8..2b208412c 100644 --- a/src/sqlancer/stonedb/StoneDBErrors.java +++ b/src/sqlancer/stonedb/StoneDBErrors.java @@ -1,7 +1,14 @@ package sqlancer.stonedb; +import sqlancer.common.query.ExpectedErrors; + public final class StoneDBErrors { private StoneDBErrors() { } + public static void addExpectedSelectErrors(ExpectedErrors errors) { + // java.sql.SQLException: Incorrect DATE value: '292269055-12-02' + errors.add("Incorrect DATE value: "); + } + } diff --git a/src/sqlancer/stonedb/StoneDBSchema.java b/src/sqlancer/stonedb/StoneDBSchema.java index 2150cbba1..1ebe98589 100644 --- a/src/sqlancer/stonedb/StoneDBSchema.java +++ b/src/sqlancer/stonedb/StoneDBSchema.java @@ -9,6 +9,7 @@ import java.util.stream.Stream; import sqlancer.Randomly; +import sqlancer.Randomly.StringGenerationStrategy; import sqlancer.SQLConnection; import sqlancer.common.ast.newast.Node; import sqlancer.common.schema.AbstractRelationalTable; @@ -70,7 +71,9 @@ public static Node getRandomValue(StoneDBDataType dataType) { case TINYTEXT: break; case TEXT: - return StoneDBConstant.createTextConstant(new Randomly().getString()); + StringGenerationStrategy strategy = StringGenerationStrategy.ALPHANUMERIC; + String str = strategy.getString(new Randomly()); + return StoneDBConstant.createTextConstant(str); case MEDIUMTEXT: break; case LONGTEXT: diff --git a/src/sqlancer/stonedb/gen/StoneDBExpressionGenerator.java b/src/sqlancer/stonedb/gen/StoneDBExpressionGenerator.java index 6c9057911..3fc580a4e 100644 --- a/src/sqlancer/stonedb/gen/StoneDBExpressionGenerator.java +++ b/src/sqlancer/stonedb/gen/StoneDBExpressionGenerator.java @@ -8,6 +8,7 @@ import sqlancer.IgnoreMeException; import sqlancer.Randomly; +import sqlancer.Randomly.StringGenerationStrategy; import sqlancer.common.ast.BinaryOperatorNode.Operator; import sqlancer.common.ast.newast.ColumnReferenceNode; import sqlancer.common.ast.newast.NewBetweenOperatorNode; @@ -85,7 +86,9 @@ public Node generateConstant(StoneDBDataType dataType) { case TIMESTAMP: return StoneDBConstant.createTimestampConstant(globalState.getRandomly().getInteger()); case VARCHAR: - return StoneDBConstant.createTextConstant(globalState.getRandomly().getString()); + StringGenerationStrategy strategy = StringGenerationStrategy.ALPHANUMERIC; + String str = strategy.getString(new Randomly()); + return StoneDBConstant.createTextConstant(str); case DOUBLE: return StoneDBConstant.createDoubleConstant(globalState.getRandomly().getDouble()); default: diff --git a/src/sqlancer/stonedb/gen/StoneDBTableAlterGenerator.java b/src/sqlancer/stonedb/gen/StoneDBTableAlterGenerator.java index b1e4872aa..ee6ef8ff6 100644 --- a/src/sqlancer/stonedb/gen/StoneDBTableAlterGenerator.java +++ b/src/sqlancer/stonedb/gen/StoneDBTableAlterGenerator.java @@ -44,6 +44,9 @@ private void addExpectedErrors() { errors.addRegex(Pattern.compile("Data truncation: Data too long for column 'c\\d{1,3}' at row \\d{1,3}")); // java.sql.SQLSyntaxErrorException: Specified key was too long; max key length is 3072 bytes errors.add("Specified key was too long; max key length is 3072 bytes"); + // com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Incorrect datetime value: + // '0.571272522740968' for column 'c1' at row 1 + errors.add("Incorrect datetime value: "); // java.sql.SQLSyntaxErrorException: You can't delete all columns with ALTER TABLE; use DROP TABLE instead errors.add("You can't delete all columns with ALTER TABLE; use DROP TABLE instead"); // java.sql.SQLSyntaxErrorException: Unknown column 'c0' in 't1' diff --git a/src/sqlancer/stonedb/gen/StoneDBTableDeleteGenerator.java b/src/sqlancer/stonedb/gen/StoneDBTableDeleteGenerator.java index ab0828d30..16b9c1061 100644 --- a/src/sqlancer/stonedb/gen/StoneDBTableDeleteGenerator.java +++ b/src/sqlancer/stonedb/gen/StoneDBTableDeleteGenerator.java @@ -55,6 +55,12 @@ public SQLQueryAdapter getQuery() { sb.append(" LIMIT "); sb.append(r.getInteger(0, (int) randomTable.getNrRows(globalState))); } + addExpectedErrors(); return new SQLQueryAdapter(sb.toString(), errors); } + + private void addExpectedErrors() { + // java.sql.SQLException: Incorrect string value: '\xBC\xE7\xC9\x91\x05R...' for column 'c1' at row 1 + errors.add("Incorrect string value: "); + } } diff --git a/src/sqlancer/stonedb/oracle/StoneDBNoRECOracle.java b/src/sqlancer/stonedb/oracle/StoneDBNoRECOracle.java index 2625bbb7c..0dc741aff 100644 --- a/src/sqlancer/stonedb/oracle/StoneDBNoRECOracle.java +++ b/src/sqlancer/stonedb/oracle/StoneDBNoRECOracle.java @@ -19,6 +19,7 @@ import sqlancer.common.oracle.TestOracle; import sqlancer.common.query.SQLQueryAdapter; import sqlancer.common.query.SQLancerResultSet; +import sqlancer.stonedb.StoneDBErrors; import sqlancer.stonedb.StoneDBProvider.StoneDBGlobalState; import sqlancer.stonedb.StoneDBSchema; import sqlancer.stonedb.StoneDBSchema.StoneDBColumn; @@ -53,6 +54,7 @@ public void check() throws Exception { .map(t -> new TableReferenceNode(t)).collect(Collectors.toList()); List> joins = StoneDBJoin.getJoins(tableList, state); // get and check count + StoneDBErrors.addExpectedSelectErrors(errors); int secondCount = getUnoptimizedQueryCount(new ArrayList<>(tableList), randomWhereCondition, joins); int firstCount = getOptimizedQueryCount(con, new ArrayList<>(tableList), columns, randomWhereCondition, joins); if (firstCount == -1 || secondCount == -1) { From 5edc2097eba4c20119861afad6caf23a263deada Mon Sep 17 00:00:00 2001 From: zhenglinli <1125806272@qq.com> Date: Fri, 14 Jul 2023 12:00:28 +0800 Subject: [PATCH 13/23] feat: add expected errors --- src/sqlancer/stonedb/gen/StoneDBTableAlterGenerator.java | 8 ++++++-- src/sqlancer/stonedb/gen/StoneDBTableInsertGenerator.java | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/sqlancer/stonedb/gen/StoneDBTableAlterGenerator.java b/src/sqlancer/stonedb/gen/StoneDBTableAlterGenerator.java index ee6ef8ff6..539744485 100644 --- a/src/sqlancer/stonedb/gen/StoneDBTableAlterGenerator.java +++ b/src/sqlancer/stonedb/gen/StoneDBTableAlterGenerator.java @@ -42,11 +42,15 @@ private SQLQueryAdapter getQuery() { private void addExpectedErrors() { // com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Data too long for column 'c0' at row 2 errors.addRegex(Pattern.compile("Data truncation: Data too long for column 'c\\d{1,3}' at row \\d{1,3}")); - // java.sql.SQLSyntaxErrorException: Specified key was too long; max key length is 3072 bytes - errors.add("Specified key was too long; max key length is 3072 bytes"); // com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Incorrect datetime value: // '0.571272522740968' for column 'c1' at row 1 errors.add("Incorrect datetime value: "); + // java.sql.SQLSyntaxErrorException: Invalid default value for 'c0' + errors.add("Invalid default value for "); + // com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column 'c0' at row 2 + errors.add("Data truncation: Out of range value for column "); + // java.sql.SQLSyntaxErrorException: Specified key was too long; max key length is 3072 bytes + errors.add("Specified key was too long; max key length is 3072 bytes"); // java.sql.SQLSyntaxErrorException: You can't delete all columns with ALTER TABLE; use DROP TABLE instead errors.add("You can't delete all columns with ALTER TABLE; use DROP TABLE instead"); // java.sql.SQLSyntaxErrorException: Unknown column 'c0' in 't1' diff --git a/src/sqlancer/stonedb/gen/StoneDBTableInsertGenerator.java b/src/sqlancer/stonedb/gen/StoneDBTableInsertGenerator.java index 2fdb7b6fa..c8b34b425 100644 --- a/src/sqlancer/stonedb/gen/StoneDBTableInsertGenerator.java +++ b/src/sqlancer/stonedb/gen/StoneDBTableInsertGenerator.java @@ -50,6 +50,8 @@ private SQLQueryAdapter getQuery() { } private void addExpectedErrors() { + // java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '1970-01-14' for key 'PRIMARY' + errors.add("Duplicate entry "); // com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column 'c0' at row errors.add("Data truncation: Out of range value for column "); // java.sql.SQLSyntaxErrorException: Unknown column 'c0' in 'field list' From ddece0ff83264e022443717a77c64361c122b51c Mon Sep 17 00:00:00 2001 From: zhenglinli <1125806272@qq.com> Date: Fri, 14 Jul 2023 12:10:17 +0800 Subject: [PATCH 14/23] fix: binary type should have a max length --- src/sqlancer/stonedb/StoneDBSchema.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sqlancer/stonedb/StoneDBSchema.java b/src/sqlancer/stonedb/StoneDBSchema.java index 1ebe98589..aa0e764f6 100644 --- a/src/sqlancer/stonedb/StoneDBSchema.java +++ b/src/sqlancer/stonedb/StoneDBSchema.java @@ -144,7 +144,8 @@ public static String getTypeAndValue(StoneDBDataType dataType) { case LONGTEXT: return "LONGTEXT"; case BINARY: - return "BINARY"; + sb.append("BINARY").append("(").append(new Randomly().getInteger(0, 255)).append(")"); + return sb.toString(); case VARBINARY: sb.append("VARBINARY").append("(").append(new Randomly().getInteger(0, 65535)).append(")"); return sb.toString(); From 563322168f1aeed9b1fc8c813b2434a3c33f604a Mon Sep 17 00:00:00 2001 From: zhenglinli <1125806272@qq.com> Date: Fri, 14 Jul 2023 13:53:01 +0800 Subject: [PATCH 15/23] fix: mvn format --- src/sqlancer/stonedb/gen/StoneDBTableAlterGenerator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sqlancer/stonedb/gen/StoneDBTableAlterGenerator.java b/src/sqlancer/stonedb/gen/StoneDBTableAlterGenerator.java index 539744485..de06f6d1e 100644 --- a/src/sqlancer/stonedb/gen/StoneDBTableAlterGenerator.java +++ b/src/sqlancer/stonedb/gen/StoneDBTableAlterGenerator.java @@ -47,7 +47,8 @@ private void addExpectedErrors() { errors.add("Incorrect datetime value: "); // java.sql.SQLSyntaxErrorException: Invalid default value for 'c0' errors.add("Invalid default value for "); - // com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column 'c0' at row 2 + // com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column 'c0' at row + // 2 errors.add("Data truncation: Out of range value for column "); // java.sql.SQLSyntaxErrorException: Specified key was too long; max key length is 3072 bytes errors.add("Specified key was too long; max key length is 3072 bytes"); From 334f1d3420f8fa9b32571caea490f86b420bf883 Mon Sep 17 00:00:00 2001 From: zhenglinli <1125806272@qq.com> Date: Fri, 14 Jul 2023 14:14:47 +0800 Subject: [PATCH 16/23] fix: MySQL 5.7 does not support double, change to decimal --- .../stonedb/oracle/StoneDBQueryPartitioningAggregateTester.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningAggregateTester.java b/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningAggregateTester.java index 7322411ce..e0543d790 100644 --- a/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningAggregateTester.java +++ b/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningAggregateTester.java @@ -126,7 +126,7 @@ private List> mapped( NewFunctionNode sum = new NewFunctionNode<>( aggregate.getArgs(), StoneDBAggregateFunction.SUM); count = new StoneDBCastOperation(new NewFunctionNode<>(aggregate.getArgs(), StoneDBAggregateFunction.COUNT), - new StoneDBCompositeDataType(StoneDBDataType.FLOAT, 8).getPrimitiveDataType()); + new StoneDBCompositeDataType(StoneDBDataType.DECIMAL).getPrimitiveDataType()); return aliasArgs(Arrays.asList(sum, count)); default: throw new AssertionError(aggregate.getFunc()); From 6988c3d56a0304d96a910bd79b1c45541ad664c1 Mon Sep 17 00:00:00 2001 From: zhenglinli <1125806272@qq.com> Date: Fri, 14 Jul 2023 14:27:36 +0800 Subject: [PATCH 17/23] fix: natural join type --- src/sqlancer/stonedb/ast/StoneDBJoin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sqlancer/stonedb/ast/StoneDBJoin.java b/src/sqlancer/stonedb/ast/StoneDBJoin.java index d32d49f5b..9c53316a0 100644 --- a/src/sqlancer/stonedb/ast/StoneDBJoin.java +++ b/src/sqlancer/stonedb/ast/StoneDBJoin.java @@ -22,7 +22,7 @@ public static JoinType getRandom() { } public enum NaturalJoinType { - FULL, LEFT, RIGHT; + OUTER, LEFT, RIGHT; public static NaturalJoinType getRandom() { return Randomly.fromOptions(values()); From d7f10959162ad2c0a2a1d35c4727cb46359978f7 Mon Sep 17 00:00:00 2001 From: zhenglinli <1125806272@qq.com> Date: Fri, 14 Jul 2023 15:38:56 +0800 Subject: [PATCH 18/23] fix: only one alter option one time --- .../stonedb/gen/StoneDBTableAlterGenerator.java | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/sqlancer/stonedb/gen/StoneDBTableAlterGenerator.java b/src/sqlancer/stonedb/gen/StoneDBTableAlterGenerator.java index de06f6d1e..540025c0e 100644 --- a/src/sqlancer/stonedb/gen/StoneDBTableAlterGenerator.java +++ b/src/sqlancer/stonedb/gen/StoneDBTableAlterGenerator.java @@ -1,6 +1,5 @@ package sqlancer.stonedb.gen; -import java.util.List; import java.util.regex.Pattern; import sqlancer.Randomly; @@ -34,7 +33,7 @@ private SQLQueryAdapter getQuery() { sb.append("ALTER TABLE "); sb.append(table.getName()); sb.append(" "); - appendAlterOptions(); + appendAlterOption(Randomly.fromOptions(Action.values())); addExpectedErrors(); return new SQLQueryAdapter(sb.toString(), errors, true); } @@ -64,19 +63,6 @@ private void addExpectedErrors() { .compile("Column length too big for column 'c\\d{1,3}' \\(max = 16383\\); use BLOB or TEXT instead")); } - private void appendAlterOptions() { - List actions; - if (Randomly.getBooleanWithSmallProbability()) { - actions = Randomly.subset(Action.values()); - } else { - actions = List.of(Randomly.fromOptions(Action.values())); - } - for (Action action : actions) { - appendAlterOption(action); - sb.append(" "); - } - } - private void appendAlterOption(Action action) { StoneDBExpressionGenerator generator = new StoneDBExpressionGenerator(globalState) .setColumns(table.getColumns()); From 6b354edd189f90b6a79d53f988d1a4d54dba2e50 Mon Sep 17 00:00:00 2001 From: zhenglinli <1125806272@qq.com> Date: Fri, 14 Jul 2023 15:41:05 +0800 Subject: [PATCH 19/23] feat: add expected errors --- src/sqlancer/stonedb/gen/StoneDBTableInsertGenerator.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sqlancer/stonedb/gen/StoneDBTableInsertGenerator.java b/src/sqlancer/stonedb/gen/StoneDBTableInsertGenerator.java index c8b34b425..2ffc7c236 100644 --- a/src/sqlancer/stonedb/gen/StoneDBTableInsertGenerator.java +++ b/src/sqlancer/stonedb/gen/StoneDBTableInsertGenerator.java @@ -50,6 +50,8 @@ private SQLQueryAdapter getQuery() { } private void addExpectedErrors() { + // java.sql.SQLException: Incorrect DATE value: '292278994-08-17' + errors.add("Incorrect DATE value: '"); // java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '1970-01-14' for key 'PRIMARY' errors.add("Duplicate entry "); // com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column 'c0' at row From 4d547ed17dbfe0af2d75ccf7b165d11e0ed2eeb8 Mon Sep 17 00:00:00 2001 From: zhenglinli <1125806272@qq.com> Date: Sat, 15 Jul 2023 10:51:56 +0800 Subject: [PATCH 20/23] git: manually revert commits --- src/sqlancer/stonedb/StoneDBErrors.java | 8 -------- src/sqlancer/stonedb/StoneDBSchema.java | 8 ++------ src/sqlancer/stonedb/ast/StoneDBJoin.java | 2 +- src/sqlancer/stonedb/gen/StoneDBExpressionGenerator.java | 9 +++------ src/sqlancer/stonedb/gen/StoneDBTableAlterGenerator.java | 8 -------- .../stonedb/gen/StoneDBTableDeleteGenerator.java | 6 ------ .../stonedb/gen/StoneDBTableInsertGenerator.java | 4 ---- src/sqlancer/stonedb/oracle/StoneDBNoRECOracle.java | 2 -- 8 files changed, 6 insertions(+), 41 deletions(-) diff --git a/src/sqlancer/stonedb/StoneDBErrors.java b/src/sqlancer/stonedb/StoneDBErrors.java index 2b208412c..bdbd6a447 100644 --- a/src/sqlancer/stonedb/StoneDBErrors.java +++ b/src/sqlancer/stonedb/StoneDBErrors.java @@ -1,14 +1,6 @@ package sqlancer.stonedb; -import sqlancer.common.query.ExpectedErrors; - public final class StoneDBErrors { private StoneDBErrors() { } - - public static void addExpectedSelectErrors(ExpectedErrors errors) { - // java.sql.SQLException: Incorrect DATE value: '292269055-12-02' - errors.add("Incorrect DATE value: "); - } - } diff --git a/src/sqlancer/stonedb/StoneDBSchema.java b/src/sqlancer/stonedb/StoneDBSchema.java index aa0e764f6..2150cbba1 100644 --- a/src/sqlancer/stonedb/StoneDBSchema.java +++ b/src/sqlancer/stonedb/StoneDBSchema.java @@ -9,7 +9,6 @@ import java.util.stream.Stream; import sqlancer.Randomly; -import sqlancer.Randomly.StringGenerationStrategy; import sqlancer.SQLConnection; import sqlancer.common.ast.newast.Node; import sqlancer.common.schema.AbstractRelationalTable; @@ -71,9 +70,7 @@ public static Node getRandomValue(StoneDBDataType dataType) { case TINYTEXT: break; case TEXT: - StringGenerationStrategy strategy = StringGenerationStrategy.ALPHANUMERIC; - String str = strategy.getString(new Randomly()); - return StoneDBConstant.createTextConstant(str); + return StoneDBConstant.createTextConstant(new Randomly().getString()); case MEDIUMTEXT: break; case LONGTEXT: @@ -144,8 +141,7 @@ public static String getTypeAndValue(StoneDBDataType dataType) { case LONGTEXT: return "LONGTEXT"; case BINARY: - sb.append("BINARY").append("(").append(new Randomly().getInteger(0, 255)).append(")"); - return sb.toString(); + return "BINARY"; case VARBINARY: sb.append("VARBINARY").append("(").append(new Randomly().getInteger(0, 65535)).append(")"); return sb.toString(); diff --git a/src/sqlancer/stonedb/ast/StoneDBJoin.java b/src/sqlancer/stonedb/ast/StoneDBJoin.java index 9c53316a0..d32d49f5b 100644 --- a/src/sqlancer/stonedb/ast/StoneDBJoin.java +++ b/src/sqlancer/stonedb/ast/StoneDBJoin.java @@ -22,7 +22,7 @@ public static JoinType getRandom() { } public enum NaturalJoinType { - OUTER, LEFT, RIGHT; + FULL, LEFT, RIGHT; public static NaturalJoinType getRandom() { return Randomly.fromOptions(values()); diff --git a/src/sqlancer/stonedb/gen/StoneDBExpressionGenerator.java b/src/sqlancer/stonedb/gen/StoneDBExpressionGenerator.java index 3fc580a4e..54d2c4113 100644 --- a/src/sqlancer/stonedb/gen/StoneDBExpressionGenerator.java +++ b/src/sqlancer/stonedb/gen/StoneDBExpressionGenerator.java @@ -8,7 +8,6 @@ import sqlancer.IgnoreMeException; import sqlancer.Randomly; -import sqlancer.Randomly.StringGenerationStrategy; import sqlancer.common.ast.BinaryOperatorNode.Operator; import sqlancer.common.ast.newast.ColumnReferenceNode; import sqlancer.common.ast.newast.NewBetweenOperatorNode; @@ -86,9 +85,7 @@ public Node generateConstant(StoneDBDataType dataType) { case TIMESTAMP: return StoneDBConstant.createTimestampConstant(globalState.getRandomly().getInteger()); case VARCHAR: - StringGenerationStrategy strategy = StringGenerationStrategy.ALPHANUMERIC; - String str = strategy.getString(new Randomly()); - return StoneDBConstant.createTextConstant(str); + return StoneDBConstant.createTextConstant(globalState.getRandomly().getString()); case DOUBLE: return StoneDBConstant.createDoubleConstant(globalState.getRandomly().getDouble()); default: @@ -171,7 +168,7 @@ protected List> generateColumns() { // https://stonedb.io/docs/SQL-reference/functions/aggregate-functions/ public enum StoneDBAggregateFunction { - MAX(1), MIN(1), AVG(1), COUNT(1), SUM(1); + MAX(1), MIN(1), AVG(1), COUNT(1), FIRST(1), SUM(1); private int nrArgs; @@ -303,7 +300,7 @@ public String getTextRepresentation() { * Bitwise operators supported by StoneDB: https://stonedb.io/docs/SQL-reference/operators/bitwise-operators */ public enum StoneDBBinaryBitwiseOperator implements Operator { - AND("&"), OR("|"), LEFTSHIFT("<<"), RIGHTSHIFT(">>"); + AND("&"), OR("|"), XOR("^"), LEFTSHIFT("<<"), RIGHTSHIFT(">>"); private final String textRepr; diff --git a/src/sqlancer/stonedb/gen/StoneDBTableAlterGenerator.java b/src/sqlancer/stonedb/gen/StoneDBTableAlterGenerator.java index 540025c0e..429be2dfe 100644 --- a/src/sqlancer/stonedb/gen/StoneDBTableAlterGenerator.java +++ b/src/sqlancer/stonedb/gen/StoneDBTableAlterGenerator.java @@ -41,14 +41,6 @@ private SQLQueryAdapter getQuery() { private void addExpectedErrors() { // com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Data too long for column 'c0' at row 2 errors.addRegex(Pattern.compile("Data truncation: Data too long for column 'c\\d{1,3}' at row \\d{1,3}")); - // com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Incorrect datetime value: - // '0.571272522740968' for column 'c1' at row 1 - errors.add("Incorrect datetime value: "); - // java.sql.SQLSyntaxErrorException: Invalid default value for 'c0' - errors.add("Invalid default value for "); - // com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column 'c0' at row - // 2 - errors.add("Data truncation: Out of range value for column "); // java.sql.SQLSyntaxErrorException: Specified key was too long; max key length is 3072 bytes errors.add("Specified key was too long; max key length is 3072 bytes"); // java.sql.SQLSyntaxErrorException: You can't delete all columns with ALTER TABLE; use DROP TABLE instead diff --git a/src/sqlancer/stonedb/gen/StoneDBTableDeleteGenerator.java b/src/sqlancer/stonedb/gen/StoneDBTableDeleteGenerator.java index 16b9c1061..ab0828d30 100644 --- a/src/sqlancer/stonedb/gen/StoneDBTableDeleteGenerator.java +++ b/src/sqlancer/stonedb/gen/StoneDBTableDeleteGenerator.java @@ -55,12 +55,6 @@ public SQLQueryAdapter getQuery() { sb.append(" LIMIT "); sb.append(r.getInteger(0, (int) randomTable.getNrRows(globalState))); } - addExpectedErrors(); return new SQLQueryAdapter(sb.toString(), errors); } - - private void addExpectedErrors() { - // java.sql.SQLException: Incorrect string value: '\xBC\xE7\xC9\x91\x05R...' for column 'c1' at row 1 - errors.add("Incorrect string value: "); - } } diff --git a/src/sqlancer/stonedb/gen/StoneDBTableInsertGenerator.java b/src/sqlancer/stonedb/gen/StoneDBTableInsertGenerator.java index 2ffc7c236..2fdb7b6fa 100644 --- a/src/sqlancer/stonedb/gen/StoneDBTableInsertGenerator.java +++ b/src/sqlancer/stonedb/gen/StoneDBTableInsertGenerator.java @@ -50,10 +50,6 @@ private SQLQueryAdapter getQuery() { } private void addExpectedErrors() { - // java.sql.SQLException: Incorrect DATE value: '292278994-08-17' - errors.add("Incorrect DATE value: '"); - // java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '1970-01-14' for key 'PRIMARY' - errors.add("Duplicate entry "); // com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column 'c0' at row errors.add("Data truncation: Out of range value for column "); // java.sql.SQLSyntaxErrorException: Unknown column 'c0' in 'field list' diff --git a/src/sqlancer/stonedb/oracle/StoneDBNoRECOracle.java b/src/sqlancer/stonedb/oracle/StoneDBNoRECOracle.java index 0dc741aff..2625bbb7c 100644 --- a/src/sqlancer/stonedb/oracle/StoneDBNoRECOracle.java +++ b/src/sqlancer/stonedb/oracle/StoneDBNoRECOracle.java @@ -19,7 +19,6 @@ import sqlancer.common.oracle.TestOracle; import sqlancer.common.query.SQLQueryAdapter; import sqlancer.common.query.SQLancerResultSet; -import sqlancer.stonedb.StoneDBErrors; import sqlancer.stonedb.StoneDBProvider.StoneDBGlobalState; import sqlancer.stonedb.StoneDBSchema; import sqlancer.stonedb.StoneDBSchema.StoneDBColumn; @@ -54,7 +53,6 @@ public void check() throws Exception { .map(t -> new TableReferenceNode(t)).collect(Collectors.toList()); List> joins = StoneDBJoin.getJoins(tableList, state); // get and check count - StoneDBErrors.addExpectedSelectErrors(errors); int secondCount = getUnoptimizedQueryCount(new ArrayList<>(tableList), randomWhereCondition, joins); int firstCount = getOptimizedQueryCount(con, new ArrayList<>(tableList), columns, randomWhereCondition, joins); if (firstCount == -1 || secondCount == -1) { From 190b8a9980b2af15aaabb57020a21fc9a841b473 Mon Sep 17 00:00:00 2001 From: zhenglinli <1125806272@qq.com> Date: Sat, 15 Jul 2023 10:55:55 +0800 Subject: [PATCH 21/23] git: manually revert commits --- .../stonedb/gen/StoneDBIndexCreateGenerator.java | 3 +-- .../stonedb/gen/StoneDBTableAlterGenerator.java | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/sqlancer/stonedb/gen/StoneDBIndexCreateGenerator.java b/src/sqlancer/stonedb/gen/StoneDBIndexCreateGenerator.java index 82eab3413..b50f07a6a 100644 --- a/src/sqlancer/stonedb/gen/StoneDBIndexCreateGenerator.java +++ b/src/sqlancer/stonedb/gen/StoneDBIndexCreateGenerator.java @@ -28,8 +28,7 @@ public static SQLQueryAdapter generate(StoneDBGlobalState globalState) { private SQLQueryAdapter getQuery() { sb.append("CREATE "); - // Tianmu engine does not support fulltext index. - sb.append(Randomly.fromOptions("UNIQUE" /* "FULLTEXT" */, "SPATIAL")); + sb.append(Randomly.fromOptions("UNIQUE", "FULLTEXT", "SPATIAL")); sb.append(" INDEX "); sb.append(globalState.getSchema().getFreeIndexName()); if (Randomly.getBoolean()) { diff --git a/src/sqlancer/stonedb/gen/StoneDBTableAlterGenerator.java b/src/sqlancer/stonedb/gen/StoneDBTableAlterGenerator.java index 429be2dfe..b1e4872aa 100644 --- a/src/sqlancer/stonedb/gen/StoneDBTableAlterGenerator.java +++ b/src/sqlancer/stonedb/gen/StoneDBTableAlterGenerator.java @@ -1,5 +1,6 @@ package sqlancer.stonedb.gen; +import java.util.List; import java.util.regex.Pattern; import sqlancer.Randomly; @@ -33,7 +34,7 @@ private SQLQueryAdapter getQuery() { sb.append("ALTER TABLE "); sb.append(table.getName()); sb.append(" "); - appendAlterOption(Randomly.fromOptions(Action.values())); + appendAlterOptions(); addExpectedErrors(); return new SQLQueryAdapter(sb.toString(), errors, true); } @@ -55,6 +56,19 @@ private void addExpectedErrors() { .compile("Column length too big for column 'c\\d{1,3}' \\(max = 16383\\); use BLOB or TEXT instead")); } + private void appendAlterOptions() { + List actions; + if (Randomly.getBooleanWithSmallProbability()) { + actions = Randomly.subset(Action.values()); + } else { + actions = List.of(Randomly.fromOptions(Action.values())); + } + for (Action action : actions) { + appendAlterOption(action); + sb.append(" "); + } + } + private void appendAlterOption(Action action) { StoneDBExpressionGenerator generator = new StoneDBExpressionGenerator(globalState) .setColumns(table.getColumns()); From 68fec906e140f7c29471d1ee9fdd94cd83dafba0 Mon Sep 17 00:00:00 2001 From: zhenglinli <1125806272@qq.com> Date: Wed, 19 Jul 2023 11:46:45 +0800 Subject: [PATCH 22/23] fix: use latest version and set tianmu_insert_delayed=0 --- .github/workflows/main.yml | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8a469004a..9aaed3c70 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -385,12 +385,11 @@ jobs: fetch-depth: 0 - name: Set up StoneDB run: | - docker pull stoneatom/stonedb:v1.0.3 - docker run -p 3306:3306 -itd -e MYSQL_ROOT_PASSWORD='123456' stoneatom/stonedb:v1.0.3 - docker ps - ContainerID=$(docker ps --filter ancestor=stoneatom/stonedb:v1.0.3 --format "{{.ID}}") + docker run -p 3306:3306 -itd -e MYSQL_ROOT_PASSWORD='123456' stoneatom/stonedb + ContainerID=$(docker ps --filter ancestor=stoneatom/stonedb --format "{{.ID}}") docker exec $ContainerID bash - sleep 180s + sleep 60s + docker exec $ContainerID sed -i "s/tianmu_insert_delayed=1/tianmu_insert_delayed=0/" /opt/stonedb57/install/my.cnf docker exec $ContainerID /opt/stonedb57/install/bin/mysql -uroot -p123456 -e "CREATE USER 'sqlancer'@'%' IDENTIFIED WITH mysql_native_password BY 'sqlancer'; GRANT ALL PRIVILEGES ON *.* TO 'sqlancer'@'%' WITH GRANT OPTION; FLUSH PRIVILEGES;" - name: Set up JDK 11 uses: actions/setup-java@v1.4.4 @@ -412,12 +411,11 @@ jobs: fetch-depth: 0 - name: Set up StoneDB run: | - docker pull stoneatom/stonedb:v1.0.3 - docker run -p 3306:3306 -itd -e MYSQL_ROOT_PASSWORD='123456' stoneatom/stonedb:v1.0.3 - docker ps - ContainerID=$(docker ps --filter ancestor=stoneatom/stonedb:v1.0.3 --format "{{.ID}}") + docker run -p 3306:3306 -itd -e MYSQL_ROOT_PASSWORD='123456' stoneatom/stonedb + ContainerID=$(docker ps --filter ancestor=stoneatom/stonedb --format "{{.ID}}") docker exec $ContainerID bash - sleep 180s + sleep 60s + docker exec $ContainerID sed -i "s/tianmu_insert_delayed=1/tianmu_insert_delayed=0/" /opt/stonedb57/install/my.cnf docker exec $ContainerID /opt/stonedb57/install/bin/mysql -uroot -p123456 -e "CREATE USER 'sqlancer'@'%' IDENTIFIED WITH mysql_native_password BY 'sqlancer'; GRANT ALL PRIVILEGES ON *.* TO 'sqlancer'@'%' WITH GRANT OPTION; FLUSH PRIVILEGES;" - name: Set up JDK 11 uses: actions/setup-java@v1.4.4 From 054df712a043d019ba24ab47c8804cced1a682b8 Mon Sep 17 00:00:00 2001 From: zhenglinli <1125806272@qq.com> Date: Wed, 19 Jul 2023 15:50:29 +0800 Subject: [PATCH 23/23] rename: rename oracle --- src/sqlancer/stonedb/StoneDBOptions.java | 6 +++--- ...ningAggregateTester.java => StoneDBAggregateOracle.java} | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) rename src/sqlancer/stonedb/oracle/{StoneDBQueryPartitioningAggregateTester.java => StoneDBAggregateOracle.java} (97%) diff --git a/src/sqlancer/stonedb/StoneDBOptions.java b/src/sqlancer/stonedb/StoneDBOptions.java index 3bb71eff8..7e6a2f09b 100644 --- a/src/sqlancer/stonedb/StoneDBOptions.java +++ b/src/sqlancer/stonedb/StoneDBOptions.java @@ -13,8 +13,8 @@ import sqlancer.common.oracle.TestOracle; import sqlancer.stonedb.StoneDBOptions.StoneDBOracleFactory; import sqlancer.stonedb.StoneDBProvider.StoneDBGlobalState; +import sqlancer.stonedb.oracle.StoneDBAggregateOracle; import sqlancer.stonedb.oracle.StoneDBNoRECOracle; -import sqlancer.stonedb.oracle.StoneDBQueryPartitioningAggregateTester; import sqlancer.stonedb.oracle.StoneDBQueryPartitioningDistinctTester; import sqlancer.stonedb.oracle.StoneDBQueryPartitioningGroupByTester; import sqlancer.stonedb.oracle.StoneDBQueryPartitioningHavingTester; @@ -42,7 +42,7 @@ public TestOracle create(StoneDBGlobalState globalState) thr List> oracles = new ArrayList<>(); oracles.add(new StoneDBQueryPartitioningWhereTester(globalState)); oracles.add(new StoneDBQueryPartitioningHavingTester(globalState)); - oracles.add(new StoneDBQueryPartitioningAggregateTester(globalState)); + oracles.add(new StoneDBAggregateOracle(globalState)); oracles.add(new StoneDBQueryPartitioningDistinctTester(globalState)); oracles.add(new StoneDBQueryPartitioningGroupByTester(globalState)); return new CompositeTestOracle<>(oracles, globalState); @@ -70,7 +70,7 @@ public TestOracle create(StoneDBGlobalState globalState) thr @Override public TestOracle create(StoneDBGlobalState globalState) throws SQLException { - return new StoneDBQueryPartitioningAggregateTester(globalState); + return new StoneDBAggregateOracle(globalState); } }, diff --git a/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningAggregateTester.java b/src/sqlancer/stonedb/oracle/StoneDBAggregateOracle.java similarity index 97% rename from src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningAggregateTester.java rename to src/sqlancer/stonedb/oracle/StoneDBAggregateOracle.java index e0543d790..df09e8961 100644 --- a/src/sqlancer/stonedb/oracle/StoneDBQueryPartitioningAggregateTester.java +++ b/src/sqlancer/stonedb/oracle/StoneDBAggregateOracle.java @@ -26,9 +26,9 @@ import sqlancer.stonedb.gen.StoneDBExpressionGenerator.StoneDBUnaryPostfixOperator; import sqlancer.stonedb.gen.StoneDBExpressionGenerator.StoneDBUnaryPrefixOperator; -public class StoneDBQueryPartitioningAggregateTester extends StoneDBQueryPartitioningBase { +public class StoneDBAggregateOracle extends StoneDBQueryPartitioningBase { - public StoneDBQueryPartitioningAggregateTester(StoneDBGlobalState state) { + public StoneDBAggregateOracle(StoneDBGlobalState state) { super(state); }