Added query result equality algorithm.

This commit is contained in:
Andrew Lalis 2019-02-23 07:25:43 +01:00 committed by andrewlalis
parent 305ea4211c
commit 9efc91f82f
4 changed files with 137 additions and 6 deletions

View File

@ -121,7 +121,7 @@ public class DatabaseHelper {
// 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), isQueryOrdered(query));
window.appendOutput(action.toString()); window.appendOutput(action.toString());
return action; return action;
} else { } else {
@ -162,4 +162,13 @@ public class DatabaseHelper {
return upper.startsWith("SELECT"); return upper.startsWith("SELECT");
} }
/**
* Determines if a query is ordered by something.
* @param query The query to check.
* @return True if the query makes use of the 'ORDER BY' clause.
*/
private static boolean isQueryOrdered(String query) {
return query.toUpperCase().contains("ORDER BY");
}
} }

View File

@ -44,7 +44,7 @@
<component id="c2e9b" class="javax.swing.JTextArea" binding="templateTextArea"> <component id="c2e9b" class="javax.swing.JTextArea" binding="templateTextArea">
<constraints/> <constraints/>
<properties> <properties>
<text value="select * from primes;"/> <text value="select id, value, other_value from primes;"/>
</properties> </properties>
</component> </component>
</children> </children>
@ -89,7 +89,7 @@
<component id="17867" class="javax.swing.JTextArea" binding="testingTextArea"> <component id="17867" class="javax.swing.JTextArea" binding="testingTextArea">
<constraints/> <constraints/>
<properties> <properties>
<text value="select * from primes;"/> <text value="select value, other_value, id from primes;"/>
</properties> </properties>
</component> </component>
</children> </children>
@ -356,7 +356,7 @@
<component id="cc50b" class="javax.swing.JTextArea" binding="initializationTextArea"> <component id="cc50b" class="javax.swing.JTextArea" binding="initializationTextArea">
<constraints/> <constraints/>
<properties> <properties>
<text value="CREATE TABLE primes (&#10;&#9;id SERIAL NOT NULL,&#10;&#9;value INT NOT NULL&#10;);&#10;&#10;INSERT INTO primes(value) VALUES&#10;(2), (3), (5), (7), (11);" noi18n="true"/> <text value="CREATE TABLE primes (&#10;&#9;id SERIAL NOT NULL,&#10;&#9;value INT NOT NULL,&#10;&#9;other_value TEXT NOT NULL DEFAULT 'fuck'&#10;);&#10;&#10;INSERT INTO primes(value, other_value) VALUES&#10;(2, 'nigger'), (3, 'cunt'), (5, 'piss'), (7, 'shit'), (11, 'spic');" noi18n="true"/>
</properties> </properties>
</component> </component>
</children> </children>

View File

@ -42,6 +42,9 @@ public class ExecutionLog {
ExecutionAction theirAction = otherLogActions.get(i); ExecutionAction theirAction = otherLogActions.get(i);
System.out.println("My action: " + myAction + "\nTheir action: " + theirAction); System.out.println("My action: " + myAction + "\nTheir action: " + theirAction);
System.out.println("\tEqual? " + myAction.equals(theirAction)); System.out.println("\tEqual? " + myAction.equals(theirAction));
if (!myAction.equals(theirAction)) {
return false;
}
} }
return true; return true;

View File

