Repository: hive Updated Branches: refs/heads/beeline-cli 1f5c745cd -> 3d088de02
HIVE-11637: Support hive.cli.print.current.db in new CLI[beeline-cli branch](Ferdinand Xu, reviewed by Dong Chen) Project: http://git-wip-us.apache.org/repos/asf/hive/repo Commit: http://git-wip-us.apache.org/repos/asf/hive/commit/3d088de0 Tree: http://git-wip-us.apache.org/repos/asf/hive/tree/3d088de0 Diff: http://git-wip-us.apache.org/repos/asf/hive/diff/3d088de0 Branch: refs/heads/beeline-cli Commit: 3d088de024ee277e9bb1d650ffef71c300266e7f Parents: 1f5c745 Author: Ferdinand Xu <cheng.a...@intel.com> Authored: Wed Aug 26 23:18:43 2015 -0400 Committer: Ferdinand Xu <cheng.a...@intel.com> Committed: Wed Aug 26 23:18:43 2015 -0400 ---------------------------------------------------------------------- .../java/org/apache/hive/beeline/BeeLine.java | 62 ++++++----- .../hive/beeline/ClientCommandHookFactory.java | 85 +++++++++++++++ .../org/apache/hive/beeline/ClientHook.java | 33 ++++++ .../java/org/apache/hive/beeline/Commands.java | 8 ++ .../beeline/TestClientCommandHookFactory.java | 32 ++++++ .../apache/hive/beeline/cli/TestHiveCli.java | 103 ++++++++++++++----- 6 files changed, 269 insertions(+), 54 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/hive/blob/3d088de0/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 406059d..1e4759b 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.hadoop.io.IOUtils; 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. * <p> @@ -132,6 +134,7 @@ public class BeeLine implements Closeable { private List<String> batch = null; private final Reflector reflector; private String dbName = null; + private String currentDatabase = null; private History history; private boolean isBeeLine = true; @@ -1121,32 +1124,8 @@ public class BeeLine implements Closeable { return cmdMap.values().iterator().next() .execute(line); } else { - boolean needsUpdate = isConfNeedsUpdate(line); - boolean res = commands.sql(line, getOpts().getEntireLineAsCommand()); - if (needsUpdate) { - getOpts().setHiveConf(getCommands().getHiveConf(false)); - } - return res; - } - } - - /** - * 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 commands.sql(line, getOpts().getEntireLineAsCommand()); } - return containsSetCMD; } /** @@ -1410,7 +1389,27 @@ public class BeeLine implements Closeable { 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 +2157,15 @@ public class BeeLine implements Closeable { 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/3d088de0/beeline/src/java/org/apache/hive/beeline/ClientCommandHookFactory.java ---------------------------------------------------------------------- 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..c4d97bc --- /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 + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * 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 final 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 = strs[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; + } + } +} http://git-wip-us.apache.org/repos/asf/hive/blob/3d088de0/beeline/src/java/org/apache/hive/beeline/ClientHook.java ---------------------------------------------------------------------- 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..3de6def --- /dev/null +++ b/beeline/src/java/org/apache/hive/beeline/ClientHook.java @@ -0,0 +1,33 @@ +/** + * 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 + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * 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 and used for new Hive CLI. For some configurations like + * set and use, it may change some prompt information in the client side. So the hook + * will be executed after some of the commands are used. + */ +public abstract class ClientHook { + protected String sql; + + public ClientHook(String sql) { + this.sql = sql; + } + + abstract void postHook(BeeLine beeLine); +} http://git-wip-us.apache.org/repos/asf/hive/blob/3d088de0/beeline/src/java/org/apache/hive/beeline/Commands.java ---------------------------------------------------------------------- diff --git a/beeline/src/java/org/apache/hive/beeline/Commands.java b/beeline/src/java/org/apache/hive/beeline/Commands.java index 01349e2..5e5cfec 100644 --- a/beeline/src/java/org/apache/hive/beeline/Commands.java +++ b/beeline/src/java/org/apache/hive/beeline/Commands.java @@ -921,6 +921,11 @@ public class Commands { return true; } + ClientHook hook = null; + if (!beeLine.isBeeLine()) { + hook = ClientCommandHookFactory.get().getHook(sql); + } + try { Statement stmnt = null; boolean hasResults; @@ -988,6 +993,9 @@ public class Commands { return beeLine.error(e); } beeLine.showWarnings(); + if (hook != null) { + hook.postHook(beeLine); + } return true; } http://git-wip-us.apache.org/repos/asf/hive/blob/3d088de0/beeline/src/test/org/apache/hive/beeline/TestClientCommandHookFactory.java ---------------------------------------------------------------------- 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 + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * 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); + } +} http://git-wip-us.apache.org/repos/asf/hive/blob/3d088de0/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 index 7f6ab13..e06d2ea 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,111 @@ public class TestHiveCli { } } - 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 + */ + private 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 + "\" doesn'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", "Unknown command: lss", errS, 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 +186,42 @@ public class TestHiveCli { 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' '<EOF>' '<EOF>'", errS, null, ERRNO_OK); + verifyCMD( + "show tables;set system:xxx=5;set system:yyy=${system:xxx};\nlss;", + "cannot recognize input near 'lss' '<EOF>' '<EOF>'", 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); } private void redirectOutputStream() {