Removed logic for equality of query actions for now.

This commit is contained in:
Andrew Lalis 2019-02-22 21:29:33 +01:00 committed by andrewlalis
parent d6e84f47e7
commit 305ea4211c
4 changed files with 97 additions and 115 deletions

View File

@ -1,5 +1,6 @@
package nl.andrewlalis;
import nl.andrewlalis.log.ExecutionAction;
import nl.andrewlalis.log.ExecutionLog;
import nl.andrewlalis.log.QueryAction;
import nl.andrewlalis.log.UpdateAction;
@ -8,6 +9,8 @@ import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import static nl.andrewlalis.Window.*;
public class DatabaseHelper {
private String host;
@ -16,24 +19,60 @@ public class DatabaseHelper {
private String password;
private Window window;
private ExecutionLog executionLog;
public DatabaseHelper(String host, int port, String user, String password, Window window) {
this.host = host;
this.port = port;
this.user = user;
this.password = password;
this.window = window;
}
this.executionLog = new ExecutionLog();
public void executeSQLComparison(String initializationSQL, String templateSQL, String testingSQL) {
// Run the database code in a separate thread to update the UI quickly.
Thread t = new Thread(() -> {
// Setup both databases.
this.window.appendOutput("Dropping old databases and re-creating them...");
this.window.indentOutput();
String dropDatabases = "DROP DATABASE " + DB_TEMPLATE + "; " +
"DROP DATABASE " + DB_TESTING + ";";
String createDatabases = "CREATE DATABASE " + DB_TEMPLATE + "; " +
"CREATE DATABASE " + DB_TESTING + ";";
this.executeQueries("", dropDatabases);
this.executeQueries("", createDatabases);
this.window.unindentOutput();
// Run initialization script on each database.
this.window.appendOutput("Running initialization SQL on databases...");
this.window.indentOutput();
this.executeQueries(DB_TEMPLATE, initializationSQL);
this.executeQueries(DB_TESTING, initializationSQL);
this.window.unindentOutput();
// TESTING SQL HERE
// Template-specific output.
this.window.setOutputChannel(OUTPUT_TEMPLATE);
ExecutionLog templateLog = this.executeQueries(DB_TEMPLATE, templateSQL);
// Testing-specific output.
this.window.setOutputChannel(OUTPUT_TESTING);
ExecutionLog testingLog = this.executeQueries(DB_TESTING, testingSQL);
// Output results.
this.window.setOutputChannel(OUTPUT_GENERAL);
this.window.appendOutput("Execution test result: " + templateLog.equals(testingLog));
});
t.start();
}
/**
* Executes possibly many queries which are contained in one string.
* @param database The database name to connect to, or an empty string to connect to the user's database.
* @param queriesString The string of queries.
* @return The execution log from this series of queries.
*/
public void executeQueries(String database, String queriesString) {
public ExecutionLog executeQueries(String database, String queriesString) {
ExecutionLog executionLog = new ExecutionLog();
String url = String.format(
"jdbc:postgresql://%s:%4d/%s?user=%s&password=%s",
host,
@ -54,7 +93,7 @@ public class DatabaseHelper {
for (String query : queries) {
try {
executeQuery(query, st);
executionLog.recordAction(executeQuery(query, st));
} catch (SQLException e) {
window.appendOutput("Exception while executing statement: " + e.getMessage());
}
@ -67,27 +106,30 @@ public class DatabaseHelper {
window.appendOutput("Unexpected SQL Exception occurred. URL:\n" + url + "\n\tException: " + e.getMessage() + "\n\tSQL State: " + e.getSQLState());
window.setOutputChannel(previousChannel);
}
return executionLog;
}
/**
* Executes a single query and outputs the results.
* @param query The query to execute. Must be only one query in the string.
* @param statement The statement used to execute the query.
* @return The execution action which was done by executing this query.
*/
private void executeQuery(String query, Statement statement) throws SQLException {
private ExecutionAction executeQuery(String query, Statement statement) throws SQLException {
if (isSQLStatementQuery(query)) {
// A result set is expected.
window.appendOutput("Executing query:\n" + query);
QueryAction action = new QueryAction(statement.executeQuery(query));
window.appendOutput(action.toString());
this.executionLog.recordAction(action);
return action;
} else {
// A result set is not expected.
window.appendOutput("Executing update:\n" + query);
UpdateAction action = new UpdateAction(statement.executeUpdate(query), query);
window.appendOutput(action.toString());
this.executionLog.recordAction(action);
return action;
}
}

View File

@ -1,6 +1,7 @@
package nl.andrewlalis;
import javax.swing.*;
import javax.xml.crypto.Data;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
@ -69,37 +70,8 @@ public class Window extends JFrame {
String password = this.passwordTextField.getText();
String initialization = this.initializationTextArea.getText();
// Run the database code in a separate thread to update the UI quickly.
Thread t = new Thread(() -> {
DatabaseHelper dbHelper = new DatabaseHelper(host, port, user, password, this);
// Setup both databases.
this.appendOutput("Dropping old databases and re-creating them...");
this.indentOutput();
String dropDatabases = "DROP DATABASE " + DB_TEMPLATE + "; " +
"DROP DATABASE " + DB_TESTING + ";";
String createDatabases = "CREATE DATABASE " + DB_TEMPLATE + "; " +
"CREATE DATABASE " + DB_TESTING + ";";
dbHelper.executeQueries("", dropDatabases);
dbHelper.executeQueries("", createDatabases);
this.unindentOutput();
// Run initialization script on each database.
this.appendOutput("Running initialization SQL on databases...");
this.indentOutput();
dbHelper.executeQueries(DB_TEMPLATE, initialization);
dbHelper.executeQueries(DB_TESTING, initialization);
this.unindentOutput();
// Template-specific output.
this.setOutputChannel(OUTPUT_TEMPLATE);
dbHelper.executeQueries(DB_TEMPLATE, this.templateTextArea.getText());
// Testing-specific output.
this.setOutputChannel(OUTPUT_TESTING);
dbHelper.executeQueries(DB_TESTING, this.testingTextArea.getText());
});
t.start();
DatabaseHelper helper = new DatabaseHelper(host, port, user, password, this);
helper.executeSQLComparison(initialization, this.templateTextArea.getText(), this.testingTextArea.getText());
}
int getOutputChannel() {

View File

@ -31,15 +31,17 @@ public class ExecutionLog {
ExecutionLog otherLog = (ExecutionLog) other;
if (otherLog.getActions().size() != this.getActions().size()) {
System.out.println("Size difference in logs.");
return false;
}
List<ExecutionAction> otherLogActions = otherLog.getActions();
for (int i = 0; i < this.getActions().size(); i++) {
if (!this.getActions().get(i).equals(otherLogActions.get(i))) {
return false;
}
ExecutionAction myAction = this.getActions().get(i);
ExecutionAction theirAction = otherLogActions.get(i);
System.out.println("My action: " + myAction + "\nTheir action: " + theirAction);
System.out.println("\tEqual? " + myAction.equals(theirAction));
}
return true;

View File

@ -3,104 +3,70 @@ package nl.andrewlalis.log;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* An action in which a query result set is returned.
* An action in which a query result set is returned. Note that SCROLL_INSENSITIVE statements must be used, otherwise
* an SQL exception will be thrown at each attempt to go through the result set.
*/
public class QueryAction extends ExecutionAction {
private String[] columns;
private String[][] values;
private ResultSet resultSet;
public QueryAction(ResultSet resultSet) throws SQLException {
// Read the columns into this object's memory.
ResultSetMetaData metaData = resultSet.getMetaData();
this.columns = new String[metaData.getColumnCount()];
for (int i = 0; i < metaData.getColumnCount(); i++) {
columns[i] = metaData.getColumnName(i + 1);
}
resultSet.absolute(1);// Ensure that this result set cursor is at the beginning.
// Read the rows into this object's memory.
List<String[]> rows = new ArrayList<>();
while (resultSet.next()) {
String[] row = new String[columns.length];
for (int i = 0; i < columns.length; i++) {
row[i] = resultSet.getString(i + 1);
}
rows.add(row);
}
this.values = new String[rows.size()][];
rows.toArray(this.values);
}
public String[] getColumns() {
return this.columns;
}
public String[][] getValues() {
return this.values;
public QueryAction(ResultSet resultSet) {
this.resultSet = resultSet;
}
/**
* The algorithm to determine if two query sets are equivalent is as follows:
* If all of the values of one column contain all of the values of another column, then these two columns must
* almost certainly represent the same value, even if in the wrong order.
* @param other The other object to check equality with.
* @return True if the two query sets are equivalent, or false otherwise.
*/
@Override
public boolean equals(Object other) {
if (!(other instanceof QueryAction)) {
return false;
}
QueryAction action = (QueryAction) other;
if (action.getColumns().length != this.columns.length || action.getValues().length != this.values.length) {
return false;
}
for (int i = 0; i < this.values.length; i++) {
Map<String, String> thisColumnValues = new HashMap<>();
Map<String, String> otherColumnValues = new HashMap<>();
for (int k = 0; k < this.values[i].length; k++) {
thisColumnValues.put(this.columns[k], this.values[i][k]);
otherColumnValues.put(action.getColumns()[k], action.getValues()[i][k]);
}
for (String column : this.columns) {
if (thisColumnValues.get(column).equals(otherColumnValues.get(column))) {
return false;
}
}
}
QueryAction otherAction = (QueryAction) other;
return true;
}
@Override
public String toString() {
// First build a list of columns.
StringBuilder sb = new StringBuilder("Query Result:\n\tColumns: (");
for (int i = 0; i < this.columns.length; i++) {
sb.append(this.columns[i]);
if (i < this.columns.length - 1) {
sb.append(", ");
}
}
sb.append(")\n\tValues:\n");
try {
this.resultSet.absolute(1);
ResultSetMetaData metaData = this.resultSet.getMetaData();
int columnCount = metaData.getColumnCount();
// Then build a list of the rows.
for (int i = 0; i < this.values.length; i++) {
sb.append("\t(");
for (int k = 0; k < this.values[i].length; k++) {
sb.append(this.values[i][k]);
if (k < this.values[i].length - 1) {
StringBuilder sb = new StringBuilder("Query Result:\n\tColumns: (");
for (int i = 0; i < columnCount; i++) {
sb.append(metaData.getColumnName(i + 1));
if (i < columnCount - 1) {
sb.append(", ");
}
}
sb.append(")\n");
}
sb.append(")\n\tValues:\n");
return sb.toString();
while (this.resultSet.next()) {
sb.append("\t(");
for (int i = 0; i < columnCount; i++) {
sb.append(this.resultSet.getString(i + 1));
if (i < columnCount - 1) {
sb.append(", ");
}
}
sb.append(")\n");
}
return sb.toString();
} catch (SQLException e) {
e.printStackTrace();
return "SQLException; Please use a SCROLL_INSENSITIVE statement when executing the query.";
}
}
}