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
36 changes: 36 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,42 @@ jobs:
- name: Run Tests
run: mvn -Dtest=TestH2 test

hive:
name: DBMS Tests (Hive)
runs-on: ubuntu-latest
services:
metastore:
image: apache/hive:4.0.1
env:
SERVICE_NAME: 'metastore'
ports:
- 9083:9083
volumes:
- warehouse:/opt/hive/data/warehouse
hiveserver2:
image: apache/hive:4.0.1
env:
SERVICE_NAME: 'hiveserver2'
ports:
- 10000:10000
- 10002:10002
volumes:
- warehouse:/opt/hive/data/warehouse
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '11'
cache: 'maven'
- name: Build SQLancer
run: mvn -B package -DskipTests=true
- name: Run Tests
run: HIVE_AVAILABLE=true mvn -Dtest=TestHiveTLP test

hsqldb:
name: DBMS Tests (HSQLB)
runs-on: ubuntu-latest
Expand Down
4 changes: 1 addition & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
target/
.classpath
.settings/org.eclipse.core.resources.prefs
.settings/org.eclipse.m2e.core.prefs
.settings/org.eclipse.jdt.core.prefs
.settings/
.vscode
.project
.checkstyle
Expand Down
15 changes: 15 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,21 @@
<groupId>org.apache.arrow</groupId>
<artifactId>flight-sql-jdbc-driver</artifactId>
<version>16.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-jdbc</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-serde</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-cli</artifactId>
<version>4.0.1</version>
</dependency>
</dependencies>
<reporting>
Expand Down
2 changes: 2 additions & 0 deletions src/sqlancer/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import sqlancer.doris.DorisProvider;
import sqlancer.duckdb.DuckDBProvider;
import sqlancer.h2.H2Provider;
import sqlancer.hive.HiveProvider;
import sqlancer.hsqldb.HSQLDBProvider;
import sqlancer.mariadb.MariaDBProvider;
import sqlancer.materialize.MaterializeProvider;
Expand Down Expand Up @@ -735,6 +736,7 @@ private static void checkForIssue799(List<DatabaseProvider<?, ?, ?>> providers)
providers.add(new DorisProvider());
providers.add(new DuckDBProvider());
providers.add(new H2Provider());
providers.add(new HiveProvider());
providers.add(new HSQLDBProvider());
providers.add(new MariaDBProvider());
providers.add(new MaterializeProvider());
Expand Down
40 changes: 40 additions & 0 deletions src/sqlancer/hive/HiveErrors.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package sqlancer.hive;

import java.util.ArrayList;
import java.util.List;

import sqlancer.common.query.ExpectedErrors;

public class HiveErrors {

private HiveErrors() {
}

public static List<String> getExpressionErrors() {
ArrayList<String> errors = new ArrayList<>();

errors.add("cannot recognize input near");
errors.add("Argument type mismatch");
errors.add("Error while compiling statement");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this an expected error or could it be an actual bug (e.g., like an internal error)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These errors are expected since I use an untyped expression generator for Hive, and syntactically invalid statements will cause these errors so they're ignored.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a quick follow up question on this: for an untyped expression generator, I would expected semantically invalid statements, but not syntactically invalid ones. Would it be possible to show an example where this causes such an error?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type mismatch wrong argument Those are error details. They are showed as Hive SemanticException but actually are all caused by mismatched types. So I believe maybe they are expected errors when using untyped expression generator?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for responding. Yes, Agreed! Does the "Invalid Constraint syntax" below also relate to an actual semantic error?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh thanks for mentioning, "Invalid Constraint syntax" also relates to mismatched types, but I believe it's not needed anymore since it will be covered by the above HiveErrors. It's removed in the latest commit.


return errors;
}

public static void addExpressionErrors(ExpectedErrors errors) {
errors.addAll(getExpressionErrors());
}

public static List<String> getInsertErrors() {
ArrayList<String> errors = new ArrayList<>();

errors.add("Either CHECK or NOT NULL constraint violated!");
errors.add("Error running query");
errors.add("is different from preceding arguments");

return errors;
}

public static void addInsertErrors(ExpectedErrors errors) {
errors.addAll(getInsertErrors());
}
}
11 changes: 11 additions & 0 deletions src/sqlancer/hive/HiveGlobalState.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package sqlancer.hive;

import sqlancer.SQLGlobalState;

public class HiveGlobalState extends SQLGlobalState<HiveOptions, HiveSchema> {

@Override
protected HiveSchema readSchema() throws Exception {
return HiveSchema.fromConnection(getConnection(), getDatabaseName());
}
}
43 changes: 43 additions & 0 deletions src/sqlancer/hive/HiveOptions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package sqlancer.hive;

import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;

import sqlancer.common.oracle.TLPWhereOracle;
import sqlancer.common.oracle.TestOracle;
import sqlancer.common.query.ExpectedErrors;
import sqlancer.DBMSSpecificOptions;
import sqlancer.hive.gen.HiveExpressionGenerator;
import sqlancer.OracleFactory;

import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;

@Parameters(separators = "=", commandDescription = "Hive (default port: " + HiveOptions.DEFAULT_PORT
+ ", default host: " + HiveOptions.DEFAULT_HOST + ")")
public class HiveOptions implements DBMSSpecificOptions<HiveOptions.HiveOracleFactory> {
public static final String DEFAULT_HOST = "localhost";
public static final int DEFAULT_PORT = 10000;

@Parameter(names = "--oracle")
public List<HiveOracleFactory> oracle = Arrays.asList(HiveOracleFactory.TLPWhere);

public enum HiveOracleFactory implements OracleFactory<HiveGlobalState> {
TLPWhere {
@Override
public TestOracle<HiveGlobalState> create(HiveGlobalState globalState) throws SQLException {
HiveExpressionGenerator gen = new HiveExpressionGenerator(globalState);
ExpectedErrors expectedErrors = ExpectedErrors.newErrors()
.with(HiveErrors.getExpressionErrors()).build();

return new TLPWhereOracle<>(globalState, gen, expectedErrors);
}
};
}

@Override
public List<HiveOracleFactory> getTestOracleFactory() {
return oracle;
}
}
121 changes: 121 additions & 0 deletions src/sqlancer/hive/HiveProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package sqlancer.hive;

import sqlancer.AbstractAction;
import sqlancer.DatabaseProvider;
import sqlancer.IgnoreMeException;
import sqlancer.MainOptions;
import sqlancer.Randomly;
import sqlancer.SQLConnection;
import sqlancer.SQLProviderAdapter;
import sqlancer.StatementExecutor;
import sqlancer.common.query.SQLQueryAdapter;
import sqlancer.common.query.SQLQueryProvider;
import sqlancer.hive.gen.HiveInsertGenerator;
import sqlancer.hive.gen.HiveTableGenerator;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

import com.google.auto.service.AutoService;

@AutoService(DatabaseProvider.class)
public class HiveProvider extends SQLProviderAdapter<HiveGlobalState, HiveOptions> {

public HiveProvider() {
super(HiveGlobalState.class, HiveOptions.class);
}

public enum Action implements AbstractAction<HiveGlobalState> {

INSERT(HiveInsertGenerator::getQuery);

private final SQLQueryProvider<HiveGlobalState> sqlQueryProvider;

Action(SQLQueryProvider<HiveGlobalState> sqlQueryProvider) {
this.sqlQueryProvider = sqlQueryProvider;
}

@Override
public SQLQueryAdapter getQuery(HiveGlobalState state) throws Exception {
return sqlQueryProvider.getQuery(state);
}
}

private static int mapActions(HiveGlobalState globalState, Action a) {
Randomly r = globalState.getRandomly();
switch (a) {
case INSERT:
return r.getInteger(0, globalState.getOptions().getMaxNumberInserts());
default:
throw new AssertionError(a);
}
}

@Override
public void generateDatabase(HiveGlobalState globalState) throws Exception {
for (int i = 0; i < Randomly.fromOptions(1, 2); i++) {
boolean success;
do {
String tableName = globalState.getSchema().getFreeTableName();
SQLQueryAdapter qt = HiveTableGenerator.generate(globalState, tableName);
success = globalState.executeStatement(qt);
} while(!success);
}
if (globalState.getSchema().getDatabaseTables().isEmpty()) {
throw new IgnoreMeException(); // TODO
}

StatementExecutor<HiveGlobalState, Action> se = new StatementExecutor<HiveGlobalState, Action>(
globalState, Action.values(),
HiveProvider::mapActions, (q) -> {
if (globalState.getSchema().getDatabaseTables().isEmpty()) {
throw new IgnoreMeException();
}
});
se.executeStatements();
}

@Override
public SQLConnection createDatabase(HiveGlobalState globalState) throws SQLException {
String username = globalState.getOptions().getUserName();
String password = globalState.getOptions().getPassword();
String host = globalState.getOptions().getHost();
int port = globalState.getOptions().getPort();
if (host == null) {
host = HiveOptions.DEFAULT_HOST;
}
if (port == MainOptions.NO_SET_PORT) {
port = HiveOptions.DEFAULT_PORT;
}

String databaseName = globalState.getDatabaseName();

String url = String.format("jdbc:hive2://%s:%d/%s", host, port, "default");
Connection con = DriverManager.getConnection(url, username, password);
globalState.getState().logStatement("DROP DATABASE IF EXISTS " + databaseName + " CASCADE");
globalState.getState().logStatement("CREATE DATABASE " + databaseName);
globalState.getState().logStatement("USE " + databaseName);
try (Statement s = con.createStatement()) {
s.execute("DROP DATABASE IF EXISTS " + databaseName + " CASCADE");
}
try (Statement s = con.createStatement()) {
s.execute("CREATE DATABASE " + databaseName);
}
try (Statement s = con.createStatement()) {
s.execute("USE " + databaseName);
}
con.close();
con = DriverManager.getConnection(
String.format("jdbc:hive2://%s:%d/%s", host, port, databaseName,
username, password));

return new SQLConnection(con);
}

@Override
public String getDBMSName() {
return "hive";
}
}
Loading
Loading