Author: [EMAIL PROTECTED]
Date: Thu Oct  2 15:15:58 2008
New Revision: 2744

Added:
trunk/src/ca/sqlpower/architect/swingui/query/ConnectionAndStatementBean.java
Modified:
   trunk/src/ca/sqlpower/architect/swingui/query/SQLQueryEntryPanel.java
   trunk/src/ca/sqlpower/architect/swingui/query/messages.properties

Log:
Added a stop button to the SQL Query tool.

Also added a bean class to hold the connection with a statement currently running on the connection. This way we can send the statement a cancel command.

The bean also holds a boolean to tell if the connection has been modified while not in auto commit to better handle when to pop up a window asking to commit or roll back.

Added: trunk/src/ca/sqlpower/architect/swingui/query/ConnectionAndStatementBean.java
==============================================================================
--- (empty file)
+++ trunk/src/ca/sqlpower/architect/swingui/query/ConnectionAndStatementBean.java Thu Oct 2 15:15:58 2008
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2008, SQL Power Group Inc.
+ *
+ * This file is part of Power*Architect.
+ *
+ * Power*Architect is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Power*Architect is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package ca.sqlpower.architect.swingui.query;
+
+import java.sql.Connection;
+import java.sql.Statement;
+
+/**
+ * This is a container that holds a connection, a statement that is currently executing + * on the connection and a boolean that is true if the connection is not in auto commit + * mode and has had statements executed on it but not committed. This is a collection + * of elements to store in a map to prevent the need to create multiple maps.
+ */
+public class ConnectionAndStatementBean {
+
+    /**
+     * The statement stored in this class
+     */
+    private Connection con;
+
+    /**
+ * The statement currently executing on the connection. This will be null if no + * statements are currently running on the connection. Only one statement should be
+     * run on the connection at a time.
+     */
+    private Statement currentStmt;
+
+    /**
+ * A boolean to track if the connection is not in auto commit mode and if there are
+     * uncommitted statements executed on it.
+     */
+    private boolean connectionUncommitted;
+
+    public ConnectionAndStatementBean(Connection con) {
+        this.con = con;
+        currentStmt = null;
+        connectionUncommitted = false;
+    }
+
+    public Connection getConnection() {
+        return con;
+    }
+
+    public synchronized void setConnection(Connection con) {
+        this.con = con;
+    }
+
+    public Statement getCurrentStmt() {
+        return currentStmt;
+    }
+
+    public synchronized void setCurrentStmt(Statement currentStmt) {
+        this.currentStmt = currentStmt;
+    }
+
+    public boolean isConnectionUncommitted() {
+        return connectionUncommitted;
+    }
+
+ public synchronized void setConnectionUncommitted(boolean connectionUncommitted) {
+        this.connectionUncommitted = connectionUncommitted;
+    }
+
+}

Modified: trunk/src/ca/sqlpower/architect/swingui/query/SQLQueryEntryPanel.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/query/SQLQueryEntryPanel.java (original) +++ trunk/src/ca/sqlpower/architect/swingui/query/SQLQueryEntryPanel.java Thu Oct 2 15:15:58 2008
@@ -81,6 +81,8 @@
 import ca.sqlpower.sql.DatabaseListChangeListener;
 import ca.sqlpower.sql.SPDataSource;
 import ca.sqlpower.swingui.SPSUtils;
+import ca.sqlpower.swingui.SPSwingWorker;
+import ca.sqlpower.swingui.SwingWorkerRegistry;

 import com.jgoodies.forms.builder.DefaultFormBuilder;
 import com.jgoodies.forms.layout.FormLayout;
@@ -213,34 +215,68 @@
                 SPDataSource ds = (SPDataSource)e.getItem();
                 try {
                     Connection con = ds.createConnection();
-                    conMap.put(ds, con);
+                    conMap.put(ds, new ConnectionAndStatementBean(con));
                 } catch (SQLException e1) {
SPSUtils.showExceptionDialogNoReport(parent, Messages.getString("SQLQuery.failedConnectingToDBWithName", ds.getName()), e1);
                     return;
                 }
             }
             try {
- autoCommitToggleButton.setSelected(conMap.get(e.getItem()).getAutoCommit()); + autoCommitToggleButton.setSelected(conMap.get(e.getItem()).getConnection().getAutoCommit());
             } catch (SQLException ex) {
SPSUtils.showExceptionDialogNoReport(parent, Messages.getString("SQLQuery.failedConnectingToDB"), ex);
             }
