Coverage Report - org.kuali.db.SQLExecutor
 
Classes in this File Line Coverage Branch Coverage Complexity
SQLExecutor
0%
0/256
0%
0/96
2.018
 
 1  
 package org.kuali.db;
 2  
 
 3  
 import java.io.BufferedReader;
 4  
 import java.io.IOException;
 5  
 import java.io.PrintStream;
 6  
 import java.io.Reader;
 7  
 import java.sql.Connection;
 8  
 import java.sql.ResultSet;
 9  
 import java.sql.ResultSetMetaData;
 10  
 import java.sql.SQLException;
 11  
 import java.sql.SQLWarning;
 12  
 import java.sql.Statement;
 13  
 import java.util.ArrayList;
 14  
 import java.util.Enumeration;
 15  
 import java.util.List;
 16  
 import java.util.StringTokenizer;
 17  
 import java.util.Vector;
 18  
 
 19  
 import org.apache.commons.lang.StringEscapeUtils;
 20  
 import org.apache.commons.logging.Log;
 21  
 import org.apache.commons.logging.LogFactory;
 22  
 
 23  
 import static org.apache.commons.io.IOUtils.*;
 24  
 import static org.kuali.db.JDBCUtils.*;
 25  
 
 26  
 /**
 27  
  * Executes SQL statements
 28  
  */
 29  0
 public class SQLExecutor {
 30  0
         private static final Log log = LogFactory.getLog(SQLExecutor.class);
 31  
 
 32  
         /**
 33  
          * Call {@link #setOnError(String)} with this value to abort SQL command execution if an error is found.
 34  
          */
 35  
         public static final String ON_ERROR_ABORT = "abort";
 36  
 
 37  
         /**
 38  
          * Call {@link #setOnError(String)} with this value to continue SQL command execution until all commands have been
 39  
          * attempted, then abort the build if an SQL error occurred in any of the commands.
 40  
          */
 41  
         public static final String ON_ERROR_ABORT_AFTER = "abortAfter";
 42  
 
 43  
         /**
 44  
          * Call {@link #setOnError(String)} with this value to continue SQL command execution if an error is found.
 45  
          */
 46  
         public static final String ON_ERROR_CONTINUE = "continue";
 47  
 
 48  
         Vector<Transaction> transactions;
 49  0
         boolean keepFormat = true;
 50  0
         String delimiterType = "row";
 51  0
         String delimiter = "/";
 52  0
         boolean printResultSet = false;;
 53  0
         String onError = ON_ERROR_ABORT;
 54  0
         boolean showheaders = true;
 55  0
         String outputDelimiter = ",";
 56  
         int totalStatements;
 57  
         int successfulStatements;
 58  
         Connection conn;
 59  
         Statement statement;
 60  0
         boolean autocommit = false;
 61  0
         boolean escapeProcessing = true;
 62  
         boolean skipOnConnectionError;
 63  
         boolean connectionError;
 64  0
         boolean append = false;
 65  0
         List<DatabaseListener> listeners = new ArrayList<DatabaseListener>();
 66  
 
 67  
         public void addListener(DatabaseListener listener) {
 68  0
                 listeners.add(listener);
 69  0
         }
 70  
 
 71  
         protected void fireMessageLogged(String message) {
 72  0
                 fireMessageLogged(message, MessagePriority.INFO);
 73  0
         }
 74  
 
 75  
         protected void fireMessageLogged(String message, MessagePriority priority) {
 76  0
                 DatabaseEvent event = new DatabaseEvent(message, priority);
 77  0
                 for (DatabaseListener listener : listeners) {
 78  0
                         listener.messageLogged(event);
 79  
                 }
 80  0
         }
 81  
 
 82  
         protected void fireBeginTransaction(Transaction transaction) {
 83  0
                 DatabaseEvent event = new DatabaseEvent();
 84  0
                 event.setTransaction(transaction);
 85  0
                 for (DatabaseListener listener : listeners) {
 86  0
                         listener.beginTransaction(event);
 87  
                 }
 88  0
         }
 89  
 
 90  
         protected void fireFinishTransaction(Transaction transaction) {
 91  0
                 DatabaseEvent event = new DatabaseEvent();
 92  0
                 event.setTransaction(transaction);
 93  0
                 for (DatabaseListener listener : listeners) {
 94  0
                         listener.finishTransaction(event);
 95  
                 }
 96  0
         }
 97  
 
 98  
         protected DatabaseEvent getExecuteSQLEvent(int totalStatements, String sql) {
 99  0
                 DatabaseEvent event = new DatabaseEvent();
 100  0
                 event.setSql(sql);
 101  0
                 event.setTotalStatements(totalStatements);
 102  0
                 return event;
 103  
         }
 104  
 
 105  
         protected void fireBeforeExecuteSQL(int totalStatements, String sql) {
 106  0
                 for (DatabaseListener listener : listeners) {
 107  0
                         listener.beforeExecuteSQL(getExecuteSQLEvent(totalStatements, sql));
 108  
                 }
 109  0
         }
 110  
 
 111  
         protected void fireAfterExecuteSQL(int totalStatements, String sql) {
 112  0
                 for (DatabaseListener listener : listeners) {
 113  0
                         listener.afterExecuteSQL(getExecuteSQLEvent(totalStatements, sql));
 114  
                 }
 115  0
         }
 116  
 
 117  
         protected void fireAfterProcessingSQLResults(int totalStatements, int successfulStatements, int updateCountTotal, String sql) {
 118  0
                 DatabaseEvent event = getExecuteSQLEvent(totalStatements, sql);
 119  0
                 event.setSuccessfulStatements(successfulStatements);
 120  0
                 event.setUpdateCountTotal(updateCountTotal);
 121  0
                 for (DatabaseListener listener : listeners) {
 122  0
                         listener.afterExecuteSQL(event);
 123  
                 }
 124  0
         }
 125  
 
 126  
         public void info(String message) {
 127  0
                 log.info(message);
 128  0
                 fireMessageLogged(message);
 129  0
         }
 130  
 
 131  
         public void debug(String message) {
 132  0
                 log.debug(message);
 133  0
                 fireMessageLogged(message, MessagePriority.DEBUG);
 134  0
         }
 135  
 
 136  
         public void error(Throwable throwable, String message) {
 137  0
                 if (throwable == null) {
 138  0
                         log.error(message);
 139  
                 } else {
 140  0
                         log.error(message, throwable);
 141  
                 }
 142  0
                 DatabaseEvent event = new DatabaseEvent(message, MessagePriority.ERROR);
 143  0
                 event.setException(throwable);
 144  0
                 for (DatabaseListener listener : listeners) {
 145  0
                         listener.messageLogged(event);
 146  
                 }
 147  0
         }
 148  
 
 149  
         public void error(String message) {
 150  0
                 error(null, message);
 151  0
         }
 152  
 
 153  
         public void executeSql(String sql) throws SQLException {
 154  0
                 Transaction transaction = new Transaction();
 155  0
                 transaction.setSqlCommand(sql);
 156  0
                 executeTransaction(transaction);
 157  0
         }
 158  
 
 159  
         public void executeTransaction(Transaction transaction) throws SQLException {
 160  0
                 this.transactions = new Vector<Transaction>();
 161  0
                 transactions.add(transaction);
 162  0
                 execute();
 163  0
         }
 164  
 
 165  
         public void execute() throws SQLException {
 166  
                 try {
 167  0
                         statement = conn.createStatement();
 168  0
                         statement.setEscapeProcessing(escapeProcessing);
 169  
 
 170  
                         // Process all transactions
 171  0
                         for (Enumeration<Transaction> e = transactions.elements(); e.hasMoreElements();) {
 172  0
                                 Transaction t = (Transaction) e.nextElement();
 173  
 
 174  0
                                 fireBeginTransaction(t);
 175  0
                                 runTransaction(t, System.out);
 176  0
                                 fireFinishTransaction(t);
 177  
 
 178  0
                                 if (!autocommit) {
 179  0
                                         debug("Committing transaction");
 180  0
                                         conn.commit();
 181  
                                 }
 182  0
                         }
 183  0
                 } catch (IOException e) {
 184  0
                         throw new SQLException(e);
 185  0
                 } catch (SQLException e) {
 186  0
                         if (!autocommit && ON_ERROR_ABORT.equalsIgnoreCase(getOnError())) {
 187  0
                                 rollbackQuietly(conn);
 188  
                         }
 189  0
                         throw e;
 190  
                 } finally {
 191  0
                         closeQuietly(statement, conn);
 192  0
                 }
 193  
 
 194  0
                 log.info(getSuccessfulStatements() + " of " + getTotalStatements() + " SQL statements executed successfully");
 195  
 
 196  0
                 if (ON_ERROR_ABORT_AFTER.equalsIgnoreCase(getOnError()) && totalStatements != successfulStatements) {
 197  0
                         throw new SQLException("Some SQL statements failed to execute");
 198  
                 }
 199  0
         }
 200  
 
 201  
         protected void runTransaction(Transaction t, PrintStream out) throws IOException, SQLException {
 202  0
                 Reader in = null;
 203  
                 try {
 204  0
                         in = t.getReader();
 205  0
                         runStatements(in, out);
 206  
                 } finally {
 207  0
                         closeQuietly(in);
 208  0
                 }
 209  0
         }
 210  
 
 211  
         /**
 212  
          * Exec the sql statement.
 213  
          * 
 214  
          * @param sql
 215  
          *            query to execute
 216  
          * @param out
 217  
          *            the outputstream
 218  
          */
 219  
         protected void execSQL(String sql, PrintStream out) throws SQLException {
 220  
                 // Check and ignore empty statements
 221  0
                 if ("".equals(sql.trim())) {
 222  0
                         return;
 223  
                 }
 224  
 
 225  0
                 ResultSet resultSet = null;
 226  
                 try {
 227  0
                         totalStatements++;
 228  0
                         debug("SQL: " + sql);
 229  
 
 230  
                         boolean ret;
 231  0
                         int updateCountTotal = 0;
 232  
 
 233  0
                         fireBeforeExecuteSQL(totalStatements, sql);
 234  0
                         ret = statement.execute(sql);
 235  0
                         fireAfterExecuteSQL(totalStatements, sql);
 236  
                         do {
 237  0
                                 if (!ret) {
 238  0
                                         int updateCount = statement.getUpdateCount();
 239  0
                                         if (updateCount != -1) {
 240  0
                                                 updateCountTotal += updateCount;
 241  
                                         }
 242  0
                                 } else {
 243  0
                                         resultSet = statement.getResultSet();
 244  0
                                         if (printResultSet) {
 245  0
                                                 printResultSet(resultSet, out);
 246  
                                         }
 247  
                                 }
 248  0
                                 ret = statement.getMoreResults();
 249  0
                         } while (ret);
 250  
 
 251  0
                         debug(updateCountTotal + " rows affected");
 252  
 
 253  0
                         if (printResultSet) {
 254  0
                                 StringBuffer line = new StringBuffer();
 255  0
                                 line.append(updateCountTotal).append(" rows affected");
 256  0
                                 out.println(line);
 257  
                         }
 258  
 
 259  0
                         SQLWarning warning = conn.getWarnings();
 260  0
                         while (warning != null) {
 261  0
                                 debug(warning + " sql warning");
 262  0
                                 warning = warning.getNextWarning();
 263  
                         }
 264  0
                         conn.clearWarnings();
 265  0
                         successfulStatements++;
 266  0
                         fireAfterProcessingSQLResults(totalStatements, successfulStatements, updateCountTotal, sql);
 267  0
                 } catch (SQLException e) {
 268  0
                         error("Failed to execute: " + sql + "\n\n" + e.getMessage());
 269  0
                         if (ON_ERROR_ABORT.equalsIgnoreCase(getOnError())) {
 270  0
                                 throw e;
 271  
                         }
 272  
                 } finally {
 273  0
                         closeQuietly(resultSet);
 274  0
                 }
 275  0
         }
 276  
 
 277  
         /**
 278  
          * read in lines and execute them
 279  
          * 
 280  
          * @param reader
 281  
          *            the reader
 282  
          * @param out
 283  
          *            the outputstream
 284  
          * @throws SQLException
 285  
          * @throws IOException
 286  
          */
 287  
         protected void runStatements(Reader reader, PrintStream out) throws SQLException, IOException {
 288  
                 String line;
 289  
 
 290  0
                 StringBuffer sql = new StringBuffer();
 291  
 
 292  0
                 BufferedReader in = new BufferedReader(reader);
 293  
 
 294  0
                 while ((line = in.readLine()) != null) {
 295  0
                         if (!keepFormat) {
 296  0
                                 line = line.trim();
 297  
                         }
 298  
 
 299  0
                         if (!keepFormat) {
 300  0
                                 if (line.startsWith("//")) {
 301  0
                                         continue;
 302  
                                 }
 303  0
                                 if (line.startsWith("--")) {
 304  0
                                         continue;
 305  
                                 }
 306  0
                                 StringTokenizer st = new StringTokenizer(line);
 307  0
                                 if (st.hasMoreTokens()) {
 308  0
                                         String token = st.nextToken();
 309  0
                                         if ("REM".equalsIgnoreCase(token)) {
 310  0
                                                 continue;
 311  
                                         }
 312  
                                 }
 313  
                         }
 314  
 
 315  0
                         if (!keepFormat) {
 316  0
                                 sql.append(" ").append(line);
 317  
                         } else {
 318  0
                                 sql.append("\n").append(line);
 319  
                         }
 320  
 
 321  
                         // SQL defines "--" as a comment to EOL
 322  
                         // and in Oracle it may contain a hint
 323  
                         // so we cannot just remove it, instead we must end it
 324  0
                         if (!keepFormat) {
 325  0
                                 if (SqlSplitter.containsSqlEnd(line, delimiter) == SqlSplitter.NO_END) {
 326  0
                                         sql.append("\n");
 327  
                                 }
 328  
                         }
 329  
 
 330  0
                         if ((delimiterType.equals(DelimiterType.NORMAL) && SqlSplitter.containsSqlEnd(line, delimiter) > 0) || (delimiterType.equals(DelimiterType.ROW) && line.trim().equals(delimiter))) {
 331  0
                                 execSQL(sql.substring(0, sql.length() - delimiter.length()), out);
 332  0
                                 sql.setLength(0); // clean buffer
 333  
                         }
 334  
                 }
 335  
 
 336  
                 // Catch any statements not followed by ;
 337  0
                 if (!sql.toString().equals("")) {
 338  0
                         execSQL(sql.toString(), out);
 339  
                 }
 340  0
         }
 341  
 
 342  
         /**
 343  
          * print any results in the result set.
 344  
          * 
 345  
          * @param rs
 346  
          *            the resultset to print information about
 347  
          * @param out
 348  
          *            the place to print results
 349  
          * @throws SQLException
 350  
          *             on SQL problems.
 351  
          */
 352  
         protected void printResultSet(ResultSet rs, PrintStream out) throws SQLException {
 353  0
                 if (rs == null) {
 354  0
                         return;
 355  
                 }
 356  0
                 debug("Processing new result set.");
 357  0
                 ResultSetMetaData md = rs.getMetaData();
 358  0
                 int columnCount = md.getColumnCount();
 359  0
                 StringBuffer line = new StringBuffer();
 360  0
                 if (showheaders) {
 361  0
                         boolean first = true;
 362  0
                         for (int col = 1; col <= columnCount; col++) {
 363  0
                                 String columnValue = md.getColumnName(col);
 364  
 
 365  0
                                 if (columnValue != null) {
 366  0
                                         columnValue = columnValue.trim();
 367  
 
 368  0
                                         if (",".equals(outputDelimiter)) {
 369  0
                                                 columnValue = StringEscapeUtils.escapeCsv(columnValue);
 370  
                                         }
 371  
                                 }
 372  
 
 373  0
                                 if (first) {
 374  0
                                         first = false;
 375  
                                 } else {
 376  0
                                         line.append(outputDelimiter);
 377  
                                 }
 378  0
                                 line.append(columnValue);
 379  
                         }
 380  0
                         out.println(line);
 381  0
                         line = new StringBuffer();
 382  
                 }
 383  0
                 while (rs.next()) {
 384  0
                         boolean first = true;
 385  0
                         for (int col = 1; col <= columnCount; col++) {
 386  0
                                 String columnValue = rs.getString(col);
 387  0
                                 if (columnValue != null) {
 388  0
                                         columnValue = columnValue.trim();
 389  
 
 390  0
                                         if (",".equals(outputDelimiter)) {
 391  0
                                                 columnValue = StringEscapeUtils.escapeCsv(columnValue);
 392  
                                         }
 393  
                                 }
 394  
 
 395  0
                                 if (first) {
 396  0
                                         first = false;
 397  
                                 } else {
 398  0
                                         line.append(outputDelimiter);
 399  
                                 }
 400  0
                                 line.append(columnValue);
 401  
                         }
 402  0
                         out.println(line);
 403  0
                         line = new StringBuffer();
 404  0
                 }
 405  0
                 out.println();
 406  0
         }
 407  
 
 408  
         public boolean isKeepFormat() {
 409  0
                 return keepFormat;
 410  
         }
 411  
 
 412  
         public void setKeepFormat(boolean keepFormat) {
 413  0
                 this.keepFormat = keepFormat;
 414  0
         }
 415  
 
 416  
         public String getDelimiterType() {
 417  0
                 return delimiterType;
 418  
         }
 419  
 
 420  
         public void setDelimiterType(String delimiterType) {
 421  0
                 this.delimiterType = delimiterType;
 422  0
         }
 423  
 
 424  
         public String getDelimiter() {
 425  0
                 return delimiter;
 426  
         }
 427  
 
 428  
         public void setDelimiter(String delimiter) {
 429  0
                 this.delimiter = delimiter;
 430  0
         }
 431  
 
 432  
         public boolean isPrintResultSet() {
 433  0
                 return printResultSet;
 434  
         }
 435  
 
 436  
         public void setPrintResultSet(boolean printResultSet) {
 437  0
                 this.printResultSet = printResultSet;
 438  0
         }
 439  
 
 440  
         public String getOnError() {
 441  0
                 return onError;
 442  
         }
 443  
 
 444  
         public void setOnError(String onError) {
 445  0
                 this.onError = onError;
 446  0
         }
 447  
 
 448  
         public boolean isShowheaders() {
 449  0
                 return showheaders;
 450  
         }
 451  
 
 452  
         public void setShowheaders(boolean showheaders) {
 453  0
                 this.showheaders = showheaders;
 454  0
         }
 455  
 
 456  
         public String getOutputDelimiter() {
 457  0
                 return outputDelimiter;
 458  
         }
 459  
 
 460  
         public void setOutputDelimiter(String outputDelimiter) {
 461  0
                 this.outputDelimiter = outputDelimiter;
 462  0
         }
 463  
 
 464  
         public int getTotalStatements() {
 465  0
                 return totalStatements;
 466  
         }
 467  
 
 468  
         public void setTotalStatements(int totalStatements) {
 469  0
                 this.totalStatements = totalStatements;
 470  0
         }
 471  
 
 472  
         public int getSuccessfulStatements() {
 473  0
                 return successfulStatements;
 474  
         }
 475  
 
 476  
         public void setSuccessfulStatements(int successfulStatements) {
 477  0
                 this.successfulStatements = successfulStatements;
 478  0
         }
 479  
 
 480  
         public Connection getConn() {
 481  0
                 return conn;
 482  
         }
 483  
 
 484  
         public void setConn(Connection conn) {
 485  0
                 this.conn = conn;
 486  0
         }
 487  
 
 488  
         public Statement getStatement() {
 489  0
                 return statement;
 490  
         }
 491  
 
 492  
         public void setStatement(Statement statement) {
 493  0
                 this.statement = statement;
 494  0
         }
 495  
 
 496  
         public boolean isAutocommit() {
 497  0
                 return autocommit;
 498  
         }
 499  
 
 500  
         public void setAutocommit(boolean autocommit) {
 501  0
                 this.autocommit = autocommit;
 502  0
         }
 503  
 
 504  
         public boolean isEscapeProcessing() {
 505  0
                 return escapeProcessing;
 506  
         }
 507  
 
 508  
         public void setEscapeProcessing(boolean escapeProcessing) {
 509  0
                 this.escapeProcessing = escapeProcessing;
 510  0
         }
 511  
 
 512  
         public boolean isAppend() {
 513  0
                 return append;
 514  
         }
 515  
 
 516  
         public void setAppend(boolean append) {
 517  0
                 this.append = append;
 518  0
         }
 519  
 
 520  
         public boolean isSkipOnConnectionError() {
 521  0
                 return skipOnConnectionError;
 522  
         }
 523  
 
 524  
         public void setSkipOnConnectionError(boolean skipOnConnectionError) {
 525  0
                 this.skipOnConnectionError = skipOnConnectionError;
 526  0
         }
 527  
 
 528  
         public boolean isConnectionError() {
 529  0
                 return connectionError;
 530  
         }
 531  
 
 532  
         public void setConnectionError(boolean connectionError) {
 533  0
                 this.connectionError = connectionError;
 534  0
         }
 535  
 
 536  
         public List<DatabaseListener> getListeners() {
 537  0
                 return listeners;
 538  
         }
 539  
 
 540  
         public void setListeners(List<DatabaseListener> listeners) {
 541  0
                 this.listeners = listeners;
 542  0
         }
 543  
 
 544  
         public Vector<Transaction> getTransactions() {
 545  0
                 return transactions;
 546  
         }
 547  
 
 548  
         public void setTransactions(Vector<Transaction> transactions) {
 549  0
                 this.transactions = transactions;
 550  0
         }
 551  
 }