镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

HIVE-30241: Beeline -f corrupts statements from script files - #6947

Open
dengzhhu653 wants to merge 1 commit into
apache:masterfrom
dengzhhu653:HIVE-30241
Open

dengzhhu653 wants to merge 1 commit into
apache:masterfrom
dengzhhu653:HIVE-30241

Conversation

@dengzhhu653

@dengzhhu653 dengzhhu653 commented Nov 5, 2026 •

Copy link
Copy Markdown
Member

What changes were proposed in this pull request?

Avoid TerminalBuilder.build() for script input so JLine does not select PosixPtyTerminal via native providers’ newTerminal, so it reads bytes/lines matching the input file.

Why are the changes needed?

Statement sent to HS2 gets corrupted

Does this PR introduce any user-facing change?

No

How was this patch tested?

Re-run the scripts in my macOS laptop.

@utafrali utafrali left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix targets a real bug but uses a jline3 internal impl class as the solution, which creates a fragile dependency. Additionally, hardcoding UTF-8 can silently corrupt scripts in other encodings. No automated regression test covers this path, and the PR description's 'What changes were proposed' section is blank, making it impossible to verify intent from the diff alone.

import org.jline.reader.LineReaderBuilder;
import org.jline.reader.impl.DefaultParser;
import org.jline.reader.impl.LineReaderImpl;
import org.jline.reader.impl.history.DefaultHistory;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Importing from org.jline.terminal.impl couples Beeline to jline3's internal implementation package. Classes in impl packages are not part of the stable public API and can be removed or changed in patch releases of jline3 without notice.

The same behavior can be achieved through the public TerminalBuilder API:

terminal = TerminalBuilder.builder()
    .streams(inputStream, getErrorStream())
    .type(Terminal.TYPE_DUMB)
    .encoding(StandardCharsets.UTF_8)
    .build();

This avoids the impl import entirely while still forcing a dumb, encoding-fixed terminal for file input.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point.

if (inputStream != null) { // typically when there is a file script to read from
terminal = TerminalBuilder.builder().streams(inputStream, getErrorStream()).build();
// An ExternalTerminal is a plain stream pump and reads the script faithfully.
terminal = new ExternalTerminal("beeline", Terminal.TYPE_DUMB, inputStream, getErrorStream(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoding StandardCharsets.UTF_8 here is a silent regression for users whose script files are in a different encoding (e.g. Latin-1, GBK, Shift-JIS). The original TerminalBuilder path would have derived the encoding from the JVM default or terminal negotiation.

Consider reading the charset from an existing Beeline option (e.g. getOpts().getScriptCharset() or a system property fallback), or at minimum document the UTF-8 requirement prominently, since any non-UTF-8 script will now be silently misread rather than just having its statements reordered.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For beeline today, getCommands(File) already uses "UTF-8", other beeline I/O also standardizes on UTF-8 (password file contents, OutputFile with "UTF-8"). Explicit UTF-8 aligns -f with existing file handling.
We can support something like getOpts().getScriptCharset() in the future.

Terminal terminal;
if (inputStream != null) { // typically when there is a file script to read from
terminal = TerminalBuilder.builder().streams(inputStream, getErrorStream()).build();
// An ExternalTerminal is a plain stream pump and reads the script faithfully.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment "a plain stream pump" is not accurate for ExternalTerminal. According to jline3 source, ExternalTerminal spawns a background thread to process input and handle signals (e.g. Ctrl+C). It is designed for SSH/telnet connections, not file reading. This comment will mislead future readers about what ExternalTerminal actually does. If the goal is simply to suppress terminal capability detection, please describe that instead.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch, Thanks

@dengzhhu653

Copy link
Copy Markdown
Member Author

@utafrali I don't add the regression test due to, I want to kept the diff small, 500 lines of a script file is noisy compared to few lines of fix, and this issue might depend on the environment. The jira provides a script file I can show the case locally, after patching the fix, issue is gone.

@sonarqubecloud

sonarqubecloud Bot commented Nov 5, 2026

Copy link
Copy Markdown

@dengzhhu653
dengzhhu653 requested review from utafrali and a balanced review from Copilot and removed request for utafrali November 6, 2026 00:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Existing tests bypass the changed terminal-construction path, so a regression test is needed to verify that real provider selection preserves every line of large scripts, including UTF-8 text and a final line without a newline.

1 open issue
What changed in this PR

This PR addresses statement corruption when Beeline reads script files with -f, changing JLine terminal selection to avoid native pseudo-terminals.

Changes:

  • Forces the exec provider and dumb terminal type for script input.
  • Explicitly uses UTF-8 for script decoding.
  • Leaves interactive system-terminal construction unchanged.
File Description
beeline/​src/​java/​org/​apache/​hive/​beeline/​BeeLine.java Configures a non-PTY, UTF-8 terminal for script input to prevent statement corruption.

Review effort: Balanced

Comment on lines +1553 to +1556
.provider(TerminalBuilder.PROP_PROVIDER_EXEC)
.type(Terminal.TYPE_DUMB)
.streams(inputStream, getErrorStream())
.encoding(StandardCharsets.UTF_8)

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants