Added EVERYTHING
This commit is contained in:
parent
6670c245c2
commit
d6e84f47e7
|
@ -0,0 +1 @@
|
||||||
|
select * from primes;
|
|
@ -0,0 +1,7 @@
|
||||||
|
CREATE TABLE primes (
|
||||||
|
id SERIAL NOT NULL,
|
||||||
|
value INT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO primes(value) VALUES
|
||||||
|
(2), (3), (5), (7), (11);
|
|
@ -0,0 +1 @@
|
||||||
|
select * from primes;
|
|
@ -0,0 +1,123 @@
|
||||||
|
package nl.andrewlalis;
|
||||||
|
|
||||||
|
import nl.andrewlalis.log.ExecutionLog;
|
||||||
|
import nl.andrewlalis.log.QueryAction;
|
||||||
|
import nl.andrewlalis.log.UpdateAction;
|
||||||
|
|
||||||
|
import java.sql.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class DatabaseHelper {
|
||||||
|
|
||||||
|
private String host;
|
||||||
|
private int port;
|
||||||
|
private String user;
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
public void executeQueries(String database, String queriesString) {
|
||||||
|
String url = String.format(
|
||||||
|
"jdbc:postgresql://%s:%4d/%s?user=%s&password=%s",
|
||||||
|
host,
|
||||||
|
port,
|
||||||
|
database,
|
||||||
|
user,
|
||||||
|
password);
|
||||||
|
try {
|
||||||
|
Connection conn = DriverManager.getConnection(url);
|
||||||
|
|
||||||
|
if (!conn.isValid(1000)) {
|
||||||
|
throw new SQLException("Invalid connection.");
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> queries = splitQueries(queriesString);
|
||||||
|
|
||||||
|
Statement st = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
|
||||||
|
|
||||||
|
for (String query : queries) {
|
||||||
|
try {
|
||||||
|
executeQuery(query, st);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
window.appendOutput("Exception while executing statement: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
int previousChannel = window.getOutputChannel();
|
||||||
|
window.setOutputChannel(Window.OUTPUT_GENERAL);
|
||||||
|
window.appendOutput("Unexpected SQL Exception occurred. URL:\n" + url + "\n\tException: " + e.getMessage() + "\n\tSQL State: " + e.getSQLState());
|
||||||
|
window.setOutputChannel(previousChannel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
private void 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);
|
||||||
|
} 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Splits and cleans each query so that it will run properly.
|
||||||
|
* @param queriesString A string containing one or more queries to execute.
|
||||||
|
* @return A list of individual queries.
|
||||||
|
*/
|
||||||
|
private static List<String> splitQueries(String queriesString) {
|
||||||
|
String[] sections = queriesString.split(";");
|
||||||
|
List<String> strings = new ArrayList<>();
|
||||||
|
|
||||||
|
for (String section : sections) {
|
||||||
|
String s = section.trim();
|
||||||
|
if (!s.isEmpty()) {
|
||||||
|
strings.add(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if an SQL string is a query (it should return a result set)
|
||||||
|
* @param str The string to check.
|
||||||
|
* @return True if this is a query, or false if it is an update.
|
||||||
|
*/
|
||||||
|
private static boolean isSQLStatementQuery(String str) {
|
||||||
|
String upper = str.toUpperCase();
|
||||||
|
return upper.startsWith("SELECT");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package nl.andrewlalis;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
|
||||||
|
public static final String APPLICATION_NAME = "SQL-Assesser";
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Window window = new Window(APPLICATION_NAME);
|
||||||
|
window.pack();
|
||||||
|
window.setSize(1000, 800);
|
||||||
|
window.setVisible(true);
|
||||||
|
window.setLocationRelativeTo(null);
|
||||||
|
window.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,381 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="nl.andrewlalis.Window">
|
||||||
|
<grid id="27dc6" binding="mainPanel" layout-manager="BorderLayout" hgap="0" vgap="0">
|
||||||
|
<constraints>
|
||||||
|
<xy x="20" y="20" width="1195" height="814"/>
|
||||||
|
</constraints>
|
||||||
|
<properties/>
|
||||||
|
<border type="none"/>
|
||||||
|
<children>
|
||||||
|
<component id="3de6c" class="javax.swing.JLabel">
|
||||||
|
<constraints border-constraint="North"/>
|
||||||
|
<properties>
|
||||||
|
<horizontalAlignment value="0"/>
|
||||||
|
<text value="SQL-Assesser"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
|
<grid id="e44a4" binding="inputPanel" layout-manager="GridBagLayout">
|
||||||
|
<constraints border-constraint="Center"/>
|
||||||
|
<properties/>
|
||||||
|
<border type="none"/>
|
||||||
|
<children>
|
||||||
|
<grid id="bfff3" layout-manager="BorderLayout" hgap="0" vgap="0">
|
||||||
|
<constraints>
|
||||||
|
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||||
|
<gridbag weightx="1.0" weighty="1.0"/>
|
||||||
|
</constraints>
|
||||||
|
<properties/>
|
||||||
|
<border type="bevel-lowered"/>
|
||||||
|
<children>
|
||||||
|
<component id="5a36e" class="javax.swing.JLabel">
|
||||||
|
<constraints border-constraint="North"/>
|
||||||
|
<properties>
|
||||||
|
<horizontalAlignment value="0"/>
|
||||||
|
<text value="Template"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
|
<scrollpane id="4a4c7">
|
||||||
|
<constraints border-constraint="Center"/>
|
||||||
|
<properties>
|
||||||
|
<verticalScrollBarPolicy value="22"/>
|
||||||
|
</properties>
|
||||||
|
<border type="none"/>
|
||||||
|
<children>
|
||||||
|
<component id="c2e9b" class="javax.swing.JTextArea" binding="templateTextArea">
|
||||||
|
<constraints/>
|
||||||
|
<properties>
|
||||||
|
<text value="select * from primes;"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
|
</children>
|
||||||
|
</scrollpane>
|
||||||
|
<grid id="2493e" layout-manager="FlowLayout" hgap="5" vgap="5" flow-align="1">
|
||||||
|
<constraints border-constraint="South"/>
|
||||||
|
<properties/>
|
||||||
|
<border type="none"/>
|
||||||
|
<children>
|
||||||
|
<component id="15c71" class="javax.swing.JButton" binding="loadTemplateFromFileButton">
|
||||||
|
<constraints/>
|
||||||
|
<properties>
|
||||||
|
<text value="Load From File"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
|
</children>
|
||||||
|
</grid>
|
||||||
|
</children>
|
||||||
|
</grid>
|
||||||
|
<grid id="ce988" layout-manager="BorderLayout" hgap="0" vgap="0">
|
||||||
|
<constraints>
|
||||||
|
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||||
|
<gridbag weightx="1.0" weighty="1.0"/>
|
||||||
|
</constraints>
|
||||||
|
<properties/>
|
||||||
|
<border type="bevel-lowered"/>
|
||||||
|
<children>
|
||||||
|
<component id="e3b9a" class="javax.swing.JLabel">
|
||||||
|
<constraints border-constraint="North"/>
|
||||||
|
<properties>
|
||||||
|
<horizontalAlignment value="0"/>
|
||||||
|
<text value="Testing"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
|
<scrollpane id="28e0d">
|
||||||
|
<constraints border-constraint="Center"/>
|
||||||
|
<properties>
|
||||||
|
<verticalScrollBarPolicy value="22"/>
|
||||||
|
</properties>
|
||||||
|
<border type="none"/>
|
||||||
|
<children>
|
||||||
|
<component id="17867" class="javax.swing.JTextArea" binding="testingTextArea">
|
||||||
|
<constraints/>
|
||||||
|
<properties>
|
||||||
|
<text value="select * from primes;"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
|
</children>
|
||||||
|
</scrollpane>
|
||||||
|
<grid id="7bdad" layout-manager="FlowLayout" hgap="5" vgap="5" flow-align="1">
|
||||||
|
<constraints border-constraint="South"/>
|
||||||
|
<properties/>
|
||||||
|
<border type="none"/>
|
||||||
|
<children>
|
||||||
|
<component id="781f9" class="javax.swing.JButton" binding="loadTestingFromFileButton">
|
||||||
|
<constraints/>
|
||||||
|
<properties>
|
||||||
|
<text value="Load From File"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
|
</children>
|
||||||
|
</grid>
|
||||||
|
</children>
|
||||||
|
</grid>
|
||||||
|
<grid id="a5211" layout-manager="FlowLayout" hgap="5" vgap="5" flow-align="1">
|
||||||
|
<constraints>
|
||||||
|
<grid row="1" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||||
|
<gridbag weightx="1.0" weighty="0.0"/>
|
||||||
|
</constraints>
|
||||||
|
<properties/>
|
||||||
|
<border type="bevel-lowered"/>
|
||||||
|
<children>
|
||||||
|
<grid id="a0bad" layout-manager="BorderLayout" hgap="0" vgap="0">
|
||||||
|
<constraints/>
|
||||||
|
<properties/>
|
||||||
|
<border type="none"/>
|
||||||
|
<children>
|
||||||
|
<component id="1ff5c" class="javax.swing.JLabel">
|
||||||
|
<constraints border-constraint="North"/>
|
||||||
|
<properties>
|
||||||
|
<text value="Host"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
|
<component id="99396" class="javax.swing.JTextField" binding="hostTextField">
|
||||||
|
<constraints border-constraint="Center"/>
|
||||||
|
<properties>
|
||||||
|
<text value="localhost"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
|
</children>
|
||||||
|
</grid>
|
||||||
|
<grid id="87583" layout-manager="BorderLayout" hgap="0" vgap="0">
|
||||||
|
<constraints/>
|
||||||
|
<properties/>
|
||||||
|
<border type="none"/>
|
||||||
|
<children>
|
||||||
|
<component id="274c3" class="javax.swing.JLabel">
|
||||||
|
<constraints border-constraint="North"/>
|
||||||
|
<properties>
|
||||||
|
<text value="Port"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
|
<component id="44d44" class="javax.swing.JTextField" binding="portTextField">
|
||||||
|
<constraints border-constraint="Center"/>
|
||||||
|
<properties>
|
||||||
|
<text value="5432"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
|
</children>
|
||||||
|
</grid>
|
||||||
|
<grid id="881cf" layout-manager="BorderLayout" hgap="0" vgap="0">
|
||||||
|
<constraints/>
|
||||||
|
<properties/>
|
||||||
|
<border type="none"/>
|
||||||
|
<children>
|
||||||
|
<component id="a2ebb" class="javax.swing.JLabel">
|
||||||
|
<constraints border-constraint="North"/>
|
||||||
|
<properties>
|
||||||
|
<text value="User"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
|
<component id="c33e3" class="javax.swing.JTextField" binding="userTextField">
|
||||||
|
<constraints border-constraint="Center"/>
|
||||||
|
<properties>
|
||||||
|
<text value="andrew"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
|
</children>
|
||||||
|
</grid>
|
||||||
|
<grid id="2eb2f" layout-manager="BorderLayout" hgap="0" vgap="0">
|
||||||
|
<constraints/>
|
||||||
|
<properties/>
|
||||||
|
<border type="none"/>
|
||||||
|
<children>
|
||||||
|
<component id="bf4a1" class="javax.swing.JLabel">
|
||||||
|
<constraints border-constraint="North"/>
|
||||||
|
<properties>
|
||||||
|
<text value="Password"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
|
<component id="e2839" class="javax.swing.JTextField" binding="passwordTextField">
|
||||||
|
<constraints border-constraint="Center"/>
|
||||||
|
<properties>
|
||||||
|
<text value="root"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
|
</children>
|
||||||
|
</grid>
|
||||||
|
</children>
|
||||||
|
</grid>
|
||||||
|
</children>
|
||||||
|
</grid>
|
||||||
|
<grid id="5241a" binding="outputPanel" layout-manager="BorderLayout" hgap="0" vgap="0">
|
||||||
|
<constraints border-constraint="South"/>
|
||||||
|
<properties/>
|
||||||
|
<border type="none"/>
|
||||||
|
<children>
|
||||||
|
<grid id="4eed0" layout-manager="BorderLayout" hgap="0" vgap="0">
|
||||||
|
<constraints border-constraint="South"/>
|
||||||
|
<properties/>
|
||||||
|
<border type="none"/>
|
||||||
|
<children>
|
||||||
|
<scrollpane id="adb12" binding="outputScrollPane">
|
||||||
|
<constraints border-constraint="Center"/>
|
||||||
|
<properties>
|
||||||
|
<preferredSize width="2" height="300"/>
|
||||||
|
<verticalScrollBarPolicy value="22"/>
|
||||||
|
</properties>
|
||||||
|
<border type="none"/>
|
||||||
|
<children>
|
||||||
|
<component id="aca43" class="javax.swing.JTextArea" binding="outputTextArea">
|
||||||
|
<constraints/>
|
||||||
|
<properties>
|
||||||
|
<editable value="false"/>
|
||||||
|
<lineWrap value="true"/>
|
||||||
|
<wrapStyleWord value="true"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
|
</children>
|
||||||
|
</scrollpane>
|
||||||
|
<component id="730ad" class="javax.swing.JLabel">
|
||||||
|
<constraints border-constraint="North"/>
|
||||||
|
<properties>
|
||||||
|
<font style="1"/>
|
||||||
|
<horizontalAlignment value="0"/>
|
||||||
|
<text value="General Output"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
|
<grid id="6c3b1" layout-manager="FlowLayout" hgap="5" vgap="5" flow-align="1">
|
||||||
|
<constraints border-constraint="South"/>
|
||||||
|
<properties/>
|
||||||
|
<border type="none"/>
|
||||||
|
<children>
|
||||||
|
<component id="cfab2" class="javax.swing.JButton" binding="executeButton" default-binding="true">
|
||||||
|
<constraints/>
|
||||||
|
<properties>
|
||||||
|
<text value="Execute"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
|
<component id="167c9" class="javax.swing.JButton" binding="clearOutputButton" default-binding="true">
|
||||||
|
<constraints/>
|
||||||
|
<properties>
|
||||||
|
<text value="Clear Output"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
|
</children>
|
||||||
|
</grid>
|
||||||
|
</children>
|
||||||
|
</grid>
|
||||||
|
<grid id="4fb1a" layout-manager="GridBagLayout">
|
||||||
|
<constraints border-constraint="Center"/>
|
||||||
|
<properties>
|
||||||
|
<preferredSize width="70" height="200"/>
|
||||||
|
</properties>
|
||||||
|
<border type="none"/>
|
||||||
|
<children>
|
||||||
|
<grid id="60b96" layout-manager="BorderLayout" hgap="0" vgap="0">
|
||||||
|
<constraints>
|
||||||
|
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||||
|
<gridbag weightx="1.0" weighty="1.0"/>
|
||||||
|
</constraints>
|
||||||
|
<properties>
|
||||||
|
<preferredSize width="105" height="300"/>
|
||||||
|
</properties>
|
||||||
|
<border type="none"/>
|
||||||
|
<children>
|
||||||
|
<component id="a32af" class="javax.swing.JLabel">
|
||||||
|
<constraints border-constraint="North"/>
|
||||||
|
<properties>
|
||||||
|
<horizontalAlignment value="0"/>
|
||||||
|
<text value="Template Output"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
|
<scrollpane id="ae321">
|
||||||
|
<constraints border-constraint="Center"/>
|
||||||
|
<properties>
|
||||||
|
<verticalScrollBarPolicy value="22"/>
|
||||||
|
</properties>
|
||||||
|
<border type="none"/>
|
||||||
|
<children>
|
||||||
|
<component id="1e89d" class="javax.swing.JTextArea" binding="templateOutputTextArea">
|
||||||
|
<constraints/>
|
||||||
|
<properties>
|
||||||
|
<editable value="false"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
|
</children>
|
||||||
|
</scrollpane>
|
||||||
|
</children>
|
||||||
|
</grid>
|
||||||
|
<grid id="f3ff1" layout-manager="BorderLayout" hgap="0" vgap="0">
|
||||||
|
<constraints>
|
||||||
|
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||||
|
<gridbag weightx="1.0" weighty="1.0"/>
|
||||||
|
</constraints>
|
||||||
|
<properties>
|
||||||
|
<preferredSize width="93" height="300"/>
|
||||||
|
</properties>
|
||||||
|
<border type="none"/>
|
||||||
|
<children>
|
||||||
|
<component id="67bc9" class="javax.swing.JLabel">
|
||||||
|
<constraints border-constraint="North"/>
|
||||||
|
<properties>
|
||||||
|
<horizontalAlignment value="0"/>
|
||||||
|
<text value="Testing Output"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
|
<scrollpane id="c31b2">
|
||||||
|
<constraints border-constraint="Center"/>
|
||||||
|
<properties>
|
||||||
|
<verticalScrollBarPolicy value="22"/>
|
||||||
|
</properties>
|
||||||
|
<border type="none"/>
|
||||||
|
<children>
|
||||||
|
<component id="f0d22" class="javax.swing.JTextArea" binding="testingOutputTextArea">
|
||||||
|
<constraints/>
|
||||||
|
<properties>
|
||||||
|
<editable value="false"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
|
</children>
|
||||||
|
</scrollpane>
|
||||||
|
</children>
|
||||||
|
</grid>
|
||||||
|
</children>
|
||||||
|
</grid>
|
||||||
|
</children>
|
||||||
|
</grid>
|
||||||
|
<grid id="1e3e8" binding="initializationPanel" layout-manager="BorderLayout" hgap="0" vgap="0">
|
||||||
|
<constraints border-constraint="West"/>
|
||||||
|
<properties/>
|
||||||
|
<border type="bevel-lowered"/>
|
||||||
|
<children>
|
||||||
|
<component id="3f0fa" class="javax.swing.JLabel">
|
||||||
|
<constraints border-constraint="North"/>
|
||||||
|
<properties>
|
||||||
|
<horizontalAlignment value="0"/>
|
||||||
|
<text value="Initialization"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
|
<scrollpane id="27433">
|
||||||
|
<constraints border-constraint="Center"/>
|
||||||
|
<properties>
|
||||||
|
<preferredSize width="400" height="18"/>
|
||||||
|
<verticalScrollBarPolicy value="22"/>
|
||||||
|
</properties>
|
||||||
|
<border type="none"/>
|
||||||
|
<children>
|
||||||
|
<component id="cc50b" class="javax.swing.JTextArea" binding="initializationTextArea">
|
||||||
|
<constraints/>
|
||||||
|
<properties>
|
||||||
|
<text value="CREATE TABLE primes ( 	id SERIAL NOT NULL, 	value INT NOT NULL ); INSERT INTO primes(value) VALUES (2), (3), (5), (7), (11);" noi18n="true"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
|
</children>
|
||||||
|
</scrollpane>
|
||||||
|
<grid id="2ca80" layout-manager="FlowLayout" hgap="5" vgap="5" flow-align="1">
|
||||||
|
<constraints border-constraint="South"/>
|
||||||
|
<properties/>
|
||||||
|
<border type="none"/>
|
||||||
|
<children>
|
||||||
|
<component id="ffb59" class="javax.swing.JButton" binding="loadInitializationFromFileButton">
|
||||||
|
<constraints/>
|
||||||
|
<properties>
|
||||||
|
<text value="Load From File"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
|
</children>
|
||||||
|
</grid>
|
||||||
|
</children>
|
||||||
|
</grid>
|
||||||
|
</children>
|
||||||
|
</grid>
|
||||||
|
</form>
|
|
@ -0,0 +1,150 @@
|
||||||
|
package nl.andrewlalis;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
|
||||||
|
public class Window extends JFrame {
|
||||||
|
private JPanel mainPanel;
|
||||||
|
private JPanel inputPanel;
|
||||||
|
private JPanel outputPanel;
|
||||||
|
private JTextArea outputTextArea;
|
||||||
|
private JButton executeButton;
|
||||||
|
private JTextArea templateTextArea;
|
||||||
|
private JTextArea testingTextArea;
|
||||||
|
private JTextField hostTextField;
|
||||||
|
private JTextField portTextField;
|
||||||
|
private JTextField userTextField;
|
||||||
|
private JTextField passwordTextField;
|
||||||
|
private JScrollPane outputScrollPane;
|
||||||
|
private JTextArea testingOutputTextArea;
|
||||||
|
private JTextArea templateOutputTextArea;
|
||||||
|
private JTextArea initializationTextArea;
|
||||||
|
private JPanel initializationPanel;
|
||||||
|
private JButton clearOutputButton;
|
||||||
|
private JButton loadTemplateFromFileButton;
|
||||||
|
private JButton loadTestingFromFileButton;
|
||||||
|
private JButton loadInitializationFromFileButton;
|
||||||
|
|
||||||
|
public static final int OUTPUT_GENERAL = 0;
|
||||||
|
public static final int OUTPUT_TEMPLATE = 1;
|
||||||
|
public static final int OUTPUT_TESTING = 2;
|
||||||
|
|
||||||
|
public static final String DB_TEMPLATE = "sql_assess_template";
|
||||||
|
public static final String DB_TESTING = "sql_assess_testing";
|
||||||
|
|
||||||
|
private int outputChannel;
|
||||||
|
private int outputIndent;
|
||||||
|
|
||||||
|
public Window(String applicationName) {
|
||||||
|
super(applicationName);
|
||||||
|
|
||||||
|
this.setOutputChannel(OUTPUT_GENERAL);
|
||||||
|
|
||||||
|
this.setContentPane(mainPanel);
|
||||||
|
|
||||||
|
executeButton.addActionListener(actionEvent -> {
|
||||||
|
this.executeSQL();
|
||||||
|
});
|
||||||
|
|
||||||
|
clearOutputButton.addActionListener(actionEvent -> {
|
||||||
|
this.templateOutputTextArea.setText(null);
|
||||||
|
this.testingOutputTextArea.setText(null);
|
||||||
|
this.outputTextArea.setText(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
loadInitializationFromFileButton.addActionListener(actionEvent -> {
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the SQL in the two text areas, and provides output.
|
||||||
|
*/
|
||||||
|
private void executeSQL() {
|
||||||
|
this.setOutputChannel(OUTPUT_GENERAL);
|
||||||
|
String host = this.hostTextField.getText();
|
||||||
|
int port = Integer.parseInt(this.portTextField.getText());
|
||||||
|
String user = this.userTextField.getText();
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
int getOutputChannel() {
|
||||||
|
return this.outputChannel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setOutputChannel(int channel) {
|
||||||
|
this.outputChannel = channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void indentOutput() {
|
||||||
|
this.outputIndent++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unindentOutput() {
|
||||||
|
this.outputIndent--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds some text to the current output channel, followed by a new line.
|
||||||
|
* @param text The text to append.
|
||||||
|
*/
|
||||||
|
void appendOutput(String text) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i < this.outputIndent; i++) {
|
||||||
|
sb.append('\t');
|
||||||
|
}
|
||||||
|
String tabs = sb.toString();
|
||||||
|
StringBuilder resultSb = new StringBuilder();
|
||||||
|
for (String line : text.split("\n")) {
|
||||||
|
resultSb.append(tabs).append(line).append('\n');
|
||||||
|
}
|
||||||
|
String result = resultSb.toString();
|
||||||
|
switch (this.outputChannel) {
|
||||||
|
case OUTPUT_GENERAL:
|
||||||
|
this.outputTextArea.append(result);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OUTPUT_TEMPLATE:
|
||||||
|
this.templateOutputTextArea.append(result);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OUTPUT_TESTING:
|
||||||
|
this.testingOutputTextArea.append(result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package nl.andrewlalis.log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an action performed on a database.
|
||||||
|
*/
|
||||||
|
public abstract class ExecutionAction {
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
package nl.andrewlalis.log;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains a log of all actions performed to a database.
|
||||||
|
*/
|
||||||
|
public class ExecutionLog {
|
||||||
|
|
||||||
|
private List<ExecutionAction> actions;
|
||||||
|
|
||||||
|
public ExecutionLog() {
|
||||||
|
this.actions = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recordAction(ExecutionAction action) {
|
||||||
|
this.actions.add(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ExecutionAction> getActions() {
|
||||||
|
return this.actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object other) {
|
||||||
|
if (!(other instanceof ExecutionLog)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExecutionLog otherLog = (ExecutionLog) other;
|
||||||
|
|
||||||
|
if (otherLog.getActions().size() != this.getActions().size()) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
public class QueryAction extends ExecutionAction {
|
||||||
|
|
||||||
|
private String[] columns;
|
||||||
|
private String[][] values;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
sb.append(", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sb.append(")\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package nl.andrewlalis.log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an action in which the schema or data was updated and no result set was returned.
|
||||||
|
*/
|
||||||
|
public class UpdateAction extends ExecutionAction {
|
||||||
|
|
||||||
|
private int rowsAffected;
|
||||||
|
|
||||||
|
public UpdateAction(int rowsAffected, String statement) {
|
||||||
|
this.rowsAffected = rowsAffected;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object other) {
|
||||||
|
if (!(other instanceof UpdateAction)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateAction action = (UpdateAction) other;
|
||||||
|
|
||||||
|
return action.rowsAffected == this.rowsAffected;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Update result:\n\tRows affected: " + this.rowsAffected + "\n";
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue