/** * Connect to a JDBC Database and execute the commands given on stdin or in SQL file(s). * * <p>This method is changed for HSQLDB 1.8.0.8 and later to never System.exit(). Developers may * catch Throwables to handle all fatal situations. * * @param arg Run "java... org.hsqldb.cmdline.SqlTool --help" for syntax. * @throws SqlToolException Upon any fatal error, with useful reason as the exception's message. */ public static void objectMain(String[] arg) throws SqlToolException { logger.finer("Invoking SqlTool"); /* * The big picture is, we parse input args; load a RCData; * get a JDBC Connection with the RCData; instantiate and * execute as many SqlFiles as we need to. */ String rcFile = null; PipedReader tmpReader = null; String sqlText = null; String driver = null; String targetDb = null; boolean debug = false; File[] scriptFiles = null; int i = -1; boolean listMode = false; boolean interactive = false; boolean noinput = false; boolean noautoFile = false; boolean autoCommit = false; Boolean coeOverride = null; Boolean stdinputOverride = null; String rcParams = null; String rcUrl = null; String rcUsername = null; String rcPassword = null; String rcCharset = null; String rcTruststore = null; String rcTransIso = null; Map<String, String> rcFields = null; String parameter; SqlFile[] sqlFiles = null; Connection conn = null; Map<String, String> userVars = new HashMap<String, String>(); try { // Try block to GC tmpReader try { // Try block for BadCmdline while ((i + 1 < arg.length)) if (arg[i + 1].startsWith("--")) { i++; if (arg[i].length() == 2) { break; // "--" } parameter = arg[i].substring(2).toLowerCase(); if (parameter.equals("help")) { System.out.println( SqltoolRB.SqlTool_syntax.getString(revnum, RCData.DEFAULT_JDBC_DRIVER)); return; } if (parameter.equals("abortonerr")) { if (coeOverride != null) { throw new SqlToolException( SYNTAXERR_EXITVAL, SqltoolRB.SqlTool_abort_continue_mutuallyexclusive.getString()); } coeOverride = Boolean.FALSE; } else if (parameter.equals("continueonerr")) { if (coeOverride != null) { throw new SqlToolException( SYNTAXERR_EXITVAL, SqltoolRB.SqlTool_abort_continue_mutuallyexclusive.getString()); } coeOverride = Boolean.TRUE; } else if (parameter.startsWith("continueonerr=")) { if (coeOverride != null) { throw new SqlToolException( SYNTAXERR_EXITVAL, SqltoolRB.SqlTool_abort_continue_mutuallyexclusive.getString()); } coeOverride = Boolean.valueOf(arg[i].substring("--continueonerr=".length())); } else if (parameter.equals("list")) { if (listMode) { throw new SqlToolException( SYNTAXERR_EXITVAL, SqltoolRB.SqlTool_params_redundant.getString()); } listMode = true; } else if (parameter.equals("rcfile")) { if (++i == arg.length) { throw bcl; } if (rcFile != null) { throw new SqlToolException( SYNTAXERR_EXITVAL, SqltoolRB.SqlTool_params_redundant.getString()); } rcFile = arg[i]; } else if (parameter.startsWith("rcfile=")) { if (rcFile != null) { throw new SqlToolException( SYNTAXERR_EXITVAL, SqltoolRB.SqlTool_params_redundant.getString()); } rcFile = arg[i].substring("--rcfile=".length()); } else if (parameter.equals("setvar")) { if (++i == arg.length) { throw bcl; } try { varParser(arg[i], userVars, false); } catch (PrivateException pe) { throw new SqlToolException(RCERR_EXITVAL, pe.getMessage()); } } else if (parameter.startsWith("setvar=")) { try { varParser(arg[i].substring("--setvar=".length()), userVars, false); } catch (PrivateException pe) { throw new SqlToolException(RCERR_EXITVAL, pe.getMessage()); } } else if (parameter.equals("sql")) { noinput = true; // but turn back on if file "-" specd. if (++i == arg.length) { throw bcl; } if (sqlText != null) { throw new SqlToolException( SYNTAXERR_EXITVAL, SqltoolRB.SqlTool_params_redundant.getString()); } sqlText = arg[i]; } else if (parameter.startsWith("sql=")) { noinput = true; // but turn back on if file "-" specd. if (sqlText != null) { throw new SqlToolException( SYNTAXERR_EXITVAL, SqltoolRB.SqlTool_params_redundant.getString()); } sqlText = arg[i].substring("--sql=".length()); } else if (parameter.equals("debug")) { if (debug) { throw new SqlToolException( SYNTAXERR_EXITVAL, SqltoolRB.SqlTool_params_redundant.getString()); } debug = true; } else if (parameter.equals("noautofile")) { if (noautoFile) { throw new SqlToolException( SYNTAXERR_EXITVAL, SqltoolRB.SqlTool_params_redundant.getString()); } noautoFile = true; } else if (parameter.equals("autocommit")) { if (autoCommit) { throw new SqlToolException( SYNTAXERR_EXITVAL, SqltoolRB.SqlTool_params_redundant.getString()); } autoCommit = true; } else if (parameter.equals("stdinput")) { noinput = false; if (stdinputOverride != null) { throw new SqlToolException( SYNTAXERR_EXITVAL, SqltoolRB.SqlTool_params_redundant.getString()); } stdinputOverride = Boolean.TRUE; } else if (parameter.equals("noinput")) { noinput = true; if (stdinputOverride != null) { throw new SqlToolException( SYNTAXERR_EXITVAL, SqltoolRB.SqlTool_params_redundant.getString()); } stdinputOverride = Boolean.FALSE; } else if (parameter.equals("driver")) { if (++i == arg.length) { throw bcl; } if (driver != null) { throw new SqlToolException( SYNTAXERR_EXITVAL, SqltoolRB.SqlTool_params_redundant.getString()); } driver = arg[i]; } else if (parameter.startsWith("driver=")) { if (driver != null) { throw new SqlToolException( SYNTAXERR_EXITVAL, SqltoolRB.SqlTool_params_redundant.getString()); } driver = arg[i].substring("--driver=".length()); } else if (parameter.equals("inlinerc")) { if (++i == arg.length) { throw bcl; } if (rcParams != null) { throw new SqlToolException( SYNTAXERR_EXITVAL, SqltoolRB.SqlTool_params_redundant.getString()); } rcParams = arg[i]; } else if (parameter.startsWith("inlinerc=")) { if (rcParams != null) { throw new SqlToolException( SYNTAXERR_EXITVAL, SqltoolRB.SqlTool_params_redundant.getString()); } rcParams = arg[i].substring("--inlinerc=".length()); } else { throw bcl; } } else if (arg[i + 1].startsWith("-P") || arg[i + 1].startsWith("-p")) { i++; boolean sepSwitch = arg[i].length() < 3; if (sepSwitch) { if (++i == arg.length) { throw bcl; } } int equalAt = arg[i].indexOf('='); if (equalAt < (sepSwitch ? 1 : 3)) { throw new SqlToolException(RCERR_EXITVAL, "Specified var assignment contains no '='"); } userVars.put( arg[i].substring(sepSwitch ? 0 : 2, equalAt), arg[i].substring(equalAt + 1)); } else { break; } if (!listMode && rcParams == null && ++i != arg.length) { // If an inline RC file was specified, don't look for targetDb targetDb = arg[i]; if (targetDb.equals("-")) targetDb = null; } int scriptIndex = 0; if (sqlText != null) { try { tmpReader = new PipedReader(); PipedWriter tmpWriter = new PipedWriter(tmpReader); // My best guess is that the encoding here will be however // we read the SQL text from the command-line, which will // be the platform default encoding. Therefore, don't // specify an encoding for this pipe. try { tmpWriter.write(sqlText + LS); tmpWriter.flush(); } finally { try { tmpWriter.close(); } finally { tmpWriter = null; // Encourage GC of buffers } } } catch (IOException ioe) { throw new SqlToolException( IOERR_EXITVAL, SqltoolRB.sqltempfile_fail.getString(ioe.toString())); } } if (stdinputOverride != null) { noinput = !stdinputOverride.booleanValue(); } interactive = (!noinput) && (arg.length <= i + 1); if (arg.length == i + 2 && arg[i + 1].equals("-")) { if (stdinputOverride == null) { noinput = false; } } else if (arg.length > i + 1) { // I.e., if there are any SQL files specified. scriptFiles = new File [arg.length - i - 1 + ((stdinputOverride == null || !stdinputOverride.booleanValue()) ? 0 : 1)]; if (debug) { System.err.println("scriptFiles has " + scriptFiles.length + " elements"); } while (i + 1 < arg.length) { scriptFiles[scriptIndex++] = new File(arg[++i]); } if (stdinputOverride != null && stdinputOverride.booleanValue()) { scriptFiles[scriptIndex++] = null; noinput = true; } } } catch (BadCmdline bcle) { throw new SqlToolException( SYNTAXERR_EXITVAL, SqltoolRB.SqlTool_syntax.getString(revnum, RCData.DEFAULT_JDBC_DRIVER)); } RCData conData = null; // Use the inline RC file if it was specified if (rcParams != null) { rcFields = new HashMap<String, String>(); try { varParser(rcParams, rcFields, true); } catch (PrivateException e) { throw new SqlToolException(SYNTAXERR_EXITVAL, e.getMessage()); } rcUrl = rcFields.remove("url"); rcUsername = rcFields.remove("user"); rcCharset = rcFields.remove("charset"); rcTruststore = rcFields.remove("truststore"); rcPassword = rcFields.remove("password"); rcTransIso = rcFields.remove("transiso"); // Don't ask for password if what we have already is invalid! if (rcUrl == null || rcUrl.length() < 1) throw new SqlToolException(RCERR_EXITVAL, SqltoolRB.rcdata_inlineurl_missing.getString()); // We now allow both null and "" user name, but we require password // if the user name != null. if (rcPassword != null && rcPassword.length() > 0) throw new SqlToolException(RCERR_EXITVAL, SqltoolRB.rcdata_password_visible.getString()); if (rcFields.size() > 0) { throw new SqlToolException( INPUTERR_EXITVAL, SqltoolRB.rcdata_inline_extravars.getString(rcFields.keySet().toString())); } if (rcUsername != null && rcPassword == null) try { rcPassword = promptForPassword(rcUsername); } catch (PrivateException e) { throw new SqlToolException( INPUTERR_EXITVAL, SqltoolRB.password_readfail.getString(e.getMessage())); } try { conData = new RCData( CMDLINE_ID, rcUrl, rcUsername, rcPassword, driver, rcCharset, rcTruststore, null, rcTransIso); } catch (RuntimeException re) { throw re; // Unrecoverable } catch (Exception e) { throw new SqlToolException( RCERR_EXITVAL, SqltoolRB.rcdata_genfromvalues_fail.getString()); } } else if (listMode || targetDb != null) { try { conData = new RCData(new File((rcFile == null) ? DEFAULT_RCFILE : rcFile), targetDb); } catch (RuntimeException re) { throw re; // Unrecoverable } catch (Exception e) { throw new SqlToolException( RCERR_EXITVAL, SqltoolRB.conndata_retrieval_fail.getString(targetDb, e.getMessage())); } } // if (debug) { // conData.report(); // } if (listMode) { // listMode has been handled above. // Just returning here to prevent unexpected consequences if the // user specifies both an inline RC (will will be ignored) and // --list. return; } if (interactive) System.out.print("SqlTool v. " + revnum + '.' + LS); if (conData != null) try { conn = conData.getConnection(driver, System.getProperty("javax.net.ssl.trustStore")); conn.setAutoCommit(autoCommit); String conBanner; if (interactive && (conBanner = SqlFile.getBanner(conn)) != null) { System.out.println(conBanner); } } catch (RuntimeException re) { throw re; // Unrecoverable } catch (Exception e) { if (debug) logger.error(e.getClass().getName(), e); // Let's not continue as if nothing is wrong. String reportUser = (conData.username == null) ? "<DFLTUSER>" : conData.username; throw new SqlToolException( CONNECTERR_EXITVAL, SqltoolRB.connection_fail.getString(conData.url, reportUser, e.getMessage())); } File[] emptyFileArray = {}; File[] singleNullFileArray = {null}; File autoFile = null; if (interactive && !noautoFile) { autoFile = new File(System.getProperty("user.home") + "/auto.sql"); if ((!autoFile.isFile()) || !autoFile.canRead()) { autoFile = null; } } if (scriptFiles == null) { // I.e., if no SQL files given on command-line. // Input file list is either nothing or {null} to read stdin. scriptFiles = (noinput ? emptyFileArray : singleNullFileArray); } int numFiles = scriptFiles.length; if (tmpReader != null) { numFiles += 1; } if (autoFile != null) { numFiles += 1; } sqlFiles = new SqlFile[numFiles]; // We print version before execing this one. int interactiveFileIndex = -1; String encoding = (conData == null) ? null : conData.charset; try { int fileIndex = 0; if (autoFile != null) { sqlFiles[fileIndex++] = new SqlFile(autoFile, encoding); } if (tmpReader != null) { sqlFiles[fileIndex++] = new SqlFile(tmpReader, "--sql", System.out, null, false, null); } for (File scriptFile : scriptFiles) { if (interactiveFileIndex < 0 && interactive) { interactiveFileIndex = fileIndex; } sqlFiles[fileIndex++] = (scriptFile == null) ? (new SqlFile(encoding, interactive)) : (new SqlFile(scriptFile, encoding, interactive)); } } catch (IOException ioe) { try { if (conn != null) conn.close(); } catch (Exception e) { // Can only report on so many errors at one time } throw new SqlToolException(FILEERR_EXITVAL, ioe.getMessage()); } } finally { // DO NOT close tmpReader, since SqlFile needs to read from it // (and will auto-close it). tmpReader = null; // Encourage GC of buffers } Map<String, Token> macros = null; try { for (SqlFile sqlFile : sqlFiles) { if (conn != null) sqlFile.setConnection(conn); if (userVars.size() > 0) sqlFile.addUserVars(userVars); if (macros != null) sqlFile.addMacros(macros); if (coeOverride != null) sqlFile.setContinueOnError(coeOverride.booleanValue()); sqlFile.execute(); userVars = sqlFile.getUserVars(); macros = sqlFile.getMacros(); conn = sqlFile.getConnection(); } // Following two Exception types are handled properly inside of // SqlFile. We just need to return an appropriate error status. } catch (SqlToolError ste) { throw new SqlToolException(SQLTOOLERR_EXITVAL); } catch (SQLException se) { // SqlTool will only throw an SQLException if it is in // "\c false" mode. throw new SqlToolException(SQLERR_EXITVAL); } finally { try { if (conn != null) conn.close(); } catch (Exception e) { // Purposefully doing nothing } } }