Removed logic for equality of query actions for now.
This commit is contained in:
parent
d6e84f47e7
commit
305ea4211c
|
@ -1,5 +1,6 @@
|
||||||
package nl.andrewlalis;
|
package nl.andrewlalis;
|
||||||
|
|
||||||
|
import nl.andrewlalis.log.ExecutionAction;
|
||||||
import nl.andrewlalis.log.ExecutionLog;
|
import nl.andrewlalis.log.ExecutionLog;
|
||||||
import nl.andrewlalis.log.QueryAction;
|
import nl.andrewlalis.log.QueryAction;
|
||||||
import nl.andrewlalis.log.UpdateAction;
|
import nl.andrewlalis.log.UpdateAction;
|
||||||
|
@ -8,6 +9,8 @@ import java.sql.*;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static nl.andrewlalis.Window.*;
|
||||||
|
|
||||||
public class DatabaseHelper {
|
public class DatabaseHelper {
|
||||||
|
|
||||||
private String host;
|
private String host;
|
||||||
|
@ -16,24 +19,60 @@ public class DatabaseHelper {
|
||||||
private String password;
|
private String password;
|
||||||
private Window window;
|
private Window window;
|
||||||
|
|
||||||
private ExecutionLog executionLog;
|
|
||||||
|
|
||||||
public DatabaseHelper(String host, int port, String user, String password, Window window) {
|
public DatabaseHelper(String host, int port, String user, String password, Window window) {
|
||||||
this.host = host;
|
this.host = host;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.user = user;
|
this.user = user;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
this.window = window;
|
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.
|
* 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 database The database name to connect to, or an empty string to connect to the user's database.
|
||||||
* @param queriesString The string of queries.
|
* @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(
|
String url = String.format(
|
||||||
"jdbc:postgresql://%s:%4d/%s?user=%s&password=%s",
|
"jdbc:postgresql://%s:%4d/%s?user=%s&password=%s",
|
||||||
host,
|
host,
|
||||||
|
@ -54,7 +93,7 @@ public class DatabaseHelper {
|
||||||
|
|
||||||
for (String query : queries) {
|
for (String query : queries) {
|
||||||
try {
|
try {
|
||||||
executeQuery(query, st);
|
executionLog.recordAction(executeQuery(query, st));
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
window.appendOutput("Exception while executing statement: " + e.getMessage());
|
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.appendOutput("Unexpected SQL Exception occurred. URL:\n" + url + "\n\tException: " + e.getMessage() + "\n\tSQL State: " + e.getSQLState());
|
||||||
window.setOutputChannel(previousChannel);
|
window.setOutputChannel(previousChannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return executionLog;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes a single query and outputs the results.
|
* Executes a single query and outputs the results.
|
||||||
* @param query The query to execute. Must be only one query in the string.
|
* @param query The query to execute. Must be only one query in the string.
|
||||||
* @param statement The statement used to execute the query.
|
* @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)) {
|
if (isSQLStatementQuery(query)) {
|
||||||
// A result set is expected.
|
// A result set is expected.
|
||||||
window.appendOutput("Executing query:\n" + query);
|
window.appendOutput("Executing query:\n" + query);
|
||||||
|
|
||||||
QueryAction action = new QueryAction(statement.executeQuery(query));
|
QueryAction action = new QueryAction(statement.executeQuery(query));
|
||||||
window.appendOutput(action.toString());
|
window.appendOutput(action.toString());
|
||||||
this.executionLog.recordAction(action);
|
return action;
|
||||||
} else {
|
} else {
|
||||||
// A result set is not expected.
|
// A result set is not expected.
|
||||||
window.appendOutput("Executing update:\n" + query);
|
window.appendOutput("Executing update:\n" + query);
|
||||||
UpdateAction action = new UpdateAction(statement.executeUpdate(query), query);
|
UpdateAction action = new UpdateAction(statement.executeUpdate(query), query);
|
||||||
window.appendOutput(action.toString());
|
window.appendOutput(action.toString());
|
||||||
this.executionLog.recordAction(action);
|
return action;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package nl.andrewlalis;
|
package nl.andrewlalis;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
import javax.xml.crypto.Data;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
|
|
||||||
|
@ -69,37 +70,8 @@ public class Window extends JFrame {
|
||||||
String password = this.passwordTextField.getText();
|
String password = this.passwordTextField.getText();
|
||||||
String initialization = this.initializationTextArea.getText();
|
String initialization = this.initializationTextArea.getText();
|
||||||
|
|
||||||
// Run the database code in a separate thread to update the UI quickly.
|
DatabaseHelper helper = new DatabaseHelper(host, port, user, password, this);
|
||||||
Thread t = new Thread(() -> {
|
helper.executeSQLComparison(initialization, this.templateTextArea.getText(), this.testingTextArea.getText());
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int getOutputChannel() {
|
int getOutputChannel() {
|
||||||
|
|
|
@ -31,15 +31,17 @@ public class ExecutionLog {
|
||||||
ExecutionLog otherLog = (ExecutionLog) other;
|
ExecutionLog otherLog = (ExecutionLog) other;
|
||||||
|
|
||||||
if (otherLog.getActions().size() != this.getActions().size()) {
|
if (otherLog.getActions().size() != this.getActions().size()) {
|
||||||
|
System.out.println("Size difference in logs.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ExecutionAction> otherLogActions = otherLog.getActions();
|
List<ExecutionAction> otherLogActions = otherLog.getActions();
|
||||||
|
|
||||||
for (int i = 0; i < this.getActions().size(); i++) {
|
for (int i = 0; i < this.getActions().size(); i++) {
|
||||||
if (!this.getActions().get(i).equals(otherLogActions.get(i))) {
|
ExecutionAction myAction = this.getActions().get(i);
|
||||||
return false;
|
ExecutionAction theirAction = otherLogActions.get(i);
|
||||||
}
|
System.out.println("My action: " + myAction + "\nTheir action: " + theirAction);
|
||||||
|
System.out.println("\tEqual? " + myAction.equals(theirAction));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -3,97 +3,58 @@ package nl.andrewlalis.log;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.ResultSetMetaData;
|
import java.sql.ResultSetMetaData;
|
||||||
import java.sql.SQLException;
|
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 {
|
public class QueryAction extends ExecutionAction {
|
||||||
|
|
||||||
private String[] columns;
|
private ResultSet resultSet;
|
||||||
private String[][] values;
|
|
||||||
|
|
||||||
public QueryAction(ResultSet resultSet) throws SQLException {
|
public QueryAction(ResultSet resultSet) {
|
||||||
// Read the columns into this object's memory.
|
this.resultSet = resultSet;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if (!(other instanceof QueryAction)) {
|
if (!(other instanceof QueryAction)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QueryAction action = (QueryAction) other;
|
QueryAction otherAction = (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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
// First build a list of columns.
|
try {
|
||||||
|
this.resultSet.absolute(1);
|
||||||
|
ResultSetMetaData metaData = this.resultSet.getMetaData();
|
||||||
|
int columnCount = metaData.getColumnCount();
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder("Query Result:\n\tColumns: (");
|
StringBuilder sb = new StringBuilder("Query Result:\n\tColumns: (");
|
||||||
for (int i = 0; i < this.columns.length; i++) {
|
for (int i = 0; i < columnCount; i++) {
|
||||||
sb.append(this.columns[i]);
|
sb.append(metaData.getColumnName(i + 1));
|
||||||
if (i < this.columns.length - 1) {
|
if (i < columnCount - 1) {
|
||||||
sb.append(", ");
|
sb.append(", ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sb.append(")\n\tValues:\n");
|
sb.append(")\n\tValues:\n");
|
||||||
|
|
||||||
// Then build a list of the rows.
|
while (this.resultSet.next()) {
|
||||||
for (int i = 0; i < this.values.length; i++) {
|
|
||||||
sb.append("\t(");
|
sb.append("\t(");
|
||||||
for (int k = 0; k < this.values[i].length; k++) {
|
for (int i = 0; i < columnCount; i++) {
|
||||||
sb.append(this.values[i][k]);
|
sb.append(this.resultSet.getString(i + 1));
|
||||||
if (k < this.values[i].length - 1) {
|
if (i < columnCount - 1) {
|
||||||
sb.append(", ");
|
sb.append(", ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,6 +62,11 @@ public class QueryAction extends ExecutionAction {
|
||||||
}
|
}
|
||||||
|
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
|
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return "SQLException; Please use a SCROLL_INSENSITIVE statement when executing the query.";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue