| /* Copyright (C) 2004-2011 Scott Dunbar (scott@xigole.com) |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| * use this file except in compliance with the License. You may obtain a copy of |
| * the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package org.apache.util.sql; |
| |
| import java.io.BufferedReader; |
| import java.io.File; |
| import java.io.FileNotFoundException; |
| import java.io.FileReader; |
| import java.io.IOException; |
| import java.io.InputStreamReader; |
| import java.sql.Connection; |
| import java.sql.DatabaseMetaData; |
| import java.sql.Driver; |
| import java.sql.DriverManager; |
| import java.sql.DriverPropertyInfo; |
| import java.sql.ResultSet; |
| import java.sql.ResultSetMetaData; |
| import java.sql.SQLException; |
| import java.sql.Statement; |
| import java.util.Properties; |
| |
| import joptsimple.OptionParser; |
| import joptsimple.OptionSet; |
| |
| import org.apache.util.outputformatter.JisqlFormatter; |
| |
| /** |
| * A simple utility to provide an interactive session with a SQL server. This |
| * application is conceptually modeled on the Sybase 'isql' program with, |
| * obviously, strong similarities to Microsoft SQL/Server isql and osql (as |
| * Microsoft got SQL Server from Sybase). |
| * <p> |
| * |
| * The program can act in a similar way to Oracle's sqlplus and PostgreSQL's |
| * psql. |
| * <p> |
| * |
| * A simple command line might look like (this should be all on one line) is: <br> |
| * <code> |
| * java -classpath lib/jisql.jar:<file containing native driver> |
| * org.apache.util.sql.Jisql -user scott -password blah -driver postgresql |
| * -cstring jdbc:postgresql://localhost:5432/scott -c \; |
| * </code> |
| * <p> |
| * |
| * This logs into a PostgreSQL database as the user "scott", password "blah". It |
| * connects to the database named "scott". It uses the command terminator of |
| * ";", just like psql or sqlplus (which is escaped in the example so that it |
| * will not be interpreted by the Unix shell). If you do not use this the |
| * default is the term "go" on a single line like Sybase's isql or MS/SQL's |
| * isql/osql. Note that there is a dependency on <a |
| * href="http://jopt-simple.sourceforge.net/">JOpt Simple</a> in for the base |
| * configuration. |
| * |
| * |
| * Options: |
| * <ul> |
| * <li><b>-driver </b> This option allows you to specify the JDBC driver class |
| * name of the driver. There are several shortcuts that can be used: |
| * <ul> |
| * <li><b>jconnect4 </b>- short for <code>com.sybase.jdbc.SybDriver</code></li> |
| * <li><b>jconnect5 </b>- short for <code>com.sybase.jdbc2.jdbc.SybDriver</code> |
| * <li><b>jconnect6 </b>- short for <code>com.sybase.jdbc3.jdbc.SybDriver</code> |
| * </li> |
| * <li><b>oraclethin </b>- short for |
| * <code>oracle.jdbc.driver.OracleDriver</code></li> |
| * <li><b>db2app </b>- the DB2 "App" driver - |
| * <code>COM.ibm.db2.jdbc.app.DB2Driver</code></li> |
| * <li><b>db2net </b>- the DB2 "Net" driver - |
| * <code>COM.ibm.db2.jdbc.net.DB2Driver</code></li> |
| * <li><b>mssql </b>- short for |
| * <code>com.microsoft.jdbc.sqlserver.SQLServerDriver</code></li> |
| * <li><b>cloudscape </b>- short for <code>COM.cloudscape.core.JDBCDriver</code> |
| * </li> |
| * <li><b>pointbase </b>- short for |
| * <code>com.pointbase.jdbc.jdbcUniversalDriver</code></li> |
| * <li><b>postgresql </b>- short for <code>org.postgresql.Driver</code></li> |
| * <li><b>mysqlconj </b>- short for <code>com.mysql.jdbc.Driver</code>- the |
| * Connector/J driver for MySQL</li> |
| * <li><b>mysqlcaucho </b>- short for <code>com.caucho.jdbc.mysql.Driver</code>- |
| * the Caucho driver for MySQL</li> |
| * </ul> |
| * |
| * Alternatively, any class name can be specified here. The shortcuts only exist |
| * for those of us who generate more typos than real text :)</li> |
| * |
| * <li><b>-cstring </b> This option allows you to specify the connection string |
| * to the database. This string is driver specific but almost always starts with |
| * "jdbc:". Connection strings for the drivers I have tested look |
| * like: |
| * <ul> |
| * <li><b>jconnect4, jconnect5, jconnect6 </b>- Sybase connection strings take |
| * the form "jdbc:sybase:Tds:[hostname]:[port]/[db_name]"</li> |
| * <li><b>oraclethin </b>- The Oracle "thin" driver connection string |
| * looks like "jdbc:oracle:thin:@[hostname]:[port]:[oracle sid]"</li> |
| * <li><b>db2app </b>- The DB2 "App" driver connection string looks |
| * like "jdbc:db2:[db_name]"</li> |
| * <li><b>db2net </b>- The DB2 "Net" driver connection string looks |
| * like "jdbc:db2://[hostname]:[port]/[db_name]"</li> |
| * <li><b>mssql </b>- The MS/SQL driver connection string looks like |
| * "jdbc:microsoft:sqlserver://[hostname]:[port]/[db_name]"</li> |
| * <li><b>cloudscape </b>- The Cloudscape driver connection string looks like |
| * "jdbc:cloudscape:[db_name];create=true;autocommit=false"</li> |
| * <li><b>pointbase </b>- The Pointbase driver connection string looks like |
| * "jdbc:pointbase:server://[hostname]:[port]/[db_name]"</li> |
| * <li><b>postgresql </b>- The PostgreSQL driver connection string looks like |
| * "jdbc:postgresql://[hostname]:[port]/[db_name]"</li> |
| * <li><b>mysqlconj </b>- The MySQL Connector/J driver connection string looks |
| * like "jdbc:mysql://[hostname]:[port]/[db_name]"</li> |
| * <li><b>mysqlcaucho </b>- The MySQL Cahcho driver connection string looks like |
| * "jdbc:mysql-caucho://[hostname]:[port]/[db_name]"</li> |
| * </ul> |
| * |
| * <b>Important </b>- each JDBC vendor has other flags and parameters that can |
| * be passed on the connection string. You should look at the documentation for |
| * your JDBC driver for more information. The strings listed are just a sample |
| * and may change with a new release of the driver. None of these strings are |
| * coded within the application - the list is provided for reference only.</li> |
| * |
| * <li><b>-user or -u </b> The user name to use to log into the database with.</li> |
| * <li><b>-password or -p </b> The password to use to log into the database |
| * with. If this option is missing then the program asks for the password.</li> |
| * <li><b>-c </b> The "command terminator" to use. By default this |
| * application uses the string "go" (case insensitive) on a line by |
| * itself to determine when to send the string buffer to the database. You may |
| * specify something else with the -c option. For example, users of Oracle may |
| * prefer either the ";" (semi-colon) character or the "/" |
| * (forwardslash) character as that is what sqlplus uses. This string may occur |
| * as a standalone line or at the end of a particular line.</li> |
| * <li><b>-pf</b> Optional file to specify the password. This prevents having to |
| * have it visible when looking at a process status. The first line of the file |
| * is read and used as the password. If both the command line password and this |
| * option are specified the command line password is used.</li> |
| * <li><b>-input </b> The name of a file to read commands from instead of |
| * System.in.</li> |
| * <li><b>-query </b> An optional single query to run instead of interacting |
| * with the command line or a file. <b>Note</b> - the command <i>must</i> have a |
| * command terminator. So, for example, your command line may be something like |
| * "-c \; -query "select * from blah;". If you do not include the command |
| * terminator then the command will hang, waiting for you to enter the default |
| * "go".</li> |
| * <li><b>-debug </b> This turns on some internal debugging code. Not generally |
| * useful.</li> |
| * <li><b>-driverinfo </b> Allows you to print some information that the driver |
| * returns. Generally not very useful in all but a few cases.</li> |
| * <li><b>-formatter</b> Optionally specify a class name or short cut to format |
| * the output. There are three built in short cuts: |
| * <ul> |
| * <li><b>csv</b> output the data in CSV format.</li> |
| * <li><b>xml</b> output the data in XML format.</li> |
| * <li><b>default</b> (does not have to be specified) - output the format in the |
| * "normal" format.</li> |
| * </ul> |
| * Otherwise, this is a class name that implements |
| * org.apache.util.outputformatter.JisqlFormatter. See the code for more |
| * information on implementing your own output formatter.</li> |
| * </ul> |
| * <p> |
| * |
| * </p> |
| * The included default formatter supports the following command line options: |
| * <ul> |
| * <li><b>-noheader</b> do not print the header column info.</li> |
| * <li><b>-spacer</b> The character to use for "empty" space. This |
| * defaults to the space character. From mrider - "I added the ability to |
| * specify the spacer for columns - which used to be the single char ' '. I did |
| * this because of brain-dead Windows' command line copy/paste. It seems that |
| * when a line of text ends in space, copy does not copy that space. Which makes |
| * it difficult to copy/paste into another program. This can probably be ignored |
| * most of the time."</li> |
| * <li><b>-w</b>Specifies the maximum field width for a column. By default jisql |
| * defaults columns to a maximum width of 2048. By specifying a value |
| * for this jisql with truncate the output of columns that are wider than this |
| * parameter.</li> |
| * <li><b>-delimiter</b> Specify a single character delimiter for columns.</li> |
| * <li><b>-trim</b> trim the spaces from columns.</li> |
| * <li><b>-nonull</b> print an empty string instead of the word "NULL" |
| * when there is a null value. |
| * <li> |
| * <li><b>-left</b> left justify the output</li> |
| * <li><b>-debug</b> print debugging information about the result set.</li> |
| * </ul> |
| * <p> |
| * |
| * </p> |
| * The include CSV formatter supports the following command line options: |
| * <ul> |
| * <li><b>-delimiter</b> specifies the delimiter to use. By default a comma is |
| * used</li> |
| * <li><b>-colnames</b> if included then column names are printed as the first |
| * line of output. By default they are not included</li> |
| * </ul> |
| * <p> |
| * |
| * </p> |
| * The included XML formatter does not have any additional output options. |
| * <p> |
| * |
| * </p> |
| */ |
| public class Jisql { |
| //Sybase SQL Anywhere JDBC4-Type2 (Native) Driver |
| private static final String sapJDBC4SqlAnywhereDriverName= "sap.jdbc4.sqlanywhere.IDriver"; |
| private static final String sybaseJDBC4SqlAnywhereDriverName= "sybase.jdbc4.sqlanywhere.IDriver"; |
| private static final String sybaseJConnect6DriverName = "com.sybase.jdbc3.jdbc.SybDriver"; |
| private static final String sybaseJConnect5DriverName = "com.sybase.jdbc2.jdbc.SybDriver"; |
| private static final String sybaseJConnect4DriverName = "com.sybase.jdbc.SybDriver"; |
| private static final String oracleThinDriverName = "oracle.jdbc.driver.OracleDriver"; |
| private static final String db2AppDriverName = "COM.ibm.db2.jdbc.app.DB2Driver"; |
| private static final String db2NetDriverName = "COM.ibm.db2.jdbc.net.DB2Driver"; |
| private static final String cloudscapeDriverName = "COM.cloudscape.core.JDBCDriver"; |
| private static final String msqlDriverName = "com.microsoft.sqlserver.jdbc.SQLServerDriver"; |
| private static final String pointbaseDriverName = "com.pointbase.jdbc.jdbcUniversalDriver"; |
| private static final String postgresqlDriverName = "org.postgresql.Driver"; |
| private static final String mySQLConnectJDriverName = "com.mysql.jdbc.Driver"; |
| private static final String mySQLCauchoDriverName = "com.caucho.jdbc.mysql.Driver"; |
| |
| private static final String defaultFormatterClassName = "org.apache.util.outputformatter.DefaultFormatter"; |
| private static final String csvFormatterClassName = "org.apache.util.outputformatter.CSVFormatter"; |
| private static final String xmlFormatterClassName = "org.apache.util.outputformatter.XMLFormatter"; |
| |
| private String driverName = null; |
| private String connectString = null; |
| private String userName = null; |
| private String password = null; |
| private String passwordFileName = null; |
| private String formatterClassName = defaultFormatterClassName; |
| |
| private JisqlFormatter formatter = null; |
| |
| private Connection connection = null; |
| private boolean printDebug = false; |
| private boolean printDriverDetails = false; |
| private Driver driver = null; |
| private Properties props = null; |
| private String inputFileName = null; |
| private String commandTerminator = "go"; |
| private String inputQuery = null; |
| |
| /** |
| * Runs Jisql with the command line arguments provided. |
| * |
| */ |
| public static void main(String argv[]) { |
| Jisql jisql = new Jisql(); |
| |
| try { |
| jisql.parseArgs(argv); |
| } |
| catch (Throwable t) { |
| t.printStackTrace(); |
| jisql.usage(); |
| System.exit(1); |
| } |
| |
| try { |
| jisql.run(); |
| } |
| catch (Exception e) { |
| e.printStackTrace(); |
| System.exit(1); |
| } |
| |
| System.exit(0); |
| } |
| |
| public void run() throws Exception { |
| boolean isExit=false; |
| try { |
| driver = (Driver) Class.forName(driverName).newInstance(); |
| props = new Properties(); |
| |
| props.put("user", userName); |
| if (password != null) |
| props.put("password", password); |
| |
| connection = DriverManager.getConnection(connectString, props); |
| if (printDriverDetails) { |
| printDriverInfo(); |
| } |
| else { |
| if(connectString.toLowerCase().startsWith("jdbc:mysql") && inputFileName!=null){ |
| MySQLPLRunner scriptRunner = new MySQLPLRunner(connection, false, true,printDebug); |
| scriptRunner.setDelimiter(commandTerminator,false); |
| FileReader reader = new FileReader(inputFileName); |
| try { |
| scriptRunner.runScript(reader); |
| } |
| finally { |
| if (reader != null) { |
| try { |
| reader.close(); |
| } catch (IOException ioe) { |
| // Ignore error during closing of the reader stream |
| } |
| } |
| } |
| }else{ |
| doIsql(); |
| } |
| } |
| } |
| catch (SQLException sqle) { |
| printAllExceptions(sqle); |
| isExit=true; |
| } |
| catch (IOException ie) { |
| isExit=true; |
| } |
| catch (ClassNotFoundException cnfe) { |
| isExit=true; |
| System.err.println("Cannot find the driver class \"" + driverName + "\" in the current classpath."); |
| } |
| catch (InstantiationException ie) { |
| isExit=true; |
| System.err.println("Cannot instantiate the driver class \"" + driverName + "\""); |
| ie.printStackTrace(System.err); |
| } |
| catch (IllegalAccessException iae) { |
| isExit=true; |
| System.err.println("Cannot instantiate the driver class \"" + driverName + "\" because of an IllegalAccessException"); |
| iae.printStackTrace(System.err); |
| } |
| finally { |
| if (connection != null) { |
| try { |
| connection.close(); |
| } |
| catch (SQLException ignore) { |
| /* ignored */ |
| } |
| if(isExit){ |
| System.exit(1); |
| } |
| } |
| } |
| } |
| |
| /** |
| * The main loop for the Jisql program. This method handles the input from |
| * either a command line or from a file. Output is handled through the |
| * Formatter. |
| * |
| * @throws SQLException |
| * if an exception occurs. |
| * |
| */ |
| public void doIsql() throws IOException, SQLException { |
| BufferedReader reader = null; |
| Statement statement = null; |
| ResultSet resultSet = null; |
| ResultSetMetaData resultSetMetaData = null; |
| StringBuilder query = null; |
| |
| if (inputFileName != null) { |
| try { |
| reader = new BufferedReader(new FileReader(inputFileName)); |
| } |
| catch (FileNotFoundException fnfe) { |
| System.err.println("Unable to open file \"" + inputFileName + "\""); |
| fnfe.printStackTrace(System.err); |
| throw fnfe; |
| } |
| } |
| else { |
| reader = new BufferedReader(new InputStreamReader(System.in)); |
| } |
| if(printDebug) |
| printAllExceptions(connection.getWarnings()); |
| statement = connection.createStatement(); |
| connection.clearWarnings(); |
| String trimmedLine=null; |
| |
| try { |
| |
| while (true) { |
| int linecount = 1; |
| query = new StringBuilder(); |
| |
| try { |
| if ((inputFileName == null) && (inputQuery == null)) |
| System.out.print("\nEnter a query:\n"); |
| |
| while (true) { |
| if ((inputFileName == null) && (inputQuery == null)) { |
| System.out.print(linecount++ + " > "); |
| System.out.flush(); |
| } |
| |
| String line = null; |
| if (inputQuery == null) |
| line = reader.readLine(); |
| else |
| line = inputQuery.toString(); |
| |
| if (line == null || line.equalsIgnoreCase("quit") || line.equalsIgnoreCase("exit")){ |
| if ((inputFileName != null) && (inputQuery != null)) { |
| break; |
| }else{ |
| return; |
| } |
| } |
| |
| if (line.equals("reset")) { |
| query = new StringBuilder(); |
| break; |
| } |
| trimmedLine=line.trim(); |
| if (trimmedLine.startsWith("--") ||trimmedLine.length()<1) { |
| continue; |
| } |
| if(connectString.toLowerCase().startsWith("jdbc:oracle") && inputFileName!=null){ |
| if (trimmedLine.startsWith("/") ||trimmedLine.length()<2) { |
| commandTerminator=";"; |
| continue; |
| } |
| if (trimmedLine.toUpperCase().startsWith("DECLARE")) { |
| commandTerminator="/"; |
| } |
| if ((trimmedLine.toUpperCase().startsWith("CREATE OR REPLACE PROCEDURE")) || (trimmedLine.toUpperCase().startsWith("CREATE OR REPLACE FUNCTION"))) { |
| commandTerminator="/"; |
| } |
| } |
| if(connectString.toLowerCase().startsWith("jdbc:postgresql") && inputFileName!=null){ |
| if (trimmedLine.toLowerCase().startsWith("select 'delimiter start';")) { |
| commandTerminator="select 'delimiter end';"; |
| continue; |
| } |
| } |
| |
| if (line.trim().equalsIgnoreCase(commandTerminator) || line.trim().endsWith(commandTerminator)) { |
| if (line.trim().endsWith(commandTerminator)) { |
| line = line.substring(0, line.length() - commandTerminator.length()); |
| query.append("\n"); |
| query.append(line); |
| } |
| break; |
| } |
| |
| query.append("\n"); |
| query.append(line); |
| } |
| |
| if (query.toString().length() == 0) |
| continue; |
| |
| if (printDebug) |
| System.out.println("executing: " + query.toString()); |
| |
| boolean moreResults = statement.execute(query.toString()); |
| int rowsAffected = 0; |
| do { |
| if(printDebug) |
| printAllExceptions(statement.getWarnings()); |
| statement.clearWarnings(); |
| if (moreResults) { |
| resultSet = statement.getResultSet(); |
| if(printDebug) |
| printAllExceptions(resultSet.getWarnings()); |
| resultSet.clearWarnings(); |
| resultSetMetaData = resultSet.getMetaData(); |
| |
| formatter.formatHeader(System.out, resultSetMetaData); |
| formatter.formatData(System.out, resultSet, resultSetMetaData); |
| formatter.formatFooter(System.out, resultSetMetaData); |
| |
| int rowsSelected = statement.getUpdateCount(); |
| |
| if (rowsSelected >= 0 && printDebug) { |
| System.out.println(rowsSelected + " rows affected."); |
| } |
| } |
| else { |
| rowsAffected = statement.getUpdateCount(); |
| if (printDebug) |
| printAllExceptions(statement.getWarnings()); |
| statement.clearWarnings(); |
| if (rowsAffected >= 0 && printDebug) { |
| System.out.println(rowsAffected + " rows affected."); |
| } |
| } |
| |
| // |
| // I was having problems with the PostgreSQL driver throwing |
| // a NullPointerException here so I just catch it and tell |
| // the loop that it is done if it happens. |
| // |
| try { |
| moreResults = statement.getMoreResults(); |
| } |
| catch (NullPointerException npe) { |
| moreResults = false; |
| } |
| } |
| |
| while (moreResults || rowsAffected != -1); |
| } |
| catch (SQLException sqle) { |
| printAllExceptions(sqle); |
| statement.cancel(); |
| statement.clearWarnings(); |
| throw sqle; |
| } |
| catch (Exception e) { |
| e.printStackTrace(System.err); |
| } |
| |
| if (inputQuery != null) |
| return; |
| } |
| } |
| finally { |
| if (reader != null) { |
| try { |
| reader.close(); |
| } |
| catch(IOException ioe) { |
| // Ignore IOE when closing streams |
| } |
| } |
| if (resultSet != null) { |
| try { |
| resultSet.close(); |
| } catch (SQLException sqle) { |
| } |
| } |
| if (statement != null) { |
| try { |
| statement.close(); |
| } catch (SQLException sqle) { |
| // Ignore |
| } |
| } |
| } |
| } |
| |
| /** |
| * Prints some information about the JDBC driver in use. |
| * |
| * @throws SQLException |
| * if one of the methods called does. |
| * |
| */ |
| private void printDriverInfo() throws SQLException { |
| System.out.println("driver.getMajorVersion() is " + driver.getMajorVersion()); |
| System.out.println("driver.getMinorVersion() is " + driver.getMinorVersion()); |
| System.out.println("driver is " + (driver.jdbcCompliant() ? "" : "not ") + "JDBC compliant"); |
| |
| DriverPropertyInfo[] infos = driver.getPropertyInfo(connectString, props); |
| |
| for (DriverPropertyInfo info : infos) { |
| System.out.println("driver property named \"" + info.name + "\""); |
| if (info.choices != null) { |
| System.out.println("choices:"); |
| for (int j = 0; j < info.choices.length; j++) |
| System.out.println("\tchoice " + j + ": \"" + info.choices[j] + "\""); |
| } |
| System.out.println("description: \"" + info.description + "\""); |
| System.out.println("required parameter?: \"" + info.required + "\""); |
| System.out.println("current value: \"" + info.value + "\"\n"); |
| } |
| |
| DatabaseMetaData metaData = connection.getMetaData(); |
| |
| System.out.println("metaData.getDatabaseProductName(): \"" + metaData.getDatabaseProductName() + "\""); |
| System.out.println("metaData.getDatabaseProductVersion(): \"" + metaData.getDatabaseProductVersion() + "\""); |
| |
| System.out.println("metaData.getDriverName(): \"" + metaData.getDriverName() + "\""); |
| System.out.println("metaData.getDriverVersion(): \"" + metaData.getDriverVersion() + "\""); |
| } |
| |
| /** |
| * Parse the command line arguments. This method parses what is needed for |
| * the Jisql driver program and lets the configured formatter do the same. |
| * |
| * @param argv the command line arguments. |
| * |
| * @throws Exception if there are any errors parsing the command line arguments. |
| * |
| */ |
| public void parseArgs(String argv[]) throws Throwable { |
| // |
| // I'm sure that there has to be a better way but I couldn't find a |
| // command lineparser that would let me ignore unknown arguments. so |
| // walk through the list once to find the formatter. then, use the |
| // command line parser to do it "for real" |
| // |
| String passwordValue=null; |
| for (int argumentIndex = 0; argumentIndex < argv.length; argumentIndex++) { |
| if ("-p".equalsIgnoreCase(argv[argumentIndex]) || "-password".equalsIgnoreCase(argv[argumentIndex]) ) { |
| if(argv.length>argumentIndex + 1){ |
| passwordValue=argv[argumentIndex + 1]; |
| argv[argumentIndex + 1]=""; |
| break; |
| } |
| } |
| } |
| for (int argumentIndex = 0; argumentIndex < argv.length; argumentIndex++) { |
| if (argv[argumentIndex].equals("-formatter")) { |
| formatterClassName = argv[argumentIndex + 1]; |
| break; |
| } |
| } |
| |
| if (formatterClassName.compareToIgnoreCase("csv") == 0) |
| formatterClassName = csvFormatterClassName; |
| else if (formatterClassName.compareToIgnoreCase("xml") == 0) |
| formatterClassName = xmlFormatterClassName; |
| else if (formatterClassName.compareToIgnoreCase("default") == 0) |
| formatterClassName = defaultFormatterClassName; |
| |
| formatter = (JisqlFormatter) Class.forName(formatterClassName).newInstance(); |
| |
| OptionParser parser = new OptionParser(); |
| parser.posixlyCorrect(false); |
| |
| parser.accepts("c").withRequiredArg().ofType(String.class); |
| parser.accepts("cstring").withRequiredArg().ofType(String.class); |
| parser.accepts("debug"); |
| parser.accepts("driver").withRequiredArg().ofType(String.class); |
| parser.accepts("driverinfo"); |
| parser.accepts("formatter").withRequiredArg().ofType(String.class); |
| parser.accepts("help"); |
| parser.accepts("input").withRequiredArg().ofType(String.class); |
| parser.accepts("password").withOptionalArg().ofType(String.class); |
| parser.accepts("p").withOptionalArg().ofType(String.class); |
| parser.accepts("pf").withRequiredArg().ofType(String.class); |
| parser.accepts("query").withRequiredArg().ofType(String.class); |
| parser.accepts("user").withRequiredArg().ofType(String.class); |
| parser.accepts("u").withRequiredArg().ofType(String.class); |
| |
| formatter.setSupportedOptions(parser); |
| |
| OptionSet options = parser.parse(argv); |
| |
| if (options.has("help")) { |
| usage(); |
| System.exit(1); |
| } |
| |
| if (options.has("driver")) { |
| driverName = (String) options.valueOf("driver"); |
| |
| if (driverName.compareToIgnoreCase("jconnect4") == 0) |
| driverName = sybaseJConnect4DriverName; |
| else if (driverName.compareToIgnoreCase("jconnect5") == 0) |
| driverName = sybaseJConnect5DriverName; |
| else if (driverName.compareToIgnoreCase("jconnect6") == 0) |
| driverName = sybaseJConnect6DriverName; |
| else if (driverName.compareToIgnoreCase("oraclethin") == 0) |
| driverName = oracleThinDriverName; |
| else if (driverName.compareToIgnoreCase("db2app") == 0) |
| driverName = db2AppDriverName; |
| else if (driverName.compareToIgnoreCase("db2net") == 0) |
| driverName = db2NetDriverName; |
| else if (driverName.compareToIgnoreCase("cloudscape") == 0) |
| driverName = cloudscapeDriverName; |
| else if (driverName.compareToIgnoreCase("mssql") == 0) |
| driverName = msqlDriverName; |
| else if (driverName.compareToIgnoreCase("pointbase") == 0) |
| driverName = pointbaseDriverName; |
| else if (driverName.compareToIgnoreCase("postgresql") == 0) |
| driverName = postgresqlDriverName; |
| else if (driverName.compareToIgnoreCase("mysqlconj") == 0) |
| driverName = mySQLConnectJDriverName; |
| else if (driverName.compareToIgnoreCase("mysqlcaucho") == 0) |
| driverName = mySQLCauchoDriverName; |
| else if (driverName.compareToIgnoreCase("sapsajdbc4") == 0) |
| driverName = sapJDBC4SqlAnywhereDriverName; |
| else if (driverName.compareToIgnoreCase("sybasesajdbc4") == 0) |
| driverName = sybaseJDBC4SqlAnywhereDriverName; |
| } |
| |
| connectString = (String) options.valueOf("cstring"); |
| |
| if (options.has("c")) |
| commandTerminator = (String) options.valueOf("c"); |
| |
| if (options.has("debug")) |
| printDebug = true; |
| |
| if (options.has("user")) |
| userName = (String) options.valueOf("user"); |
| else if (options.has("u")) |
| userName = (String) options.valueOf("u"); |
| |
| password=passwordValue; |
| |
| if (options.has("driverinfo")) |
| printDriverDetails = true; |
| |
| if (options.has("input")) |
| inputFileName = (String) options.valueOf("input"); |
| |
| if (options.has("pf")) |
| passwordFileName = (String) options.valueOf("pf"); |
| |
| if (options.has("query")) |
| inputQuery = (String) options.valueOf("query"); |
| |
| if (driverName == null) |
| throw new Exception("driver name must exist"); |
| |
| if (connectString == null) |
| throw new Exception("connect string must exist"); |
| |
| if (userName == null) |
| throw new Exception("user name must exist"); |
| |
| if ((password == null) && (passwordFileName == null)) { |
| password=""; |
| } |
| else if (password == null) { |
| File passwordFile = null; |
| BufferedReader reader = null; |
| |
| passwordFile = new File(passwordFileName); |
| if (!passwordFile.exists()) |
| throw new Exception("the password file \"" + passwordFileName + "\" does not exist"); |
| |
| if (!passwordFile.isFile()) |
| throw new Exception("the password file \"" + passwordFileName + "\" is not a normal file"); |
| |
| if (!passwordFile.canRead()) |
| throw new Exception("the password file \"" + passwordFileName + "\" is not readable"); |
| |
| try { |
| reader = new BufferedReader(new FileReader(passwordFile)); |
| password = reader.readLine().trim(); |
| } |
| catch (Exception e) { |
| throw new Exception("An error occured reading the password file", e); |
| } |
| finally { |
| if (reader != null) { |
| try { |
| reader.close(); |
| } |
| catch (Exception ignore) { /* ignored */ |
| } |
| } |
| } |
| } |
| |
| formatter.consumeOptions(options); |
| } |
| |
| /** |
| * Walks through a SQLException and prints out every exception. |
| * |
| * @param sqle the Exception to print |
| * |
| */ |
| private void printAllExceptions(SQLException sqle) { |
| while (sqle != null) { |
| System.err.println("SQLException : " + "SQL state: " + sqle.getSQLState() + " " + sqle.toString() + " ErrorCode: " |
| + sqle.getErrorCode()); |
| sqle = sqle.getNextException(); |
| } |
| } |
| |
| /** |
| * Prints out the usage message for the Jisql driver and the configured |
| * formatter. |
| * |
| */ |
| private void usage() { |
| System.err.println(); |
| System.err.println("usage: java " + getClass().getName() + |
| " -driver driver -cstring connect_string -user|-u username -password|-p password [-pf password_file] " + |
| "[-c command_term] [-input file_name] [-debug] [-driverinfo] [-formatter formatter]"); |
| System.err.println("where:"); |
| System.err |
| .println("\t-driver specifies the JDBC driver to use. There are several builtin shortcuts - see the docs for details."); |
| System.err.println("\t-cstring specifies the connection string to use. These are driver specific."); |
| System.err.println("\t-user specifies a user name to log into a database server with."); |
| System.err.println("\t-password specifies the user name to log into a database server with."); |
| System.err.println("\t-pf specifies the name of a file that contains the password to log into a database server with."); |
| System.err.println("\t The first line of file should contain the password and nothing else."); |
| System.err.println("\t-c specifies the command terminator. The default is \"" + commandTerminator + "\""); |
| System.err.println("\t-input specifies a file name to read commands from."); |
| System.err |
| .println("\t-query specifies an optional single query to run instead of interacting with the command line or a file."); |
| System.err.println("\t Note that the command must include a command terminator or the command will hang"); |
| System.err.println("\t-debug prints to stdout (System.out) debugging information"); |
| System.err.println("\t-driverinfo prints to stdout (System.out) detailed driver information and then exits"); |
| System.err |
| .println("\t-formatter specifies either a class name or a pre-configured output formatter. See the docs for details."); |
| |
| if (formatter != null) { |
| System.err.println("Additional command line arguments of the " + formatter.getClass().getName() + " class are"); |
| formatter.usage(System.err); |
| } |
| |
| System.err.println(); |
| } |
| } |