How can one get the output from Oracle's dbms_output.get_lines in a Java app using JDBC without creating additional objects in the database?
If the server output is enabled, the dbms_output. put_line command will print the output of PL/SQL code in the console window. The dbms_output.
The PUT_LINE function in the DBMS_OUTPUT package is one of the most widely-used functions, in my experience. This function allows you to write a message to the screen. It works by placing the text you specify onto a buffer. That buffer is written to the screen in your IDE or program when the procedure completes.
The DBMS_OUTPUT package enables you to send messages from stored procedures and packages. The package is especially useful for displaying PL/SQL debugging information.
I've also blogged about this issue here. Here's a snippet that illustrates how this can be done:
try (CallableStatement call = c.prepareCall(
    "declare "
  + "  num integer := 1000;" // Adapt this as needed
  + "begin "
  // You have to enable buffering any server output that you may want to fetch
  + "  dbms_output.enable();"
  // This might as well be a call to third-party stored procedures, etc., whose
  // output you want to capture
  + "  dbms_output.put_line('abc');"
  + "  dbms_output.put_line('hello');"
  + "  dbms_output.put_line('so cool');"
  // This is again your call here to capture the output up until now.
  // The below fetching the PL/SQL TABLE type into a SQL cursor works with Oracle 12c.
  // In an 11g version, you'd need an auxiliary SQL TABLE type
  + "  dbms_output.get_lines(?, num);"
  // Don't forget this or the buffer will overflow eventually
  + "  dbms_output.disable();"
  + "end;"
)) {
    call.registerOutParameter(1, Types.ARRAY, "DBMSOUTPUT_LINESARRAY");
    call.execute();
    Array array = null;
    try {
        array = call.getArray(1);
        System.out.println(Arrays.asList((Object[]) array.getArray()));
    }
    finally {
        if (array != null)
            array.free();
    }
}
The above will print:
[abc, hello, so cool, null]
Note that the ENABLE / DISABLE setting is a connection wide setting, so you can also do this over several JDBC statements:
try (Connection c = DriverManager.getConnection(url, properties);
     Statement s = c.createStatement()) {
    try {
        s.executeUpdate("begin dbms_output.enable(); end;");
        s.executeUpdate("begin dbms_output.put_line('abc'); end;");
        s.executeUpdate("begin dbms_output.put_line('hello'); end;");
        s.executeUpdate("begin dbms_output.put_line('so cool'); end;");
        try (CallableStatement call = c.prepareCall(
            "declare "
          + "  num integer := 1000;"
          + "begin "
          + "  dbms_output.get_lines(?, num);"
          + "end;"
        )) {
            call.registerOutParameter(1, Types.ARRAY, "DBMSOUTPUT_LINESARRAY");
            call.execute();
            Array array = null;
            try {
                array = call.getArray(1);
                System.out.println(Arrays.asList((Object[]) array.getArray()));
            }
            finally {
                if (array != null)
                    array.free();
            }
        }
    }
    finally {
        s.executeUpdate("begin dbms_output.disable(); end;");
    }
}
Note also that this will fetch a fixed size of 1000 lines at most. You may need to loop in PL/SQL or poll the database if you want more lines.
DBMS_OUTPUT.GET_LINE insteadPreviously, there was a now-deleted answer that suggested individual calls to DBMS_OUTPUT.GET_LINE instead, which returns one line at a time. I've benchmarked the approach comparing it with DBMS_OUTPUT.GET_LINES, and the differences are drastic - up to a factor 30x slower when called from JDBC (even if there's not really a big difference when calling the procedures from PL/SQL).
So, the bulk data transferring approach using DBMS_OUTPUT.GET_LINES is definitely worth it. Here's a link to the benchmark:
https://blog.jooq.org/2017/12/18/the-cost-of-jdbc-server-roundtrips/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With