0

I have a Spring Boot REST application with 2 endpoints: first starts the Process (db shell) with a command like 'mysql -e root'. Second one accepts command (query) and writes it to OutputStream (which is BufferedOutputStream from Process implementation).

Starting the Process (MySQL shell):

ProcessBuilder builder = new ProcessBuilder(commands);
builder.redirectErrorStream(true);
process = builder.start();
out = process.getInputStream();
in = process.getOutputStream();

Executing a command (e.g. 'select * from db.some_table;\n'):

byte[] commandBytes = command.getBytes(Charset.defaultCharset());
in.write(commandBytes, 0, commandBytes.length);
in.flush();

After running a command (query) I want to return its result (or at least, output it to the console) with:

int no = out.available();
 if (no > 0) {
 int n = out.read(buffer, 0, Math.min(no, buffer.length));
 System.out.println(new String(buffer, 0, n));
 }

The problem is that out.available() is always 0. If I call close() on an output stream, out.available() returns all the input stream length and I can read from it. But that is not what I want.

Can I somehow force BufferedInputStream to make result available to be read without closing the stream?

I see that internally BufferedInputStream uses FileInputStream and FileChannel, but I haven't found a way to capture the result when output stream is not closed.

Federico klez Culloca
27.3k17 gold badges61 silver badges102 bronze badges
asked Nov 11, 2022 at 10:10
3
  • Yes, try to read from it, and it will block until data is available. Checking available() is almost always the wrong thing to do. Read the JavaDoc for the method for an explanation docs.oracle.com/en/java/javase/18/docs/api/java.base/java/io/… Commented Nov 11, 2022 at 10:35
  • @TimMoore Well, that is my question how to make it available. If I use read(), it just blocks the stream forever (though data should be available almost immediately, that is 1 row to return query performed). I suppose that BufferedInputStream collects all the data and releases it when output stream is closed. And I need to read it before the stream closed (if it's possible), after each command execution. Commented Nov 11, 2022 at 10:43
  • It's extraordinary how we seem to get spates of questions. This last week it's been the specialized "how do I execute a mysql (usually) command line client". Why are you doing this and not using Java APIs? This kind of process interaction is non-trivial Commented Nov 11, 2022 at 12:35

1 Answer 1

1

I think what's happening is that the mysql client detects that standard input is not a terminal, and runs in batch mode rather than in interactive mode. This isn't caused by the behaviour of BufferedReader: it's blocking indefinitely on read, and reporting 0 bytes available because there genuinely isn't anything to read from the output of the subprocess.

In batch mode, the client expects to read a list of commands from standard input, and only executes them once the end of file is reached. In other words, the subprocess will not produce any output on the InputStream you see in your parent process until your parent process closes the OutputStream of the subprocess.

It appears that there's no way to force mysql to run in interactive mode (according to this question: "How to force mysql.exe to run in "interactive" mode?", and the documentation of command line options).

The mysqlsh client can be forced into interactive mode, but it is worth considering whether this is really the best solution for your use case. Other alternatives include:

  1. Embracing batch mode and executing all of the commands together, if the form of each command does not depend on the results of previous ones
  2. Sequentially invoking the subprocess multiple times in batch mode, if subsequent commands do depend on the results of previous ones
  3. Performing the queries using JDBC (as g00se recommended in the comments)
answered Nov 12, 2022 at 0:21
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.