Repository: hive Updated Branches: refs/heads/master d7f043a44 -> 26b84ffab
HIVE-14001: beeline doesn't give out an error when takes either "-e" or "-f" in command instead of both (Peter Vary, reviewed by Sergio Pena) Project: http://git-wip-us.apache.org/repos/asf/hive/repo Commit: http://git-wip-us.apache.org/repos/asf/hive/commit/26b84ffa Tree: http://git-wip-us.apache.org/repos/asf/hive/tree/26b84ffa Diff: http://git-wip-us.apache.org/repos/asf/hive/diff/26b84ffa Branch: refs/heads/master Commit: 26b84ffab379b5951906c5e138dde3eb0e932a97 Parents: d7f043a Author: Peter Vary <[email protected]> Authored: Wed Jun 22 11:26:00 2016 -0500 Committer: Sergio Pena <[email protected]> Committed: Wed Jun 22 11:26:00 2016 -0500 ---------------------------------------------------------------------- .../java/org/apache/hive/beeline/BeeLine.java | 5 + .../org/apache/hive/beeline/BeeLine.java.orig | 2213 ++++++++++++++++++ .../hive/beeline/TestBeelineArgParsing.java | 10 + 3 files changed, 2228 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/hive/blob/26b84ffa/beeline/src/java/org/apache/hive/beeline/BeeLine.java ---------------------------------------------------------------------- diff --git a/beeline/src/java/org/apache/hive/beeline/BeeLine.java b/beeline/src/java/org/apache/hive/beeline/BeeLine.java index d02ea84..66185f6 100644 --- a/beeline/src/java/org/apache/hive/beeline/BeeLine.java +++ b/beeline/src/java/org/apache/hive/beeline/BeeLine.java @@ -766,6 +766,11 @@ public class BeeLine implements Closeable { commands = Arrays.asList(cl.getOptionValues('e')); } + if (!commands.isEmpty() && getOpts().getScriptFile() != null) { + System.err.println("The '-e' and '-f' options cannot be specified simultaneously"); + return 1; + } + // TODO: temporary disable this for easier debugging /* if (url == null) { http://git-wip-us.apache.org/repos/asf/hive/blob/26b84ffa/beeline/src/java/org/apache/hive/beeline/BeeLine.java.orig ---------------------------------------------------------------------- diff --git a/beeline/src/java/org/apache/hive/beeline/BeeLine.java.orig b/beeline/src/java/org/apache/hive/beeline/BeeLine.java.orig new file mode 100644 index 0000000..d02ea84 --- /dev/null +++ b/beeline/src/java/org/apache/hive/beeline/BeeLine.java.orig @@ -0,0 +1,2213 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/* + * This source file is based on code taken from SQLLine 1.0.2 + * See SQLLine notice in LICENSE + */ +package org.apache.hive.beeline; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.Closeable; +import java.io.EOFException; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import java.io.SequenceInputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.net.JarURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.Driver; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.SQLWarning; +import java.sql.Statement; +import java.text.ChoiceFormat; +import java.text.MessageFormat; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Properties; +import java.util.ResourceBundle; +import java.util.Set; +import java.util.SortedSet; +import java.util.StringTokenizer; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.jar.Attributes; +import java.util.jar.Manifest; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import jline.console.completer.Completer; +import jline.console.completer.StringsCompleter; +import jline.console.completer.FileNameCompleter; +import jline.console.ConsoleReader; +import jline.console.history.History; +import jline.console.history.FileHistory; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.GnuParser; +import org.apache.commons.cli.OptionBuilder; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.apache.hadoop.fs.FSDataInputStream; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.hive.conf.HiveConf; +import org.apache.hadoop.io.IOUtils; +import org.apache.hive.beeline.cli.CliOptionsProcessor; +import org.apache.thrift.transport.TTransportException; + +import org.apache.hive.jdbc.Utils; +import org.apache.hive.jdbc.Utils.JdbcConnectionParams; + +/** + * A console SQL shell with command completion. + * <p> + * TODO: + * <ul> + * <li>User-friendly connection prompts</li> + * <li>Page results</li> + * <li>Handle binary data (blob fields)</li> + * <li>Implement command aliases</li> + * <li>Stored procedure execution</li> + * <li>Binding parameters to prepared statements</li> + * <li>Scripting language</li> + * <li>XA transactions</li> + * </ul> + * + */ +@SuppressWarnings("static-access") +public class BeeLine implements Closeable { + private static final ResourceBundle resourceBundle = + ResourceBundle.getBundle(BeeLine.class.getSimpleName()); + private final BeeLineSignalHandler signalHandler = null; + private static final String separator = System.getProperty("line.separator"); + private boolean exit = false; + private final DatabaseConnections connections = new DatabaseConnections(); + public static final String COMMAND_PREFIX = "!"; + private Collection<Driver> drivers = null; + private final BeeLineOpts opts = new BeeLineOpts(this, System.getProperties()); + private String lastProgress = null; + private final Map<SQLWarning, Date> seenWarnings = new HashMap<SQLWarning, Date>(); + private final Commands commands = new Commands(this); + private OutputFile scriptOutputFile = null; + private OutputFile recordOutputFile = null; + private PrintStream outputStream = new PrintStream(System.out, true); + private PrintStream errorStream = new PrintStream(System.err, true); + private ConsoleReader consoleReader; + private List<String> batch = null; + private final Reflector reflector = new Reflector(this); + private String dbName = null; + private String currentDatabase = null; + + private History history; + private boolean isBeeLine = true; + + private static final Options options = new Options(); + + public static final String BEELINE_DEFAULT_JDBC_DRIVER = "org.apache.hive.jdbc.HiveDriver"; + public static final String DEFAULT_DATABASE_NAME = "default"; + + private static final String SCRIPT_OUTPUT_PREFIX = ">>>"; + private static final int SCRIPT_OUTPUT_PAD_SIZE = 5; + + private static final int ERRNO_OK = 0; + private static final int ERRNO_ARGS = 1; + private static final int ERRNO_OTHER = 2; + + private static final String HIVE_VAR_PREFIX = "--hivevar"; + private static final String HIVE_CONF_PREFIX = "--hiveconf"; + private static final String PROP_FILE_PREFIX = "--property-file"; + static final String PASSWD_MASK = "[passwd stripped]"; + + private final Map<Object, Object> formats = map(new Object[] { + "vertical", new VerticalOutputFormat(this), + "table", new TableOutputFormat(this), + "csv2", new SeparatedValuesOutputFormat(this, ','), + "tsv2", new SeparatedValuesOutputFormat(this, '\t'), + "dsv", new SeparatedValuesOutputFormat(this, BeeLineOpts.DEFAULT_DELIMITER_FOR_DSV), + "csv", new DeprecatedSeparatedValuesOutputFormat(this, ','), + "tsv", new DeprecatedSeparatedValuesOutputFormat(this, '\t'), + "xmlattr", new XMLAttributeOutputFormat(this), + "xmlelements", new XMLElementOutputFormat(this), + }); + + private List<String> supportedLocalDriver = + new ArrayList<String>(Arrays.asList("com.mysql.jdbc.Driver", "org.postgresql.Driver")); + + final CommandHandler[] commandHandlers = new CommandHandler[] { + new ReflectiveCommandHandler(this, new String[] {"quit", "done", "exit"}, + null), + new ReflectiveCommandHandler(this, new String[] {"connect", "open"}, + new Completer[] {new StringsCompleter(getConnectionURLExamples())}), + new ReflectiveCommandHandler(this, new String[] {"describe"}, + new Completer[] {new TableNameCompletor(this)}), + new ReflectiveCommandHandler(this, new String[] {"indexes"}, + new Completer[] {new TableNameCompletor(this)}), + new ReflectiveCommandHandler(this, new String[] {"primarykeys"}, + new Completer[] {new TableNameCompletor(this)}), + new ReflectiveCommandHandler(this, new String[] {"exportedkeys"}, + new Completer[] {new TableNameCompletor(this)}), + new ReflectiveCommandHandler(this, new String[] {"manual"}, + null), + new ReflectiveCommandHandler(this, new String[] {"importedkeys"}, + new Completer[] {new TableNameCompletor(this)}), + new ReflectiveCommandHandler(this, new String[] {"procedures"}, + null), + new ReflectiveCommandHandler(this, new String[] {"tables"}, + null), + new ReflectiveCommandHandler(this, new String[] {"typeinfo"}, + null), + new ReflectiveCommandHandler(this, new String[] {"columns"}, + new Completer[] {new TableNameCompletor(this)}), + new ReflectiveCommandHandler(this, new String[] {"reconnect"}, + null), + new ReflectiveCommandHandler(this, new String[] {"dropall"}, + new Completer[] {new TableNameCompletor(this)}), + new ReflectiveCommandHandler(this, new String[] {"history"}, + null), + new ReflectiveCommandHandler(this, new String[] {"metadata"}, + new Completer[] { + new StringsCompleter(getMetadataMethodNames())}), + new ReflectiveCommandHandler(this, new String[] {"nativesql"}, + null), + new ReflectiveCommandHandler(this, new String[] {"dbinfo"}, + null), + new ReflectiveCommandHandler(this, new String[] {"rehash"}, + null), + new ReflectiveCommandHandler(this, new String[] {"verbose"}, + null), + new ReflectiveCommandHandler(this, new String[] {"run"}, + new Completer[] {new FileNameCompleter()}), + new ReflectiveCommandHandler(this, new String[] {"batch"}, + null), + new ReflectiveCommandHandler(this, new String[] {"list"}, + null), + new ReflectiveCommandHandler(this, new String[] {"all"}, + null), + new ReflectiveCommandHandler(this, new String[] {"go", "#"}, + null), + new ReflectiveCommandHandler(this, new String[] {"script"}, + new Completer[] {new FileNameCompleter()}), + new ReflectiveCommandHandler(this, new String[] {"record"}, + new Completer[] {new FileNameCompleter()}), + new ReflectiveCommandHandler(this, new String[] {"brief"}, + null), + new ReflectiveCommandHandler(this, new String[] {"close"}, + null), + new ReflectiveCommandHandler(this, new String[] {"closeall"}, + null), + new ReflectiveCommandHandler(this, new String[] {"isolation"}, + new Completer[] {new StringsCompleter(getIsolationLevels())}), + new ReflectiveCommandHandler(this, new String[] {"outputformat"}, + new Completer[] {new StringsCompleter( + formats.keySet().toArray(new String[0]))}), + new ReflectiveCommandHandler(this, new String[] {"autocommit"}, + null), + new ReflectiveCommandHandler(this, new String[] {"commit"}, + null), + new ReflectiveCommandHandler(this, new String[] {"properties"}, + new Completer[] {new FileNameCompleter()}), + new ReflectiveCommandHandler(this, new String[] {"rollback"}, + null), + new ReflectiveCommandHandler(this, new String[] {"help", "?"}, + null), + new ReflectiveCommandHandler(this, new String[] {"set"}, + getOpts().optionCompleters()), + new ReflectiveCommandHandler(this, new String[] {"save"}, + null), + new ReflectiveCommandHandler(this, new String[] {"scan"}, + null), + new ReflectiveCommandHandler(this, new String[] {"sql"}, + null), + new ReflectiveCommandHandler(this, new String[] {"sh"}, + null), + new ReflectiveCommandHandler(this, new String[] {"call"}, + null), + new ReflectiveCommandHandler(this, new String[] {"nullemptystring"}, + new Completer[] {new BooleanCompleter()}), + new ReflectiveCommandHandler(this, new String[]{"addlocaldriverjar"}, + null), + new ReflectiveCommandHandler(this, new String[]{"addlocaldrivername"}, + null) + }; + + private final Completer beeLineCommandCompleter = new BeeLineCommandCompleter(Arrays.asList(commandHandlers)); + + static final SortedSet<String> KNOWN_DRIVERS = new TreeSet<String>(Arrays.asList( + new String[] { + "org.apache.hive.jdbc.HiveDriver", + "org.apache.hadoop.hive.jdbc.HiveDriver", + })); + + + static { + try { + Class.forName("jline.console.ConsoleReader"); + } catch (Throwable t) { + throw new ExceptionInInitializerError("jline-missing"); + } + } + + static { + // -d <driver class> + options.addOption(OptionBuilder + .hasArg() + .withArgName("driver class") + .withDescription("the driver class to use") + .create('d')); + + // -u <database url> + options.addOption(OptionBuilder + .hasArg() + .withArgName("database url") + .withDescription("the JDBC URL to connect to") + .create('u')); + + // -r + options.addOption(OptionBuilder + .withLongOpt("reconnect") + .withDescription("Reconnect to last saved connect url (in conjunction with !save)") + .create('r')); + + // -n <username> + options.addOption(OptionBuilder + .hasArg() + .withArgName("username") + .withDescription("the username to connect as") + .create('n')); + + // -p <password> + options.addOption(OptionBuilder + .hasArg() + .withArgName("password") + .withDescription("the password to connect as") + .create('p')); + + // -w (or) --password-file <file> + options.addOption(OptionBuilder + .hasArg() + .withArgName("password-file") + .withDescription("the password file to read password from") + .withLongOpt("password-file") + .create('w')); + + // -a <authType> + options.addOption(OptionBuilder + .hasArg() + .withArgName("authType") + .withDescription("the authentication type") + .create('a')); + + // -i <init file> + options.addOption(OptionBuilder + .hasArg() + .withArgName("init") + .withDescription("script file for initialization") + .create('i')); + + // -e <query> + options.addOption(OptionBuilder + .hasArgs() + .withArgName("query") + .withDescription("query that should be executed") + .create('e')); + + // -f <script file> + options.addOption(OptionBuilder + .hasArg() + .withArgName("file") + .withDescription("script file that should be executed") + .create('f')); + + // -help + options.addOption(OptionBuilder + .withLongOpt("help") + .withDescription("display this message") + .create('h')); + + // Substitution option --hivevar + options.addOption(OptionBuilder + .withValueSeparator() + .hasArgs(2) + .withArgName("key=value") + .withLongOpt("hivevar") + .withDescription("hive variable name and value") + .create()); + + //hive conf option --hiveconf + options.addOption(OptionBuilder + .withValueSeparator() + .hasArgs(2) + .withArgName("property=value") + .withLongOpt("hiveconf") + .withDescription("Use value for given property") + .create()); + + // --property-file <file> + options.addOption(OptionBuilder + .hasArg() + .withLongOpt("property-file") + .withDescription("the file to read configuration properties from") + .create()); + } + + + static Manifest getManifest() throws IOException { + URL base = BeeLine.class.getResource("/META-INF/MANIFEST.MF"); + URLConnection c = base.openConnection(); + if (c instanceof JarURLConnection) { + return ((JarURLConnection) c).getManifest(); + } + return null; + } + + + String getManifestAttribute(String name) { + try { + Manifest m = getManifest(); + if (m == null) { + return "??"; + } + + Attributes attrs = m.getAttributes("beeline"); + if (attrs == null) { + return "???"; + } + + String val = attrs.getValue(name); + if (val == null || "".equals(val)) { + return "????"; + } + + return val; + } catch (Exception e) { + e.printStackTrace(errorStream); + return "?????"; + } + } + + + String getApplicationTitle() { + Package pack = BeeLine.class.getPackage(); + + return loc("app-introduction", new Object[] { "Beeline", + pack.getImplementationVersion() == null ? "???" : pack.getImplementationVersion(), + "Apache Hive", + // getManifestAttribute ("Specification-Title"), + // getManifestAttribute ("Implementation-Version"), + // getManifestAttribute ("Implementation-ReleaseDate"), + // getManifestAttribute ("Implementation-Vendor"), + // getManifestAttribute ("Implementation-License"), + }); + } + + String getApplicationContactInformation() { + return getManifestAttribute("Implementation-Vendor"); + } + + String loc(String res) { + return loc(res, new Object[0]); + } + + String loc(String res, int param) { + try { + return MessageFormat.format( + new ChoiceFormat(resourceBundle.getString(res)).format(param), + new Object[] {new Integer(param)}); + } catch (Exception e) { + return res + ": " + param; + } + } + + String loc(String res, Object param1) { + return loc(res, new Object[] {param1}); + } + + String loc(String res, Object param1, Object param2) { + return loc(res, new Object[] {param1, param2}); + } + + String loc(String res, Object[] params) { + try { + return MessageFormat.format(resourceBundle.getString(res), params); + } catch (Exception e) { + e.printStackTrace(getErrorStream()); + try { + return res + ": " + Arrays.asList(params); + } catch (Exception e2) { + return res; + } + } + } + + protected String locElapsedTime(long milliseconds) { + if (getOpts().getShowElapsedTime()) { + return loc("time-ms", new Object[] {new Double(milliseconds / 1000d)}); + } + return ""; + } + + + /** + * Starts the program. + */ + public static void main(String[] args) throws IOException { + mainWithInputRedirection(args, null); + } + + /** + * Starts the program with redirected input. For redirected output, + * setOutputStream() and setErrorStream can be used. + * Exits with 0 on success, 1 on invalid arguments, and 2 on any other error + * + * @param args + * same as main() + * + * @param inputStream + * redirected input, or null to use standard input + */ + public static void mainWithInputRedirection(String[] args, InputStream inputStream) + throws IOException { + BeeLine beeLine = new BeeLine(); + int status = beeLine.begin(args, inputStream); + + if (!Boolean.getBoolean(BeeLineOpts.PROPERTY_NAME_EXIT)) { + System.exit(status); + } + } + + + public BeeLine() { + this(true); + } + + public BeeLine(boolean isBeeLine) { + this.isBeeLine = isBeeLine; + } + + DatabaseConnection getDatabaseConnection() { + return getDatabaseConnections().current(); + } + + + Connection getConnection() throws SQLException { + if (getDatabaseConnections().current() == null) { + throw new IllegalArgumentException(loc("no-current-connection")); + } + if (getDatabaseConnections().current().getConnection() == null) { + throw new IllegalArgumentException(loc("no-current-connection")); + } + return getDatabaseConnections().current().getConnection(); + } + + + DatabaseMetaData getDatabaseMetaData() { + if (getDatabaseConnections().current() == null) { + throw new IllegalArgumentException(loc("no-current-connection")); + } + if (getDatabaseConnections().current().getDatabaseMetaData() == null) { + throw new IllegalArgumentException(loc("no-current-connection")); + } + return getDatabaseConnections().current().getDatabaseMetaData(); + } + + + public String[] getIsolationLevels() { + return new String[] { + "TRANSACTION_NONE", + "TRANSACTION_READ_COMMITTED", + "TRANSACTION_READ_UNCOMMITTED", + "TRANSACTION_REPEATABLE_READ", + "TRANSACTION_SERIALIZABLE", + }; + } + + + public String[] getMetadataMethodNames() { + try { + TreeSet<String> mnames = new TreeSet<String>(); + Method[] m = DatabaseMetaData.class.getDeclaredMethods(); + for (int i = 0; m != null && i < m.length; i++) { + mnames.add(m[i].getName()); + } + return mnames.toArray(new String[0]); + } catch (Throwable t) { + return new String[0]; + } + } + + + public String[] getConnectionURLExamples() { + return new String[] { + "jdbc:JSQLConnect://<hostname>/database=<database>", + "jdbc:cloudscape:<database>;create=true", + "jdbc:twtds:sqlserver://<hostname>/<database>", + "jdbc:daffodilDB_embedded:<database>;create=true", + "jdbc:datadirect:db2://<hostname>:50000;databaseName=<database>", + "jdbc:inetdae:<hostname>:1433", + "jdbc:datadirect:oracle://<hostname>:1521;SID=<database>;MaxPooledStatements=0", + "jdbc:datadirect:sqlserver://<hostname>:1433;SelectMethod=cursor;DatabaseName=<database>", + "jdbc:datadirect:sybase://<hostname>:5000", + "jdbc:db2://<hostname>/<database>", + "jdbc:hive2://<hostname>", + "jdbc:hsqldb:<database>", + "jdbc:idb:<database>.properties", + "jdbc:informix-sqli://<hostname>:1526/<database>:INFORMIXSERVER=<database>", + "jdbc:interbase://<hostname>//<database>.gdb", + "jdbc:microsoft:sqlserver://<hostname>:1433;DatabaseName=<database>;SelectMethod=cursor", + "jdbc:mysql://<hostname>/<database>?autoReconnect=true", + "jdbc:oracle:thin:@<hostname>:1521:<database>", + "jdbc:pointbase:<database>,database.home=<database>,create=true", + "jdbc:postgresql://<hostname>:5432/<database>", + "jdbc:postgresql:net//<hostname>/<database>", + "jdbc:sybase:Tds:<hostname>:4100/<database>?ServiceName=<database>", + "jdbc:weblogic:mssqlserver4:<database>@<hostname>:1433", + "jdbc:odbc:<database>", + "jdbc:sequelink://<hostname>:4003/[Oracle]", + "jdbc:sequelink://<hostname>:4004/[Informix];Database=<database>", + "jdbc:sequelink://<hostname>:4005/[Sybase];Database=<database>", + "jdbc:sequelink://<hostname>:4006/[SQLServer];Database=<database>", + "jdbc:sequelink://<hostname>:4011/[ODBC MS Access];Database=<database>", + "jdbc:openlink://<hostname>/DSN=SQLServerDB/UID=sa/PWD=", + "jdbc:solid://<hostname>:<port>/<UID>/<PWD>", + "jdbc:dbaw://<hostname>:8889/<database>", + }; + } + + /** + * Entry point to creating a {@link ColorBuffer} with color + * enabled or disabled depending on the value of {@link BeeLineOpts#getColor}. + */ + ColorBuffer getColorBuffer() { + return new ColorBuffer(getOpts().getColor()); + } + + + /** + * Entry point to creating a {@link ColorBuffer} with color + * enabled or disabled depending on the value of {@link BeeLineOpts#getColor}. + */ + ColorBuffer getColorBuffer(String msg) { + return new ColorBuffer(msg, getOpts().getColor()); + } + + + public class BeelineParser extends GnuParser { + + @Override + protected void processOption(final String arg, final ListIterator iter) throws ParseException { + if ((arg.startsWith("--")) && !(arg.equals(HIVE_VAR_PREFIX) || (arg.equals(HIVE_CONF_PREFIX)) + || (arg.equals("--help") || (arg.equals(PROP_FILE_PREFIX))))) { + String stripped = arg.substring(2, arg.length()); + String[] parts = split(stripped, "="); + debug(loc("setting-prop", Arrays.asList(parts))); + if (parts.length >= 2) { + getOpts().set(parts[0], parts[1], true); + } else { + getOpts().set(parts[0], "true", true); + } + } else { + super.processOption(arg, iter); + } + } + } + + int initArgsFromCliVars(String[] args) { + List<String> commands = Collections.emptyList(); + + CliOptionsProcessor optionsProcessor = new CliOptionsProcessor(); + if (!optionsProcessor.process(args)) { + return 1; + } + CommandLine commandLine = optionsProcessor.getCommandLine(); + + + Properties confProps = commandLine.getOptionProperties("hiveconf"); + for (String propKey : confProps.stringPropertyNames()) { + setHiveConfVar(propKey, confProps.getProperty(propKey)); + } + + Properties hiveVars = commandLine.getOptionProperties("define"); + for (String propKey : hiveVars.stringPropertyNames()) { + getOpts().getHiveConfVariables().put(propKey, hiveVars.getProperty(propKey)); + } + + Properties hiveVars2 = commandLine.getOptionProperties("hivevar"); + for (String propKey : hiveVars2.stringPropertyNames()) { + getOpts().getHiveConfVariables().put(propKey, hiveVars2.getProperty(propKey)); + } + + getOpts().setScriptFile(commandLine.getOptionValue("f")); + + if (commandLine.getOptionValues("i") != null) { + getOpts().setInitFiles(commandLine.getOptionValues("i")); + } + + dbName = commandLine.getOptionValue("database"); + getOpts().setVerbose(Boolean.parseBoolean(commandLine.getOptionValue("verbose"))); + getOpts().setSilent(Boolean.parseBoolean(commandLine.getOptionValue("slient"))); + + int code = 0; + if (commandLine.getOptionValues("e") != null) { + commands = Arrays.asList(commandLine.getOptionValues("e")); + } + + if (!commands.isEmpty() && getOpts().getScriptFile() != null) { + System.err.println("The '-e' and '-f' options cannot be specified simultaneously"); + optionsProcessor.printCliUsage(); + return 1; + } + + if (!commands.isEmpty()) { + embeddedConnect(); + connectDBInEmbededMode(); + for (Iterator<String> i = commands.iterator(); i.hasNext(); ) { + String command = i.next().toString(); + debug(loc("executing-command", command)); + if (!dispatch(command)) { + code++; + } + } + exit = true; // execute and exit + } + return code; + } + + int initArgs(String[] args) { + List<String> commands = Collections.emptyList(); + + CommandLine cl; + BeelineParser beelineParser; + + try { + beelineParser = new BeelineParser(); + cl = beelineParser.parse(options, args); + } catch (ParseException e1) { + output(e1.getMessage()); + usage(); + return -1; + } + + String driver = null, user = null, pass = null, url = null; + String auth = null; + + + if (cl.hasOption("help")) { + usage(); + getOpts().setHelpAsked(true); + return 0; + } + + Properties hiveVars = cl.getOptionProperties("hivevar"); + for (String key : hiveVars.stringPropertyNames()) { + getOpts().getHiveVariables().put(key, hiveVars.getProperty(key)); + } + + Properties hiveConfs = cl.getOptionProperties("hiveconf"); + for (String key : hiveConfs.stringPropertyNames()) { + setHiveConfVar(key, hiveConfs.getProperty(key)); + } + + driver = cl.getOptionValue("d"); + auth = cl.getOptionValue("a"); + user = cl.getOptionValue("n"); + getOpts().setAuthType(auth); + if (cl.hasOption("w")) { + pass = obtainPasswordFromFile(cl.getOptionValue("w")); + } else { + pass = cl.getOptionValue("p"); + } + url = cl.getOptionValue("u"); + if ((url == null) && cl.hasOption("reconnect")){ + // If url was not specified with -u, but -r was present, use that. + url = getOpts().getLastConnectedUrl(); + } + getOpts().setInitFiles(cl.getOptionValues("i")); + getOpts().setScriptFile(cl.getOptionValue("f")); + if (cl.getOptionValues('e') != null) { + commands = Arrays.asList(cl.getOptionValues('e')); + } + + // TODO: temporary disable this for easier debugging + /* + if (url == null) { + url = BEELINE_DEFAULT_JDBC_URL; + } + if (driver == null) { + driver = BEELINE_DEFAULT_JDBC_DRIVER; + } + */ + + if (url != null) { + if (user == null) { + user = Utils.parsePropertyFromUrl(url, JdbcConnectionParams.AUTH_USER); + } + + if (pass == null) { + pass = Utils.parsePropertyFromUrl(url, JdbcConnectionParams.AUTH_PASSWD); + } + + String com = constructCmd(url, user, pass, driver, false); + String comForDebug = constructCmd(url, user, pass, driver, true); + debug("issuing: " + comForDebug); + dispatch(com); + } + + // load property file + String propertyFile = cl.getOptionValue("property-file"); + if (propertyFile != null) { + try { + this.consoleReader = new ConsoleReader(); + } catch (IOException e) { + handleException(e); + } + if (!dispatch("!properties " + propertyFile)) { + exit = true; + return 1; + } + } + + int code = 0; + if (!commands.isEmpty()) { + for (Iterator<String> i = commands.iterator(); i.hasNext();) { + String command = i.next().toString(); + debug(loc("executing-command", command)); + if (!dispatch(command)) { + code++; + } + } + exit = true; // execute and exit + } + return code; + } + + + private void setHiveConfVar(String key, String val) { + getOpts().getHiveConfVariables().put(key, val); + if (HiveConf.ConfVars.HIVE_EXECUTION_ENGINE.varname.equals(key) && "mr".equals(val)) { + info(HiveConf.generateMrDeprecationWarning()); + } + } + + private String constructCmd(String url, String user, String pass, String driver, boolean stripPasswd) { + String com = "!connect " + + url + " " + + (user == null || user.length() == 0 ? "''" : user) + " "; + if (stripPasswd) { + com += PASSWD_MASK + " "; + } else { + com += (pass == null || pass.length() == 0 ? "''" : pass) + " "; + } + com += (driver == null ? "" : driver); + return com; + } + /** + * Obtains a password from the passed file path. + */ + private String obtainPasswordFromFile(String passwordFilePath) { + try { + Path path = Paths.get(passwordFilePath); + byte[] passwordFileContents = Files.readAllBytes(path); + return new String(passwordFileContents, "UTF-8").trim(); + } catch (Exception e) { + throw new RuntimeException("Unable to read user password from the password file: " + + passwordFilePath, e); + } + } + + public void updateOptsForCli() { + getOpts().updateBeeLineOptsFromConf(); + getOpts().setShowHeader(false); + getOpts().setOutputFormat("dsv"); + getOpts().setDelimiterForDSV(' '); + getOpts().setNullEmptyString(true); + } + + /** + * Start accepting input from stdin, and dispatch it + * to the appropriate {@link CommandHandler} until the + * global variable <code>exit</code> is true. + */ + public int begin(String[] args, InputStream inputStream) throws IOException { + try { + // load the options first, so we can override on the command line + getOpts().load(); + } catch (Exception e) { + // nothing + } + + try { + if (isBeeLine) { + int code = initArgs(args); + if (code != 0) { + return code; + } + } else { + int code = initArgsFromCliVars(args); + if (code != 0 || exit) { + return code; + } + defaultConnect(false); + } + + if (getOpts().isHelpAsked()) { + return 0; + } + if (getOpts().getScriptFile() != null) { + return executeFile(getOpts().getScriptFile()); + } + try { + info(getApplicationTitle()); + } catch (Exception e) { + // ignore + } + ConsoleReader reader = getConsoleReader(inputStream); + return execute(reader, false); + } finally { + close(); + } + } + + int runInit() { + String initFiles[] = getOpts().getInitFiles(); + if (initFiles != null && initFiles.length != 0) { + for (String initFile : initFiles) { + info("Running init script " + initFile); + try { + return executeFile(initFile); + } finally { + exit = false; + } + } + } + return ERRNO_OK; + } + + private int embeddedConnect() { + if (!execCommandWithPrefix("!connect " + Utils.URL_PREFIX + " '' ''")) { + return ERRNO_OTHER; + } else { + return ERRNO_OK; + } + } + + private int connectDBInEmbededMode() { + if (dbName != null && !dbName.isEmpty()) { + if (!dispatch("use " + dbName + ";")) { + return ERRNO_OTHER; + } + } + return ERRNO_OK; + } + + public int defaultConnect(boolean exitOnError) { + if (embeddedConnect() != ERRNO_OK && exitOnError) { + return ERRNO_OTHER; + } + if (connectDBInEmbededMode() != ERRNO_OK && exitOnError) { + return ERRNO_OTHER; + } + return ERRNO_OK; + } + + private int executeFile(String fileName) { + InputStream initStream = null; + try { + if (!isBeeLine) { + org.apache.hadoop.fs.Path path = new org.apache.hadoop.fs.Path(fileName); + FileSystem fs; + HiveConf conf = getCommands().getHiveConf(true); + if (!path.toUri().isAbsolute()) { + fs = FileSystem.getLocal(conf); + path = fs.makeQualified(path); + } else { + fs = FileSystem.get(path.toUri(), conf); + } + initStream = fs.open(path); + } else { + initStream = new FileInputStream(fileName); + } + return execute(getConsoleReader(initStream), !getOpts().getForce()); + } catch (Throwable t) { + handleException(t); + return ERRNO_OTHER; + } finally { + IOUtils.closeStream(initStream); + consoleReader = null; + output(""); // dummy new line + } + } + + private int execute(ConsoleReader reader, boolean exitOnError) { + int lastExecutionResult = ERRNO_OK; + while (!exit) { + try { + // Execute one instruction; terminate on executing a script if there is an error + // in silent mode, prevent the query and prompt being echoed back to terminal + String line = (getOpts().isSilent() && getOpts().getScriptFile() != null) ? reader + .readLine(null, ConsoleReader.NULL_MASK) : reader.readLine(getPrompt()); + + // trim line + if (line != null) { + line = line.trim(); + } + + if (!dispatch(line)) { + lastExecutionResult = ERRNO_OTHER; + if (exitOnError) break; + } else if (line != null) { + lastExecutionResult = ERRNO_OK; + } + + } catch (Throwable t) { + handleException(t); + return ERRNO_OTHER; + } + } + return lastExecutionResult; + } + + @Override + public void close() { + commands.closeall(null); + } + + public ConsoleReader getConsoleReader(InputStream inputStream) throws IOException { + if (inputStream != null) { + // ### NOTE: fix for sf.net bug 879425. + // Working around an issue in jline-2.1.2, see https://github.com/jline/jline/issues/10 + // by appending a newline to the end of inputstream + InputStream inputStreamAppendedNewline = new SequenceInputStream(inputStream, + new ByteArrayInputStream((new String("\n")).getBytes())); + consoleReader = new ConsoleReader(inputStreamAppendedNewline, getOutputStream()); + consoleReader.setCopyPasteDetection(true); // jline will detect if <tab> is regular character + } else { + consoleReader = new ConsoleReader(); + } + + //disable the expandEvents for the purpose of backward compatibility + consoleReader.setExpandEvents(false); + + // setup history + ByteArrayOutputStream hist = new ByteArrayOutputStream(); + if (new File(getOpts().getHistoryFile()).isFile()) { + try { + // save the current contents of the history buffer. This gets + // around a bug in JLine where setting the output before the + // input will clobber the history input, but setting the + // input before the output will cause the previous commands + // to not be saved to the buffer. + try (FileInputStream historyIn = new FileInputStream(getOpts().getHistoryFile())) { + int n; + while ((n = historyIn.read()) != -1) { + hist.write(n); + } + } + } catch (Exception e) { + handleException(e); + } + } + + try { + // now set the output for the history + consoleReader.setHistory(new FileHistory(new File(getOpts().getHistoryFile()))); + } catch (Exception e) { + handleException(e); + } + + if (inputStream instanceof FileInputStream || inputStream instanceof FSDataInputStream) { + // from script.. no need to load history and no need of completer, either + return consoleReader; + } + try { + // now load in the previous history + if (hist != null) { + History h = consoleReader.getHistory(); + if (!(h instanceof FileHistory)) { + consoleReader.getHistory().add(hist.toString()); + } + } + } catch (Exception e) { + handleException(e); + } + + // add shutdown hook to flush the history to history file + Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { + @Override + public void run() { + History h = consoleReader.getHistory(); + if (h instanceof FileHistory) { + try { + ((FileHistory) h).flush(); + } catch (IOException e) { + error(e); + } + } + } + })); + + consoleReader.addCompleter(new BeeLineCompleter(this)); + return consoleReader; + } + + void usage() { + output(loc("cmd-usage")); + } + + /** + * This method is used for executing commands beginning with ! + * @param line + * @return + */ + public boolean execCommandWithPrefix(String line) { + Map<String, CommandHandler> cmdMap = new TreeMap<String, CommandHandler>(); + line = line.substring(1); + for (int i = 0; i < commandHandlers.length; i++) { + String match = commandHandlers[i].matches(line); + if (match != null) { + cmdMap.put(match, commandHandlers[i]); + } + } + + if (cmdMap.size() == 0) { + return error(loc("unknown-command", line)); + } + if (cmdMap.size() > 1) { + // any exact match? + CommandHandler handler = cmdMap.get(line); + if (handler == null) { + return error(loc("multiple-matches", cmdMap.keySet().toString())); + } + return handler.execute(line); + } + return cmdMap.values().iterator().next().execute(line); + } + + /** + * Dispatch the specified line to the appropriate {@link CommandHandler}. + * + * @param line + * the command-line to dispatch + * @return true if the command was "successful" + */ + boolean dispatch(String line) { + if (line == null) { + // exit + exit = true; + return true; + } + + if (line.trim().length() == 0) { + return true; + } + + if (isComment(line)) { + return true; + } + + line = line.trim(); + + // save it to the current script, if any + if (scriptOutputFile != null) { + scriptOutputFile.addLine(line); + } + + if (isHelpRequest(line)) { + line = "!help"; + } + + if (isBeeLine) { + if (line.startsWith(COMMAND_PREFIX)) { + // handle SQLLine command in beeline which starts with ! and does not end with ; + return execCommandWithPrefix(line); + } else { + return commands.sql(line, getOpts().getEntireLineAsCommand()); + } + } else { + return commands.sql(line, getOpts().getEntireLineAsCommand()); + } + } + + /** + * Test whether a line requires a continuation. + * + * @param line + * the line to be tested + * + * @return true if continuation required + */ + boolean needsContinuation(String line) { + if (isHelpRequest(line)) { + return false; + } + + if (line.startsWith(COMMAND_PREFIX)) { + return false; + } + + if (isComment(line)) { + return false; + } + + String trimmed = line.trim(); + + if (trimmed.length() == 0) { + return false; + } + + if (!getOpts().isAllowMultiLineCommand()) { + return false; + } + + return !trimmed.endsWith(";"); + } + + /** + * Test whether a line is a help request other than !help. + * + * @param line + * the line to be tested + * + * @return true if a help request + */ + boolean isHelpRequest(String line) { + return line.equals("?") || line.equalsIgnoreCase("help"); + } + + /** + * Test whether a line is a comment. + * + * @param line + * the line to be tested + * + * @return true if a comment + */ + boolean isComment(String line) { + // SQL92 comment prefix is "--" + // beeline also supports shell-style "#" prefix + String lineTrimmed = line.trim(); + return lineTrimmed.startsWith("#") || lineTrimmed.startsWith("--"); + } + + /** + * Print the specified message to the console + * + * @param msg + * the message to print + */ + void output(String msg) { + output(msg, true); + } + + + void info(String msg) { + if (!(getOpts().isSilent())) { + output(msg, true, getErrorStream()); + } + } + + + void info(ColorBuffer msg) { + if (!(getOpts().isSilent())) { + output(msg, true, getErrorStream()); + } + } + + + /** + * Issue the specified error message + * + * @param msg + * the message to issue + * @return false always + */ + boolean error(String msg) { + output(getColorBuffer().red(msg), true, getErrorStream()); + return false; + } + + + boolean error(Throwable t) { + handleException(t); + return false; + } + + + void debug(String msg) { + if (getOpts().getVerbose()) { + output(getColorBuffer().blue(msg), true, getErrorStream()); + } + } + + + void output(ColorBuffer msg) { + output(msg, true); + } + + + void output(String msg, boolean newline, PrintStream out) { + output(getColorBuffer(msg), newline, out); + } + + + void output(ColorBuffer msg, boolean newline) { + output(msg, newline, getOutputStream()); + } + + + void output(ColorBuffer msg, boolean newline, PrintStream out) { + if (newline) { + out.println(msg.getColor()); + } else { + out.print(msg.getColor()); + } + + if (recordOutputFile == null) { + return; + } + + // only write to the record file if we are writing a line ... + // otherwise we might get garbage from backspaces and such. + if (newline) { + recordOutputFile.addLine(msg.getMono()); // always just write mono + } else { + recordOutputFile.print(msg.getMono()); + } + } + + + /** + * Print the specified message to the console + * + * @param msg + * the message to print + * @param newline + * if false, do not append a newline + */ + void output(String msg, boolean newline) { + output(getColorBuffer(msg), newline); + } + + + void autocommitStatus(Connection c) throws SQLException { + info(loc("autocommit-status", c.getAutoCommit() + "")); + } + + + /** + * Ensure that autocommit is on for the current connection + * + * @return true if autocommit is set + */ + boolean assertAutoCommit() { + if (!(assertConnection())) { + return false; + } + try { + if (getDatabaseConnection().getConnection().getAutoCommit()) { + return error(loc("autocommit-needs-off")); + } + } catch (Exception e) { + return error(e); + } + return true; + } + + + /** + * Assert that we have an active, living connection. Print + * an error message if we do not. + * + * @return true if there is a current, active connection + */ + boolean assertConnection() { + try { + if (getDatabaseConnection() == null || getDatabaseConnection().getConnection() == null) { + return error(loc("no-current-connection")); + } + if (getDatabaseConnection().getConnection().isClosed()) { + return error(loc("connection-is-closed")); + } + } catch (SQLException sqle) { + return error(loc("no-current-connection")); + } + return true; + } + + + /** + * Print out any warnings that exist for the current connection. + */ + void showWarnings() { + try { + if (getDatabaseConnection().getConnection() == null + || !getOpts().getVerbose()) { + return; + } + showWarnings(getDatabaseConnection().getConnection().getWarnings()); + } catch (Exception e) { + handleException(e); + } + } + + + /** + * Print the specified warning on the console, as well as + * any warnings that are returned from {@link SQLWarning#getNextWarning}. + * + * @param warn + * the {@link SQLWarning} to print + */ + void showWarnings(SQLWarning warn) { + if (warn == null) { + return; + } + + if (seenWarnings.get(warn) == null) { + // don't re-display warnings we have already seen + seenWarnings.put(warn, new java.util.Date()); + handleSQLException(warn); + } + + SQLWarning next = warn.getNextWarning(); + if (next != warn) { + showWarnings(next); + } + } + + String getPrompt() { + if (isBeeLine) { + return getPromptForBeeline(); + } else { + return getPromptForCli(); + } + } + + String getPromptForCli() { + String prompt; + // read prompt configuration and substitute variables. + HiveConf conf = getCommands().getHiveConf(true); + prompt = conf.getVar(HiveConf.ConfVars.CLIPROMPT); + prompt = getCommands().substituteVariables(conf, prompt); + return prompt + getFormattedDb(conf) + "> "; + } + + /** + * Retrieve the current database name string to display, based on the + * configuration value. + * + * @param conf storing whether or not to show current db + * @return String to show user for current db value + */ + String getFormattedDb(HiveConf conf) { + if (!HiveConf.getBoolVar(conf, HiveConf.ConfVars.CLIPRINTCURRENTDB)) { + return ""; + } + String currDb = getCurrentDatabase(); + + if (currDb == null) { + return ""; + } + + return " (" + currDb + ")"; + } + + String getPromptForBeeline() { + if (getDatabaseConnection() == null || getDatabaseConnection().getUrl() == null) { + return "beeline> "; + } else { + String printClosed = getDatabaseConnection().isClosed() ? " (closed)" : ""; + return getPromptForBeeline(getDatabaseConnections().getIndex() + + ": " + getDatabaseConnection().getUrl()) + printClosed + "> "; + } + } + + + static String getPromptForBeeline(String url) { + if (url == null || url.length() == 0) { + url = "beeline"; + } + if (url.indexOf(";") > -1) { + url = url.substring(0, url.indexOf(";")); + } + if (url.indexOf("?") > -1) { + url = url.substring(0, url.indexOf("?")); + } + if (url.length() > 45) { + url = url.substring(0, 45); + } + return url; + } + + + /** + * Try to obtain the current size of the specified {@link ResultSet} by jumping to the last row + * and getting the row number. + * + * @param rs + * the {@link ResultSet} to get the size for + * @return the size, or -1 if it could not be obtained + */ + int getSize(ResultSet rs) { + try { + if (rs.getType() == rs.TYPE_FORWARD_ONLY) { + return -1; + } + rs.last(); + int total = rs.getRow(); + rs.beforeFirst(); + return total; + } catch (SQLException sqle) { + return -1; + } + // JDBC 1 driver error + catch (AbstractMethodError ame) { + return -1; + } + } + + + ResultSet getColumns(String table) throws SQLException { + if (!(assertConnection())) { + return null; + } + return getDatabaseConnection().getDatabaseMetaData().getColumns( + getDatabaseConnection().getDatabaseMetaData().getConnection().getCatalog(), null, table, "%"); + } + + + ResultSet getTables() throws SQLException { + if (!(assertConnection())) { + return null; + } + return getDatabaseConnection().getDatabaseMetaData().getTables( + getDatabaseConnection().getDatabaseMetaData().getConnection().getCatalog(), null, "%", + new String[] {"TABLE"}); + } + + + String[] getColumnNames(DatabaseMetaData meta) throws SQLException { + Set<String> names = new HashSet<String>(); + info(loc("building-tables")); + try { + ResultSet columns = getColumns("%"); + try { + int total = getSize(columns); + int index = 0; + + while (columns.next()) { + // add the following strings: + // 1. column name + // 2. table name + // 3. tablename.columnname + + progress(index++, total); + String name = columns.getString("TABLE_NAME"); + names.add(name); + names.add(columns.getString("COLUMN_NAME")); + names.add(columns.getString("TABLE_NAME") + "." + + columns.getString("COLUMN_NAME")); + } + progress(index, index); + } finally { + columns.close(); + } + info(loc("done")); + return names.toArray(new String[0]); + } catch (Throwable t) { + handleException(t); + return new String[0]; + } + } + + + // ////////////////// + // String utilities + // ////////////////// + + + /** + * Split the line into an array by tokenizing on space characters + * + * @param line + * the line to break up + * @return an array of individual words + */ + String[] split(String line) { + return split(line, " "); + } + + + String dequote(String str) { + if (str == null) { + return null; + } + while ((str.startsWith("'") && str.endsWith("'")) + || (str.startsWith("\"") && str.endsWith("\""))) { + str = str.substring(1, str.length() - 1); + } + return str; + } + + + String[] split(String line, String delim) { + StringTokenizer tok = new StringTokenizer(line, delim); + String[] ret = new String[tok.countTokens()]; + int index = 0; + while (tok.hasMoreTokens()) { + String t = tok.nextToken(); + t = dequote(t); + ret[index++] = t; + } + return ret; + } + + + static Map<Object, Object> map(Object[] obs) { + Map<Object, Object> m = new HashMap<Object, Object>(); + for (int i = 0; i < obs.length - 1; i += 2) { + m.put(obs[i], obs[i + 1]); + } + return Collections.unmodifiableMap(m); + } + + + static boolean getMoreResults(Statement stmnt) { + try { + return stmnt.getMoreResults(); + } catch (Throwable t) { + return false; + } + } + + + static String xmlattrencode(String str) { + str = replace(str, "\"", """); + str = replace(str, "<", "<"); + return str; + } + + + static String replace(String source, String from, String to) { + if (source == null) { + return null; + } + + if (from.equals(to)) { + return source; + } + + StringBuilder replaced = new StringBuilder(); + + int index = -1; + while ((index = source.indexOf(from)) != -1) { + replaced.append(source.substring(0, index)); + replaced.append(to); + source = source.substring(index + from.length()); + } + replaced.append(source); + + return replaced.toString(); + } + + + /** + * Split the line based on spaces, asserting that the + * number of words is correct. + * + * @param line + * the line to split + * @param assertLen + * the number of words to assure + * @param usage + * the message to output if there are an incorrect + * number of words. + * @return the split lines, or null if the assertion failed. + */ + String[] split(String line, int assertLen, String usage) { + String[] ret = split(line); + + if (ret.length != assertLen) { + error(usage); + return null; + } + + return ret; + } + + + /** + * Wrap the specified string by breaking on space characters. + * + * @param toWrap + * the string to wrap + * @param len + * the maximum length of any line + * @param start + * the number of spaces to pad at the + * beginning of a line + * @return the wrapped string + */ + String wrap(String toWrap, int len, int start) { + StringBuilder buff = new StringBuilder(); + StringBuilder line = new StringBuilder(); + + char[] head = new char[start]; + Arrays.fill(head, ' '); + + for (StringTokenizer tok = new StringTokenizer(toWrap, " "); tok.hasMoreTokens();) { + String next = tok.nextToken(); + if (line.length() + next.length() > len) { + buff.append(line).append(separator).append(head); + line.setLength(0); + } + + line.append(line.length() == 0 ? "" : " ").append(next); + } + + buff.append(line); + return buff.toString(); + } + + + /** + * Output a progress indicator to the console. + * + * @param cur + * the current progress + * @param max + * the maximum progress, or -1 if unknown + */ + void progress(int cur, int max) { + StringBuilder out = new StringBuilder(); + + if (lastProgress != null) { + char[] back = new char[lastProgress.length()]; + Arrays.fill(back, '\b'); + out.append(back); + } + + String progress = cur + "/" + + (max == -1 ? "?" : "" + max) + " " + + (max == -1 ? "(??%)" + : ("(" + (cur * 100 / (max == 0 ? 1 : max)) + "%)")); + + if (cur >= max && max != -1) { + progress += " " + loc("done") + separator; + lastProgress = null; + } else { + lastProgress = progress; + } + + out.append(progress); + + outputStream.print(out.toString()); + outputStream.flush(); + } + + // ///////////////////////////// + // Exception handling routines + // ///////////////////////////// + + void handleException(Throwable e) { + while (e instanceof InvocationTargetException) { + e = ((InvocationTargetException) e).getTargetException(); + } + + if (e instanceof SQLException) { + handleSQLException((SQLException) e); + } else if (e instanceof EOFException) { + setExit(true); // CTRL-D + } else if (!(getOpts().getVerbose())) { + if (e.getMessage() == null) { + error(e.getClass().getName()); + } else { + error(e.getMessage()); + } + } else { + e.printStackTrace(getErrorStream()); + } + } + + + void handleSQLException(SQLException e) { + if (e instanceof SQLWarning && !(getOpts().getShowWarnings())) { + return; + } + + if (e.getCause() instanceof TTransportException) { + error(loc("hs2-unavailable")); + } + + error(loc(e instanceof SQLWarning ? "Warning" : "Error", + new Object[] { + e.getMessage() == null ? "" : e.getMessage().trim(), + e.getSQLState() == null ? "" : e.getSQLState().trim(), + new Integer(e.getErrorCode())})); + + if (getOpts().getVerbose()) { + e.printStackTrace(getErrorStream()); + } + + if (!getOpts().getShowNestedErrs()) { + return; + } + + for (SQLException nested = e.getNextException(); nested != null && nested != e; nested = nested + .getNextException()) { + handleSQLException(nested); + } + } + + + boolean scanForDriver(String url) { + try { + // already registered + if (findRegisteredDriver(url) != null) { + return true; + } + + // first try known drivers... + scanDrivers(true); + + if (findRegisteredDriver(url) != null) { + return true; + } + + // now really scan... + scanDrivers(false); + + if (findRegisteredDriver(url) != null) { + return true; + } + + // find whether exists a local driver to accept the url + if (findLocalDriver(url) != null) { + return true; + } + + return false; + } catch (Exception e) { + debug(e.toString()); + return false; + } + } + + + private Driver findRegisteredDriver(String url) { + for (Enumeration drivers = DriverManager.getDrivers(); drivers != null + && drivers.hasMoreElements();) { + Driver driver = (Driver) drivers.nextElement(); + try { + if (driver.acceptsURL(url)) { + return driver; + } + } catch (Exception e) { + } + } + return null; + } + + public Driver findLocalDriver(String url) throws Exception { + if(drivers == null){ + return null; + } + + for (Driver d : drivers) { + try { + String clazzName = d.getClass().getName(); + Driver driver = (Driver) Class.forName(clazzName, true, + Thread.currentThread().getContextClassLoader()).newInstance(); + if (driver.acceptsURL(url) && isSupportedLocalDriver(driver)) { + return driver; + } + } catch (SQLException e) { + error(e); + throw new Exception(e); + } + } + return null; + } + + public boolean isSupportedLocalDriver(Driver driver) { + String driverName = driver.getClass().getName(); + for (String name : supportedLocalDriver) { + if (name.equals(driverName)) { + return true; + } + } + return false; + } + + public void addLocalDriverClazz(String driverClazz) { + supportedLocalDriver.add(driverClazz); + } + + Driver[] scanDrivers(String line) throws IOException { + return scanDrivers(false); + } + + + Driver[] scanDrivers(boolean knownOnly) throws IOException { + long start = System.currentTimeMillis(); + + Set<String> classNames = new HashSet<String>(); + + if (!knownOnly) { + classNames.addAll(Arrays.asList( + ClassNameCompleter.getClassNames())); + } + + classNames.addAll(KNOWN_DRIVERS); + + Set driverClasses = new HashSet(); + + for (Iterator<String> i = classNames.iterator(); i.hasNext();) { + String className = i.next().toString(); + + if (className.toLowerCase().indexOf("driver") == -1) { + continue; + } + + try { + Class c = Class.forName(className, false, + Thread.currentThread().getContextClassLoader()); + if (!Driver.class.isAssignableFrom(c)) { + continue; + } + + if (Modifier.isAbstract(c.getModifiers())) { + continue; + } + + // now instantiate and initialize it + driverClasses.add(c.newInstance()); + } catch (Throwable t) { + } + } + info("scan complete in " + + (System.currentTimeMillis() - start) + "ms"); + return (Driver[]) driverClasses.toArray(new Driver[0]); + } + + + private Driver[] scanDriversOLD(String line) { + long start = System.currentTimeMillis(); + + Set<String> paths = new HashSet<String>(); + Set driverClasses = new HashSet(); + + for (StringTokenizer tok = new StringTokenizer( + System.getProperty("java.ext.dirs"), + System.getProperty("path.separator")); tok.hasMoreTokens();) { + File[] files = new File(tok.nextToken()).listFiles(); + for (int i = 0; files != null && i < files.length; i++) { + paths.add(files[i].getAbsolutePath()); + } + } + + for (StringTokenizer tok = new StringTokenizer( + System.getProperty("java.class.path"), + System.getProperty("path.separator")); tok.hasMoreTokens();) { + paths.add(new File(tok.nextToken()).getAbsolutePath()); + } + + for (Iterator<String> i = paths.iterator(); i.hasNext();) { + File f = new File(i.next()); + output(getColorBuffer().pad(loc("scanning", f.getAbsolutePath()), 60), + false); + + try { + ZipFile zf = new ZipFile(f); + int total = zf.size(); + int index = 0; + + for (Enumeration zfEnum = zf.entries(); zfEnum.hasMoreElements();) { + ZipEntry entry = (ZipEntry) zfEnum.nextElement(); + String name = entry.getName(); + progress(index++, total); + + if (name.endsWith(".class")) { + name = name.replace('/', '.'); + name = name.substring(0, name.length() - 6); + + try { + // check for the string "driver" in the class + // to see if we should load it. Not perfect, but + // it is far too slow otherwise. + if (name.toLowerCase().indexOf("driver") != -1) { + Class c = Class.forName(name, false, + getClass().getClassLoader()); + if (Driver.class.isAssignableFrom(c) + && !(Modifier.isAbstract( + c.getModifiers()))) { + try { + // load and initialize + Class.forName(name); + } catch (Exception e) { + } + driverClasses.add(c.newInstance()); + } + } + } catch (Throwable t) { + } + } + } + progress(total, total); + } catch (Exception e) { + } + } + + info("scan complete in " + + (System.currentTimeMillis() - start) + "ms"); + return (Driver[]) driverClasses.toArray(new Driver[0]); + } + + + // ///////////////////////////////////// + // ResultSet output formatting classes + // ///////////////////////////////////// + + + + int print(ResultSet rs) throws SQLException { + String format = getOpts().getOutputFormat(); + OutputFormat f = (OutputFormat) formats.get(format); + + if (f == null) { + error(loc("unknown-format", new Object[] { + format, formats.keySet()})); + f = new TableOutputFormat(this); + } + + Rows rows; + + if (getOpts().getIncremental()) { + rows = new IncrementalRows(this, rs); + } else { + rows = new BufferedRows(this, rs); + } + return f.print(rows); + } + + + Statement createStatement() throws SQLException { + Statement stmnt = getDatabaseConnection().getConnection().createStatement(); + if (getOpts().timeout > -1) { + stmnt.setQueryTimeout(getOpts().timeout); + } + if (signalHandler != null) { + signalHandler.setStatement(stmnt); + } + return stmnt; + } + + + void runBatch(List<String> statements) { + try { + Statement stmnt = createStatement(); + try { + for (Iterator<String> i = statements.iterator(); i.hasNext();) { + stmnt.addBatch(i.next().toString()); + } + int[] counts = stmnt.executeBatch(); + + output(getColorBuffer().pad(getColorBuffer().bold("COUNT"), 8) + .append(getColorBuffer().bold("STATEMENT"))); + + for (int i = 0; counts != null && i < counts.length; i++) { + output(getColorBuffer().pad(counts[i] + "", 8) + .append(statements.get(i).toString())); + } + } finally { + try { + stmnt.close(); + } catch (Exception e) { + } + } + } catch (Exception e) { + handleException(e); + } + } + + public int runCommands(String[] cmds) { + return runCommands(Arrays.asList(cmds)); + } + + public int runCommands(List<String> cmds) { + int successCount = 0; + try { + // TODO: Make script output prefixing configurable. Had to disable this since + // it results in lots of test diffs. + for (String cmd : cmds) { + info(getColorBuffer().pad(SCRIPT_OUTPUT_PREFIX, SCRIPT_OUTPUT_PAD_SIZE).append(cmd)); + // if we do not force script execution, abort + // when a failure occurs. + if (dispatch(cmd) || getOpts().getForce()) { + ++successCount; + } else { + error(loc("abort-on-error", cmd)); + return successCount; + } + } + } catch (Exception e) { + handleException(e); + } + return successCount; + } + + // //////////////////////// + // Command methods follow + // //////////////////////// + + void setCompletions() throws SQLException, IOException { + if (getDatabaseConnection() != null) { + getDatabaseConnection().setCompletions(getOpts().getFastConnect()); + } + } + + public BeeLineOpts getOpts() { + return opts; + } + + DatabaseConnections getDatabaseConnections() { + return connections; + } + + Completer getCommandCompletor() { + return beeLineCommandCompleter; + } + + public boolean isExit() { + return exit; + } + + public void setExit(boolean exit) { + this.exit = exit; + } + + Collection<Driver> getDrivers() { + return drivers; + } + + void setDrivers(Collection<Driver> drivers) { + this.drivers = drivers; + } + + public static String getSeparator() { + return separator; + } + + Commands getCommands() { + return commands; + } + + OutputFile getScriptOutputFile() { + return scriptOutputFile; + } + + void setScriptOutputFile(OutputFile script) { + this.scriptOutputFile = script; + } + + OutputFile getRecordOutputFile() { + return recordOutputFile; + } + + void setRecordOutputFile(OutputFile record) { + this.recordOutputFile = record; + } + + public void setOutputStream(PrintStream outputStream) { + this.outputStream = new PrintStream(outputStream, true); + } + + PrintStream getOutputStream() { + return outputStream; + } + + public void setErrorStream(PrintStream errorStream) { + this.errorStream = new PrintStream(errorStream, true); + } + + PrintStream getErrorStream() { + return errorStream; + } + + ConsoleReader getConsoleReader() { + return consoleReader; + } + + void setConsoleReader(ConsoleReader reader) { + this.consoleReader = reader; + } + + List<String> getBatch() { + return batch; + } + + void setBatch(List<String> batch) { + this.batch = batch; + } + + protected Reflector getReflector() { + return reflector; + } + + public boolean isBeeLine() { + return isBeeLine; + } + + public void setBeeLine(boolean isBeeLine) { + this.isBeeLine = isBeeLine; + } + + public String getCurrentDatabase() { + if (currentDatabase == null) { + currentDatabase = DEFAULT_DATABASE_NAME; + } + return currentDatabase; + } + + public void setCurrentDatabase(String currentDatabase) { + this.currentDatabase = currentDatabase; + } +} http://git-wip-us.apache.org/repos/asf/hive/blob/26b84ffa/beeline/src/test/org/apache/hive/beeline/TestBeelineArgParsing.java ---------------------------------------------------------------------- diff --git a/beeline/src/test/org/apache/hive/beeline/TestBeelineArgParsing.java b/beeline/src/test/org/apache/hive/beeline/TestBeelineArgParsing.java index d27c949..ce1f538 100644 --- a/beeline/src/test/org/apache/hive/beeline/TestBeelineArgParsing.java +++ b/beeline/src/test/org/apache/hive/beeline/TestBeelineArgParsing.java @@ -201,6 +201,16 @@ public class TestBeelineArgParsing { } /** + * Test beeline with -f and -e simultaneously + */ + @Test + public void testCommandAndFileSimultaneously() throws Exception { + TestBeeline bl = new TestBeeline(); + String args[] = new String[] {"-e", "myselect", "-f", "myscript"}; + Assert.assertEquals(1, bl.initArgs(args)); + } + + /** * Displays the usage. */ @Test