+ stopButton.setEnabled(conMap.get(e.getItem()).getCurrentStmt() != null); + executeButton.setEnabled(conMap.get(e.getItem()).getCurrentStmt() == null);
         }
     }

     /**
-     * The action for executing and displaying a user's query.
+     * This will execute the sql statement in the sql text area.
      */
- private final AbstractAction executeAction = new AbstractAction(Messages.getString("SQLQuery.execute")) {
-        public void actionPerformed(ActionEvent e) {
+    private class ExecuteSQLWorker extends SPSwingWorker {
+
+        List<CachedRowSet> resultSets = new ArrayList<CachedRowSet>();
+        List<Integer> rowsAffected = new ArrayList<Integer>();
+
+        public ExecuteSQLWorker(SwingWorkerRegistry registry) {
+            super(registry);
+        }
+
+        @Override
+        public void cleanup() throws Exception {
+            Throwable e = getDoStuffException();
+            if (e != null) {
+                if (e instanceof SQLException) {
+ SPSUtils.showExceptionDialogNoReport(getParent(), Messages.getString("SQLQuery.failedConnectingToDB"), e);
+                } else {
+                    throw new RuntimeException(e);
+                }
+            }
+
+            for (ExecuteActionListener listener : executeListeners) {
+                List<ResultSet> newRSList = new ArrayList<ResultSet>();
+                for (CachedRowSet rs : resultSets) {
+                    newRSList.add(rs.createShared());
+                }
+                listener.sqlQueryExecuted(newRSList, rowsAffected);
+            }
+        }
+
+        @Override
+        public void doStuff() throws Exception {
             logger.debug("Starting execute action.");
             SPDataSource ds = (SPDataSource)databases.getSelectedItem();
             if (ds == null) {
                 return;
             }
-            Connection con = conMap.get(ds);
+            Connection con = conMap.get(ds).getConnection();
             Statement stmt = null;
             try {
+                executeButton.setEnabled(false);
+                stopButton.setEnabled(true);
                 stmt = con.createStatement();
+                conMap.get(ds).setCurrentStmt(stmt);
                 try {
                     rowLimitSpinner.commitEdit();
                 } catch (ParseException e1) {
@@ -252,16 +288,17 @@
                 logger.debug("Row limit is " + rowLimit);

                 stmt.setMaxRows(rowLimit);
-                boolean sqlResult = stmt.execute(queryArea.getText());
+                String sql = queryArea.getText();
+                logger.debug("Executing statement " + sql);
+                boolean sqlResult = stmt.execute(sql);
+                logger.debug("Finished execution");
                 boolean hasNext = true;

-                List<ResultSet> resultSets = new ArrayList<ResultSet>();
-                List<Integer> rowsAffected = new ArrayList<Integer>();
-
                 while (hasNext) {
                     if (sqlResult) {
                         ResultSet rs = stmt.getResultSet();
                         CachedRowSet rowSet = new CachedRowSet();
+                        logger.debug("Populating cached row set");
                         rowSet.populate(rs);
logger.debug("Result set row count is " + rowSet.size());
                         resultSets.add(rowSet);
@@ -274,19 +311,7 @@
                     sqlResult = stmt.getMoreResults();
hasNext = !((sqlResult == false) && (stmt.getUpdateCount() == -1));
                 }
-
-                for (ExecuteActionListener listener : executeListeners) {
-                    List<ResultSet> newRSList = new ArrayList<ResultSet>();
-                    for (ResultSet rs : resultSets) {
-                        CachedRowSet rowSet = new CachedRowSet();
-                        rowSet.populate(rs);
-                        newRSList.add(rowSet);
-                    }
-                    listener.sqlQueryExecuted(resultSets, rowsAffected);
-                }
-
-            } catch (SQLException ex) {
- SPSUtils.showExceptionDialogNoReport(getParent(), Messages.getString("SQLQuery.failedConnectingToDB"), ex);
+                logger.debug("Finished Execute method");
             } finally {
                 if (stmt != null) {
                     try {
@@ -294,8 +319,38 @@
                     } catch (SQLException ex) {
                         ex.printStackTrace();
                     }
+                    conMap.get(ds).setCurrentStmt(null);
+                }
+                executeButton.setEnabled(true);
+                stopButton.setEnabled(false);
+            }
+        }
+
+    }
+
+
+    /**
+ * The worker that the execute action runs on to query the database and create the
+     * result sets.
+     */
+    private ExecuteSQLWorker sqlExecuteWorker;
+
+    /**
+     * The action for executing and displaying a user's query.
+     */
+ private final AbstractAction executeAction = new AbstractSQLQueryAction(this, Messages.getString("SQLQuery.execute")) {
+
+        public void actionPerformed(ActionEvent e) {
+ ConnectionAndStatementBean conBean = conMap.get(databases.getSelectedItem());
+            try {
+                if (!conBean.getConnection().getAutoCommit()) {
+                    conBean.setConnectionUncommitted(true);
                 }
+            } catch (SQLException e1) {
+ SPSUtils.showExceptionDialogNoReport(parent, Messages.getString("SQLQuery.failedRetrievingConnection", ((SPDataSource)databases.getSelectedItem()).getName()), e1);
             }
+            sqlExecuteWorker = new ExecuteSQLWorker(session);
+            new Thread(sqlExecuteWorker).start();
         }
     };

@@ -306,7 +361,7 @@
* committing or rolling back. Additionally, it will allow switching of data * sources while keeping the commit or rollback execution sequence preserved.
      */
-    private Map<SPDataSource, Connection> conMap;
+    private Map<SPDataSource, ConnectionAndStatementBean> conMap;

     /**
* The text area users can enter SQL queries to get data from the database.
@@ -412,10 +467,10 @@
             logger.debug("Removing database list change listener");
session.getContext().getPlDotIni().removeDatabaseListChangeListener(dbListChangeListener);

- for (Map.Entry<SPDataSource, Connection> entry : conMap.entrySet()) { + for (Map.Entry<SPDataSource, ConnectionAndStatementBean> entry : conMap.entrySet()) {
                 try {
-                    Connection con = entry.getValue();
-                    if (!con.getAutoCommit()) {
+                    Connection con = entry.getValue().getConnection();
+ if (!con.getAutoCommit() && entry.getValue().isConnectionUncommitted()) { int result = JOptionPane.showOptionDialog(session.getArchitectFrame(), Messages.getString("SQLQuery.commitOrRollback", entry.getKey().getName()), Messages.getString("SQLQuery.commitOrRollbackTitle"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, new Object[] {Messages.getString("SQLQuery.commit"), Messages.getString("SQLQuery.rollback")}, Messages.getString("SQLQuery.commit"));
@@ -432,6 +487,17 @@
             }

         }};
+
+    /**
+     * This button will execute the sql statements in the text area.
+     */
+    private JButton executeButton;
+
+    /**
+ * This button will stop the execution of the currently executing statement
+     * on the selected data source's connection that this panel holds.
+     */
+    private JButton stopButton;

     /**
      * Creates a SQLQueryEntryPanel and attaches a drag and drop listener
@@ -450,20 +516,20 @@
autoCommitToggleButton = new JToggleButton(new AbstractSQLQueryAction(this, Messages.getString("SQLQuery.autoCommit")) {

             public void actionPerformed(ActionEvent e) {
-                Connection con = conMap.get(databases.getSelectedItem());
+ Connection con = conMap.get(databases.getSelectedItem()).getConnection();
                 if (con == null) {
                     return;
                 }
                 try {
boolean isPressed = autoCommitToggleButton.getModel().isSelected();
-                    if (isPressed) {
+ if (isPressed && conMap.get(databases.getSelectedItem()).isConnectionUncommitted()) { int result = JOptionPane.showOptionDialog(parent, Messages.getString("SQLQuery.commitOrRollbackBeforeAutoCommit"), Messages.getString("SQLQuery.commitOrRollbackTitle"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, new Object[] {Messages.getString("SQLQuery.commit"), Messages.getString("SQLQuery.cancel"), Messages.getString("SQLQuery.rollback")}, Messages.getString("SQLQuery.commit"));
                         if (result == JOptionPane.OK_OPTION) {
-                            con.commit();
+                            commitCurrentDB();
                         } else if (result == JOptionPane.CANCEL_OPTION) {
-                            con.rollback();
+                            rollbackCurrentDB();
                         } else {
((JToggleButton)e.getSource()).setSelected(con.getAutoCommit());
                             return;
@@ -492,36 +558,14 @@
             }
         });

- commitButton = new JButton(new AbstractSQLQueryAction(this, Messages.getString("SQLQuery.commit")){ + commitButton = new JButton(new AbstractSQLQueryAction(this, Messages.getString("SQLQuery.commit")) {
             public void actionPerformed(ActionEvent e) {
-                Connection con = conMap.get(databases.getSelectedItem());
-                if (con == null) {
-                    return;
-                }
-                try {
-                    if (!con.getAutoCommit()) {
-                        con.commit();
-                    }
-                } catch (SQLException ex) {
- SPSUtils.showExceptionDialogNoReport(parent, Messages.getString("SQlQuery.failedCommit"), ex);
-                }
+                commitCurrentDB();
             }});

rollbackButton = new JButton(new AbstractSQLQueryAction(this, Messages.getString("SQLQuery.rollback")){
-
             public void actionPerformed(ActionEvent e) {
-                Connection con = conMap.get(databases.getSelectedItem());
-                if (con == null) {
-                    return;
-                }
-                try {
-                    if (!con.getAutoCommit()) {
-                        con.rollback();
-                    }
-                } catch (SQLException ex) {
- SPSUtils.showExceptionDialogNoReport(parent, Messages.getString("SQLQuery.failedRollback"), ex);
-                }
-
+                rollbackCurrentDB();
             }});


@@ -540,7 +584,7 @@
queryArea.getActionMap().put(REDO_SQL_EDIT, redoSQLStatementAction); queryArea.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Z, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() + InputEvent.SHIFT_MASK), REDO_SQL_EDIT);

-        conMap = new HashMap<SPDataSource, Connection>();
+        conMap = new HashMap<SPDataSource, ConnectionAndStatementBean>();

databases = new JComboBox(s.getContext().getConnections().toArray());
         databases.setSelectedItem(null);
@@ -561,7 +605,28 @@
      */
     private void buildUI() {
         JToolBar toolbar = new JToolBar();
-        toolbar.add(executeAction);
+        executeButton = new JButton(executeAction);
+        toolbar.add(executeButton);
+ stopButton = new JButton(new AbstractSQLQueryAction(this, Messages.getString("SQLQuery.stop")) {
+            public void actionPerformed(ActionEvent arg0) {
+ ConnectionAndStatementBean conBean = conMap.get(databases.getSelectedItem());
+                if (conBean != null) {
+                    Statement stmt = conBean.getCurrentStmt();
+                    if (stmt != null) {
+                        try {
+ logger.debug("stmt is being cancelled...supposely");
+                            stmt.cancel();
+                            if (sqlExecuteWorker != null) {
+                                sqlExecuteWorker.kill();
+                            }
+                        } catch (SQLException e) {
+ SPSUtils.showExceptionDialogNoReport(parent, Messages.getString("SQLQuery.stopException", ((SPDataSource)databases.getSelectedItem()).getName()), e);
+                        }
+                    }
+                }
+            }
+        });
+        toolbar.add(stopButton);
toolbar.add(new AbstractSQLQueryAction(this, Messages.getString("SQLQuery.clear")){
             public void actionPerformed(ActionEvent arg0) {
                 queryArea.setText("");
@@ -599,6 +664,46 @@

     public void removeExecuteAction(ExecuteActionListener l) {
         executeListeners.remove(l);
+    }
+
+    /**
+ * If the connection to the database currently selected in the combo box is not in
+     * auto commit mode then any changes will be committed.
+     */
+    private void commitCurrentDB() {
+ ConnectionAndStatementBean conBean = conMap.get(databases.getSelectedItem());
+        Connection con = conBean.getConnection();
+        if (con == null) {
+            return;
+        }
+        try {
+            if (!con.getAutoCommit()) {
+                con.commit();
+                conBean.setConnectionUncommitted(false);
+            }
+        } catch (SQLException ex) {
+ SPSUtils.showExceptionDialogNoReport(this, Messages.getString("SQlQuery.failedCommit"), ex);
+        }
+    }
+
+    /**
+ * If the connection to the database currently selected in the combo box is not in
+     * auto commit mode then any changes will be rolled back.
+     */
+    private void rollbackCurrentDB() {
+ ConnectionAndStatementBean conBean = conMap.get(databases.getSelectedItem());
+        Connection con = conBean.getConnection();
+        if (con == null) {
+            return;
+        }
+        try {
+            if (!con.getAutoCommit()) {
+                con.rollback();
+                conBean.setConnectionUncommitted(false);
+            }
+        } catch (SQLException ex) {
+ SPSUtils.showExceptionDialogNoReport(this, Messages.getString("SQLQuery.failedRollback"), ex);
+        }
     }

 }

Modified: trunk/src/ca/sqlpower/architect/swingui/query/messages.properties
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/query/messages.properties (original) +++ trunk/src/ca/sqlpower/architect/swingui/query/messages.properties Thu Oct 2 15:15:58 2008
@@ -19,4 +19,7 @@
 SQLQuery.filter=Filter
 SQLQuery.result=Result
 SQLQuery.undo=Undo
-SQLQuery.redo=Redo
\ No newline at end of file
+SQLQuery.redo=Redo
+SQLQuery.stop=Stop
+SQLQuery.stopException=Could not stop the current statement from executing on {0}. +SQLQuery.failedRetrievingConnection=Could not retrieve the connection to {0}.
\ No newline at end of file

Reply via email to