diff --git a/beeline/src/java/org/apache/hive/beeline/BeeLine.java b/beeline/src/java/org/apache/hive/beeline/BeeLine.java
index 406059d..28ff133 100644
--- a/beeline/src/java/org/apache/hive/beeline/BeeLine.java
+++ b/beeline/src/java/org/apache/hive/beeline/BeeLine.java
@@ -94,6 +94,8 @@
import org.apache.hive.beeline.cli.CliOptionsProcessor;
import org.apache.hive.jdbc.Utils;
+import static org.apache.hadoop.hive.metastore.MetaStoreUtils.DEFAULT_DATABASE_NAME;
+
/**
* A console SQL shell with command completion.
*
@@ -132,6 +134,7 @@
private List batch = null;
private final Reflector reflector;
private String dbName = null;
+ private String currentDatabase = null;
private History history;
private boolean isBeeLine = true;
@@ -692,6 +695,7 @@ int initArgsFromCliVars(String[] args) {
if (!commands.isEmpty()) {
embeddedConnect();
connectDBInEmbededMode();
+ updateOptsForCli();
for (Iterator i = commands.iterator(); i.hasNext(); ) {
String command = i.next().toString();
debug(loc("executing-command", command));
@@ -808,6 +812,13 @@ private String obtainPasswordFromFile(String passwordFilePath) {
}
}
+ private void updateOptsForCli() {
+ getOpts().updateBeeLineOptsFromConf();
+ getOpts().setShowHeader(false);
+ getOpts().setOutputFormat("dsv");
+ getOpts().setDelimiterForDSV(' ');
+ }
+
/**
* Start accepting input from stdin, and dispatch it
* to the appropriate {@link CommandHandler} until the
@@ -833,10 +844,7 @@ public int begin(String[] args, InputStream inputStream) throws IOException {
return code;
}
defaultConnect(false);
- getOpts().updateBeeLineOptsFromConf();
- getOpts().setShowHeader(false);
- getOpts().setOutputFormat("dsv");
- getOpts().setDelimiterForDSV(' ');
+ updateOptsForCli();
processInitFiles(opts.getInitFiles());
}
@@ -955,6 +963,7 @@ private int execute(ConsoleReader reader, boolean exitOnError) {
// trim line
line = (line == null) ? null : line.trim();
+
if (!dispatch(line) && exitOnError) {
return ERRNO_OTHER;
}
@@ -1056,8 +1065,32 @@ void usage() {
output(loc("cmd-usage"));
}
- private String[] tokenizeCmd(String cmd) {
- return cmd.split("\\s+");
+ public boolean execCommandWithPrefix(String line) {
+ Map cmdMap = new TreeMap();
+ line = line.substring(1);
+ for (int i = 0; i < commandHandlers.length; i++) {
+ String match = commandHandlers[i].matches(line);
+ if (match != null) {
+ CommandHandler prev = cmdMap.put(match, commandHandlers[i]);
+ if (prev != null) {
+ return error(
+ loc("multiple-matches", Arrays.asList(prev.getName(), commandHandlers[i].getName())));
+ }
+ }
+ }
+
+ 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);
}
/**
@@ -1092,64 +1125,14 @@ boolean dispatch(String line) {
if (isHelpRequest(line)) {
line = "!help";
}
-
- if (line.startsWith(COMMAND_PREFIX)) {
- Map cmdMap = new TreeMap();
- line = line.substring(1);
- for (int i = 0; i < commandHandlers.length; i++) {
- String match = commandHandlers[i].matches(line);
- if (match != null) {
- CommandHandler prev = cmdMap.put(match, commandHandlers[i]);
- if (prev != null) {
- return error(loc("multiple-matches",
- Arrays.asList(prev.getName(), commandHandlers[i].getName())));
- }
- }
- }
-
- 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);
+ if (line.startsWith("!connect")) {
+ return execCommandWithPrefix(line);
} else {
- boolean needsUpdate = isConfNeedsUpdate(line);
- boolean res = commands.sql(line, getOpts().getEntireLineAsCommand());
- if (needsUpdate) {
- getOpts().setHiveConf(getCommands().getHiveConf(false));
- }
- return res;
+ return commands.sql(line, getOpts().getEntireLineAsCommand());
}
}
/**
- * Update the configurations for the CLI mode in the client side
- *
- * @param line
- */
- private boolean isConfNeedsUpdate(String line) {
- if (isBeeLine) {
- return false;
- }
- String[] cmds = line.split(";");
- boolean containsSetCMD = false;
- for (String s : cmds) {
- if (s.toLowerCase().startsWith("set")) {
- return true;
- }
- }
- return containsSetCMD;
- }
-
- /**
* Test whether a line requires a continuation.
*
* @param line
@@ -1410,7 +1393,27 @@ String getPromptForCli() {
HiveConf conf = getCommands().getHiveConf(true);
prompt = conf.getVar(HiveConf.ConfVars.CLIPROMPT);
prompt = getCommands().substituteVariables(conf, prompt);
- return 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() {
@@ -2158,4 +2161,15 @@ public boolean 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;
+ }
}
diff --git a/beeline/src/java/org/apache/hive/beeline/ClientCommandHookFactory.java b/beeline/src/java/org/apache/hive/beeline/ClientCommandHookFactory.java
new file mode 100644
index 0000000..73c88dd
--- /dev/null
+++ b/beeline/src/java/org/apache/hive/beeline/ClientCommandHookFactory.java
@@ -0,0 +1,85 @@
+/**
+ * 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;
+
+/**
+ * We need to update some client side information after executing some Hive Commands
+ */
+public class ClientCommandHookFactory {
+ private static ClientCommandHookFactory instance = new ClientCommandHookFactory();
+
+ private ClientCommandHookFactory() {
+ }
+
+ public static ClientCommandHookFactory get() {
+ return instance;
+ }
+
+ public class SetCommandHook extends ClientHook {
+
+ public SetCommandHook(String sql) {
+ super(sql);
+ }
+
+ @Override
+ public void postHook(BeeLine beeLine) {
+ if (!beeLine.isBeeLine()) {
+ beeLine.getOpts().setHiveConf(beeLine.getCommands().getHiveConf(false));
+ }
+ }
+ }
+
+ public class UseCommandHook extends ClientHook {
+
+ public UseCommandHook(String sql) {
+ super(sql);
+ }
+
+ @Override
+ public void postHook(BeeLine beeLine) {
+ if (!beeLine.isBeeLine()) {
+ // Handler multi-line sql
+ String line = sql.replaceAll("\\s+", " ");
+ String strs[] = line.split(" ");
+ String dbName;
+ if (strs == null || strs.length != 2) {
+ // unable to parse the use command
+ dbName = "";
+ } else {
+ dbName = line.split(" ")[1];
+ }
+ beeLine.setCurrentDatabase(dbName);
+ }
+ }
+ }
+
+ public ClientHook getHook(String cmdLine) {
+ if (cmdLine.toLowerCase().startsWith("set")) {
+ // Only set A = B command needs updating the configuration stored in client side.
+ if (cmdLine.contains("=")) {
+ return new SetCommandHook(cmdLine);
+ } else {
+ return null;
+ }
+ } else if (cmdLine.toLowerCase().startsWith("use")) {
+ return new UseCommandHook(cmdLine);
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/beeline/src/java/org/apache/hive/beeline/ClientHook.java b/beeline/src/java/org/apache/hive/beeline/ClientHook.java
new file mode 100644
index 0000000..87c249a
--- /dev/null
+++ b/beeline/src/java/org/apache/hive/beeline/ClientHook.java
@@ -0,0 +1,31 @@
+/**
+ * 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;
+
+/**
+ * This is the client's hook
+ */
+public abstract class ClientHook {
+ protected String sql;
+
+ public ClientHook(String sql) {
+ this.sql = sql;
+ }
+
+ abstract void postHook(BeeLine beeLine);
+}
diff --git a/beeline/src/java/org/apache/hive/beeline/Commands.java b/beeline/src/java/org/apache/hive/beeline/Commands.java
index 01349e2..868d6a7 100644
--- a/beeline/src/java/org/apache/hive/beeline/Commands.java
+++ b/beeline/src/java/org/apache/hive/beeline/Commands.java
@@ -55,6 +55,7 @@
import java.util.Map;
import java.util.Properties;
import java.util.Set;
+import java.util.TreeMap;
import java.util.TreeSet;
import org.apache.hadoop.hive.common.cli.ShellCmdExecutor;
@@ -824,7 +825,7 @@ private boolean isSourceCMD(String cmd) {
if (cmd == null || cmd.isEmpty())
return false;
String[] tokens = tokenizeCmd(cmd);
- return tokens[0].equalsIgnoreCase("!source");
+ return tokens[0].equalsIgnoreCase("source");
}
private boolean sourceFile(String cmd) {
@@ -881,10 +882,7 @@ private boolean sourceFileInternal(File sourceFile) throws IOException {
private String cliToBeelineCmd(String cmd) {
if (cmd == null)
return null;
- String[] tokens = tokenizeCmd(cmd);
- if (tokens[0].equalsIgnoreCase("source")) {
- return BeeLine.COMMAND_PREFIX + cmd;
- } else if (cmd.startsWith("!")) {
+ if (cmd.startsWith("!")) {
String shell_cmd = cmd.substring(1);
return "!sh " + shell_cmd;
} else { // local mode
@@ -921,6 +919,15 @@ private boolean executeInternal(String sql, boolean call) {
return true;
}
+ if (!(beeLine.assertConnection())) {
+ return false;
+ }
+
+ ClientHook hook = null;
+ if (!beeLine.isBeeLine()) {
+ hook = ClientCommandHookFactory.get().getHook(sql);
+ }
+
try {
Statement stmnt = null;
boolean hasResults;
@@ -988,6 +995,9 @@ private boolean executeInternal(String sql, boolean call) {
return beeLine.error(e);
}
beeLine.showWarnings();
+ if (hook != null) {
+ hook.postHook(beeLine);
+ }
return true;
}
@@ -1070,6 +1080,8 @@ public boolean call(String line) {
return execute(line, true, false);
}
+ public static final String COMMAND_PREFIX = "!";
+
private boolean execute(String line, boolean call, boolean entireLineAsCommand) {
if (line == null || line.length() == 0) {
return false; // ???
@@ -1088,10 +1100,6 @@ private boolean execute(String line, boolean call, boolean entireLineAsCommand)
beeLine.handleException(e);
}
- if (!(beeLine.assertConnection())) {
- return false;
- }
-
line = line.trim();
List cmdList = new ArrayList();
if (entireLineAsCommand) {
@@ -1120,6 +1128,13 @@ private boolean execute(String line, boolean call, boolean entireLineAsCommand)
}
}
+ if (sql.startsWith(COMMAND_PREFIX)) {
+ if (!beeLine.execCommandWithPrefix(sql)) {
+ return false;
+ } else {
+ continue;
+ }
+ }
// is source CMD
if (isSourceCMD(sql)) {
sourceFile(sql);
diff --git a/beeline/src/test/org/apache/hive/beeline/TestClientCommandHookFactory.java b/beeline/src/test/org/apache/hive/beeline/TestClientCommandHookFactory.java
new file mode 100644
index 0000000..c86de0a
--- /dev/null
+++ b/beeline/src/test/org/apache/hive/beeline/TestClientCommandHookFactory.java
@@ -0,0 +1,32 @@
+/**
+ * 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;
+
+import junit.framework.Assert;
+import org.junit.Test;
+
+public class TestClientCommandHookFactory {
+ @Test
+ public void testGetHook() {
+ Assert.assertNull(ClientCommandHookFactory.get().getHook("set a;"));
+ Assert.assertTrue(ClientCommandHookFactory.get()
+ .getHook("set a=b;") instanceof ClientCommandHookFactory.SetCommandHook);
+ Assert.assertTrue(ClientCommandHookFactory.get()
+ .getHook("USE a.b") instanceof ClientCommandHookFactory.UseCommandHook);
+ }
+}
diff --git a/beeline/src/test/org/apache/hive/beeline/cli/TestHiveCli.java b/beeline/src/test/org/apache/hive/beeline/cli/TestHiveCli.java
index 7f6ab13..88857b0 100644
--- a/beeline/src/test/org/apache/hive/beeline/cli/TestHiveCli.java
+++ b/beeline/src/test/org/apache/hive/beeline/cli/TestHiveCli.java
@@ -74,92 +74,116 @@ private void executeCMD(String[] args, String input, int retCode) {
}
}
- private void verifyCMD(String CMD, String keywords, OutputStream os, String[] options,
- int retCode) {
+ /**
+ * This method is used for verifying CMD to see whether the output contains the keywords provided.
+ *
+ * @param CMD
+ * @param keywords
+ * @param os
+ * @param options
+ * @param retCode
+ * @param contains
+ */
+ public void verifyCMD(String CMD, String keywords, OutputStream os, String[] options, int retCode,
+ boolean contains) {
executeCMD(options, CMD, retCode);
String output = os.toString();
LOG.debug(output);
- Assert.assertTrue(
- "The expected keyword \"" + keywords + "\" doesn't occur in the output: " + output,
- output.contains(keywords));
+ if (contains) {
+ Assert.assertTrue(
+ "The expected keyword \"" + keywords + "\" doesn't occur in the output: " + output,
+ output.contains(keywords));
+ } else {
+ Assert.assertFalse(
+ "The expected keyword \"" + keywords + "\" are't occur in the output: " + output,
+ output.contains(keywords));
+ }
}
@Test
public void testInValidCmd() {
- verifyCMD("!lss\n", "Unknown command: lss", errS, null, ERRNO_OK);
+ verifyCMD("!lss\n", "Failed to execute lss", errS, null, ERRNO_OK, true);
+ }
+
+ @Test
+ public void testCmd() {
+ verifyCMD("show tables;!ls;show tables;\n", "src", os, null, ERRNO_OK, true);
}
@Test
public void testSetPromptValue() {
- verifyCMD("set hive.cli.prompt=MYCLI;SHOW\nTABLES;", "MYCLI> ", os, null, ERRNO_OK);
+ verifyCMD("set hive.cli.prompt=MYCLI;SHOW\nTABLES;", "MYCLI> ", os, null,
+ ERRNO_OK, true);
}
@Test
public void testSetHeaderValue() {
verifyCMD(
"create database if not exists test;\ncreate table if not exists test.testTbl(a string, b string);\nset hive.cli.print.header=true;\n select * from test.testTbl;\n",
- "testtbl.a testtbl.b", os, null, ERRNO_OK);
+ "testtbl.a testtbl.b", os, null, ERRNO_OK, true);
}
@Test
public void testHelp() {
- verifyCMD(null, "usage: hive", os, new String[] { "-H" }, ERRNO_ARGS);
+ verifyCMD(null, "usage: hive", os, new String[] { "-H" }, ERRNO_ARGS, true);
}
@Test
public void testInvalidDatabaseOptions() {
- verifyCMD("\nshow tables;\nquit;\n", "Database does not exist: invalidDB", errS,
- new String[] { "--database", "invalidDB" }, ERRNO_OK);
+ verifyCMD("\nshow tables;\nquit;\n", "Database does not exist: invalidDB",
+ errS, new String[] { "--database", "invalidDB" }, ERRNO_OK, true);
}
@Test
public void testDatabaseOptions() {
- verifyCMD("\nshow tables;\nquit;", "testtbl", os, new String[] { "--database", "test" },
- ERRNO_OK);
+ verifyCMD("\nshow tables;\nquit;", "testtbl", os,
+ new String[] { "--database", "test" }, ERRNO_OK, true);
}
@Test
public void testSourceCmd() {
File f = generateTmpFile(SOURCE_CONTEXT);
- verifyCMD("source " + f.getPath() + ";" + "desc testSrcTbl;\nquit;\n", "sc1", os,
- new String[] { "--database", "test" }, ERRNO_OK);
+ verifyCMD("source " + f.getPath() + ";" + "desc testSrcTbl;\nquit;\n",
+ "sc1", os, new String[] { "--database", "test" }, ERRNO_OK, true);
f.delete();
}
@Test
public void testSourceCmd2() {
File f = generateTmpFile(SOURCE_CONTEXT3);
- verifyCMD("source " + f.getPath() + ";" + "desc testSrcTbl3;\nquit;\n", "sc3", os,
- new String[] { "--database", "test" }, ERRNO_OK);
+ verifyCMD("source " + f.getPath() + ";" + "desc testSrcTbl3;\nquit;\n",
+ "sc3", os, new String[] { "--database", "test" }, ERRNO_OK, true);
f.delete();
}
@Test
public void testSqlFromCmd() {
- verifyCMD(null, "", os, new String[] { "-e", "show databases;" }, ERRNO_OK);
+ verifyCMD(null, "", os, new String[] { "-e", "show databases;" }, ERRNO_OK, true);
}
@Test
public void testSqlFromCmdWithDBName() {
- verifyCMD(null, "testtbl", os, new String[] { "-e", "show tables;", "--database", "test" },
- ERRNO_OK);
+ verifyCMD(null, "testtbl", os,
+ new String[] { "-e", "show tables;", "--database", "test" }, ERRNO_OK, true);
}
@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" }, ERRNO_ARGS);
+ verifyCMD(null,
+ "The '-e' and '-f' options cannot be specified simultaneously", errS,
+ new String[] { "-e", "show tables;", "-f", "path/to/file" }, ERRNO_ARGS, true);
}
@Test
public void testInvalidOptions2() {
- verifyCMD(null, "Unrecognized option: -k", errS, new String[] { "-k" }, ERRNO_ARGS);
+ verifyCMD(null, "Unrecognized option: -k", errS, new String[] { "-k" },
+ ERRNO_ARGS, true);
}
@Test
public void testVariables() {
- verifyCMD("set system:xxx=5;\nset system:yyy=${system:xxx};\nset system:yyy;", "", os, null,
- ERRNO_OK);
+ verifyCMD(
+ "set system:xxx=5;\nset system:yyy=${system:xxx};\nset system:yyy;", "", os, null, ERRNO_OK, true);
}
@Test
@@ -167,14 +191,47 @@ public void testVariablesForSource() {
File f = generateTmpFile(SOURCE_CONTEXT2);
verifyCMD(
"set hiveconf:zzz=" + f.getAbsolutePath() + ";\nsource ${hiveconf:zzz};\ndesc testSrcTbl2;",
- "sc2", os, new String[] { "--database", "test" }, ERRNO_OK);
+ "sc2", os, new String[] { "--database", "test" }, ERRNO_OK, true);
f.delete();
}
@Test
public void testErrOutput() {
verifyCMD("show tables;set system:xxx=5;set system:yyy=${system:xxx};\nlss;",
- "cannot recognize input near 'lss' '' ''", errS, null, ERRNO_OK);
+ "cannot recognize input near 'lss' '' ''", errS, null, ERRNO_OK, true);
+ }
+
+ @Test
+ public void testUseCurrentDB1() {
+ verifyCMD(
+ "create database if not exists testDB; set hive.cli.print.current.db=true;use testDB;\n"
+ + "use default;drop if exists testDB;", "hive (testDB)>", os, null, ERRNO_OK, true);
+ }
+
+ @Test
+ public void testUseCurrentDB2() {
+ verifyCMD(
+ "create database if not exists testDB; set hive.cli.print.current.db=true;use\ntestDB;\nuse default;drop if exists testDB;",
+ "hive (testDB)>", os, null, ERRNO_OK, true);
+ }
+
+ @Test
+ public void testUseCurrentDB3() {
+ verifyCMD(
+ "create database if not exists testDB; set hive.cli.print.current.db=true;use testDB;\n"
+ + "use default;drop if exists testDB;", "hive (testDB)>", os, null, ERRNO_OK, true);
+ }
+
+ @Test
+ public void testUseInvalidDB() {
+ verifyCMD("set hive.cli.print.current.db=true;use invalidDB;",
+ "hive (invalidDB)>", os, null, ERRNO_OK, false);
+ }
+
+ @Test
+ public void testNoErrorDB() {
+ verifyCMD(null, "Error: Method not supported (state=,code=0)", errS, new String[] { "-e", "show tables;" },
+ ERRNO_OK, false);
}
private void redirectOutputStream() {