HIVE-10623: Implement hive cli options using beeline functionality (Ferdinand 
via Xuefu)


Project: http://git-wip-us.apache.org/repos/asf/hive/repo
Commit: http://git-wip-us.apache.org/repos/asf/hive/commit/03366392
Tree: http://git-wip-us.apache.org/repos/asf/hive/tree/03366392
Diff: http://git-wip-us.apache.org/repos/asf/hive/diff/03366392

Branch: refs/heads/master
Commit: 03366392c6f17ae7688ad1646046af4c5b5b6792
Parents: 753b2b3
Author: Xuefu Zhang <xzh...@cloudera.com>
Authored: Thu May 14 21:33:44 2015 -0700
Committer: Xuefu Zhang <xzh...@cloudera.com>
Committed: Thu May 14 21:33:44 2015 -0700

----------------------------------------------------------------------
 .../java/org/apache/hive/beeline/BeeLine.java   | 140 ++++++++++++++++-
 .../hive/beeline/cli/CliOptionsProcessor.java   | 104 +++++++++++++
 .../org/apache/hive/beeline/cli/HiveCli.java    |  41 +++++
 .../apache/hive/beeline/cli/TestHiveCli.java    | 153 +++++++++++++++++++
 beeline/src/test/resources/hive-site.xml        |  37 +++++
 5 files changed, 468 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hive/blob/03366392/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 0da15f6..4a82635 100644
--- a/beeline/src/java/org/apache/hive/beeline/BeeLine.java
+++ b/beeline/src/java/org/apache/hive/beeline/BeeLine.java
@@ -88,6 +88,8 @@ import org.apache.commons.cli.OptionBuilder;
 import org.apache.commons.cli.Options;
 import org.apache.commons.cli.ParseException;
 import org.apache.hadoop.io.IOUtils;
+import org.apache.hive.beeline.cli.CliOptionsProcessor;
+import org.apache.hive.jdbc.Utils;
 
 /**
  * A console SQL shell with command completion.
@@ -126,8 +128,10 @@ public class BeeLine implements Closeable {
   private ConsoleReader consoleReader;
   private List<String> batch = null;
   private final Reflector reflector;
+  private String dbName = null;
 
   private History history;
+  private boolean isBeeLine = true;
 
   private static final Options options = new Options();
 
@@ -491,10 +495,14 @@ public class BeeLine implements Closeable {
 
 
   public BeeLine() {
+    this(true);
+  }
+
+  public BeeLine(boolean isBeeLine) {
     beeLineCommandCompleter = new 
BeeLineCommandCompleter(BeeLineCommandCompleter.getCompleters
         (this));
     reflector = new Reflector(this);
-
+    this.isBeeLine = isBeeLine;
     // attempt to dynamically load signal handler
     /* TODO disable signal handler
     try {
@@ -508,7 +516,6 @@ public class BeeLine implements Closeable {
     */
   }
 
-
   DatabaseConnection getDatabaseConnection() {
     return getDatabaseConnections().current();
   }
@@ -633,7 +640,63 @@ public class BeeLine implements Closeable {
         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()) {
+      getOpts().getHiveConfVariables().put(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"));
+
+    dbName = commandLine.getOptionValue("database");
+    
getOpts().setVerbose(Boolean.valueOf(commandLine.getOptionValue("verbose")));
+    getOpts().setSilent(Boolean.valueOf(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) {
@@ -687,7 +750,6 @@ public class BeeLine implements Closeable {
       commands = Arrays.asList(cl.getOptionValues('e'));
     }
 
-
     // TODO: temporary disable this for easier debugging
     /*
     if (url == null) {
@@ -755,9 +817,15 @@ public class BeeLine implements Closeable {
     }
 
     try {
-      int code = initArgs(args);
-      if (code != 0) {
-        return code;
+      if (isBeeLine) {
+        int code = initArgs(args);
+        if (code != 0) {
+          return code;
+        }
+      } else {
+        int code = initArgsFromCliVars(args);
+        if (code != 0)
+          return code;
       }
 
       if (getOpts().getScriptFile() != null) {
@@ -788,6 +856,33 @@ public class BeeLine implements Closeable {
     return ERRNO_OK;
   }
 
+  private int embeddedConnect() {
+    if (!dispatch("!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) {
     FileInputStream initStream = null;
     try {
@@ -805,13 +900,20 @@ public class BeeLine implements Closeable {
 
   private int execute(ConsoleReader reader, boolean exitOnError) {
     String line;
+    if (!isBeeLine) {
+      if (defaultConnect(exitOnError) != ERRNO_OK && exitOnError) {
+        return ERRNO_OTHER;
+      }
+    }
     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
         line = (getOpts().isSilent() && getOpts().getScriptFile() != null) ?
                  reader.readLine(null, ConsoleReader.NULL_MASK) : 
reader.readLine(getPrompt());
-
+        if (!isBeeLine) {
+          line = cliToBeelineCmd(line);
+        }
         if (!dispatch(line) && exitOnError) {
           return ERRNO_OTHER;
         }
@@ -914,6 +1016,30 @@ public class BeeLine implements Closeable {
     output(loc("cmd-usage"));
   }
 
+  private String[] tokenizeCmd(String cmd) {
+    return cmd.split("\\s+");
+  }
+
+  public String cliToBeelineCmd(String cmd) {
+    if (cmd == null)
+      return null;
+    String cmd_trimmed = cmd.trim();
+    String[] tokens = tokenizeCmd(cmd_trimmed);
+
+    if (cmd_trimmed.equalsIgnoreCase("quit") || 
cmd_trimmed.equalsIgnoreCase("exit")) {
+      return null;
+    } else if (tokens[0].equalsIgnoreCase("source")) {
+      //TODO
+      return cmd;
+    } else if (cmd_trimmed.startsWith("!")) {
+      String shell_cmd = cmd_trimmed.substring(1);
+      return "!sh " + shell_cmd;
+    } else { // local mode
+      // command like dfs
+      return cmd;
+    }
+  }
+
 
   /**
    * Dispatch the specified line to the appropriate {@link CommandHandler}.

http://git-wip-us.apache.org/repos/asf/hive/blob/03366392/beeline/src/java/org/apache/hive/beeline/cli/CliOptionsProcessor.java
----------------------------------------------------------------------
diff --git 
a/beeline/src/java/org/apache/hive/beeline/cli/CliOptionsProcessor.java 
b/beeline/src/java/org/apache/hive/beeline/cli/CliOptionsProcessor.java
new file mode 100644
index 0000000..61c5ab6
--- /dev/null
+++ b/beeline/src/java/org/apache/hive/beeline/cli/CliOptionsProcessor.java
@@ -0,0 +1,104 @@
+/**
+ * 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.
+ */
+package org.apache.hive.beeline.cli;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.GnuParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.OptionBuilder;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+
+/**
+ * This class is used for parsing the options of Hive Cli
+ */
+public class CliOptionsProcessor {
+  private final Options options = new Options();
+  private org.apache.commons.cli.CommandLine commandLine;
+
+  public CliOptionsProcessor() {
+    // -database database
+    
options.addOption(OptionBuilder.hasArg().withArgName("databasename").withLongOpt("database")
+        .withDescription("Specify the database to use").create());
+
+    // -e 'quoted-query-string'
+    
options.addOption(OptionBuilder.hasArg().withArgName("quoted-query-string").withDescription
+        ("SQL from command line").create('e'));
+
+    // -f <query-file>
+    
options.addOption(OptionBuilder.hasArg().withArgName("filename").withDescription("SQL
 from " +
+        "files").create('f'));
+
+    // -i <init-query-file>
+    
options.addOption(OptionBuilder.hasArg().withArgName("filename").withDescription
+        ("Initialization SQL file").create('i'));
+
+    // -hiveconf x=y
+    
options.addOption(OptionBuilder.withValueSeparator().hasArgs(2).withArgName("property=value")
+        .withLongOpt("hiveconf").withDescription("Use value for given 
property").create());
+
+    // Substitution option -d, --define
+    
options.addOption(OptionBuilder.withValueSeparator().hasArgs(2).withArgName("key=value")
+        .withLongOpt("define").withDescription("Variable subsitution to apply 
to hive commands. e" +
+            ".g. -d A=B or --define A=B").create('d'));
+
+    // Substitution option --hivevar
+    
options.addOption(OptionBuilder.withValueSeparator().hasArgs(2).withArgName("key=value")
+        .withLongOpt("hivevar").withDescription("Variable subsitution to apply 
to hive commands. " +
+            "e.g. --hivevar A=B").create());
+
+    // [-S|--silent]
+    options.addOption(new Option("S", "silent", false, "Silent mode in 
interactive shell"));
+
+    // [-v|--verbose]
+    options.addOption(new Option("v", "verbose", false, "Verbose mode (echo 
executed SQL to the "
+        + "console)"));
+
+    // [-H|--help]
+    options.addOption(new Option("H", "help", false, "Print help 
information"));
+  }
+
+  public boolean process(String []argv){
+    try {
+      commandLine = new GnuParser().parse(options, argv);
+
+      if(commandLine.hasOption("help")){
+        printCliUsage();
+        return false;
+      }
+    } catch (ParseException e) {
+      System.err.println(e.getMessage());
+      printCliUsage();
+      return false;
+    }
+    return true;
+  }
+
+  public void printCliUsage() {
+    new HelpFormatter().printHelp("hive", options);
+  }
+
+  public CommandLine getCommandLine() {
+    return commandLine;
+  }
+
+  public void setCommandLine(CommandLine commandLine) {
+    this.commandLine = commandLine;
+  }
+}

http://git-wip-us.apache.org/repos/asf/hive/blob/03366392/beeline/src/java/org/apache/hive/beeline/cli/HiveCli.java
----------------------------------------------------------------------
diff --git a/beeline/src/java/org/apache/hive/beeline/cli/HiveCli.java 
b/beeline/src/java/org/apache/hive/beeline/cli/HiveCli.java
new file mode 100644
index 0000000..3e0da77
--- /dev/null
+++ b/beeline/src/java/org/apache/hive/beeline/cli/HiveCli.java
@@ -0,0 +1,41 @@
+/**
+ * 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.
+ */
+package org.apache.hive.beeline.cli;
+
+import org.apache.hive.beeline.BeeLine;
+import org.apache.hive.jdbc.Utils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class HiveCli {
+  private BeeLine beeLine;
+
+  public static void main(String[] args) throws IOException {
+    int status = new HiveCli().runWithArgs(args, null);
+    System.exit(status);
+  }
+
+  public int runWithArgs(String[] cmd, InputStream inputStream) throws 
IOException {
+    beeLine = new BeeLine(false);
+    return beeLine.begin(cmd, inputStream);
+  }
+}

http://git-wip-us.apache.org/repos/asf/hive/blob/03366392/beeline/src/test/org/apache/hive/beeline/cli/TestHiveCli.java
----------------------------------------------------------------------
diff --git a/beeline/src/test/org/apache/hive/beeline/cli/TestHiveCli.java 
b/beeline/src/test/org/apache/hive/beeline/cli/TestHiveCli.java
new file mode 100644
index 0000000..cc0b598
--- /dev/null
+++ b/beeline/src/test/org/apache/hive/beeline/cli/TestHiveCli.java
@@ -0,0 +1,153 @@
+/**
+ * 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.
+ */
+package org.apache.hive.beeline.cli;
+
+import junit.framework.Assert;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+public class TestHiveCli {
+  private static final Log LOG = 
LogFactory.getLog(TestHiveCli.class.getName());
+
+  final static String CMD = "create database if not exists test;\ncreate table 
if not exists test" +
+      ".testTbl(a " +
+      "" + "string, b string);\n";
+  private HiveCli cli;
+  private OutputStream os;
+  private PrintStream ps;
+  private OutputStream errS;
+  private PrintStream errPs;
+  private File tmp = null;
+
+  private void executeCMD(String[] args, String input, int retCode) {
+    InputStream inputStream = null;
+    int ret = 0;
+    try {
+      if (input != null) {
+        inputStream = IOUtils.toInputStream(input);
+      }
+      ret = cli.runWithArgs(args, inputStream);
+    } catch (IOException e) {
+      LOG.error("Failed to execute command due to the error: " + e);
+    } finally {
+      if (retCode != ret) {
+        LOG.error("Failed due to the error:" + errS.toString());
+        Assert.fail("Supported return code is " + retCode + " while the actual 
is " + ret);
+      }
+    }
+  }
+
+  private void verifyCMD(String CMD, String keywords, OutputStream os, 
String[] options, int
+      retCode) {
+    executeCMD(options, CMD, retCode);
+    String output = os.toString();
+    Assert.assertTrue(output.contains(keywords));
+  }
+
+  @Test
+  public void testInValidCmd() {
+    verifyCMD("!lss\n", "Failed to execute lss", errS, null, 0);
+  }
+
+  @Test
+  public void testHelp() {
+    verifyCMD(null, "usage: hive", os, new String[]{"-H"}, 1);
+  }
+
+  @Test
+  public void testInvalidDatabaseOptions() {
+    verifyCMD("\nshow tables\nquit\n", "Database does not exist: invalidDB", 
errS, new
+        String[]{"--database", "invalidDB"}, 0);
+  }
+
+  @Test
+  public void testDatabaseOptions() {
+    verifyCMD("\nshow tables;\nquit;", "testTbl", os, new 
String[]{"--database", "test"}, 0);
+  }
+
+  @Test
+  public void testSqlFromCmd() {
+    verifyCMD(null, "", os, new String[]{"-e", "show databases;"}, 0);
+  }
+
+  @Test
+  public void testSqlFromCmdWithDBName() {
+    verifyCMD(null, "testTbl", os, new String[]{"-e", "show tables;", 
"--database", "test"}, 0);
+  }
+
+  @Test
+  public void testInvalidOptions() {
+    verifyCMD(null, "The '-e' and '-f' options cannot be specified 
simultaneously", errS, new
+        String[]{"-e", "show tables;", "-f", "path/to/file"}, 1);
+  }
+
+  @Test
+  public void testInvalidOptions2() {
+    verifyCMD(null, "Unrecognized option: -k", errS, new String[]{"-k"}, 1);
+  }
+
+  private void redirectOutputStream() {
+    // Setup output stream to redirect output to
+    os = new ByteArrayOutputStream();
+    ps = new PrintStream(os);
+    errS = new ByteArrayOutputStream();
+    errPs = new PrintStream(errS);
+    System.setOut(ps);
+    System.setErr(errPs);
+  }
+
+  private void initFileFromFile() {
+    BufferedWriter bw = null;
+    try {
+      // create a tmp file
+      tmp = File.createTempFile("test", ".sql");
+      bw = new BufferedWriter(new FileWriter(tmp));
+      bw.write(CMD);
+    } catch (IOException e) {
+      LOG.error("Failed to write tmp file due to the exception: " + e);
+    } finally {
+      IOUtils.closeQuietly(bw);
+    }
+    executeCMD(new String[]{"-f", "\"" + tmp.getAbsolutePath() + "\""}, null, 
0);
+  }
+
+  @Before
+  public void setup() {
+    cli = new HiveCli();
+    redirectOutputStream();
+    initFileFromFile();
+  }
+
+  @After
+  public void tearDown() {
+    tmp.delete();
+  }
+}

http://git-wip-us.apache.org/repos/asf/hive/blob/03366392/beeline/src/test/resources/hive-site.xml
----------------------------------------------------------------------
diff --git a/beeline/src/test/resources/hive-site.xml 
b/beeline/src/test/resources/hive-site.xml
new file mode 100644
index 0000000..d2df03c
--- /dev/null
+++ b/beeline/src/test/resources/hive-site.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
+<!--
+   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.
+-->
+
+<configuration>
+  <property>
+    <name>hive.in.test</name>
+    <value>true</value>
+    <description>Internal marker for test. Used for masking env-dependent 
values</description>
+  </property>
+  <property>
+    <name>javax.jdo.option.ConnectionURL</name>
+    
<value>jdbc:derby:;databaseName=${test.tmp.dir}/metastore_db;create=true</value>
+    <description>JDBC connect string for a JDBC metastore</description>
+  </property>
+  <property>
+    <!--  this should eventually be deprecated since the metastore should 
supply this -->
+    <name>hive.metastore.warehouse.dir</name>
+    <value>${test.tmp.dir}/warehouse</value>
+    <description></description>
+  </property>
+</configuration>

Reply via email to