Mega Code Archive

 
Categories / Java / Database SQL JDBC
 

A general-purpose SQL interpreter program

/*  * Copyright (c) 2000 David Flanagan.  All rights reserved.  * This code is from the book Java Examples in a Nutshell, 2nd Edition.  * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.  * You may study, use, and modify it for any non-commercial purpose.  * You may distribute it non-commercially as long as you retain this notice.  * For a commercial use license, or to purchase the book (recommended),  * visit http://www.davidflanagan.com/javaexamples2.  */ import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.SQLWarning; import java.sql.Statement; /**  * A general-purpose SQL interpreter program.  */ public class ExecuteSQL {   public static void main(String[] args) {     Connection conn = null; // Our JDBC connection to the database server     try {       String driver = null, url = null, user = "", password = "";       // Parse all the command-line arguments       for (int n = 0; n < args.length; n++) {         if (args[n].equals("-d"))           driver = args[++n];         else if (args[n].equals("-u"))           user = args[++n];         else if (args[n].equals("-p"))           password = args[++n];         else if (url == null)           url = args[n];         else           throw new IllegalArgumentException("Unknown argument.");       }       // The only required argument is the database URL.       if (url == null)         throw new IllegalArgumentException("No database specified");       // If the user specified the classname for the DB driver, load       // that class dynamically. This gives the driver the opportunity       // to register itself with the DriverManager.       if (driver != null)         Class.forName(driver);       // Now open a connection the specified database, using the       // user-specified username and password, if any. The driver       // manager will try all of the DB drivers it knows about to try to       // parse the URL and connect to the DB server.       conn = DriverManager.getConnection(url, user, password);       // Now create the statement object we'll use to talk to the DB       Statement s = conn.createStatement();       // Get a stream to read from the console       BufferedReader in = new BufferedReader(new InputStreamReader(           System.in));       // Loop forever, reading the user's queries and executing them       while (true) {         System.out.print("sql> "); // prompt the user         System.out.flush(); // make the prompt appear now.         String sql = in.readLine(); // get a line of input from user         // Quit when the user types "quit".         if ((sql == null) || sql.equals("quit"))           break;         // Ignore blank lines         if (sql.length() == 0)           continue;         // Now, execute the user's line of SQL and display results.         try {           // We don't know if this is a query or some kind of           // update, so we use execute() instead of executeQuery()           // or executeUpdate() If the return value is true, it was           // a query, else an update.           boolean status = s.execute(sql);           // Some complex SQL queries can return more than one set           // of results, so loop until there are no more results           do {             if (status) { // it was a query and returns a ResultSet               ResultSet rs = s.getResultSet(); // Get results               printResultsTable(rs, System.out); // Display them             } else {               // If the SQL command that was executed was some               // kind of update rather than a query, then it               // doesn't return a ResultSet. Instead, we just               // print the number of rows that were affected.               int numUpdates = s.getUpdateCount();               System.out.println("Ok. " + numUpdates                   + " rows affected.");             }             // Now go see if there are even more results, and             // continue the results display loop if there are.             status = s.getMoreResults();           } while (status || s.getUpdateCount() != -1);         }         // If a SQLException is thrown, display an error message.         // Note that SQLExceptions can have a general message and a         // DB-specific message returned by getSQLState()         catch (SQLException e) {           System.err.println("SQLException: " + e.getMessage() + ":"               + e.getSQLState());         }         // Each time through this loop, check to see if there were any         // warnings. Note that there can be a whole chain of warnings.         finally { // print out any warnings that occurred           SQLWarning w;           for (w = conn.getWarnings(); w != null; w = w               .getNextWarning())             System.err.println("WARNING: " + w.getMessage() + ":"                 + w.getSQLState());         }       }     }     // Handle exceptions that occur during argument parsing, database     // connection setup, etc. For SQLExceptions, print the details.     catch (Exception e) {       System.err.println(e);       if (e instanceof SQLException)         System.err.println("SQL State: "             + ((SQLException) e).getSQLState());       System.err.println("Usage: java ExecuteSQL [-d <driver>] "           + "[-u <user>] [-p <password>] <database URL>");     }     // Be sure to always close the database connection when we exit,     // whether we exit because the user types 'quit' or because of an     // exception thrown while setting things up. Closing this connection     // also implicitly closes any open statements and result sets     // associated with it.     finally {       try {         conn.close();       } catch (Exception e) {       }     }   }   /**    * This method attempts to output the contents of a ResultSet in a textual    * table. It relies on the ResultSetMetaData class, but a fair bit of the    * code is simple string manipulation.    */   static void printResultsTable(ResultSet rs, OutputStream output)       throws SQLException {     // Set up the output stream     PrintWriter out = new PrintWriter(output);     // Get some "meta data" (column names, etc.) about the results     ResultSetMetaData metadata = rs.getMetaData();     // Variables to hold important data about the table to be displayed     int numcols = metadata.getColumnCount(); // how many columns     String[] labels = new String[numcols]; // the column labels     int[] colwidths = new int[numcols]; // the width of each     int[] colpos = new int[numcols]; // start position of each     int linewidth; // total width of table     // Figure out how wide the columns are, where each one begins,     // how wide each row of the table will be, etc.     linewidth = 1; // for the initial '|'.     for (int i = 0; i < numcols; i++) { // for each column       colpos[i] = linewidth; // save its position       labels[i] = metadata.getColumnLabel(i + 1); // get its label       // Get the column width. If the db doesn't report one, guess       // 30 characters. Then check the length of the label, and use       // it if it is larger than the column width       int size = metadata.getColumnDisplaySize(i + 1);       if (size == -1)         size = 30; // Some drivers return -1...       if (size > 500)         size = 30; // Don't allow unreasonable sizes       int labelsize = labels[i].length();       if (labelsize > size)         size = labelsize;       colwidths[i] = size + 1; // save the column the size       linewidth += colwidths[i] + 2; // increment total size     }     // Create a horizontal divider line we use in the table.     // Also create a blank line that is the initial value of each     // line of the table     StringBuffer divider = new StringBuffer(linewidth);     StringBuffer blankline = new StringBuffer(linewidth);     for (int i = 0; i < linewidth; i++) {       divider.insert(i, '-');       blankline.insert(i, " ");     }     // Put special marks in the divider line at the column positions     for (int i = 0; i < numcols; i++)       divider.setCharAt(colpos[i] - 1, '+');     divider.setCharAt(linewidth - 1, '+');     // Begin the table output with a divider line     out.println(divider);     // The next line of the table contains the column labels.     // Begin with a blank line, and put the column names and column     // divider characters "|" into it. overwrite() is defined below.     StringBuffer line = new StringBuffer(blankline.toString());     line.setCharAt(0, '|');     for (int i = 0; i < numcols; i++) {       int pos = colpos[i] + 1 + (colwidths[i] - labels[i].length()) / 2;       overwrite(line, pos, labels[i]);       overwrite(line, colpos[i] + colwidths[i], " |");     }     // Then output the line of column labels and another divider     out.println(line);     out.println(divider);     // Now, output the table data. Loop through the ResultSet, using     // the next() method to get the rows one at a time. Obtain the     // value of each column with getObject(), and output it, much as     // we did for the column labels above.     while (rs.next()) {       line = new StringBuffer(blankline.toString());       line.setCharAt(0, '|');       for (int i = 0; i < numcols; i++) {         Object value = rs.getObject(i + 1);         if (value != null)           overwrite(line, colpos[i] + 1, value.toString().trim());         overwrite(line, colpos[i] + colwidths[i], " |");       }       out.println(line);     }     // Finally, end the table with one last divider line.     out.println(divider);     out.flush();   }   /** This utility method is used when printing the table of results */   static void overwrite(StringBuffer b, int pos, String s) {     int slen = s.length(); // string length     int blen = b.length(); // buffer length     if (pos + slen > blen)       slen = blen - pos; // does it fit?     for (int i = 0; i < slen; i++)       // copy string into buffer       b.setCharAt(pos + i, s.charAt(i));   } }