DBMS_PIPE is nothing new and many have blogged it's good and bad. There's lots more but here's just a few:
http://thinkoracle.blogspot.com/2005/11/dbmspipe.html
http://www.hoekstra.co.uk/index.php/software-mainmenu-36/oracle-mainmenu-54/29-dbmspipe.html
http://www.jaredstill.com/content/debug-pipe.html
Here's the wrapper I made and the body is here:
CREATE OR REPLACE PACKAGE pipe_output IS
pv_pipe_on_bln BOOLEAN := false;
PROCEDURE set_pipeoutput_on;
PROCEDURE put_line (p_message_txt VARCHAR2);
PROCEDURE put_line (p_pipe_name VARCHAR2,p_message_txt VARCHAR2);
PROCEDURE get_line (p_waittime_num NUMBER := 1);
PROCEDURE get_line (p_pipe_name VARCHAR2,p_waittime_num NUMBER := 1);
PROCEDURE get_line (p_pipe_name IN VARCHAR2,p_waittime_num IN NUMBER := 1,p_message OUT VARCHAR2);
END pipe_output;
So what that would allow me to do in the plsql block was something like this.
begin
pipe_output.set_pipeoutput_on;
for r in ( select object_name from user_objects ) loop
pipe_output.put_line('TAIL_ME',r.object_name);
end loop;
end;
Now that something is in the pipe it's time to get it out. For that I wrote a small java program. The same thing can be done direct from a sqlplus script or perl or whatever, it's not complicated.
import java.math.BigDecimal;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Types;
public class TailDBMSPipe extends Thread {
private String v_pipe_name;
private String connName;
public TailDBMSPipe(String pipeName) {
super.setDaemon(true);
v_pipe_name = pipeName;
}
public static void main(String[] args) {
TailDBMSPipe p = new TailDBMSPipe(args[0]);
p.connName = "jdbc:oracle:thin:" + args[1];
//p.connName = "jdbc:oracle:thin:my_customers/[email protected]:1521:mcdev";
p.run();
}
public void run() {
System.out.println("Redirecting database pipe:" + v_pipe_name);
Connection conn = null;
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection(connName);
String s = null;
BigDecimal retVal;
BigDecimal bigZero = new BigDecimal(0);
while (true) {
CallableStatement cs = conn.prepareCall("{ call ? := DBMS_PIPE.RECEIVE_MESSAGE(?, ?) }");
cs.registerOutParameter(1, Types.INTEGER);
cs.setString(2, v_pipe_name);
cs.setString(3, "100");
cs.executeUpdate();
retVal = cs.getBigDecimal(1);
cs.close();
if (retVal.compareTo(bigZero) == 0) {
cs = conn.prepareCall("{ call DBMS_PIPE.UNPACK_MESSAGE( ?) }");
cs.registerOutParameter(1, Types.VARCHAR);
cs.executeUpdate();
s = cs.getString(1);
cs.close();
if (s != null) {
System.out.println(v_pipe_name + ":" + s);
}
}
}
} catch (Exception e) {
e.printStackTrace();
try {
conn.close();
} catch (Exception ex) {
System.out.println("could not close");
}
}
}
}
The results is that you can watch what comes across the pipe very fast. You may notice the timestamps in the output of what's in the demo here: