0

... before anyone marks this as a duplicate ... i have checked Is there any way to flush output from PL/SQL in Oracle? and am looking for more information on how to actually do what that answer referenced ... so hold it.

I absolutely need to use DBMS_OUTPUT due to various reasons. UTL_FILE won't help.

For the benefit of this question, let's say i'm generating a flat file.

declare

function printerFunction(someArray) <---- this function swallows an array and dumps it to 
is begin 
  for each element of some array ... dbms_output.put_line(element)
end printerFunction;

begin
   for row in some_cursor loop
       printerFunction(someArrayData);
   end loop;
end 

The aforementioned code block is essentially the jist of the matter... nothing special.

Dave Costa mentions something along the lines of "break up a large PL/SQL block into multiple smaller blocks" ... the question is how.

I understand I have a nested loop structure and this is most likely the reason behind the output buffer not flushing itself, but can't think of a way to keep some_cursor open or for all intents and purposes switch back and forth between two code blocks outside of that loop .

dbms_output.enable(null) is kind of a dumb idea in this case as well. Ideally i'd like to essentially flush out the stuff in the buffer to my sqlDeveloper scriptOutput window and move on with processing at a specific rate ... say every 10000 rows or so. is this even possible? ... I mean... the main begin [pl/sql code] end structure is essentially a code block itself.

... the db I'm working on is a production environment, and i can only use a limited, read-only set of commands. ... in other words ... SYS stuff is beyond my reach.

EverNight
  • 964
  • 7
  • 16
  • While I did give an answer to how to clear the buffer, you should still rethink the use of dbms_output for this purpose. It wasn't designed for high volume messages, but rather simple debugging or status messages. There are other better ways of I/O for programmatic use. – Paul W Feb 03 '23 at 22:20

2 Answers2

2

As Dave Costa explains in the answer you link to, if you want the client to display the information before all your processing is done, you'd need to break your code up into separate blocks that you could send separately to the database. The client has no way to read the data out of the dbms_output buffer until the database returns control to the client.

You wouldn't realistically keep a single cursor open across these separate calls. You'd open a new cursor each time. For example, if you had a block

begin
  for cursor in (select * from ... order by ... offset x fetch next y rows only)
  loop
    <<do something>>
  end loop;
end;

you could have that run for 10,000 rows (or whatever value of y you want), get the output in SQL Developer, then run another block to process the next y rows (or have x and y be variables defined in SQL Developer that you update in each iteration or create a package to save state in package variables but I assume that is not an option here). But you'd need to submit a new PL/SQL block to the database for each set of y rows that you wanted to process. And this query will get less efficient as you try to get later and later pages since it has to sort more and more data to get the results.

Practically, it is pretty unlikely that you'd really want to break your logic up like this. You'd almost always be better off submitting a single PL/SQL block and letting the client fetch the data once at the end. But using dbms_output to generate a file is pretty weird in the first place. You'd generally be better served letting SQL Developer generate the file. For example, if you return a sys_refcursor for

select *
  from table(someArrayData)

or just run whatever query that was used to generate someArrayData, SQL Developer can happily save that data into a CSV file, and XLS(X) file, etc.

Justin Cave
  • 227,342
  • 24
  • 367
  • 384
  • So, if I understand correctly, sql developer client sends some runtine logic to the dbms, dbms executes it, accumulates output, finishes, and dispatches that output back to the client. As long as that runtine logic is in the process of executing itself, it won't reach the point where it knows it's supposed to dispatch the output. ... and you essentially said something like " just run the code twice with different parameter " ... as in whole pl sql program. in other words there's no way to make it trigger that "dispatch output to client" event inside the runtime itself. correct? – EverNight Feb 04 '23 at 10:50
  • 1
    @EverNight - Correct (and that's the same answer Dave Costa gave in the answer you linked to). The client sends a request to the database. The database processes that request. The database sends a response to the client when it is done processing that request. The client at that point is free to send the next bit of PL/SQL or to do something like fetching the data from the `dbms_output` buffer. There is no option for the PL/SQL block to send data to the client before execution completes. – Justin Cave Feb 04 '23 at 12:36
  • 1
    Of course, there are other ways for PL/SQL to send status information to the client-- mostly detailed as alternate answers to the question you linked to. But if you're ruling all of those out because you're trying to generate a large file via `dbms_output` then you're likely stuck fetching the data from the `dbms_output` buffer only after the PL/SQL block finishes. – Justin Cave Feb 04 '23 at 12:37
  • well... who needs sleep anyway. Thanks Justin. – EverNight Feb 04 '23 at 12:46
0

You can clear the buffer by consuming the messages manually. This snippet puts something in the buffer and then clears it. My client shows no output.

DECLARE
  var_status integer := 0;
  var_dummy varchar2(32767);
BEGIN
  dbms_output.put_line('this is a test');
  
  WHILE var_status = 0
  LOOP
    DBMS_OUTPUT.GET_LINE (line => var_dummy,
                          status => var_status);
  END LOOP;
END;
Paul W
  • 5,507
  • 2
  • 2
  • 13
  • Thanks, I am aware of get_line, but don't know how to combine this functionality such that I still get the output in the section of sqlDeveloper. Any Ideas? – EverNight Feb 04 '23 at 10:45
  • I suppose I misread your question then, I thought you were asking how to flush/clear the buffer. I guess now I understand you're asking about how to retrieve the buffer in your client before the database call is complete. Short answer, you can't. If this is something you need, your client will have to do the looping/batching, not the database. I doubt that's something SQL Developer can do. You probably need to rethink what you're trying to accomplish and not use dbms_output for that purpose. – Paul W Feb 04 '23 at 13:35