Ejemplo n.º 1
0
  /**
   * 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
      }
    }
  }