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 <bodorlaszlo0...@gmail.com>
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>

Reply via email to