This is an automated email from the ASF dual-hosted git repository.
abstractdog pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hive.git
The following commit(s) were added to refs/heads/master by this push:
new ac1f60ab4d2 HIVE-25495: Upgrade to JLine3 (#5838)
ac1f60ab4d2 is described below
commit ac1f60ab4d21f9d19b4759b3f248a5dea7c7d26d
Author: Bodor Laszlo <[email protected]>
AuthorDate: Mon Jul 28 10:24:10 2025 +0200
HIVE-25495: Upgrade to JLine3 (#5838)
---
beeline/pom.xml | 2 +-
.../hive/beeline/AbstractCommandHandler.java | 14 +-
.../src/java/org/apache/hive/beeline/BeeLine.java | 286 ++++++++++++++-------
.../hive/beeline/BeeLineCommandCompleter.java | 18 +-
.../org/apache/hive/beeline/BeeLineCompleter.java | 23 +-
.../HiveCli.java => BeeLineDummyTerminal.java} | 35 +--
.../java/org/apache/hive/beeline/BeeLineOpts.java | 41 +--
.../org/apache/hive/beeline/BooleanCompleter.java | 11 +-
.../org/apache/hive/beeline/CommandHandler.java | 6 +-
.../src/java/org/apache/hive/beeline/Commands.java | 37 ++-
.../apache/hive/beeline/DatabaseConnection.java | 27 +-
...eter.java => NoCurrentConnectionException.java} | 15 +-
.../hive/beeline/ReflectiveCommandHandler.java | 4 +-
.../java/org/apache/hive/beeline/SQLCompleter.java | 4 +-
...eNameCompletor.java => TableNameCompleter.java} | 23 +-
.../java/org/apache/hive/beeline/cli/HiveCli.java | 6 +-
.../hive/beeline/schematool/HiveSchemaTool.java | 3 +-
.../apache/hive/beeline/TestBeeLineHistory.java | 16 +-
.../test/org/apache/hive/beeline/TestCommands.java | 8 +-
.../apache/hive/beeline/cli/HiveCliForTest.java} | 18 +-
.../org/apache/hive/beeline/cli/TestHiveCli.java | 11 +-
cli/pom.xml | 2 +-
.../java/org/apache/hadoop/hive/cli/CliDriver.java | 216 ++++++++--------
.../hadoop/hive/cli/TestCliDriverMethods.java | 174 +++++++------
common/pom.xml | 3 +-
.../hive/common/util/MatchingStringsCompleter.java | 70 +++++
hcatalog/hcatalog-pig-adapter/pom.xml | 6 +-
.../apache/hive/beeline/TestBeeLineWithArgs.java | 67 +++--
.../hive/beeline/TestBeelinePasswordOption.java | 36 +--
.../apache/hive/beeline/TestHplSqlViaBeeLine.java | 8 +-
.../BeelineWithHS2ConnectionFileTestBase.java | 14 +-
.../miniHS2/TestHs2ConnectionMetricsBinary.java | 3 +-
.../InformationSchemaWithPrivilegeTestBase.java | 3 +-
.../llap/cli/service/LlapServiceCommandLine.java | 5 +-
.../cli/status/LlapStatusServiceCommandLine.java | 6 +-
pom.xml | 10 +-
standalone-metastore/metastore-server/pom.xml | 2 +-
.../tools/metatool/HiveMetaToolCommandLine.java | 5 +-
standalone-metastore/pom.xml | 11 +-
39 files changed, 713 insertions(+), 536 deletions(-)
diff --git a/beeline/pom.xml b/beeline/pom.xml
index c482416de51..a806eb29d5c 100644
--- a/beeline/pom.xml
+++ b/beeline/pom.xml
@@ -80,7 +80,7 @@
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
- <groupId>jline</groupId>
+ <groupId>org.jline</groupId>
<artifactId>jline</artifactId>
</dependency>
<dependency>
diff --git
a/beeline/src/java/org/apache/hive/beeline/AbstractCommandHandler.java
b/beeline/src/java/org/apache/hive/beeline/AbstractCommandHandler.java
index 7fc3f958f5d..cd250ca2906 100644
--- a/beeline/src/java/org/apache/hive/beeline/AbstractCommandHandler.java
+++ b/beeline/src/java/org/apache/hive/beeline/AbstractCommandHandler.java
@@ -26,8 +26,8 @@
import java.util.LinkedList;
import java.util.List;
-import jline.console.completer.Completer;
-import jline.console.completer.NullCompleter;
+import org.jline.reader.Completer;
+import org.jline.reader.impl.completer.NullCompleter;
/**
* An abstract implementation of CommandHandler.
@@ -43,15 +43,15 @@ public abstract class AbstractCommandHandler implements
CommandHandler {
protected transient Throwable lastException;
public AbstractCommandHandler(BeeLine beeLine, String[] names, String
helpText,
- Completer[] completors) {
+ Completer[] completers) {
this.beeLine = beeLine;
name = names[0];
this.names = names;
this.helpText = helpText;
- if (completors == null || completors.length == 0) {
+ if (completers == null || completers.length == 0) {
parameterCompleters = new Completer[] { new NullCompleter() };
} else {
- List<Completer> c = new LinkedList<Completer>(Arrays.asList(completors));
+ List<Completer> c = new LinkedList<Completer>(Arrays.asList(completers));
c.add(new NullCompleter());
parameterCompleters = c.toArray(new Completer[0]);
}
@@ -94,10 +94,6 @@ public String matches(String line) {
return null;
}
- public void setParameterCompleters(Completer[] parameterCompleters) {
- this.parameterCompleters = parameterCompleters;
- }
-
@Override
public Completer[] getParameterCompleters() {
return parameterCompleters;
diff --git a/beeline/src/java/org/apache/hive/beeline/BeeLine.java
b/beeline/src/java/org/apache/hive/beeline/BeeLine.java
index 515d33f8434..3cbbc826d8d 100644
--- a/beeline/src/java/org/apache/hive/beeline/BeeLine.java
+++ b/beeline/src/java/org/apache/hive/beeline/BeeLine.java
@@ -87,7 +87,6 @@
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.hive.conf.Constants;
import org.apache.hadoop.hive.conf.HiveConf;
@@ -101,6 +100,7 @@
import org.apache.hive.beeline.hs2connection.HS2ConnectionFileUtils;
import org.apache.hive.beeline.hs2connection.HiveSiteHS2ConnectionFileParser;
import org.apache.hive.beeline.hs2connection.UserHS2ConnectionFileParser;
+import org.apache.hive.common.util.MatchingStringsCompleter;
import org.apache.hive.common.util.ShutdownHookManager;
import org.apache.hive.common.util.HiveStringUtils;
import org.apache.hive.jdbc.HiveConnection;
@@ -111,11 +111,19 @@
import com.google.common.annotations.VisibleForTesting;
-import jline.console.ConsoleReader;
-import jline.console.completer.Completer;
-import jline.console.completer.FileNameCompleter;
-import jline.console.completer.StringsCompleter;
-import jline.console.history.FileHistory;
+import org.jline.reader.Completer;
+import org.jline.reader.EndOfFileException;
+import org.jline.reader.History;
+import org.jline.reader.LineReader;
+import org.jline.reader.LineReaderBuilder;
+import org.jline.reader.impl.DefaultParser;
+import org.jline.reader.impl.LineReaderImpl;
+import org.jline.reader.impl.history.DefaultHistory;
+import org.jline.terminal.Terminal;
+import org.jline.terminal.TerminalBuilder;
+
+import static org.jline.builtins.Completers.FileNameCompleter;
+
/**
* A console SQL shell with command completion.
@@ -152,14 +160,14 @@ public class BeeLine implements Closeable {
private OutputFile recordOutputFile = null;
private PrintStream outputStream = new PrintStream(System.out, true);
private PrintStream errorStream = new PrintStream(System.err, true);
- private InputStream inputStream = System.in;
- private ConsoleReader consoleReader;
+ private LineReader lineReader;
+ private final List<Terminal> terminalsToClose = new ArrayList<>();
private List<String> batch = null;
private final Reflector reflector = new Reflector(this);
private String dbName = null;
private String currentDatabase = null;
- private FileHistory history;
+ private History history;
// Indicates if this instance of beeline is running in compatibility mode,
or beeline mode
private boolean isBeeLine = true;
@@ -205,19 +213,19 @@ public class BeeLine implements Closeable {
new ReflectiveCommandHandler(this, new String[] {"quit", "done", "exit"},
null),
new ReflectiveCommandHandler(this, new String[] {"connect", "open"},
- new Completer[] {new StringsCompleter(getConnectionURLExamples())}),
+ new Completer[] {new
MatchingStringsCompleter(getConnectionURLExamples())}),
new ReflectiveCommandHandler(this, new String[] {"describe"},
- new Completer[] {new TableNameCompletor(this)}),
+ new Completer[] {new TableNameCompleter(this)}),
new ReflectiveCommandHandler(this, new String[] {"indexes"},
- new Completer[] {new TableNameCompletor(this)}),
+ new Completer[] {new TableNameCompleter(this)}),
new ReflectiveCommandHandler(this, new String[] {"primarykeys"},
- new Completer[] {new TableNameCompletor(this)}),
+ new Completer[] {new TableNameCompleter(this)}),
new ReflectiveCommandHandler(this, new String[] {"exportedkeys"},
- new Completer[] {new TableNameCompletor(this)}),
+ new Completer[] {new TableNameCompleter(this)}),
new ReflectiveCommandHandler(this, new String[] {"manual"},
null),
new ReflectiveCommandHandler(this, new String[] {"importedkeys"},
- new Completer[] {new TableNameCompletor(this)}),
+ new Completer[] {new TableNameCompleter(this)}),
new ReflectiveCommandHandler(this, new String[] {"procedures"},
null),
new ReflectiveCommandHandler(this, new String[] {"tables"},
@@ -225,16 +233,16 @@ public class BeeLine implements Closeable {
new ReflectiveCommandHandler(this, new String[] {"typeinfo"},
null),
new ReflectiveCommandHandler(this, new String[] {"columns"},
- new Completer[] {new TableNameCompletor(this)}),
+ new Completer[] {new TableNameCompleter(this)}),
new ReflectiveCommandHandler(this, new String[] {"reconnect"},
null),
new ReflectiveCommandHandler(this, new String[] {"dropall"},
- new Completer[] {new TableNameCompletor(this)}),
+ new Completer[] {new TableNameCompleter(this)}),
new ReflectiveCommandHandler(this, new String[] {"history"},
null),
new ReflectiveCommandHandler(this, new String[] {"metadata"},
new Completer[] {
- new StringsCompleter(getMetadataMethodNames())}),
+ new MatchingStringsCompleter(getMetadataMethodNames())}),
new ReflectiveCommandHandler(this, new String[] {"nativesql"},
null),
new ReflectiveCommandHandler(this, new String[] {"dbinfo"},
@@ -264,9 +272,9 @@ public class BeeLine implements Closeable {
new ReflectiveCommandHandler(this, new String[] {"closeall"},
null),
new ReflectiveCommandHandler(this, new String[] {"isolation"},
- new Completer[] {new StringsCompleter(getIsolationLevels())}),
+ new Completer[] {new
MatchingStringsCompleter(getIsolationLevels())}),
new ReflectiveCommandHandler(this, new String[] {"outputformat"},
- new Completer[] {new StringsCompleter(
+ new Completer[] {new MatchingStringsCompleter(
formats.keySet().toArray(new String[0]))}),
new ReflectiveCommandHandler(this, new String[] {"autocommit"},
null),
@@ -310,9 +318,9 @@ public class BeeLine implements Closeable {
static {
try {
- Class.forName("jline.console.ConsoleReader");
+ Class.forName("org.jline.reader.LineReader");
} catch (Throwable t) {
- throw new ExceptionInInitializerError("jline-missing");
+ throw new ExceptionInInitializerError("jline3-missing");
}
}
@@ -401,7 +409,7 @@ public class BeeLine implements Closeable {
.withLongOpt("help")
.withDescription("Display this message")
.create('h'));
-
+
// -getUrlsFromBeelineSite
options.addOption(OptionBuilder
.withLongOpt("getUrlsFromBeelineSite")
@@ -434,7 +442,6 @@ public class BeeLine implements Closeable {
.create());
}
-
static Manifest getManifest() throws IOException {
URL base = BeeLine.class.getResource("/META-INF/MANIFEST.MF");
URLConnection c = base.openConnection();
@@ -444,7 +451,6 @@ static Manifest getManifest() throws IOException {
return null;
}
-
String getManifestAttribute(String name) {
try {
Manifest m = getManifest();
@@ -552,6 +558,11 @@ public static void main(String[] args) throws IOException {
public static void mainWithInputRedirection(String[] args, InputStream
inputStream)
throws IOException {
BeeLine beeLine = new BeeLine();
+ mainWithInputRedirection(args, inputStream, beeLine);
+ }
+
+ public static void mainWithInputRedirection(String[] args, InputStream
inputStream, BeeLine beeLine)
+ throws IOException {
try {
int status = beeLine.begin(args, inputStream);
@@ -570,19 +581,15 @@ public BeeLine() {
public BeeLine(boolean isBeeLine) {
this.isBeeLine = isBeeLine;
this.signalHandler = new SunSignalHandler(this);
- this.shutdownHook = new Runnable() {
- @Override
- public void run() {
- try {
- if (history != null) {
- history.setMaxSize(getOpts().getMaxHistoryRows());
- history.flush();
- }
- } catch (IOException e) {
- error(e);
- } finally {
- close();
+ this.shutdownHook = () -> {
+ try {
+ if (history != null) {
+ history.save();
}
+ } catch (IOException e) {
+ error(e);
+ } finally {
+ close();
}
};
}
@@ -603,10 +610,10 @@ Connection getConnection() throws SQLException {
DatabaseMetaData getDatabaseMetaData() {
if (getDatabaseConnections().current() == null) {
- throw new IllegalArgumentException(loc("no-current-connection"));
+ throw new NoCurrentConnectionException(loc("no-current-connection"));
}
if (getDatabaseConnections().current().getDatabaseMetaData() == null) {
- throw new IllegalArgumentException(loc("no-current-connection"));
+ throw new NoCurrentConnectionException(loc("no-current-connection"));
}
return getDatabaseConnections().current().getDatabaseMetaData();
}
@@ -864,7 +871,7 @@ private boolean connectUsingArgs(BeelineParser
beelineParser, CommandLine cl) {
getOpts().setHelpAsked(true);
return true;
}
-
+
if (cl.hasOption("getUrlsFromBeelineSite")) {
printBeelineSiteUrls();
getOpts().setBeelineSiteUrlsAsked(true);
@@ -937,11 +944,7 @@ private boolean connectUsingArgs(BeelineParser
beelineParser, CommandLine cl) {
// load property file
String propertyFile = cl.getOptionValue("property-file");
if (propertyFile != null) {
- try {
- this.consoleReader = new ConsoleReader();
- } catch (IOException e) {
- handleException(e);
- }
+ this.lineReader = LineReaderBuilder.builder().build();
if (!dispatch("!properties " + propertyFile)) {
exit = true;
return false;
@@ -981,7 +984,7 @@ private void printBeelineSiteUrls() {
}
}
}
-
+
private boolean isZkBasedUrl(String urlFromBeelineSite) {
String zkJdbcUriParam = ("serviceDiscoveryMode=zooKeeper").toLowerCase();
if (urlFromBeelineSite.toLowerCase().contains(zkJdbcUriParam)) {
@@ -1117,9 +1120,9 @@ public int begin(String[] args, InputStream inputStream,
boolean keepHistory) th
//add shutdown hook to cleanup the beeline for smooth exit
addBeelineShutdownHook();
- //this method also initializes the consoleReader which is
+ //this method also initializes the lineReader which is
//needed by initArgs for certain execution paths
- ConsoleReader reader = initializeConsoleReader(inputStream);
+ LineReader interactiveLineReader = initializeLineReader(inputStream);
if (isBeeLine) {
int code = initArgs(args);
if (code != 0) {
@@ -1147,7 +1150,9 @@ public int begin(String[] args, InputStream inputStream,
boolean keepHistory) th
} catch (Exception e) {
// ignore
}
- return execute(reader, false);
+ // at this point, begin phase is finished and beeline is ready for
interactive commands
+ this.lineReader = interactiveLineReader;
+ return execute(interactiveLineReader, false);
}
/*
@@ -1351,7 +1356,7 @@ private int executeFile(String fileName) {
}
fileStream = fs.open(path);
}
- return execute(initializeConsoleReader(fileStream),
!getOpts().getForce());
+ return executeFile(fileStream);
} catch (Throwable t) {
handleException(t);
return ERRNO_OTHER;
@@ -1360,17 +1365,28 @@ private int executeFile(String fileName) {
}
}
- private int execute(ConsoleReader reader, boolean exitOnError) {
+ private int executeFile(InputStream fileStream) throws IOException {
+ // This assignment is necessary because other classes (like Commands) call
BeeLine.readLine(prompt, mask)
+ // without needing to be aware of which type of reader is currently in use
+ this.lineReader = getFileLineReader(fileStream);
+ int retCode = execute(lineReader, !getOpts().getForce());
+ // nullify for clarity's sake, as this variable will later be assigned to
the interactive line reader
+ lineReader = null;
+ return retCode;
+ }
+
+ @VisibleForTesting
+ int execute(LineReader reader, boolean exitOnError) {
int lastExecutionResult = ERRNO_OK;
Character mask = (System.getProperty("jline.terminal",
"").equals("jline.UnsupportedTerminal")) ? null
- : ConsoleReader.NULL_MASK;
+ : LineReaderImpl.NULL_MASK;
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, mask) : reader.readLine(getPrompt());
+ String line = (getOpts().isSilent() && getOpts().getScriptFile() !=
null) ? readLine(reader, null, mask) :
+ readLine(reader, getPrompt(), null);
// trim line
if (line != null) {
@@ -1385,7 +1401,6 @@ private int execute(ConsoleReader reader, boolean
exitOnError) {
} else if (line != null) {
lastExecutionResult = ERRNO_OK;
}
-
} catch (Throwable t) {
handleException(t);
return ERRNO_OTHER;
@@ -1394,17 +1409,44 @@ private int execute(ConsoleReader reader, boolean
exitOnError) {
return lastExecutionResult;
}
+ public String readLine(String prompt, Character mask) {
+ return readLine(getLineReader(), prompt, mask);
+ }
+
+ /**
+ * Reads a line with the given prompt and optional mask character.
+ * Starting with JLine3, an EndOfFileException is intentionally thrown upon
reaching the end of the input stream.
+ * In interactive usage, this method returns the partial line entered before
the exception to preserve existing
+ * behavior.
+ */
+ private String readLine(LineReader reader, String prompt, Character mask) {
+ try {
+ return reader.readLine(prompt, mask);
+ } catch (EndOfFileException eof) {
+ return eof.getPartialLine();
+ }
+ }
+
@Override
public void close() {
commands.closeall(null);
+ terminalsToClose.forEach(t -> {
+ try {
+ t.close();
+ } catch (IOException e) {
+ info(String.format("Exception while closing terminal (name: %s, class:
%s): %s", t.getName(),
+ t.getClass(), e.getMessage()));
+ }
+ });
}
- private void setupHistory() throws IOException {
+ @VisibleForTesting
+ void setupHistory() {
if (this.history != null) {
return;
}
- this.history = new FileHistory(new File(getOpts().getHistoryFile()));
+ this.history = new DefaultHistory();
}
private void addBeelineShutdownHook() throws IOException {
@@ -1412,40 +1454,107 @@ private void addBeelineShutdownHook() throws
IOException {
ShutdownHookManager.addShutdownHook(getShutdownHook());
}
- public ConsoleReader initializeConsoleReader(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,
getErrorStream());
- consoleReader.setCopyPasteDetection(true); // jline will detect if <tab>
is regular character
- } else {
- consoleReader = new ConsoleReader(getInputStream(), getErrorStream());
- }
+ public LineReader getFileLineReader(InputStream inputStream) throws
IOException {
+ final LineReaderBuilder builder = LineReaderBuilder.builder();
+ defaultParser(builder);
+
+ builder.terminal(buildTerminal(prepareInputStream(inputStream)));
- //disable the expandEvents for the purpose of backward compatibility
- consoleReader.setExpandEvents(false);
+ return builder.build();
+ }
+
+ public LineReader initializeLineReader(InputStream inputStream) throws
IOException {
+ final LineReaderBuilder builder = LineReaderBuilder.builder();
+ defaultParser(builder);
+
+ Terminal lineReaderTerminal = buildTerminal(inputStream);
+ builder.terminal(lineReaderTerminal);
try {
// now set the output for the history
if (this.history != null) {
- consoleReader.setHistory(this.history);
- } else {
- consoleReader.setHistoryEnabled(false);
+ builder.history(this.history);
+ builder.variable(LineReader.HISTORY_FILE, new
File(getOpts().getHistoryFile()));
+ builder.variable(LineReader.HISTORY_FILE_SIZE,
getOpts().getMaxHistoryRows());
+ // in-memory keep more data, but at least 500 entries
+ builder.variable(LineReader.HISTORY_SIZE, Math.max(500, 3 *
getOpts().getMaxHistoryRows()));
}
} 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;
+ builder.completer(new BeeLineCompleter(this));
+ lineReader = builder.build();
+ lineReader.unsetOpt(LineReader.Option.HISTORY_TIMESTAMPED);
+ // need to disable expansion, otherwise commands (starting with "!") will
activate history items
+ lineReader.setOpt(LineReader.Option.DISABLE_EVENT_EXPANSION);
+
+ if (this.history != null) {
+ this.history.attach(lineReader);
}
+ return lineReader;
+ }
+
+ private void defaultParser(LineReaderBuilder builder) {
+ DefaultParser parser = new DefaultParser() {
+ private String extraNameCharacters;
+
+ // delimiters for SQL statements are any
+ // non-letter-or-number characters, except
+ // underscore and characters that are specified
+ // by the database to be valid name identifiers.
+ @Override
+ public boolean isDelimiterChar(CharSequence buffer, int pos) {
+ char c = buffer.charAt(pos);
+ if (Character.isWhitespace(c)) {
+ return true;
+ }
+ return !(Character.isLetterOrDigit(c))
+ && c != '_'
+ && extraNameCharacters().indexOf(c) == -1;
+ }
- consoleReader.addCompleter(new BeeLineCompleter(this));
- return consoleReader;
+ private String extraNameCharacters() {
+ if (extraNameCharacters != null) {
+ return extraNameCharacters;
+ }
+ try {
+ extraNameCharacters =
+ getDatabaseMetaData() == null ||
getDatabaseMetaData().getExtraNameCharacters() == null ? ""
+ : getDatabaseMetaData().getExtraNameCharacters();
+ return extraNameCharacters;
+ } catch (NoCurrentConnectionException noCurrentConnectionException) {
+ // this is not a problem at this point, will be tried again when a
connection is present
+ debug("No current connection found while trying to retrieve extra
name characters.");
+ return "";
+ } catch (SQLException e) {
+ throw new RuntimeException("Error while retrieving database extra
characters", e);
+ }
+ }
+ };
+ // In JLine3, special characters (e.g., backslash) are handled by the
terminal by default.
+ // This is not desired: we want to send the query string to HS2 exactly as
entered, without interpretation.
+ parser.setEscapeChars(new char[]{});
+ builder.parser(parser);
+ }
+
+ private InputStream prepareInputStream(InputStream inputStream) {
+ if (inputStream != null) {
+ inputStream = new SequenceInputStream(inputStream,
+ new ByteArrayInputStream((new String("\n")).getBytes()));
+ }
+ return inputStream;
+ }
+
+ protected Terminal buildTerminal(InputStream inputStream) throws IOException
{
+ Terminal terminal;
+ if (inputStream != null) { // typically when there is a file script to
read from
+ terminal = TerminalBuilder.builder().streams(inputStream,
getErrorStream()).build();
+ } else { // no input stream, normal operation: proper behavior needs a
system terminal (which needs system streams)
+ terminal =
TerminalBuilder.builder().system(true).dumb(false).streams(System.in,
System.err).build();
+ }
+ this.terminalsToClose.add(terminal);
+ return terminal;
}
void usage() {
@@ -1496,13 +1605,12 @@ boolean dispatch(String line) {
}
line = HiveStringUtils.removeComments(line);
+ line = line.trim();
- if (line.trim().length() == 0) {
+ if (line.isEmpty()) {
return true;
}
- line = line.trim();
-
// save it to the current script, if any
if (scriptOutputFile != null) {
scriptOutputFile.addLine(line);
@@ -2434,7 +2542,7 @@ Runnable getShutdownHook() {
return shutdownHook;
}
- Completer getCommandCompletor() {
+ Completer getCommandCompleter() {
return beeLineCommandCompleter;
}
@@ -2494,16 +2602,8 @@ PrintStream getErrorStream() {
return errorStream;
}
- InputStream getInputStream() {
- return inputStream;
- }
-
- ConsoleReader getConsoleReader() {
- return consoleReader;
- }
-
- void setConsoleReader(ConsoleReader reader) {
- this.consoleReader = reader;
+ public LineReader getLineReader() {
+ return lineReader;
}
List<String> getBatch() {
diff --git
a/beeline/src/java/org/apache/hive/beeline/BeeLineCommandCompleter.java
b/beeline/src/java/org/apache/hive/beeline/BeeLineCommandCompleter.java
index 44bfc9fa61b..8583b998af7 100644
--- a/beeline/src/java/org/apache/hive/beeline/BeeLineCommandCompleter.java
+++ b/beeline/src/java/org/apache/hive/beeline/BeeLineCommandCompleter.java
@@ -21,10 +21,10 @@
import java.util.LinkedList;
import java.util.List;
-import jline.console.completer.AggregateCompleter;
-import jline.console.completer.Completer;
-import jline.console.completer.NullCompleter;
-import jline.console.completer.StringsCompleter;
+import org.apache.hive.common.util.MatchingStringsCompleter;
+import org.jline.reader.Completer;
+import org.jline.reader.impl.completer.AggregateCompleter;
+import org.jline.reader.impl.completer.NullCompleter;
class BeeLineCommandCompleter extends AggregateCompleter {
public BeeLineCommandCompleter(Iterable<CommandHandler> handlers) {
@@ -32,21 +32,21 @@ public BeeLineCommandCompleter(Iterable<CommandHandler>
handlers) {
}
public static List<Completer> getCompleters(Iterable<CommandHandler>
handlers){
- List<Completer> completers = new LinkedList<Completer>();
+ List<Completer> completers = new LinkedList<>();
for (CommandHandler handler : handlers) {
String[] commandNames = handler.getNames();
if (commandNames != null) {
for (String commandName : commandNames) {
- List<Completer> compl = new LinkedList<Completer>();
- compl.add(new StringsCompleter(BeeLine.COMMAND_PREFIX +
commandName));
+ List<Completer> compl = new LinkedList<>();
+ compl.add(new MatchingStringsCompleter(BeeLine.COMMAND_PREFIX +
commandName));
compl.addAll(Arrays.asList(handler.getParameterCompleters()));
compl.add(new NullCompleter()); // last param no complete
- completers.add(new AggregateCompleter(compl.toArray(new
Completer[compl.size()])));
+ completers.add(new AggregateCompleter(compl.toArray(new
Completer[0])));
}
}
}
return completers;
}
-}
\ No newline at end of file
+}
diff --git a/beeline/src/java/org/apache/hive/beeline/BeeLineCompleter.java
b/beeline/src/java/org/apache/hive/beeline/BeeLineCompleter.java
index 9213bcf7678..6b6b77c4bd1 100644
--- a/beeline/src/java/org/apache/hive/beeline/BeeLineCompleter.java
+++ b/beeline/src/java/org/apache/hive/beeline/BeeLineCompleter.java
@@ -24,10 +24,13 @@
import java.util.List;
-import jline.console.completer.Completer;
+import org.jline.reader.Candidate;
+import org.jline.reader.Completer;
+import org.jline.reader.LineReader;
+import org.jline.reader.ParsedLine;
/**
- * Completor for BeeLine. It dispatches to sub-completors based on the
+ * Completer for BeeLine. It dispatches to sub-completors based on the
* current arguments.
*
*/
@@ -42,17 +45,15 @@ class BeeLineCompleter implements Completer {
}
@Override
- public int complete(String buf, int pos, List cand) {
- if (buf != null && buf.startsWith(BeeLine.COMMAND_PREFIX)
- && !buf.startsWith(BeeLine.COMMAND_PREFIX + "all")
- && !buf.startsWith(BeeLine.COMMAND_PREFIX + "sql")) {
- return beeLine.getCommandCompletor().complete(buf, pos, cand);
+ public void complete(LineReader reader, ParsedLine line, List<Candidate>
candidates) {
+ if (line != null && line.line().startsWith(BeeLine.COMMAND_PREFIX)
+ && !line.line().startsWith(BeeLine.COMMAND_PREFIX + "all")
+ && !line.line().startsWith(BeeLine.COMMAND_PREFIX + "sql")) {
+ beeLine.getCommandCompleter().complete(reader, line, candidates);
} else {
if (beeLine.getDatabaseConnection() != null &&
beeLine.getDatabaseConnection().getSQLCompleter() != null) {
- return beeLine.getDatabaseConnection().getSQLCompleter().complete(buf,
pos, cand);
- } else {
- return -1;
+ beeLine.getDatabaseConnection().getSQLCompleter().complete(reader,
line, candidates);
}
}
}
-}
\ No newline at end of file
+}
diff --git a/beeline/src/java/org/apache/hive/beeline/cli/HiveCli.java
b/beeline/src/java/org/apache/hive/beeline/BeeLineDummyTerminal.java
similarity index 53%
copy from beeline/src/java/org/apache/hive/beeline/cli/HiveCli.java
copy to beeline/src/java/org/apache/hive/beeline/BeeLineDummyTerminal.java
index 99a72797592..1c03260472f 100644
--- a/beeline/src/java/org/apache/hive/beeline/cli/HiveCli.java
+++ b/beeline/src/java/org/apache/hive/beeline/BeeLineDummyTerminal.java
@@ -15,28 +15,33 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.hive.beeline.cli;
-import org.apache.hadoop.util.ExitUtil;
-import org.apache.hive.beeline.BeeLine;
+package org.apache.hive.beeline;
import java.io.IOException;
import java.io.InputStream;
-public class HiveCli {
- private BeeLine beeLine;
+import org.jline.terminal.Terminal;
+import org.jline.terminal.impl.DumbTerminal;
- public static void main(String[] args) throws IOException {
- int status = new HiveCli().runWithArgs(args, null);
- ExitUtil.terminate(status);
+/**
+ * A Beeline implementation that always creates a DumbTerminal.
+ * This class resides in the production source code (not in tests) because
Beeline can serve as a
+ * dummy terminal tool without real user interaction (e.g., HiveSchemaTool),
not just in testing scenarios,
+ * although that is its primary use case.
+ */
+public class BeeLineDummyTerminal extends BeeLine {
+
+ public BeeLineDummyTerminal() {
+ this(true);
+ }
+
+ public BeeLineDummyTerminal(boolean isBeeLine) {
+ super(isBeeLine);
}
- public int runWithArgs(String[] cmd, InputStream inputStream) throws
IOException {
- beeLine = new BeeLine(false);
- try {
- return beeLine.begin(cmd, inputStream);
- } finally {
- beeLine.close();
- }
+ @Override
+ protected Terminal buildTerminal(InputStream inputStream) throws IOException
{
+ return new DumbTerminal(inputStream, getErrorStream());
}
}
diff --git a/beeline/src/java/org/apache/hive/beeline/BeeLineOpts.java
b/beeline/src/java/org/apache/hive/beeline/BeeLineOpts.java
index 04ebab7df2e..fa97ebe13af 100644
--- a/beeline/src/java/org/apache/hive/beeline/BeeLineOpts.java
+++ b/beeline/src/java/org/apache/hive/beeline/BeeLineOpts.java
@@ -22,6 +22,15 @@
*/
package org.apache.hive.beeline;
+import org.apache.hadoop.hive.conf.HiveConf;
+import org.apache.hive.common.util.MatchingStringsCompleter;
+import org.jline.reader.Candidate;
+import org.jline.reader.Completer;
+import org.jline.reader.LineReader;
+import org.jline.reader.ParsedLine;
+import org.jline.terminal.Terminal;
+import org.jline.terminal.TerminalBuilder;
+
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -41,13 +50,6 @@
import java.util.Set;
import java.util.TreeSet;
-import jline.Terminal;
-import jline.TerminalFactory;
-import jline.console.completer.Completer;
-import jline.console.completer.StringsCompleter;
-import jline.console.history.MemoryHistory;
-import org.apache.hadoop.hive.conf.HiveConf;
-
public class BeeLineOpts implements Completer {
public static final int DEFAULT_MAX_WIDTH = 80;
public static final int DEFAULT_MAX_HEIGHT = 80;
@@ -86,7 +88,6 @@ public class BeeLineOpts implements Completer {
private boolean showElapsedTime = true;
private boolean entireLineAsCommand = false;
private String numberFormat = "default";
- private final Terminal terminal = TerminalFactory.get();
private int maxWidth = DEFAULT_MAX_WIDTH;
private int maxHeight = DEFAULT_MAX_HEIGHT;
private int maxColumnWidth = DEFAULT_MAX_COLUMN_WIDTH;
@@ -106,7 +107,7 @@ public class BeeLineOpts implements Completer {
private final File rcFile = new File(saveDir(), "beeline.properties");
private String historyFile = new File(saveDir(),
"history").getAbsolutePath();
- private int maxHistoryRows = MemoryHistory.DEFAULT_MAX_SIZE;
+ private int maxHistoryRows = 500; // as in MemoryHistory of JLine 2
private String scriptFile = null;
private String[] initFiles = null;
@@ -152,11 +153,17 @@ public String get(String envVar) {
public BeeLineOpts(BeeLine beeLine, Properties props) {
this.beeLine = beeLine;
- if (terminal.getWidth() > 0) {
- maxWidth = terminal.getWidth();
- }
- if (terminal.getHeight() > 0) {
- maxHeight = terminal.getHeight();
+ try {
+ Terminal terminal = TerminalBuilder.terminal();
+ if (terminal.getWidth() > 0) {
+ maxWidth = terminal.getWidth();
+ }
+ if (terminal.getHeight() > 0) {
+ maxHeight = terminal.getHeight();
+ }
+ terminal.close();
+ } catch (IOException e) {
+ beeLine.debug("Failed to initialize terminal for max width/height check:
" + e.getMessage());
}
loadProperties(props);
}
@@ -195,12 +202,11 @@ public File saveDir() {
@Override
- public int complete(String buf, int pos, List cand) {
+ public void complete(LineReader reader, ParsedLine line, List<Candidate>
candidates) {
try {
- return new StringsCompleter(propertyNames()).complete(buf, pos, cand);
+ new MatchingStringsCompleter(propertyNames()).complete(reader, line,
candidates);
} catch (Exception e) {
beeLine.handleException(e);
- return -1;
}
}
@@ -742,4 +748,3 @@ public static void setEnv(Env envToUse){
env = envToUse;
}
}
-
diff --git a/beeline/src/java/org/apache/hive/beeline/BooleanCompleter.java
b/beeline/src/java/org/apache/hive/beeline/BooleanCompleter.java
index 6ab007dd05e..5295187789c 100644
--- a/beeline/src/java/org/apache/hive/beeline/BooleanCompleter.java
+++ b/beeline/src/java/org/apache/hive/beeline/BooleanCompleter.java
@@ -17,15 +17,14 @@
*/
package org.apache.hive.beeline;
-import jline.console.completer.StringsCompleter;
+import org.apache.hive.common.util.MatchingStringsCompleter;
/**
- * JLine completor boolean value (true/false)
+ * JLine completer boolean value (true/false)
*/
-class BooleanCompleter extends StringsCompleter {
+class BooleanCompleter extends MatchingStringsCompleter {
public BooleanCompleter(){
- super(new String[] {"true", "false"});
+ super("true", "false");
}
-
-}
\ No newline at end of file
+}
diff --git a/beeline/src/java/org/apache/hive/beeline/CommandHandler.java
b/beeline/src/java/org/apache/hive/beeline/CommandHandler.java
index 18fcfc40b22..9a04649a9f5 100644
--- a/beeline/src/java/org/apache/hive/beeline/CommandHandler.java
+++ b/beeline/src/java/org/apache/hive/beeline/CommandHandler.java
@@ -22,7 +22,7 @@
*/
package org.apache.hive.beeline;
-import jline.console.completer.Completer;
+import org.jline.reader.Completer;
/**
* A generic command to be executed. Execution of the command
@@ -71,7 +71,7 @@ interface CommandHandler {
/**
- * Returns the completors that can handle parameters.
+ * Returns the completers that can handle parameters.
*/
public Completer[] getParameterCompleters();
@@ -80,4 +80,4 @@ interface CommandHandler {
* @return
*/
public Throwable getLastException();
-}
\ No newline at end of file
+}
diff --git a/beeline/src/java/org/apache/hive/beeline/Commands.java
b/beeline/src/java/org/apache/hive/beeline/Commands.java
index 42cc87c1bb6..7eaa2618f84 100644
--- a/beeline/src/java/org/apache/hive/beeline/Commands.java
+++ b/beeline/src/java/org/apache/hive/beeline/Commands.java
@@ -67,6 +67,8 @@
import org.apache.hive.jdbc.Utils;
import org.apache.hive.jdbc.Utils.JdbcConnectionParams;
import org.apache.hive.jdbc.logs.InPlaceUpdateStream;
+import org.jline.reader.History;
+import org.jline.reader.impl.LineReaderImpl;
public class Commands {
@@ -186,13 +188,9 @@ public boolean addlocaldriverjar(String line) {
}
public boolean history(String line) {
- Iterator hist = beeLine.getConsoleReader().getHistory().entries();
- String[] tmp;
- while(hist.hasNext()){
- tmp = hist.next().toString().split(":", 2);
- tmp[0] = Integer.toString(Integer.parseInt(tmp[0]) + 1);
- beeLine.output(beeLine.getColorBuffer().pad(tmp[0], 6)
- .append(":" + tmp[1]));
+ for (History.Entry entry : beeLine.getLineReader().getHistory()) {
+
beeLine.output(beeLine.getColorBuffer().pad(Integer.toString(entry.index() +
1), 6)
+ .append(": " + entry.line()));
}
return true;
}
@@ -291,7 +289,7 @@ public boolean dropall(String line) {
return beeLine.error(beeLine.loc("no-current-connection"));
}
try {
- if
(!(beeLine.getConsoleReader().readLine(beeLine.loc("really-drop-all")).equals("y")))
{
+ if
(!(beeLine.getLineReader().readLine(beeLine.loc("really-drop-all")).equals("y")))
{
return beeLine.error("abort-drop-all");
}
@@ -1087,10 +1085,10 @@ private boolean showReport() {
/*
* Check if the input line is a multi-line command which needs to read
further
*/
- public String handleMultiLineCmd(String line) throws IOException {
+ public String handleMultiLineCmd(String line) {
line = HiveStringUtils.removeComments(line);
Character mask = (System.getProperty("jline.terminal",
"").equals("jline.UnsupportedTerminal")) ? null
- : jline.console.ConsoleReader.NULL_MASK;
+ : LineReaderImpl.NULL_MASK;
while (isMultiLine(line) && beeLine.getOpts().isAllowMultiLineCommand()) {
StringBuilder prompt = new StringBuilder(beeLine.getPrompt());
@@ -1101,17 +1099,15 @@ public String handleMultiLineCmd(String line) throws
IOException {
}
}
}
- String extra;
+
//avoid NPE below if for some reason -e argument has multi-line command
- if (beeLine.getConsoleReader() == null) {
+ if (beeLine.getLineReader() == null) {
throw new RuntimeException("Console reader not initialized. This could
happen when there "
+ "is a multi-line command using -e option and which requires
further reading from console");
}
- if (beeLine.getOpts().isSilent() && beeLine.getOpts().getScriptFile() !=
null) {
- extra = beeLine.getConsoleReader().readLine(null, mask);
- } else {
- extra = beeLine.getConsoleReader().readLine(prompt.toString());
- }
+
+ String extra = (beeLine.getOpts().isSilent() &&
beeLine.getOpts().getScriptFile() != null) ?
+ beeLine.readLine(null, mask) : beeLine.readLine(prompt.toString(),
null);
if (extra == null) { //it happens when using -f and the line of cmds
does not end with ;
break;
@@ -1663,12 +1659,11 @@ public boolean connect(Properties props) throws
IOException {
&& !JdbcConnectionParams.AUTH_SSO_BROWSER_MODE.equals(auth)) {
String urlForPrompt = url.substring(0, url.contains(";") ?
url.indexOf(';') : url.length());
if (username == null) {
- username = beeLine.getConsoleReader().readLine("Enter username for " +
urlForPrompt + ": ");
+ username = beeLine.readLine("Enter username for " + urlForPrompt + ":
", null);
}
props.setProperty(JdbcConnectionParams.AUTH_USER, username);
if (password == null) {
- password = beeLine.getConsoleReader().readLine("Enter password for " +
urlForPrompt + ": ",
- new Character('*'));
+ password = beeLine.readLine("Enter password for " + urlForPrompt + ":
", '*');
}
props.setProperty(JdbcConnectionParams.AUTH_PASSWD, password);
}
@@ -1963,7 +1958,7 @@ public boolean manual(String line) throws IOException {
// silly little pager
if (index % (beeLine.getOpts().getMaxHeight() - 1) == 0) {
- String ret =
beeLine.getConsoleReader().readLine(beeLine.loc("enter-for-more"));
+ String ret =
beeLine.getLineReader().readLine(beeLine.loc("enter-for-more"));
if (ret != null && ret.startsWith("q")) {
break;
}
diff --git a/beeline/src/java/org/apache/hive/beeline/DatabaseConnection.java
b/beeline/src/java/org/apache/hive/beeline/DatabaseConnection.java
index 129fc2eb9cc..c3c5365631c 100644
--- a/beeline/src/java/org/apache/hive/beeline/DatabaseConnection.java
+++ b/beeline/src/java/org/apache/hive/beeline/DatabaseConnection.java
@@ -39,8 +39,8 @@
import org.apache.hive.jdbc.HiveConnection;
-import jline.console.completer.ArgumentCompleter;
-import jline.console.completer.Completer;
+import org.jline.reader.Completer;
+import org.jline.reader.impl.completer.ArgumentCompleter;
class DatabaseConnection {
private static final String HIVE_VAR_PREFIX = "hivevar:";
@@ -74,29 +74,8 @@ public String toString() {
void setCompletions(boolean skipmeta) throws SQLException, IOException {
- final String extraNameCharacters =
- getDatabaseMetaData() == null ||
getDatabaseMetaData().getExtraNameCharacters() == null ? ""
- : getDatabaseMetaData().getExtraNameCharacters();
-
// setup the completer for the database
- sqlCompleter = new ArgumentCompleter(
- new ArgumentCompleter.AbstractArgumentDelimiter() {
- // delimiters for SQL statements are any
- // non-letter-or-number characters, except
- // underscore and characters that are specified
- // by the database to be valid name identifiers.
- @Override
- public boolean isDelimiterChar(CharSequence buffer, int pos) {
- char c = buffer.charAt(pos);
- if (Character.isWhitespace(c)) {
- return true;
- }
- return !(Character.isLetterOrDigit(c))
- && c != '_'
- && extraNameCharacters.indexOf(c) == -1;
- }
- },
- new SQLCompleter(SQLCompleter.getSQLCompleters(beeLine, skipmeta)));
+ sqlCompleter = new ArgumentCompleter(new
SQLCompleter(SQLCompleter.getSQLCompleters(beeLine, skipmeta)));
// not all argument elements need to hold true
((ArgumentCompleter) sqlCompleter).setStrict(false);
}
diff --git a/beeline/src/java/org/apache/hive/beeline/BooleanCompleter.java
b/beeline/src/java/org/apache/hive/beeline/NoCurrentConnectionException.java
similarity index 78%
copy from beeline/src/java/org/apache/hive/beeline/BooleanCompleter.java
copy to
beeline/src/java/org/apache/hive/beeline/NoCurrentConnectionException.java
index 6ab007dd05e..71117069fbd 100644
--- a/beeline/src/java/org/apache/hive/beeline/BooleanCompleter.java
+++ b/beeline/src/java/org/apache/hive/beeline/NoCurrentConnectionException.java
@@ -17,15 +17,8 @@
*/
package org.apache.hive.beeline;
-import jline.console.completer.StringsCompleter;
-
-/**
- * JLine completor boolean value (true/false)
- */
-class BooleanCompleter extends StringsCompleter {
-
- public BooleanCompleter(){
- super(new String[] {"true", "false"});
+public class NoCurrentConnectionException extends IllegalArgumentException {
+ public NoCurrentConnectionException(String message) {
+ super(message);
}
-
-}
\ No newline at end of file
+}
diff --git
a/beeline/src/java/org/apache/hive/beeline/ReflectiveCommandHandler.java
b/beeline/src/java/org/apache/hive/beeline/ReflectiveCommandHandler.java
index a37ee891420..6fbda4c670d 100644
--- a/beeline/src/java/org/apache/hive/beeline/ReflectiveCommandHandler.java
+++ b/beeline/src/java/org/apache/hive/beeline/ReflectiveCommandHandler.java
@@ -22,9 +22,9 @@
*/
package org.apache.hive.beeline;
-import jline.console.completer.Completer;
-
import org.apache.hadoop.fs.shell.Command;
+import org.jline.reader.Completer;
+
/**
* A {@link Command} implementation that uses reflection to
diff --git a/beeline/src/java/org/apache/hive/beeline/SQLCompleter.java
b/beeline/src/java/org/apache/hive/beeline/SQLCompleter.java
index b40b3a50636..bd5985ff301 100644
--- a/beeline/src/java/org/apache/hive/beeline/SQLCompleter.java
+++ b/beeline/src/java/org/apache/hive/beeline/SQLCompleter.java
@@ -30,11 +30,11 @@
import java.util.StringTokenizer;
import java.util.TreeSet;
-import jline.console.completer.StringsCompleter;
+import org.apache.hive.common.util.MatchingStringsCompleter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-class SQLCompleter extends StringsCompleter {
+class SQLCompleter extends MatchingStringsCompleter {
private static final Logger LOG =
LoggerFactory.getLogger(SQLCompleter.class.getName());
diff --git a/beeline/src/java/org/apache/hive/beeline/TableNameCompletor.java
b/beeline/src/java/org/apache/hive/beeline/TableNameCompleter.java
similarity index 63%
rename from beeline/src/java/org/apache/hive/beeline/TableNameCompletor.java
rename to beeline/src/java/org/apache/hive/beeline/TableNameCompleter.java
index 1eefe178826..96eec2e64ac 100644
--- a/beeline/src/java/org/apache/hive/beeline/TableNameCompletor.java
+++ b/beeline/src/java/org/apache/hive/beeline/TableNameCompleter.java
@@ -24,25 +24,28 @@
import java.util.List;
-import jline.console.completer.Completer;
-import jline.console.completer.StringsCompleter;
+import org.apache.hive.common.util.MatchingStringsCompleter;
+import org.jline.reader.Candidate;
+import org.jline.reader.Completer;
+import org.jline.reader.LineReader;
+import org.jline.reader.ParsedLine;
-class TableNameCompletor implements Completer {
+class TableNameCompleter implements Completer {
private final BeeLine beeLine;
/**
* @param beeLine
*/
- TableNameCompletor(BeeLine beeLine) {
+ TableNameCompleter(BeeLine beeLine) {
this.beeLine = beeLine;
}
@Override
- public int complete(String buf, int pos, List cand) {
- if (beeLine.getDatabaseConnection() == null) {
- return -1;
+ public void complete(LineReader reader, ParsedLine line, List<Candidate>
candidates) {
+ final DatabaseConnection connection = beeLine.getDatabaseConnection();
+ if (connection != null) {
+ new
MatchingStringsCompleter(beeLine.getDatabaseConnection().getTableNames(true))
+ .complete(reader, line, candidates);
}
- return new
StringsCompleter(beeLine.getDatabaseConnection().getTableNames(true))
- .complete(buf, pos, cand);
}
-}
\ No newline at end of file
+}
diff --git a/beeline/src/java/org/apache/hive/beeline/cli/HiveCli.java
b/beeline/src/java/org/apache/hive/beeline/cli/HiveCli.java
index 99a72797592..8edb16bc8b4 100644
--- a/beeline/src/java/org/apache/hive/beeline/cli/HiveCli.java
+++ b/beeline/src/java/org/apache/hive/beeline/cli/HiveCli.java
@@ -32,11 +32,15 @@ public static void main(String[] args) throws IOException {
}
public int runWithArgs(String[] cmd, InputStream inputStream) throws
IOException {
- beeLine = new BeeLine(false);
+ beeLine = createBeeline();
try {
return beeLine.begin(cmd, inputStream);
} finally {
beeLine.close();
}
}
+
+ BeeLine createBeeline() {
+ return new BeeLine(false);
+ }
}
diff --git
a/beeline/src/java/org/apache/hive/beeline/schematool/HiveSchemaTool.java
b/beeline/src/java/org/apache/hive/beeline/schematool/HiveSchemaTool.java
index 6a57763106e..22df6f0e8f5 100644
--- a/beeline/src/java/org/apache/hive/beeline/schematool/HiveSchemaTool.java
+++ b/beeline/src/java/org/apache/hive/beeline/schematool/HiveSchemaTool.java
@@ -32,6 +32,7 @@
import
org.apache.hadoop.hive.metastore.tools.schematool.HiveSchemaHelper.NestedScriptParser;
import org.apache.hadoop.util.ExitUtil;
import org.apache.hive.beeline.BeeLine;
+import org.apache.hive.beeline.BeeLineDummyTerminal;
import org.apache.tez.dag.api.TezConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -105,7 +106,7 @@ protected void execSql(String sqlScriptFile) throws
IOException {
userName, passWord, sqlScriptFile);
// run the script using Beeline
- try (BeeLine beeLine = new BeeLine()) {
+ try (BeeLine beeLine = new BeeLineDummyTerminal()) {
if (!verbose) {
beeLine.setOutputStream(new PrintStream(new NullOutputStream()));
beeLine.getOpts().setSilent(true);
diff --git a/beeline/src/test/org/apache/hive/beeline/TestBeeLineHistory.java
b/beeline/src/test/org/apache/hive/beeline/TestBeeLineHistory.java
index c8f4d4e42e5..8f42e9ea699 100644
--- a/beeline/src/test/org/apache/hive/beeline/TestBeeLineHistory.java
+++ b/beeline/src/test/org/apache/hive/beeline/TestBeeLineHistory.java
@@ -56,13 +56,11 @@ public static void beforeTests() throws Exception {
public void testNumHistories() throws Exception {
ByteArrayOutputStream os = new ByteArrayOutputStream();
PrintStream ops = new PrintStream(os);
- BeeLine beeline = new BeeLine();
+ BeeLine beeline = new BeeLineDummyTerminal();
beeline.getOpts().setHistoryFile(fileName);
beeline.setOutputStream(ops);
- Method method = beeline.getClass().getDeclaredMethod("setupHistory");
- method.setAccessible(true);
- method.invoke(beeline);
- beeline.initializeConsoleReader(null);
+ beeline.setupHistory();
+ beeline.initializeLineReader(null);
beeline.dispatch("!history");
String output = os.toString("UTF-8");
int numHistories = output.split("\n").length;
@@ -74,13 +72,11 @@ public void testNumHistories() throws Exception {
public void testHistory() throws Exception {
ByteArrayOutputStream os = new ByteArrayOutputStream();
PrintStream ops = new PrintStream(os);
- BeeLine beeline = new BeeLine();
+ BeeLine beeline = new BeeLineDummyTerminal();
beeline.getOpts().setHistoryFile(fileName);
beeline.setOutputStream(ops);
- Method method = beeline.getClass().getDeclaredMethod("setupHistory");
- method.setAccessible(true);
- method.invoke(beeline);
- beeline.initializeConsoleReader(null);
+ beeline.setupHistory();
+ beeline.initializeLineReader(null);
beeline.dispatch("!history");
String output = os.toString("UTF-8");
String[] tmp = output.split("\n");
diff --git a/beeline/src/test/org/apache/hive/beeline/TestCommands.java
b/beeline/src/test/org/apache/hive/beeline/TestCommands.java
index 2bd71b05a64..e926fd4b284 100644
--- a/beeline/src/test/org/apache/hive/beeline/TestCommands.java
+++ b/beeline/src/test/org/apache/hive/beeline/TestCommands.java
@@ -85,12 +85,14 @@ public void testLinesEndingWithComments() {
*/
@Test
public void testBeelineCommands() throws IOException {
- // avoid System.exit() call in beeline which causes JVM to exit and fails the
test
+ // avoid System.exit() call in beeline which causes JVM to exit and fails
the test
System.setProperty(BeeLineOpts.PROPERTY_NAME_EXIT, "true");
// Verify the command without ';' at the end also works fine
- BeeLine.mainWithInputRedirection(new String[] {"-u", "jdbc:hive2://",
"-e", "select 3"}, null);
+ BeeLine.mainWithInputRedirection(new String[] {"-u", "jdbc:hive2://",
"-e", "select 3"}, null,
+ new BeeLineDummyTerminal());
BeeLine.mainWithInputRedirection(
- new String[] {"-u", "jdbc:hive2://", "-e", "create table t1(x int);
show tables"}, null);
+ new String[] {"-u", "jdbc:hive2://", "-e", "create table t1(x int);
show tables"}, null,
+ new BeeLineDummyTerminal());
}
/**
diff --git a/beeline/src/java/org/apache/hive/beeline/BooleanCompleter.java
b/beeline/src/test/org/apache/hive/beeline/cli/HiveCliForTest.java
similarity index 75%
copy from beeline/src/java/org/apache/hive/beeline/BooleanCompleter.java
copy to beeline/src/test/org/apache/hive/beeline/cli/HiveCliForTest.java
index 6ab007dd05e..60e68d4b75d 100644
--- a/beeline/src/java/org/apache/hive/beeline/BooleanCompleter.java
+++ b/beeline/src/test/org/apache/hive/beeline/cli/HiveCliForTest.java
@@ -15,17 +15,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.hive.beeline;
+package org.apache.hive.beeline.cli;
-import jline.console.completer.StringsCompleter;
+import org.apache.hive.beeline.BeeLine;
+import org.apache.hive.beeline.BeeLineDummyTerminal;
-/**
- * JLine completor boolean value (true/false)
- */
-class BooleanCompleter extends StringsCompleter {
+public class HiveCliForTest extends HiveCli {
- public BooleanCompleter(){
- super(new String[] {"true", "false"});
+ @Override
+ BeeLine createBeeline() {
+ return new BeeLineDummyTerminal(false);
}
-
-}
\ No newline at end of file
+}
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 a8378d91435..89bf93672ed 100644
--- a/beeline/src/test/org/apache/hive/beeline/cli/TestHiveCli.java
+++ b/beeline/src/test/org/apache/hive/beeline/cli/TestHiveCli.java
@@ -36,6 +36,7 @@
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.URISyntaxException;
+import java.nio.charset.Charset;
public class TestHiveCli {
private static final Logger LOG =
LoggerFactory.getLogger(TestHiveCli.class.getName());
@@ -248,7 +249,7 @@ private void executeCMD(String[] args, String input, int
retCode) {
int ret = 0;
try {
if (input != null) {
- inputStream = IOUtils.toInputStream(input);
+ inputStream = IOUtils.toInputStream(input, Charset.defaultCharset());
}
ret = cli.runWithArgs(args, inputStream);
} catch (Throwable e) {
@@ -270,11 +271,11 @@ private void verifyCMD(String CMD, String keywords,
OutputStream os, String[] op
String output = os.toString();
LOG.debug(output);
if (contains) {
- Assert.assertTrue("The expected keyword \"" + keywords + "\" occur in
the output: " + output,
+ Assert.assertTrue("The expected keyword \"" + keywords + "\" should
appear in the output: " + output,
output.contains(keywords));
} else {
Assert.assertFalse(
- "The expected keyword \"" + keywords + "\" should be excluded
occurred in the output: "
+ "The expected keyword \"" + keywords + "\" should not appear in the
output: "
+ output, output.contains(keywords));
}
}
@@ -293,9 +294,9 @@ public static void init(){
@Before
public void setup() throws IOException, URISyntaxException {
System.setProperty("datanucleus.schema.autoCreateAll", "true");
- cli = new HiveCli();
- initFromFile();
+ cli = new HiveCliForTest();
redirectOutputStream();
+ initFromFile();
}
private void redirectOutputStream() {
diff --git a/cli/pom.xml b/cli/pom.xml
index defc5fbefd9..ebb0fbff8c5 100644
--- a/cli/pom.xml
+++ b/cli/pom.xml
@@ -82,7 +82,7 @@
<scope>test</scope>
</dependency>
<dependency>
- <groupId>jline</groupId>
+ <groupId>org.jline</groupId>
<artifactId>jline</artifactId>
</dependency>
<dependency>
diff --git a/cli/src/java/org/apache/hadoop/hive/cli/CliDriver.java
b/cli/src/java/org/apache/hadoop/hive/cli/CliDriver.java
index 4bff8082031..4cef3b5d657 100644
--- a/cli/src/java/org/apache/hadoop/hive/cli/CliDriver.java
+++ b/cli/src/java/org/apache/hadoop/hive/cli/CliDriver.java
@@ -16,7 +16,7 @@
* limitations under the License.
*/
-package org.apache.hadoop.hive.cli;
+ package org.apache.hadoop.hive.cli;
import static org.apache.hadoop.hive.shims.HadoopShims.USER_ID;
import static org.apache.hadoop.util.StringUtils.stringifyException;
@@ -74,25 +74,26 @@
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.util.ExitUtil;
import org.apache.hive.common.util.HiveStringUtils;
+import org.apache.hive.common.util.MatchingStringsCompleter;
import org.apache.hive.common.util.ShutdownHookManager;
+import org.jline.reader.Candidate;
+import org.jline.reader.Completer;
+import org.jline.reader.History;
+import org.jline.reader.LineReader;
+import org.jline.reader.LineReaderBuilder;
+import org.jline.reader.ParsedLine;
+import org.jline.reader.impl.DefaultParser;
+import org.jline.reader.impl.completer.ArgumentCompleter;
+import org.jline.reader.impl.history.DefaultHistory;
+import org.jline.terminal.Terminal;
+import org.jline.terminal.Terminal.Signal;
+import org.jline.terminal.Terminal.SignalHandler;
+import org.jline.terminal.TerminalBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Splitter;
-import jline.console.ConsoleReader;
-import jline.console.completer.ArgumentCompleter;
-import jline.console.completer.ArgumentCompleter.AbstractArgumentDelimiter;
-import jline.console.completer.ArgumentCompleter.ArgumentDelimiter;
-import jline.console.completer.Completer;
-import jline.console.completer.StringsCompleter;
-import jline.console.history.FileHistory;
-import jline.console.history.History;
-import jline.console.history.PersistentHistory;
-import sun.misc.Signal;
-import sun.misc.SignalHandler;
-
-
/**
* CliDriver.
*
@@ -107,7 +108,7 @@ public class CliDriver {
public static final String HIVERCFILE = ".hiverc";
private final LogHelper console;
- protected ConsoleReader reader;
+ protected LineReader reader;
private Configuration conf;
public CliDriver() {
@@ -374,8 +375,8 @@ public CommandProcessorResponse processLine(String line,
boolean allowInterrupti
if (allowInterrupting) {
// Remember all threads that were running at the time we started line
processing.
// Hook up the custom Ctrl+C handler while processing this line
- interruptSignal = new Signal("INT");
- oldSignal = Signal.handle(interruptSignal, new SignalHandler() {
+ interruptSignal = Terminal.Signal.INT;
+ oldSignal = reader.getTerminal().handle(interruptSignal, new
SignalHandler() {
private boolean interruptRequested;
@Override
@@ -437,8 +438,8 @@ public void handle(Signal signal) {
return lastRet;
} finally {
// Once we are done processing the line, restore the old handler
- if (oldSignal != null && interruptSignal != null) {
- Signal.handle(interruptSignal, oldSignal);
+ if (oldSignal != null) {
+ reader.getTerminal().handle(interruptSignal, oldSignal);
}
}
}
@@ -590,7 +591,7 @@ public void processSelectDatabase(CliSessionState ss)
throws IOException, Comman
public static Completer[] getCommandCompleter() {
// StringsCompleter matches against a pre-defined wordlist
// We start with an empty wordlist and build it up
- List<String> candidateStrings = new ArrayList<String>();
+ List<String> candidateStrings = new ArrayList<>();
// We add Hive function names
// For functions that aren't infix operators, we add an open
@@ -609,47 +610,32 @@ public static Completer[] getCommandCompleter() {
candidateStrings.add(s.toLowerCase());
}
- StringsCompleter strCompleter = new StringsCompleter(candidateStrings);
-
- // Because we use parentheses in addition to whitespace
- // as a keyword delimiter, we need to define a new ArgumentDelimiter
- // that recognizes parenthesis as a delimiter.
- ArgumentDelimiter delim = new AbstractArgumentDelimiter() {
- @Override
- public boolean isDelimiterChar(CharSequence buffer, int pos) {
- char c = buffer.charAt(pos);
- return (Character.isWhitespace(c) || c == '(' || c == ')' ||
- c == '[' || c == ']');
- }
- };
+ Completer strCompleter = new MatchingStringsCompleter(candidateStrings);
- // The ArgumentCompletor allows us to match multiple tokens
+ // The ArgumentCompleter allows us to match multiple tokens
// in the same line.
- final ArgumentCompleter argCompleter = new ArgumentCompleter(delim,
strCompleter);
- // By default ArgumentCompletor is in "strict" mode meaning
+ final ArgumentCompleter argCompleter = new ArgumentCompleter(strCompleter);
+ // By default ArgumentCompleter is in "strict" mode meaning
// a token is only auto-completed if all prior tokens
// match. We don't want that since there are valid tokens
// that are not in our wordlist (eg. table and column names)
argCompleter.setStrict(false);
- // ArgumentCompletor always adds a space after a matched token.
+ // ArgumentCompleter always adds a space after a matched token.
// This is undesirable for function names because a space after
// the opening parenthesis is unnecessary (and uncommon) in Hive.
- // We stack a custom Completor on top of our ArgumentCompletor
+ // We stack a custom Completer on top of our ArgumentCompleter
// to reverse this.
- Completer customCompletor = new Completer () {
- @Override
- public int complete (String buffer, int offset, List completions) {
- List<String> comp = completions;
- int ret = argCompleter.complete(buffer, offset, completions);
- // ConsoleReader will do the substitution if and only if there
- // is exactly one valid completion, so we ignore other cases.
- if (completions.size() == 1) {
- if (comp.get(0).endsWith("( ")) {
- comp.set(0, comp.get(0).trim());
- }
+ Completer customCompleter = (reader, line, candidates) -> {
+ argCompleter.complete(reader, line, candidates);
+ candidates.forEach(System.out::println);
+ // ConsoleReader will do the substitution if and only if there
+ // is exactly one valid completion, so we ignore other cases.
+ if (candidates.size() == 1) {
+ String candidateStr = candidates.get(0).value();
+ if (candidateStr.endsWith("( ")) {
+ candidates.set(0, new Candidate(candidateStr.trim()));
}
- return ret;
}
};
@@ -658,64 +644,58 @@ public int complete (String buffer, int offset, List
completions) {
vars.add(conf.varname);
}
- StringsCompleter confCompleter = new StringsCompleter(vars) {
+ Completer confCompleter = new MatchingStringsCompleter(vars) {
@Override
- public int complete(final String buffer, final int cursor, final
List<CharSequence> clist) {
- int result = super.complete(buffer, cursor, clist);
- if (clist.isEmpty() && cursor > 1 && buffer.charAt(cursor - 1) == '=')
{
- HiveConf.ConfVars var = HiveConf.getConfVars(buffer.substring(0,
cursor - 1));
- if (var == null) {
- return result;
+ public void complete(LineReader reader, ParsedLine line, List<Candidate>
candidates) {
+ super.complete(reader, line, candidates);
+ final int cursor = line.cursor();
+ if (candidates.isEmpty() && cursor > 1 && line.word().charAt(cursor -
1) == '=') {
+ HiveConf.ConfVars confVars =
HiveConf.getConfVars(line.word().substring(0, cursor - 1));
+ if (confVars == null) {
+ return;
}
- if (var.getValidator() instanceof Validator.StringSet) {
- Validator.StringSet validator =
(Validator.StringSet)var.getValidator();
- clist.addAll(validator.getExpected());
- } else if (var.getValidator() != null) {
- clist.addAll(Arrays.asList(var.getValidator().toDescription(),
""));
+ if (confVars.getValidator() instanceof Validator.StringSet) {
+ Validator.StringSet validator =
(Validator.StringSet)confVars.getValidator();
+
validator.getExpected().stream().map(Candidate::new).forEach(candidates::add);
+ } else if (confVars.getValidator() != null) {
+ candidates.add(new
Candidate(confVars.getValidator().toDescription()));
} else {
- clist.addAll(Arrays.asList("Expects " + var.typeString() + " type
value", ""));
+ candidates.add(new Candidate("Expects " + confVars.typeString() +
" type value"));
}
- return cursor;
+ return;
}
- if (clist.size() > DELIMITED_CANDIDATE_THRESHOLD) {
- Set<CharSequence> delimited = new LinkedHashSet<CharSequence>();
- for (CharSequence candidate : clist) {
+ if (candidates.size() > DELIMITED_CANDIDATE_THRESHOLD) {
+ Set<Candidate> delimited = new LinkedHashSet<>();
+ for (Candidate candidate : candidates) {
Iterator<String> it = Splitter.on(".").split(
- candidate.subSequence(cursor, candidate.length())).iterator();
+ candidate.value().subSequence(cursor,
candidate.value().length())).iterator();
if (it.hasNext()) {
String next = it.next();
if (next.isEmpty()) {
next = ".";
}
- candidate = buffer != null ? buffer.substring(0, cursor) + next
: next;
+ candidate = new Candidate(line.line() != null ?
line.line().substring(0, cursor) + next : next);
}
delimited.add(candidate);
}
- clist.clear();
- clist.addAll(delimited);
+ candidates.clear();
+ candidates.addAll(delimited);
}
- return result;
}
};
- StringsCompleter setCompleter = new StringsCompleter("set") {
- @Override
- public int complete(String buffer, int cursor, List<CharSequence> clist)
{
- return buffer != null && buffer.equals("set") ? super.complete(buffer,
cursor, clist) : -1;
- }
- };
+ Completer setCompleter = new MatchingStringsCompleter("set");
ArgumentCompleter propCompleter = new ArgumentCompleter(setCompleter,
confCompleter) {
@Override
- public int complete(String buffer, int offset, List<CharSequence>
completions) {
- int ret = super.complete(buffer, offset, completions);
- if (completions.size() == 1) {
- completions.set(0, ((String)completions.get(0)).trim());
+ public void complete(LineReader reader, ParsedLine line, List<Candidate>
candidates) {
+ super.complete(reader, line, candidates);
+ if (candidates.size() == 1) {
+ candidates.set(0, new Candidate(candidates.get(0).value().trim()));
}
- return ret;
}
};
- return new Completer[] {propCompleter, customCompletor};
+ return new Completer[] {propCompleter, customCompleter};
}
public static void main(String[] args) throws Exception {
@@ -831,7 +811,7 @@ protected HiveConf getConf() {
private CommandProcessorResponse executeDriver(CliSessionState ss, HiveConf
conf, OptionsProcessor oproc)
throws Exception {
- CliDriver cli = new CliDriver();
+ CliDriver cli = newCliDriver();
cli.setHiveVariables(oproc.getHiveVariables());
// use the specified database if specified
@@ -856,7 +836,7 @@ private CommandProcessorResponse
executeDriver(CliSessionState ss, HiveConf conf
console.printInfo(HiveConf.generateMrDeprecationWarning());
}
- setupConsoleReader();
+ setupLineReader();
String line;
CommandProcessorResponse response = new CommandProcessorResponse();
@@ -889,15 +869,16 @@ private CommandProcessorResponse
executeDriver(CliSessionState ss, HiveConf conf
return response;
}
- private void setupCmdHistory() {
+ protected CliDriver newCliDriver() {
+ return new CliDriver();
+ }
+
+ private String setupCmdHistory() {
final String HISTORYFILE = ".hivehistory";
String historyDirectory = System.getProperty("user.home");
- PersistentHistory history = null;
try {
if ((new File(historyDirectory)).exists()) {
- String historyFile = historyDirectory + File.separator + HISTORYFILE;
- history = new FileHistory(new File(historyFile));
- reader.setHistory(history);
+ return historyDirectory + File.separator + HISTORYFILE;
} else {
System.err.println("WARNING: Directory for Hive history file: " +
historyDirectory +
" does not exist. History will not be available
during this session.");
@@ -906,32 +887,48 @@ private void setupCmdHistory() {
System.err.println("WARNING: Encountered an error while trying to
initialize Hive's " +
"history file. History will not be available during
this session.");
System.err.println(e.getMessage());
+ return null;
}
// add shutdown hook to flush the history to history file
- ShutdownHookManager.addShutdownHook(new Runnable() {
- @Override
- public void run() {
- History h = reader.getHistory();
- if (h instanceof FileHistory) {
- try {
- ((FileHistory) h).flush();
- } catch (IOException e) {
- System.err.println("WARNING: Failed to write command history file:
" + e.getMessage());
- }
- }
+ ShutdownHookManager.addShutdownHook(() -> {
+ History h = reader.getHistory();
+ try {
+ h.save();
+ } catch (IOException e) {
+ System.err.println("WARNING: Failed to write command history file: " +
e.getMessage());
}
});
+ return null;
}
- protected void setupConsoleReader() throws IOException {
- reader = new ConsoleReader();
- reader.setExpandEvents(false);
- reader.setBellEnabled(false);
- for (Completer completer : getCommandCompleter()) {
- reader.addCompleter(completer);
+ protected void setupLineReader() throws IOException {
+ LineReaderBuilder builder = LineReaderBuilder.builder();
+ builder.variable(LineReader.BELL_STYLE, "audible");
+ Arrays.stream(getCommandCompleter()).forEach(builder::completer);
+ builder.terminal(TerminalBuilder.terminal());
+ builder.parser(getDefaultParser());
+ builder.history(new DefaultHistory());
+
+ String historyFile = setupCmdHistory();
+ if (historyFile != null) {
+ builder.variable(LineReader.HISTORY_FILE, historyFile);
}
- setupCmdHistory();
+ reader = builder.build();
+ }
+
+ static DefaultParser getDefaultParser() {
+ return new DefaultParser() {
+ @Override
+ public boolean isDelimiterChar(CharSequence buffer, int pos) {
+ // Because we use parentheses in addition to whitespace
+ // as a keyword delimiter, we need to define a new ArgumentDelimiter
+ // that recognizes parenthesis as a delimiter.
+ final char c = buffer.charAt(pos);
+ return (Character.isWhitespace(c) || c == '(' || c == ')' ||
+ c == '[' || c == ']');
+ }
+ };
}
/**
@@ -971,5 +968,4 @@ private static String spacesForString(String s) {
public void setHiveVariables(Map<String, String> hiveVariables) {
SessionState.get().setHiveVariables(hiveVariables);
}
-
}
diff --git a/cli/src/test/org/apache/hadoop/hive/cli/TestCliDriverMethods.java
b/cli/src/test/org/apache/hadoop/hive/cli/TestCliDriverMethods.java
index e22790f54d0..eade17d66fc 100644
--- a/cli/src/test/org/apache/hadoop/hive/cli/TestCliDriverMethods.java
+++ b/cli/src/test/org/apache/hadoop/hive/cli/TestCliDriverMethods.java
@@ -27,6 +27,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileWriter;
@@ -39,11 +40,6 @@
import java.util.List;
import java.util.Map;
-import jline.console.ConsoleReader;
-import jline.console.completer.ArgumentCompleter;
-import jline.console.completer.Completer;
-
-
import org.apache.commons.io.FileUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hive.common.io.SessionStream;
@@ -57,7 +53,11 @@
import org.apache.hadoop.hive.ql.processors.CommandProcessorException;
import org.apache.hadoop.hive.ql.processors.CommandProcessorResponse;
import org.apache.hadoop.util.ExitUtil;
-
+import org.jline.reader.Candidate;
+import org.jline.reader.Completer;
+import org.jline.reader.impl.LineReaderImpl;
+import org.jline.reader.impl.completer.ArgumentCompleter;
+import org.jline.terminal.impl.DumbTerminal;
import org.junit.Test;
import static org.junit.Assert.assertTrue;
@@ -148,7 +148,7 @@ public void testThatCliDriverDoesNotStripComments() throws
Exception {
CliDriver cliDriver = new CliDriver();
// issue a command with bad options
cliDriver.processCmd("!ls --abcdefghijklmnopqrstuvwxyz123456789");
- assertTrue("Comments with '--; should not have been stripped, so command
should fail", false);
+ fail("Comments with '--; should not have been stripped, so command
should fail");
} catch (CommandProcessorException e) {
// this is expected to happen
} finally {
@@ -171,8 +171,6 @@ public void testThatCliDriverDoesNotStripComments() throws
Exception {
* Schema to throw against test
* @return Output that would have been sent to the user
* @throws CommandProcessorException
- * @throws CommandNeedRetryException
- * won't actually be thrown
*/
private PrintStream headerPrintingTestDriver(Schema mockSchema) throws
CommandProcessorException {
CliDriver cliDriver = new CliDriver();
@@ -205,23 +203,25 @@ private PrintStream headerPrintingTestDriver(Schema
mockSchema) throws CommandPr
@Test
- public void testGetCommandCompletor() {
- Completer[] completors = CliDriver.getCommandCompleter();
- assertEquals(2, completors.length);
- assertTrue(completors[0] instanceof ArgumentCompleter);
- assertTrue(completors[1] instanceof Completer);
-
- List<CharSequence> testList = Arrays.asList(")");
- completors[1].complete("fdsdfsdf", 0, testList);
- assertEquals(")", testList.get(0));
- testList=new ArrayList<CharSequence>();
- completors[1].complete("len", 0, testList);
- assertTrue(testList.get(0).toString().endsWith("length("));
-
- testList=new ArrayList<CharSequence>();
- completors[0].complete("set f", 0, testList);
- assertEquals("set", testList.get(0));
-
+ public void testGetCommandCompleter() {
+ Completer[] completers = CliDriver.getCommandCompleter();
+ assertEquals(2, completers.length);
+ assertTrue(completers[0] instanceof ArgumentCompleter);
+ assertNotNull(completers[1]);
+
+ final List<Candidate> candidates1 = new ArrayList<>();
+ candidates1.add(new Candidate(")"));
+ completers[1].complete(null,
CliDriver.getDefaultParser().parse("fdsdfsdf", 0), candidates1);
+ assertEquals(")", candidates1.getFirst().value());
+
+ final List<Candidate> candidates2 = new ArrayList<>();
+ completers[1].complete(null, CliDriver.getDefaultParser().parse("length",
0), candidates2);
+ System.out.printf("--- --> %s%n", candidates2.getFirst().value());
+ assertTrue(candidates2.getFirst().value().endsWith("length("));
+
+ final List<Candidate> candidates3 = new ArrayList<>();
+ completers[0].complete(null, CliDriver.getDefaultParser().parse("set f",
0), candidates3);
+ assertEquals("set", candidates3.getFirst().value());
}
@Test
@@ -257,7 +257,6 @@ public void testRun() throws Exception {
System.setErr(oldErr);
}
-
}
/**
@@ -386,21 +385,21 @@ public void testprocessInitFiles() throws Exception {
public void testCommandSplits() {
// Test double quote in the string
String cmd1 = "insert into escape1 partition (ds='1', part='\"') values
(\"!\")";
- assertEquals(cmd1, CliDriver.splitSemiColon(cmd1).get(0));
- assertEquals(cmd1, CliDriver.splitSemiColon(cmd1 + ";").get(0));
+ assertEquals(cmd1, CliDriver.splitSemiColon(cmd1).getFirst());
+ assertEquals(cmd1, CliDriver.splitSemiColon(cmd1 + ";").getFirst());
// Test escape
String cmd2 = "insert into escape1 partition (ds='1', part='\"\\'') values
(\"!\")";
- assertEquals(cmd2, CliDriver.splitSemiColon(cmd2).get(0));
- assertEquals(cmd2, CliDriver.splitSemiColon(cmd2 + ";").get(0));
+ assertEquals(cmd2, CliDriver.splitSemiColon(cmd2).getFirst());
+ assertEquals(cmd2, CliDriver.splitSemiColon(cmd2 + ";").getFirst());
// Test multiple commands
List<String> results = CliDriver.splitSemiColon(cmd1 + ";" + cmd2);
- assertEquals(cmd1, results.get(0));
+ assertEquals(cmd1, results.getFirst());
assertEquals(cmd2, results.get(1));
results = CliDriver.splitSemiColon(cmd1 + ";" + cmd2 + ";");
- assertEquals(cmd1, results.get(0));
+ assertEquals(cmd1, results.getFirst());
assertEquals(cmd2, results.get(1));
}
@@ -423,67 +422,72 @@ private static void setEnv(String key, String value)
throws Exception {
}
private static class FakeCliDriver extends CliDriver {
-
- private HiveConf conf;
-
- public FakeCliDriver(HiveConf configuration) {
- this.conf = configuration;
- }
-
- @Override
- protected void setupConsoleReader() throws IOException {
- reader = new FakeConsoleReader();
+ private final HiveConf conf;
+
+ public FakeCliDriver(HiveConf conf) throws IOException {
+ this.conf = conf;
+
+ reader = new LineReaderImpl(new DumbTerminal(new
ByteArrayInputStream(new byte[0]), System.err)) {
+
+ File temp = null;
+ private int counter = 0;
+
+ @Override
+ public String readLine(String prompt) {
+ FileWriter writer;
+ try {
+ switch (counter++) {
+ case 0:
+ return "!echo test message;";
+ case 1:
+ temp = File.createTempFile("hive", "test");
+ temp.deleteOnExit();
+ return "source " + temp.getAbsolutePath() + ";";
+ case 2:
+ temp = File.createTempFile("hive", "test");
+ temp.deleteOnExit();
+ writer = new FileWriter(temp);
+ writer.write("bla bla bla");
+ writer.close();
+ return "list file file://" + temp.getAbsolutePath() + ";";
+ case 3:
+ return "!echo ";
+ case 4:
+ return "test message;";
+ case 5:
+ return "source fakeFile;";
+ case 6:
+ temp = File.createTempFile("hive", "test");
+ temp.deleteOnExit();
+ writer = new FileWriter(temp);
+ writer.write("source fakeFile;");
+ writer.close();
+ return "list file file://" + temp.getAbsolutePath() + ";";
+ default:
+ return null;
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ };
}
protected HiveConf getConf() {
return conf;
}
- }
-
- private static class FakeConsoleReader extends ConsoleReader {
- private int counter = 0;
- File temp = null;
-
- public FakeConsoleReader() throws IOException {
- super();
+ @Override
+ protected void setupLineReader() {
+ // NO-OP: let's use the reader created early in the constructor to
prevent NPEs
}
@Override
- public String readLine(String prompt) throws IOException {
- FileWriter writer;
- switch (counter++) {
- case 0:
- return "!echo test message;";
- case 1:
- temp = File.createTempFile("hive", "test");
- temp.deleteOnExit();
- return "source " + temp.getAbsolutePath() + ";";
- case 2:
- temp = File.createTempFile("hive", "test");
- temp.deleteOnExit();
- writer = new FileWriter(temp);
- writer.write("bla bla bla");
- writer.close();
- return "list file file://" + temp.getAbsolutePath() + ";";
- case 3:
- return "!echo ";
- case 4:
- return "test message;";
- case 5:
- return "source fakeFile;";
- case 6:
- temp = File.createTempFile("hive", "test");
- temp.deleteOnExit();
- writer = new FileWriter(temp);
- writer.write("source fakeFile;");
- writer.close();
- return "list file file://" + temp.getAbsolutePath() + ";";
-
-
- // drop table over10k;
- default:
- return null;
+ protected CliDriver newCliDriver() {
+ try {
+ return new FakeCliDriver(conf);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
}
}
}
diff --git a/common/pom.xml b/common/pom.xml
index c1ee4ffc126..66931be0c03 100644
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -82,7 +82,7 @@
</exclusions>
</dependency>
<dependency>
- <groupId>jline</groupId>
+ <groupId>org.jline</groupId>
<artifactId>jline</artifactId>
</dependency>
<dependency>
@@ -246,7 +246,6 @@
<dependency>
<groupId>org.fusesource.jansi</groupId>
<artifactId>jansi</artifactId>
- <version>${jansi.version}</version>
</dependency>
<!-- test inter-project -->
<dependency>
diff --git
a/common/src/java/org/apache/hive/common/util/MatchingStringsCompleter.java
b/common/src/java/org/apache/hive/common/util/MatchingStringsCompleter.java
new file mode 100644
index 00000000000..abe7d17f6d8
--- /dev/null
+++ b/common/src/java/org/apache/hive/common/util/MatchingStringsCompleter.java
@@ -0,0 +1,70 @@
+/*
+ * 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.common.util;
+
+import org.jline.reader.Candidate;
+import org.jline.reader.Completer;
+import org.jline.reader.LineReader;
+import org.jline.reader.ParsedLine;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+/**
+ * A matching string Completer based on JLine's StringCompleter
+ */
+public class MatchingStringsCompleter implements Completer {
+ protected SortedSet<String> candidateStrings = new TreeSet<>();
+
+ public MatchingStringsCompleter() {
+ // empty
+ }
+
+ public MatchingStringsCompleter(String... strings) {
+ this(Arrays.asList(strings));
+ }
+
+ public MatchingStringsCompleter(Iterable<String> strings) {
+ strings.forEach(candidateStrings::add);
+ }
+
+ public Collection<String> getStrings() {
+ return candidateStrings;
+ }
+
+ @Override
+ public void complete(LineReader reader, ParsedLine line, List<Candidate>
candidates) {
+ Objects.requireNonNull(candidates, "candidates must not be null");
+
+ if (line == null) {
+ candidateStrings.stream().map(Candidate::new).forEach(candidates::add);
+ } else {
+ for (String match : this.candidateStrings.tailSet(line.word())) {
+ if (!match.startsWith(line.word())) {
+ break;
+ }
+ candidates.add(new Candidate(match));
+ }
+ }
+ }
+}
diff --git a/hcatalog/hcatalog-pig-adapter/pom.xml
b/hcatalog/hcatalog-pig-adapter/pom.xml
index 1888a0a488a..f5062369ebd 100644
--- a/hcatalog/hcatalog-pig-adapter/pom.xml
+++ b/hcatalog/hcatalog-pig-adapter/pom.xml
@@ -30,6 +30,8 @@
<name>Hive HCatalog Pig Adapter</name>
<properties>
<hive.path.to.root>../..</hive.path.to.root>
+ <!-- HIVE-28992: only upgrade to newer than 3.25.0 if you tested the
prompt -->
+ <jline.version>3.25.0</jline.version>
</properties>
<dependencies>
<!-- dependencies are always listed in sorted order by groupId, artifactId
-->
@@ -123,9 +125,9 @@
<scope>test</scope>
</dependency>
<dependency>
- <groupId>jline</groupId>
+ <groupId>org.jline</groupId>
<artifactId>jline</artifactId>
- <version>0.9.94</version>
+ <version>${jline.version}</version>
<scope>test</scope>
</dependency>
<dependency>
diff --git
a/itests/hive-unit/src/test/java/org/apache/hive/beeline/TestBeeLineWithArgs.java
b/itests/hive-unit/src/test/java/org/apache/hive/beeline/TestBeeLineWithArgs.java
index 08626809fb8..92f2d8c5657 100644
---
a/itests/hive-unit/src/test/java/org/apache/hive/beeline/TestBeeLineWithArgs.java
+++
b/itests/hive-unit/src/test/java/org/apache/hive/beeline/TestBeeLineWithArgs.java
@@ -24,11 +24,12 @@
import static org.junit.Assert.fail;
import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
+import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
-import java.io.StringBufferInputStream;
import java.io.UnsupportedEncodingException;
import java.sql.Connection;
import java.sql.DriverManager;
@@ -53,6 +54,8 @@
import org.apache.hive.jdbc.Utils;
import org.apache.hive.jdbc.miniHS2.MiniHS2;
import org.apache.hive.jdbc.miniHS2.MiniHS2.MiniClusterType;
+import org.jline.terminal.Terminal;
+import org.jline.terminal.impl.DumbTerminal;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
@@ -158,10 +161,9 @@ public static void postTests() {
* @return The stderr and stdout from running the script
* @throws Throwable
*/
- static String testCommandLineScript(List<String> argList, InputStream
inputStream,
- OutStream streamType)
+ static String testCommandLineScript(List<String> argList, OutStream
streamType)
throws Throwable {
- BeeLine beeLine = new BeeLine();
+ BeeLine beeLine = getBeeLineDummyTerminal();
ByteArrayOutputStream os = new ByteArrayOutputStream();
PrintStream beelineOutputStream = new PrintStream(os);
switch (streamType) {
@@ -175,13 +177,30 @@ static String testCommandLineScript(List<String> argList,
InputStream inputStrea
throw new RuntimeException("Unexpected outstream type " + streamType);
}
String[] args = argList.toArray(new String[argList.size()]);
- beeLine.begin(args, inputStream);
+ beeLine.begin(args, null);
beeLine.close();
beelineOutputStream.close();
String output = os.toString("UTF8");
return output;
}
+ private static BeeLineDummyTerminal getBeeLineDummyTerminal() {
+ return new BeeLineDummyTerminal() {
+ /*
+ * Unit tests in this class call the begin function with a null input
stream. Once the initial (-i) and file (-f)
+ * scripts are completed, the flow enters the interactive code
path—which we want to skip in tests to allow them
+ * to exit cleanly. In the real world, this would lead to the
interactive Beeline shell, but for testing purposes,
+ * we bypass that by providing a dummy empty stream. This avoids
infinite loops or null pointer errors in the
+ * JLine read logic.
+ */
+ @Override
+ protected Terminal buildTerminal(InputStream inputStream) throws
IOException {
+ return new DumbTerminal(inputStream == null ? new
ByteArrayInputStream("".getBytes()) : inputStream,
+ getErrorStream());
+ }
+ };
+ }
+
/**
* Attempt to execute a simple script file with the -f and -i option to
* BeeLine to test for presence of an expected pattern in the output (stdout
@@ -266,8 +285,8 @@ public Tuple<Pattern> apply(Tuple<String> tuple) {
boolean matches = m.matches();
if (patternToMatch.shouldMatch != matches) {
//failed
- fail("Output" + output + " should" + (patternToMatch.shouldMatch ?
"" : " not") +
- " contain " + patternToMatch.pattern.pattern());
+ fail(String.format("Output (mode: %s) '%s' should %s contain '%s'",
mode, output,
+ (patternToMatch.shouldMatch ? "" : " not"),
patternToMatch.pattern.pattern()));
}
}
}
@@ -281,18 +300,16 @@ enum Modes {
INIT {
@Override
String output(File scriptFile, List<String> argList, OutStream
streamType) throws Throwable {
- List<String> copy = new ArrayList<>(argList);
- copy.add("-i");
- copy.add(scriptFile.getAbsolutePath());
- return testCommandLineScript(copy, new
StringBufferInputStream("!quit\n"), streamType);
+ List<String> finalArgs = new ArrayList<>(argList);
+ finalArgs.addAll(Arrays.asList("-i", scriptFile.getAbsolutePath()));
+ return testCommandLineScript(finalArgs, streamType);
}
}, SCRIPT {
@Override
String output(File scriptFile, List<String> argList, OutStream
streamType) throws Throwable {
- List<String> copy = new ArrayList<>(argList);
- copy.add("-f");
- copy.add(scriptFile.getAbsolutePath());
- return testCommandLineScript(copy, null, streamType);
+ List<String> finalArgs = new ArrayList<>(argList);
+ finalArgs.addAll(Arrays.asList("-f", scriptFile.getAbsolutePath()));
+ return testCommandLineScript(finalArgs, streamType);
}
};
@@ -314,11 +331,10 @@ abstract String output(File scriptFile, List<String>
argList, OutStream streamTy
private void testCommandEnclosedQuery(String enclosedQuery, String
expectedPattern,
boolean shouldMatch, List<String> argList, OutStream out) throws
Throwable {
- List<String> copy = new ArrayList<String>(argList);
- copy.add("-e");
- copy.add(enclosedQuery);
+ List<String> finalArgs = new ArrayList<String>(argList);
+ finalArgs.addAll(Arrays.asList("-e", enclosedQuery));
- String output = testCommandLineScript(copy, null, out);
+ String output = testCommandLineScript(finalArgs, out);
boolean matches = output.contains(expectedPattern);
if (shouldMatch != matches) {
//failed
@@ -484,7 +500,7 @@ public void testNullNonEmpty() throws Throwable {
public void testGetVariableValue() throws Throwable {
final String SCRIPT_TEXT = "set env:TERM;";
final String EXPECTED_PATTERN = "env:TERM";
- testScriptFile(SCRIPT_TEXT, getBaseArgs(miniHS2.getBaseJdbcURL()),
OutStream.ERR, EXPECTED_PATTERN, true);
+ testScriptFile(SCRIPT_TEXT, getBaseArgs(miniHS2.getBaseJdbcURL()),
OutStream.OUT, EXPECTED_PATTERN, true);
}
/**
@@ -707,7 +723,7 @@ public void testNegativeScriptFile() throws Throwable {
argList.add(scriptFile.getAbsolutePath());
try {
- String output = testCommandLineScript(argList, null, OutStream.OUT);
+ String output = testCommandLineScript(argList, OutStream.OUT);
if (output.contains(EXPECTED_PATTERN)) {
fail("Output: " + output + " Negative pattern: " + EXPECTED_PATTERN);
}
@@ -971,6 +987,10 @@ public void testBeelineReconnect() throws Throwable {
List<String> argList = getBaseArgs(miniHS2.getBaseJdbcURL());
final String SCRIPT_TEXT =
"!close\n" +
+ // 3 line breaks mimic user input in the following sequence:
+ // 1. reconnect command
+ // 2. response to username prompt
+ // 3. response to password prompt
"!reconnect\n\n\n" +
"create table reconnecttest (d int);\nshow tables;\ndrop table
reconnecttest;\n";
final String EXPECTED_PATTERN = "reconnecttest";
@@ -1027,10 +1047,7 @@ public void testSelectQueryWithNonEscapedSemiColon()
throws Throwable {
}
/**
- * Attempt to execute a simple script file with the usage of user & password
variables in URL.
- * Test for presence of an expected pattern
- * in the output (stdout or stderr), fail if not found
- * Print PASSED or FAILED
+ * Attempts to execute a simple script file and verifies that the database
name appears in the prompt as expected.
*/
@Test
public void testShowDbInPrompt() throws Throwable {
diff --git
a/itests/hive-unit/src/test/java/org/apache/hive/beeline/TestBeelinePasswordOption.java
b/itests/hive-unit/src/test/java/org/apache/hive/beeline/TestBeelinePasswordOption.java
index b6d01ce5789..0631c641177 100644
---
a/itests/hive-unit/src/test/java/org/apache/hive/beeline/TestBeelinePasswordOption.java
+++
b/itests/hive-unit/src/test/java/org/apache/hive/beeline/TestBeelinePasswordOption.java
@@ -17,6 +17,7 @@
*/
package org.apache.hive.beeline;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
@@ -113,7 +114,7 @@ public void testPromptPasswordOptionWithOtherOptions()
throws Exception {
argList.add("-e");
argList.add("show tables;");
String output = connectBeelineWithUserPrompt(argList, "hivepassword");
- Assert.assertTrue("Table name " + tableName + " not found in the output",
+ Assert.assertTrue(String.format("Table name %s not found in the output:
%s", tableName, output),
output.contains(tableName.toLowerCase()));
}
@@ -131,7 +132,7 @@ public void testPromptPasswordOptionWithBeelineOpts()
throws Exception {
argList.add("-e");
argList.add("show tables;");
String output = connectBeelineWithUserPrompt(argList, "hivepassword");
- Assert.assertTrue("Table name " + tableName + " not found in the output",
+ Assert.assertTrue(String.format("Table name %s not found in the output:
%s", tableName, output),
output.contains(tableName.toLowerCase()));
}
@@ -149,8 +150,8 @@ public void testPromptPasswordVerifyBeelineOpts() throws
Exception {
argList.add("--maxColumnWidth=57");
argList.add("-e");
argList.add("show tables;");
- String output = connectWithPromptAndVerify(argList, "hivepassword", true,
57, null, null);
- Assert.assertTrue("Table name " + tableName + " not found in the output",
+ String output = connectWithPromptAndVerify(argList, "hivepassword", 57,
null, null);
+ Assert.assertTrue(String.format("Table name %s not found in the output:
%s", tableName, output),
output.contains(tableName.toLowerCase()));
}
@@ -169,9 +170,9 @@ public void testPromptPasswordWithHiveConf() throws
Exception {
argList.add("hive.cli.print.header=true");
argList.add("-e");
argList.add("show tables;");
- String output = connectWithPromptAndVerify(argList, "hivepassword", false,
null,
+ String output = connectWithPromptAndVerify(argList, "hivepassword", -1,
"hive.cli.print.header", "true");
- Assert.assertTrue("Table name " + tableName + " not found in the output",
+ Assert.assertTrue(String.format("Table name %s not found in the output:
%s", tableName, output),
output.contains(tableName.toLowerCase()));
}
@@ -188,7 +189,7 @@ public void testNoPasswordPrompt() throws Exception {
argList.add("-e");
argList.add("show tables;");
String output = connectBeelineWithUserPrompt(argList);
- Assert.assertTrue("Table name " + tableName + " not found in the output",
+ Assert.assertTrue(String.format("Table name %s not found in the output:
%s", tableName, output),
output.contains(tableName.toLowerCase()));
}
@@ -203,7 +204,7 @@ public void testNoPasswordPrompt2() throws Exception {
argList.add("-e");
argList.add("show tables;");
String output = connectBeelineWithUserPrompt(argList);
- Assert.assertTrue("Table name " + tableName + " not found in the output",
+ Assert.assertTrue(String.format("Table name %s not found in the output:
%s", tableName, output),
output.contains(tableName.toLowerCase()));
}
@@ -221,7 +222,7 @@ public void testPromptPassOptionLastWithBeelineOpts()
throws Exception {
argList.add("show tables;");
argList.add("-p");
String output = connectBeelineWithUserPrompt(argList, "hivepassword");
- Assert.assertTrue("Table name " + tableName + " not found in the output",
+ Assert.assertTrue(String.format("Table name %s not found in the output:
%s", tableName, output),
output.contains(tableName.toLowerCase()));
}
@@ -234,18 +235,18 @@ public void testPromptPassOptionLastWithBeelineOpts()
throws Exception {
* @param prompt - String value to be given to beeline prompt during
connection
* @param beelineOptName - Name of BeelineOpt to be verified
* @param beelineOptValue - Expected value of value of BeeLineOpt
+ * @param expectedMaxColumnWidth - expected max column width to check (if
not -1)
* @param hiveConfKey - hive conf variable name to verify
* @param expectedHiveConfValue - Expected value of hive conf variable
* @return output of beeline from outputstream
* @throws Exception
*/
private String connectWithPromptAndVerify(List<String> argList, String
prompt,
- boolean testMaxColumnWidthOption, Integer expectedMaxColumnWidth, String
hiveConfKey,
- String expectedHiveConfValue) throws Exception {
+ int expectedMaxColumnWidth, String hiveConfKey, String
expectedHiveConfValue) throws Exception {
BeeLine beeLine = null;
InputStream inputStream = null;
try {
- beeLine = new BeeLine();
+ beeLine = new BeeLineDummyTerminal();
ByteArrayOutputStream os = new ByteArrayOutputStream();
PrintStream beelineOutputStream = new PrintStream(os);
beeLine.setOutputStream(beelineOutputStream);
@@ -254,12 +255,11 @@ private String connectWithPromptAndVerify(List<String>
argList, String prompt,
if (prompt != null) {
inputStream = new ByteArrayInputStream(prompt.getBytes());
}
- Assert.assertTrue(beeLine.begin(args, inputStream) == 0);
- if (testMaxColumnWidthOption) {
+ int returnCode = beeLine.begin(args, inputStream);
+ assertEquals("Beeline.begin return code is not as expected", 0,
returnCode);
+ if (expectedMaxColumnWidth != -1) {
int maxColumnWidth = beeLine.getOpts().getMaxColumnWidth();
- Assert.assertTrue(
- "Expected max columnWidth to be " + expectedMaxColumnWidth + " found
" + maxColumnWidth,
- maxColumnWidth == expectedMaxColumnWidth);
+ assertEquals("Unexpected max column width", expectedMaxColumnWidth,
maxColumnWidth);
}
if (hiveConfKey != null) {
String hiveConfValue =
beeLine.getOpts().getHiveConfVariables().get(hiveConfKey);
@@ -286,7 +286,7 @@ private String connectBeelineWithUserPrompt(List<String>
argList) throws Excepti
private String connectBeelineWithUserPrompt(List<String> argList, String
prompt)
throws Exception {
- return connectWithPromptAndVerify(argList, prompt, false, null, null,
null);
+ return connectWithPromptAndVerify(argList, prompt, -1, null, null);
}
/**
diff --git
a/itests/hive-unit/src/test/java/org/apache/hive/beeline/TestHplSqlViaBeeLine.java
b/itests/hive-unit/src/test/java/org/apache/hive/beeline/TestHplSqlViaBeeLine.java
index d9527cc78d3..994b0418023 100644
---
a/itests/hive-unit/src/test/java/org/apache/hive/beeline/TestHplSqlViaBeeLine.java
+++
b/itests/hive-unit/src/test/java/org/apache/hive/beeline/TestHplSqlViaBeeLine.java
@@ -1418,10 +1418,10 @@ private void testScriptFile(String scriptText,
List<String> argList, String expe
try (PrintStream os = new PrintStream(new FileOutputStream(scriptFile))) {
os.print(scriptText);
}
- List<String> copy = new ArrayList<>(argList);
- copy.add("-f");
- copy.add(scriptFile.getAbsolutePath());
- String output = testCommandLineScript(copy, null, outStream);
+ List<String> finalArgs = new ArrayList<>(argList);
+ finalArgs.addAll(Arrays.asList("-f", scriptFile.getAbsolutePath()));
+
+ String output = testCommandLineScript(finalArgs, outStream);
if (scriptText.equals("SELECT UNIX_TIMESTAMP()")) {
Pattern pattern = Pattern.compile("\\|\\s*(\\d+)\\s*\\|");
Matcher matcher = pattern.matcher(output);
diff --git
a/itests/hive-unit/src/test/java/org/apache/hive/beeline/hs2connection/BeelineWithHS2ConnectionFileTestBase.java
b/itests/hive-unit/src/test/java/org/apache/hive/beeline/hs2connection/BeelineWithHS2ConnectionFileTestBase.java
index 13679867c1b..bc20d733f95 100644
---
a/itests/hive-unit/src/test/java/org/apache/hive/beeline/hs2connection/BeelineWithHS2ConnectionFileTestBase.java
+++
b/itests/hive-unit/src/test/java/org/apache/hive/beeline/hs2connection/BeelineWithHS2ConnectionFileTestBase.java
@@ -35,7 +35,7 @@
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hive.conf.HiveConf;
import org.apache.hadoop.hive.conf.HiveConf.ConfVars;
-import org.apache.hive.beeline.BeeLine;
+import org.apache.hive.beeline.BeeLineDummyTerminal;
import org.apache.hive.jdbc.miniHS2.MiniHS2;
import org.apache.hive.service.cli.CLIServiceClient;
import org.apache.hive.service.cli.HiveSQLException;
@@ -75,11 +75,11 @@ public abstract class BeelineWithHS2ConnectionFileTestBase {
public String transportMode = null;
- protected class TestBeeLine extends BeeLine {
+ protected class BeelineWithConfigFileManager extends BeeLineDummyTerminal {
UserHS2ConnectionFileParser testHs2ConfigFileManager;
ByteArrayOutputStream os;
- TestBeeLine(List<String> defaultHS2ConnectionFiles) {
+ BeelineWithConfigFileManager(List<String> defaultHS2ConnectionFiles) {
testHs2ConfigFileManager = new
UserHS2ConnectionFileParser(defaultHS2ConnectionFiles);
os = new ByteArrayOutputStream();
PrintStream beelineOutputStream = new PrintStream(os);
@@ -87,7 +87,7 @@ protected class TestBeeLine extends BeeLine {
setErrorStream(beelineOutputStream);
}
- TestBeeLine() {
+ BeelineWithConfigFileManager() {
testHs2ConfigFileManager = new UserHS2ConnectionFileParser(null);
os = new ByteArrayOutputStream();
PrintStream beelineOutputStream = new PrintStream(os);
@@ -225,14 +225,14 @@ public BeelineResult(String output, int exitCode) {
}
protected BeelineResult getBeelineOutput(String path, String[] beelineArgs)
throws Exception {
- TestBeeLine beeLine = null;
+ BeelineWithConfigFileManager beeLine = null;
try {
if(path != null) {
List<String> testLocations = new ArrayList<>();
testLocations.add(path);
- beeLine = new TestBeeLine(testLocations);
+ beeLine = new BeelineWithConfigFileManager(testLocations);
} else {
- beeLine = new TestBeeLine();
+ beeLine = new BeelineWithConfigFileManager();
}
int exitCode = beeLine.begin(beelineArgs, null);
String output = beeLine.getOutput();
diff --git
a/itests/hive-unit/src/test/java/org/apache/hive/jdbc/miniHS2/TestHs2ConnectionMetricsBinary.java
b/itests/hive-unit/src/test/java/org/apache/hive/jdbc/miniHS2/TestHs2ConnectionMetricsBinary.java
index 6677b45a735..466d262dea3 100644
---
a/itests/hive-unit/src/test/java/org/apache/hive/jdbc/miniHS2/TestHs2ConnectionMetricsBinary.java
+++
b/itests/hive-unit/src/test/java/org/apache/hive/jdbc/miniHS2/TestHs2ConnectionMetricsBinary.java
@@ -25,6 +25,7 @@
import org.apache.hadoop.hive.common.metrics.metrics2.CodahaleMetrics;
import org.apache.hadoop.hive.conf.HiveConf;
import org.apache.hive.beeline.BeeLine;
+import org.apache.hive.beeline.BeeLineDummyTerminal;
import org.junit.AfterClass;
import org.junit.BeforeClass;
@@ -78,7 +79,7 @@ public void testOpenConnectionMetrics() throws Exception {
}
private BeeLine openBeeLineConnection(String[] beelineArgs) throws
IOException {
- BeeLine beeLine = new BeeLine();
+ BeeLine beeLine = new BeeLineDummyTerminal();
beeLine.begin(beelineArgs, null);
return beeLine;
}
diff --git
a/itests/hive-unit/src/test/java/org/apache/hive/service/server/InformationSchemaWithPrivilegeTestBase.java
b/itests/hive-unit/src/test/java/org/apache/hive/service/server/InformationSchemaWithPrivilegeTestBase.java
index f71aa4fa888..b43df43f8f0 100644
---
a/itests/hive-unit/src/test/java/org/apache/hive/service/server/InformationSchemaWithPrivilegeTestBase.java
+++
b/itests/hive-unit/src/test/java/org/apache/hive/service/server/InformationSchemaWithPrivilegeTestBase.java
@@ -52,6 +52,7 @@
import
org.apache.hadoop.hive.ql.security.authorization.plugin.sqlstd.DummyHiveAuthorizationValidator;
import
org.apache.hadoop.hive.ql.security.authorization.plugin.sqlstd.SQLStdHiveAccessControllerWrapper;
import org.apache.hive.beeline.BeeLine;
+import org.apache.hive.beeline.BeeLineDummyTerminal;
import org.apache.hive.jdbc.miniHS2.MiniHS2;
import org.apache.hive.service.cli.CLIServiceClient;
import org.apache.hive.service.cli.OperationHandle;
@@ -298,7 +299,7 @@ public void test() throws Exception {
List<String> args = new ArrayList<String>(baseArgs);
args.add("-f");
args.add("../../standalone-metastore/metastore-server/src/main/sql/hive/hive-schema-"
+ hiveSchemaVer + ".hive.sql");
- BeeLine beeLine = new BeeLine();
+ BeeLine beeLine = new BeeLineDummyTerminal();
int result = beeLine.begin(args.toArray(new String[] {}), null);
beeLine.close();
Assert.assertEquals(result, 0);
diff --git
a/llap-server/src/java/org/apache/hadoop/hive/llap/cli/service/LlapServiceCommandLine.java
b/llap-server/src/java/org/apache/hadoop/hive/llap/cli/service/LlapServiceCommandLine.java
index ec3164d226c..5484e0ca1a1 100644
---
a/llap-server/src/java/org/apache/hadoop/hive/llap/cli/service/LlapServiceCommandLine.java
+++
b/llap-server/src/java/org/apache/hadoop/hive/llap/cli/service/LlapServiceCommandLine.java
@@ -21,8 +21,6 @@
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
-import jline.TerminalFactory;
-
import java.util.Arrays;
import java.util.Properties;
import java.util.Set;
@@ -36,6 +34,7 @@
import org.apache.commons.cli.ParseException;
import org.apache.hadoop.hive.conf.HiveConf.ConfVars;
import org.apache.hadoop.hive.llap.log.LogHelpers;
+import org.jline.terminal.TerminalBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -403,7 +402,7 @@ private static void printUsage() {
HelpFormatter hf = new HelpFormatter();
try {
int width = hf.getWidth();
- int jlineWidth = TerminalFactory.get().getWidth();
+ int jlineWidth = TerminalBuilder.terminal().getWidth();
width = Math.min(160, Math.max(jlineWidth, width));
hf.setWidth(width);
} catch (Throwable t) { // Ignore
diff --git
a/llap-server/src/java/org/apache/hadoop/hive/llap/cli/status/LlapStatusServiceCommandLine.java
b/llap-server/src/java/org/apache/hadoop/hive/llap/cli/status/LlapStatusServiceCommandLine.java
index 61554b3b29f..1dbe3ae1d06 100644
---
a/llap-server/src/java/org/apache/hadoop/hive/llap/cli/status/LlapStatusServiceCommandLine.java
+++
b/llap-server/src/java/org/apache/hadoop/hive/llap/cli/status/LlapStatusServiceCommandLine.java
@@ -21,8 +21,6 @@
import java.util.Arrays;
import java.util.Properties;
-import jline.TerminalFactory;
-
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.HelpFormatter;
@@ -31,7 +29,7 @@
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.hadoop.util.ExitUtil;
-
+import org.jline.terminal.TerminalBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -240,7 +238,7 @@ private static void printUsage() {
HelpFormatter hf = new HelpFormatter();
try {
int width = hf.getWidth();
- int jlineWidth = TerminalFactory.get().getWidth();
+ int jlineWidth = TerminalBuilder.terminal().getWidth();
width = Math.min(160, Math.max(jlineWidth, width));
hf.setWidth(width);
} catch (Throwable t) { // Ignore
diff --git a/pom.xml b/pom.xml
index bce696397f7..28a65a35a91 100644
--- a/pom.xml
+++ b/pom.xml
@@ -162,7 +162,8 @@
<jettison.version>1.5.4</jettison.version>
<jetty.version>9.4.57.v20241219</jetty.version>
<jersey.version>1.19.4</jersey.version>
- <jline.version>2.14.6</jline.version>
+ <!-- HIVE-28992: only upgrade to newer than 3.25.0 if you tested the
prompt -->
+ <jline.version>3.25.0</jline.version>
<jms.version>2.0.2</jms.version>
<joda.version>2.13.0</joda.version>
<jodd.version>6.0.0</jodd.version>
@@ -453,7 +454,7 @@
<version>${javolution.version}</version>
</dependency>
<dependency>
- <groupId>jline</groupId>
+ <groupId>org.jline</groupId>
<artifactId>jline</artifactId>
<version>${jline.version}</version>
</dependency>
@@ -1421,6 +1422,11 @@
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.fusesource.jansi</groupId>
+ <artifactId>jansi</artifactId>
+ <version>${jansi.version}</version>
+ </dependency>
<!-- JDBC drivers -->
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
diff --git a/standalone-metastore/metastore-server/pom.xml
b/standalone-metastore/metastore-server/pom.xml
index eb329c44100..250273ceb11 100644
--- a/standalone-metastore/metastore-server/pom.xml
+++ b/standalone-metastore/metastore-server/pom.xml
@@ -303,7 +303,7 @@
<artifactId>sqlline</artifactId>
</dependency>
<dependency>
- <groupId>jline</groupId>
+ <groupId>org.jline</groupId>
<artifactId>jline</artifactId>
</dependency>
<dependency>
diff --git
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/tools/metatool/HiveMetaToolCommandLine.java
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/tools/metatool/HiveMetaToolCommandLine.java
index 58a8c921465..7df25c0c5e3 100644
---
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/tools/metatool/HiveMetaToolCommandLine.java
+++
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/tools/metatool/HiveMetaToolCommandLine.java
@@ -28,11 +28,10 @@
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.hadoop.util.ExitUtil;
-
+import org.jline.terminal.TerminalBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import jline.TerminalFactory;
class HiveMetaToolCommandLine {
private static final Logger LOGGER =
LoggerFactory.getLogger(HiveMetaToolCommandLine.class.getName());
@@ -216,7 +215,7 @@ private static void printUsage() {
HelpFormatter hf = new HelpFormatter();
try {
int width = hf.getWidth();
- int jlineWidth = TerminalFactory.get().getWidth();
+ int jlineWidth = TerminalBuilder.terminal().getWidth();
width = Math.min(160, Math.max(jlineWidth, width));
hf.setWidth(width);
} catch (Throwable t) { // Ignore
diff --git a/standalone-metastore/pom.xml b/standalone-metastore/pom.xml
index 14baad61338..6857f53bab7 100644
--- a/standalone-metastore/pom.xml
+++ b/standalone-metastore/pom.xml
@@ -101,7 +101,8 @@
<protoc.path>${env.PROTOC_PATH}</protoc.path>
<io.grpc.version>1.72.0</io.grpc.version>
<sqlline.version>1.9.0</sqlline.version>
- <jline.version>2.14.6</jline.version>
+ <!-- HIVE-28992: only upgrade to newer than 3.25.0 if you tested the
prompt -->
+ <jline.version>3.25.0</jline.version>
<ST4.version>4.0.4</ST4.version>
<storage-api.version>4.2.0-SNAPSHOT</storage-api.version>
<beanutils.version>1.9.4</beanutils.version>
@@ -338,9 +339,15 @@
<groupId>sqlline</groupId>
<artifactId>sqlline</artifactId>
<version>${sqlline.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.jline</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
- <groupId>jline</groupId>
+ <groupId>org.jline</groupId>
<artifactId>jline</artifactId>
<version>${jline.version}</version>
</dependency>