@ -3,6 +3,8 @@ 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.List;
/** /**
* An action in which a query result set is returned. Note that SCROLL_INSENSITIVE statements must be used, otherwise * An action in which a query result set is returned. Note that SCROLL_INSENSITIVE statements must be used, otherwise
@ -11,9 +13,11 @@ import java.sql.SQLException;
public class QueryAction extends ExecutionAction { public class QueryAction extends ExecutionAction {
private ResultSet resultSet; private ResultSet resultSet;
private boolean isOrdered;
public QueryAction(ResultSet resultSet) { public QueryAction(ResultSet resultSet, boolean isOrdered) {
this.resultSet = resultSet; this.resultSet = resultSet;
this.isOrdered = isOrdered;
} }
/** /**
@ -31,9 +35,124 @@ public class QueryAction extends ExecutionAction {
QueryAction otherAction = (QueryAction) other; QueryAction otherAction = (QueryAction) other;
return true; try {
ResultSetMetaData myMetaData = this.resultSet.getMetaData();
ResultSetMetaData theirMetaData = otherAction.resultSet.getMetaData();
if (myMetaData.getColumnCount() != theirMetaData.getColumnCount()) {
return false;
}
int columnCount = myMetaData.getColumnCount();
List<Integer> myColumnsQueue = new ArrayList<>(columnCount);
List<Integer> theirColumnsQueue = new ArrayList<>(columnCount);
for (int i = 1; i <= columnCount; i++) {
myColumnsQueue.add(i);
theirColumnsQueue.add(i);
}
while (!myColumnsQueue.isEmpty()) {
System.out.println(myColumnsQueue);
System.out.println(theirColumnsQueue);
// Pop the first column value.
int myColumn = myColumnsQueue.remove(0);
System.out.println("Testing my column " + myColumn);
// Find a column in their columns which has the same type as this one.
boolean columnMatchFound = false;
int failedAttempts = 0;
while (!theirColumnsQueue.isEmpty() && failedAttempts < myColumnsQueue.size() + 1) {
int theirColumn = theirColumnsQueue.remove(0);
System.out.println("\tWith their column " + theirColumn);
// Check if this column is of a compatible type.
if (myMetaData.getColumnType(myColumn) == theirMetaData.getColumnType(theirColumn)) {
System.out.println("\t\t+ Column type matches.");
// Now check if the data inside is a match.
List<String> myValues = new ArrayList<>();
List<String> theirValues = new ArrayList<>();
this.resultSet.beforeFirst();
otherAction.resultSet.beforeFirst();
// Iterate until one of the result sets goes past the last row.
while (true) {
this.resultSet.next();
otherAction.resultSet.next();
if (this.resultSet.isAfterLast() || otherAction.resultSet.isAfterLast()) {
break;
}
// Collect this row's values for both my column and their column.
myValues.add(this.resultSet.getString(myColumn));
theirValues.add(otherAction.resultSet.getString(theirColumn));
}
// Check if both row counts are the same; i.e. both reach the end at the same time.
if (this.resultSet.isAfterLast() != otherAction.resultSet.isAfterLast()) {
System.out.println("\t\t- Result sets have differing row counts!");
return false;
}
// Compare the values until an error.
boolean isMatch = true;
int index = 0;
for (String value : myValues) {
// If either query action is ordered, then require this.
if (this.isOrdered || otherAction.isOrdered) {
if (!(myValues.get(index).equals(theirValues.get(index)))) {
System.out.println("\t\t- Their column (" + theirColumn + ") does not contain my column's (" + myColumn + ") value of " + value);
isMatch = false;
break;
}
} else {
if (!theirValues.contains(value)) {
System.out.println("\t\t- Their column (" + theirColumn + ") does not contain my column's (" + myColumn + ") value of " + value);
isMatch = false;
break;
}
}
index++;
}
// If the column data matches.
if (isMatch) {
System.out.println("\t\t+ Columns Match! Ensuring my column " + myColumn +" and their column " + theirColumn + " are not added back to the queues.");
// Leave the loop knowing we found a column, without adding it back.
columnMatchFound = true;
break;
} else {
System.out.println("\t\t- Columns do not match.");
// No column was found to match, so add it back to their queue.
theirColumnsQueue.add(theirColumn);
failedAttempts++;
}
} else {
System.out.println("\t\t- Column types do not match.");
theirColumnsQueue.add(theirColumn);
failedAttempts++;
}
}
// columnMatchFound == true when a column match has been found somewhere in other result set.
if (!columnMatchFound) {
System.out.println("\t\t- Could not find a matching column for my column " + myColumn);
return false;
}
}
// If we manage to get to the end without failing, return true.
return true;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
} }
/**
* Translates the result set into a listing of column names and queries.
* @return The string representation of this QueryAction.
*/
@Override @Override
public String toString() { public String toString() {
try { try {