DBMS_PIPE lets sessions connected to the same database cluster send messages to each other through named pipes.
Do not use DBMS_PIPE with cluster endpoints. Doing so can cause long-running transactions.
Use cases
Inter-session debugging: Send debugging information from a trigger or stored procedure to a monitoring session, which reads and displays it in real time.
Alerting: Notify another session of an event without requiring it to poll repeatedly.
External service interface: Exchange messages with user-written services running outside the database.
Key concepts
Pipe types
Pipes can be created implicitly or explicitly.
Implicit pipes: Created automatically when you reference a non-existent pipe name—for example, by passing an unknown name to
SEND_MESSAGE. All implicitly created pipes are private.Explicit pipes: Created by calling
CREATE_PIPEwith a name.
Pipes can be private or public.
Private pipes: Accessible only by the creator. Even a superuser cannot access a private pipe created by another user.
Public pipes: Accessible by all users that can access the
DBMS_PIPEpackage.
Message flow
Sending a message requires two steps: pack items into the local message buffer with PACK_MESSAGE, then send the buffer contents through a pipe with SEND_MESSAGE.
Receiving a message also requires two steps: retrieve a message from the pipe into the local message buffer with RECEIVE_MESSAGE, then extract individual items from the buffer into program variables with UNPACK_MESSAGE.
Each session maintains separate buffers for sent and received messages. If RECEIVE_MESSAGE is called consecutively, only the message from the last call remains in the buffer. If a pipe contains multiple messages, RECEIVE_MESSAGE retrieves them in first-in-first-out (FIFO) order.
Functions and stored procedures
| Function or stored procedure | Return type | Description |
|---|---|---|
CREATE_PIPE(pipename [, maxpipesize] [, private]) | INTEGER | Explicitly creates a public or private pipe |
NEXT_ITEM_TYPE | INTEGER | Returns the data type code of the next item in the local message buffer |
PACK_MESSAGE(item) | N/A | Adds a data item to the local message buffer |
PURGE(pipename) | N/A | Removes unreceived messages from an implicitly created pipe |
RECEIVE_MESSAGE(pipename [, timeout]) | INTEGER | Retrieves a message from a pipe into the local message buffer |
REMOVE_PIPE(pipename) | INTEGER | Deletes an explicitly created pipe |
RESET_BUFFER | N/A | Resets the local message buffer pointer to the beginning |
SEND_MESSAGE(pipename [, timeout] [, maxpipesize]) | INTEGER | Sends the local message buffer contents through a pipe |
UNIQUE_SESSION_NAME | VARCHAR2 | Returns a name that is unique to the current session |
UNPACK_MESSAGE(item OUT) | N/A | Copies the next item from the local message buffer into a program variable |
CREATE_PIPE
CREATE_PIPE explicitly creates a public or private pipe with the specified name.
status INTEGER CREATE_PIPE(pipename VARCHAR2
[, maxpipesize INTEGER] [, private BOOLEAN])Parameters
| Parameter | Description |
|---|---|
pipename | Name of the pipe |
maxpipesize | Maximum capacity of the pipe, in bytes. Default: 8192 |
private | Set to FALSE to create a public pipe, TRUE to create a private pipe. Default: TRUE |
status | Returns 0 on success |
Examples
Create a private pipe named messages:
DECLARE
v_status INTEGER;
BEGIN
v_status := DBMS_PIPE.CREATE_PIPE('messages');
DBMS_OUTPUT.PUT_LINE('CREATE_PIPE status: ' || v_status);
END;Output:
CREATE_PIPE status: 0Create a public pipe named mailbox with the default capacity:
DECLARE
v_status INTEGER;
BEGIN
v_status := DBMS_PIPE.CREATE_PIPE('mailbox',8192,FALSE);
DBMS_OUTPUT.PUT_LINE('CREATE_PIPE status: ' || v_status);
END;Output:
CREATE_PIPE status: 0NEXT_ITEM_TYPE
NEXT_ITEM_TYPE returns an integer code identifying the data type of the next item in the local message buffer. Call it after RECEIVE_MESSAGE to inspect items before unpacking them. Returns 0 when no more items remain.
typecode INTEGER NEXT_ITEM_TYPEReturn values
| Code | Data type |
|---|---|
0 | No more items |
9 | NUMBER |
11 | VARCHAR2 |
13 | DATE |
23 | RAW |
These type codes are not compatible with Oracle databases. Oracle uses a different numbering sequence for data types.
Example
Pack a NUMBER, VARCHAR2, DATE, and RAW item, send them, then retrieve and inspect each type:
-- Pack and send items
DECLARE
v_number NUMBER := 123;
v_varchar VARCHAR2(20) := 'Character data';
v_date DATE := SYSDATE;
v_raw RAW(4) := '21222324';
v_status INTEGER;
BEGIN
DBMS_PIPE.PACK_MESSAGE(v_number);
DBMS_PIPE.PACK_MESSAGE(v_varchar);
DBMS_PIPE.PACK_MESSAGE(v_date);
DBMS_PIPE.PACK_MESSAGE(v_raw);
v_status := DBMS_PIPE.SEND_MESSAGE('datatypes');
DBMS_OUTPUT.PUT_LINE('SEND_MESSAGE status: ' || v_status);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('SQLERRM: ' || SQLERRM);
DBMS_OUTPUT.PUT_LINE('SQLCODE: ' || SQLCODE);
END;Output:
SEND_MESSAGE status: 0-- Receive and inspect each item's type
DECLARE
v_number NUMBER;
v_varchar VARCHAR2(20);
v_date DATE;
v_timestamp TIMESTAMP;
v_raw RAW(4);
v_status INTEGER;
BEGIN
v_status := DBMS_PIPE.RECEIVE_MESSAGE('datatypes');
DBMS_OUTPUT.PUT_LINE('RECEIVE_MESSAGE status: ' || v_status);
DBMS_OUTPUT.PUT_LINE('----------------------------------');
v_status := DBMS_PIPE.NEXT_ITEM_TYPE;
DBMS_OUTPUT.PUT_LINE('NEXT_ITEM_TYPE: ' || v_status);
DBMS_PIPE.UNPACK_MESSAGE(v_number);
DBMS_OUTPUT.PUT_LINE('NUMBER Item : ' || v_number);
DBMS_OUTPUT.PUT_LINE('----------------------------------');
v_status := DBMS_PIPE.NEXT_ITEM_TYPE;
DBMS_OUTPUT.PUT_LINE('NEXT_ITEM_TYPE: ' || v_status);
DBMS_PIPE.UNPACK_MESSAGE(v_varchar);
DBMS_OUTPUT.PUT_LINE('VARCHAR2 Item : ' || v_varchar);
DBMS_OUTPUT.PUT_LINE('----------------------------------');
v_status := DBMS_PIPE.NEXT_ITEM_TYPE;
DBMS_OUTPUT.PUT_LINE('NEXT_ITEM_TYPE: ' || v_status);
DBMS_PIPE.UNPACK_MESSAGE(v_date);
DBMS_OUTPUT.PUT_LINE('DATE Item : ' || v_date);
DBMS_OUTPUT.PUT_LINE('----------------------------------');
v_status := DBMS_PIPE.NEXT_ITEM_TYPE;
DBMS_OUTPUT.PUT_LINE('NEXT_ITEM_TYPE: ' || v_status);
DBMS_PIPE.UNPACK_MESSAGE(v_raw);
DBMS_OUTPUT.PUT_LINE('RAW Item : ' || v_raw);
DBMS_OUTPUT.PUT_LINE('----------------------------------');
v_status := DBMS_PIPE.NEXT_ITEM_TYPE;
DBMS_OUTPUT.PUT_LINE('NEXT_ITEM_TYPE: ' || v_status);
DBMS_OUTPUT.PUT_LINE('---------------------------------');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('SQLERRM: ' || SQLERRM);
DBMS_OUTPUT.PUT_LINE('SQLCODE: ' || SQLCODE);
END;Output:
RECEIVE_MESSAGE status: 0
----------------------------------
NEXT_ITEM_TYPE: 9
NUMBER Item : 123
----------------------------------
NEXT_ITEM_TYPE: 11
VARCHAR2 Item : Character data
----------------------------------
NEXT_ITEM_TYPE: 13
DATE Item : 02-OCT-07 11:11:43
----------------------------------
NEXT_ITEM_TYPE: 23
RAW Item : 21222324
----------------------------------
NEXT_ITEM_TYPE: 0PACK_MESSAGE
PACK_MESSAGE adds a data item to the local message buffer of the current session. Call it at least once before calling SEND_MESSAGE.
PACK_MESSAGE(item { DATE | NUMBER | VARCHAR2 | RAW })Parameters
| Parameter | Description |
|---|---|
item | A value of type DATE, NUMBER, VARCHAR2, or RAW. The value is appended to the local message buffer. |
PURGE
PURGE removes all unreceived messages from an implicitly created pipe.
PURGE(pipename VARCHAR2)Parameters
| Parameter | Description |
|---|---|
pipename | Name of the pipe |
PURGEworks only on implicitly created pipes, not on pipes created withCREATE_PIPE.
Example
Send two messages, receive the first, purge the rest, then confirm the pipe is empty:
-- Send two messages
DECLARE
v_status INTEGER;
BEGIN
DBMS_PIPE.PACK_MESSAGE('Message #1');
v_status := DBMS_PIPE.SEND_MESSAGE('pipe');
DBMS_OUTPUT.PUT_LINE('SEND_MESSAGE status: ' || v_status);
DBMS_PIPE.PACK_MESSAGE('Message #2');
v_status := DBMS_PIPE.SEND_MESSAGE('pipe');
DBMS_OUTPUT.PUT_LINE('SEND_MESSAGE status: ' || v_status);
END;Output:
SEND_MESSAGE status: 0
SEND_MESSAGE status: 0-- Receive the first message
DECLARE
v_item VARCHAR2(80);
v_status INTEGER;
BEGIN
v_status := DBMS_PIPE.RECEIVE_MESSAGE('pipe',1);
DBMS_OUTPUT.PUT_LINE('RECEIVE_MESSAGE status: ' || v_status);
DBMS_PIPE.UNPACK_MESSAGE(v_item);
DBMS_OUTPUT.PUT_LINE('Item: ' || v_item);
END;Output:
RECEIVE_MESSAGE status: 0
Item: Message #1-- Purge remaining messages
EXEC DBMS_PIPE.PURGE('pipe');-- Confirm the pipe is empty (status 1 = timeout, no messages available)
DECLARE
v_item VARCHAR2(80);
v_status INTEGER;
BEGIN
v_status := DBMS_PIPE.RECEIVE_MESSAGE('pipe',1);
DBMS_OUTPUT.PUT_LINE('RECEIVE_MESSAGE status: ' || v_status);
END;Output:
RECEIVE_MESSAGE status: 1Status code 1 indicates a timeout: no messages remain in the pipe.
RECEIVE_MESSAGE
RECEIVE_MESSAGE retrieves a message from a pipe and loads it into the local message buffer of the current session. The message is removed from the pipe when retrieved—a message can only be received once.
status INTEGER RECEIVE_MESSAGE(pipename VARCHAR2
[, timeout INTEGER])Parameters
| Parameter | Description |
|---|---|
pipename | Name of the pipe |
timeout | Maximum time to wait for a message, in seconds. Default: 86400000 (1,000 days) |
Status codes
| Status code | Description |
|---|---|
0 | Message received successfully |
1 | The operation times out |
2 | Message too large for the buffer |
3 | Operation interrupted |
ORA-23322 | Insufficient privileges to access the pipe |
REMOVE_PIPE
REMOVE_PIPE deletes an explicitly created pipe.
status INTEGER REMOVE_PIPE(pipename VARCHAR2)Parameters
| Parameter | Description |
|---|---|
pipename | Name of the pipe |
status | Returns 0 on success. Also returns 0 if the specified pipe does not exist. |
Example
Create a pipe, send two messages, receive the first, then remove the pipe:
-- Create a pipe and send two messages
DECLARE
v_status INTEGER;
BEGIN
v_status := DBMS_PIPE.CREATE_PIPE('pipe');
DBMS_OUTPUT.PUT_LINE('CREATE_PIPE status : ' || v_status);
DBMS_PIPE.PACK_MESSAGE('Message #1');
v_status := DBMS_PIPE.SEND_MESSAGE('pipe');
DBMS_OUTPUT.PUT_LINE('SEND_MESSAGE status: ' || v_status);
DBMS_PIPE.PACK_MESSAGE('Message #2');
v_status := DBMS_PIPE.SEND_MESSAGE('pipe');
DBMS_OUTPUT.PUT_LINE('SEND_MESSAGE status: ' || v_status);
END;Output:
CREATE_PIPE status : 0
SEND_MESSAGE status: 0
SEND_MESSAGE status: 0-- Receive the first message
DECLARE
v_item VARCHAR2(80);
v_status INTEGER;
BEGIN
v_status := DBMS_PIPE.RECEIVE_MESSAGE('pipe',1);
DBMS_OUTPUT.PUT_LINE('RECEIVE_MESSAGE status: ' || v_status);
DBMS_PIPE.UNPACK_MESSAGE(v_item);
DBMS_OUTPUT.PUT_LINE('Item: ' || v_item);
END;Output:
RECEIVE_MESSAGE status: 0
Item: Message #1-- Remove the pipe (discards all remaining messages)
SELECT DBMS_PIPE.REMOVE_PIPE('pipe') FROM DUAL;Output:
remove_pipe
-------------
0
(1 row)-- Confirm the pipe is gone (status 1 = timeout)
DECLARE
v_item VARCHAR2(80);
v_status INTEGER;
BEGIN
v_status := DBMS_PIPE.RECEIVE_MESSAGE('pipe',1);
DBMS_OUTPUT.PUT_LINE('RECEIVE_MESSAGE status: ' || v_status);
END;Output:
RECEIVE_MESSAGE status: 1RESET_BUFFER
RESET_BUFFER resets the local message buffer pointer to the beginning, so subsequent PACK_MESSAGE calls overwrite the existing buffer contents.
RESET_BUFFERExample
Pack a message for John, reset the buffer, pack a replacement message for Bob, then send:
DECLARE
v_status INTEGER;
BEGIN
DBMS_PIPE.PACK_MESSAGE('Hi, John');
DBMS_PIPE.PACK_MESSAGE('Can you attend a meeting at 3:00, today?');
DBMS_PIPE.PACK_MESSAGE('If not, is tomorrow at 8:30 ok with you?');
DBMS_PIPE.RESET_BUFFER;
DBMS_PIPE.PACK_MESSAGE('Hi, Bob');
DBMS_PIPE.PACK_MESSAGE('Can you attend a meeting at 9:30, tomorrow?');
v_status := DBMS_PIPE.SEND_MESSAGE('pipe');
DBMS_OUTPUT.PUT_LINE('SEND_MESSAGE status: ' || v_status);
END;Output:
SEND_MESSAGE status: 0The received message contains only the items packed after RESET_BUFFER:
DECLARE
v_item VARCHAR2(80);
v_status INTEGER;
BEGIN
v_status := DBMS_PIPE.RECEIVE_MESSAGE('pipe',1);
DBMS_OUTPUT.PUT_LINE('RECEIVE_MESSAGE status: ' || v_status);
DBMS_PIPE.UNPACK_MESSAGE(v_item);
DBMS_OUTPUT.PUT_LINE('Item: ' || v_item);
DBMS_PIPE.UNPACK_MESSAGE(v_item);
DBMS_OUTPUT.PUT_LINE('Item: ' || v_item);
END;Output:
RECEIVE_MESSAGE status: 0
Item: Hi, Bob
Item: Can you attend a meeting at 9:30, tomorrow?SEND_MESSAGE
SEND_MESSAGE sends the contents of the local message buffer through a named pipe. Call PACK_MESSAGE at least once before calling SEND_MESSAGE.
status SEND_MESSAGE(pipename VARCHAR2 [, timeout INTEGER]
[, maxpipesize INTEGER])Parameters
| Parameter | Description |
|---|---|
pipename | Name of the pipe |
timeout | Maximum time to wait if the pipe is full, in seconds. Default: 86400000 (1,000 days) |
maxpipesize | Maximum capacity of the pipe, in bytes. Default: 8192 |
Status codes
| Status code | Description |
|---|---|
0 | Message sent successfully |
1 | The operation times out |
3 | Operation interrupted |
ORA-23322 | Naming conflict: a pipe with the same name already exists and was created by a different user |
UNIQUE_SESSION_NAME
UNIQUE_SESSION_NAME returns a VARCHAR2 name that is unique to the current session. Use it to create session-specific pipe names.
name VARCHAR2 UNIQUE_SESSION_NAMEReturn value
| Value | Description |
|---|---|
name | A unique name for the current session, for example PG$PIPE$5$2752 |
Example
DECLARE
v_session VARCHAR2(30);
BEGIN
v_session := DBMS_PIPE.UNIQUE_SESSION_NAME;
DBMS_OUTPUT.PUT_LINE('Session Name: ' || v_session);
END;Output:
Session Name: PG$PIPE$5$2752UNPACK_MESSAGE
UNPACK_MESSAGE copies the next item from the local message buffer into a program variable. Call RECEIVE_MESSAGE first to load a message into the buffer.
UNPACK_MESSAGE(item OUT { DATE | NUMBER | VARCHAR2 | RAW })Parameters
| Parameter | Description |
|---|---|
item | An OUT variable that receives the next item from the buffer. Its type must be compatible with the item's data type. |
Comprehensive example
The following example implements a simple mailbox using a public pipe. The mailbox package exposes three procedures: create_mailbox creates a named pipe, add_message packs and sends messages with up to three items, and empty_mailbox reads and displays all messages then removes the pipe.
CREATE OR REPLACE PACKAGE mailbox
IS
PROCEDURE create_mailbox;
PROCEDURE add_message (
p_mailbox VARCHAR2,
p_item_1 VARCHAR2,
p_item_2 VARCHAR2 DEFAULT 'END',
p_item_3 VARCHAR2 DEFAULT 'END'
);
PROCEDURE empty_mailbox (
p_mailbox VARCHAR2,
p_waittime INTEGER DEFAULT 10
);
END mailbox;
CREATE OR REPLACE PACKAGE BODY mailbox
IS
PROCEDURE create_mailbox
IS
v_mailbox VARCHAR2(30);
v_status INTEGER;
BEGIN
v_mailbox := DBMS_PIPE.UNIQUE_SESSION_NAME;
v_status := DBMS_PIPE.CREATE_PIPE(v_mailbox,1000,FALSE);
IF v_status = 0 THEN
DBMS_OUTPUT.PUT_LINE('Created mailbox: ' || v_mailbox);
ELSE
DBMS_OUTPUT.PUT_LINE('CREATE_PIPE failed - status: ' ||
v_status);
END IF;
END create_mailbox;
PROCEDURE add_message (
p_mailbox VARCHAR2,
p_item_1 VARCHAR2,
p_item_2 VARCHAR2 DEFAULT 'END',
p_item_3 VARCHAR2 DEFAULT 'END'
)
IS
v_item_cnt INTEGER := 0;
v_status INTEGER;
BEGIN
DBMS_PIPE.PACK_MESSAGE(p_item_1);
v_item_cnt := 1;
IF p_item_2 != 'END' THEN
DBMS_PIPE.PACK_MESSAGE(p_item_2);
v_item_cnt := v_item_cnt + 1;
END IF;
IF p_item_3 != 'END' THEN
DBMS_PIPE.PACK_MESSAGE(p_item_3);
v_item_cnt := v_item_cnt + 1;
END IF;
v_status := DBMS_PIPE.SEND_MESSAGE(p_mailbox);
IF v_status = 0 THEN
DBMS_OUTPUT.PUT_LINE('Added message with ' || v_item_cnt ||
' item(s) to mailbox ' || p_mailbox);
ELSE
DBMS_OUTPUT.PUT_LINE('SEND_MESSAGE in add_message failed - ' ||
'status: ' || v_status);
END IF;
END add_message;
PROCEDURE empty_mailbox (
p_mailbox VARCHAR2,
p_waittime INTEGER DEFAULT 10
)
IS
v_msgno INTEGER DEFAULT 0;
v_itemno INTEGER DEFAULT 0;
v_item VARCHAR2(100);
v_status INTEGER;
BEGIN
v_status := DBMS_PIPE.RECEIVE_MESSAGE(p_mailbox,p_waittime);
WHILE v_status = 0 LOOP
v_msgno := v_msgno + 1;
DBMS_OUTPUT.PUT_LINE('****** Start message #' || v_msgno ||
' ******');
BEGIN
LOOP
v_status := DBMS_PIPE.NEXT_ITEM_TYPE;
EXIT WHEN v_status = 0;
DBMS_PIPE.UNPACK_MESSAGE(v_item);
v_itemno := v_itemno + 1;
DBMS_OUTPUT.PUT_LINE('Item #' || v_itemno || ': ' ||
v_item);
END LOOP;
DBMS_OUTPUT.PUT_LINE('******* End message #' || v_msgno ||
' *******');
DBMS_OUTPUT.PUT_LINE('*');
v_itemno := 0;
v_status := DBMS_PIPE.RECEIVE_MESSAGE(p_mailbox,1);
END;
END LOOP;
DBMS_OUTPUT.PUT_LINE('Number of messages received: ' || v_msgno);
v_status := DBMS_PIPE.REMOVE_PIPE(p_mailbox);
IF v_status = 0 THEN
DBMS_OUTPUT.PUT_LINE('Deleted mailbox ' || p_mailbox);
ELSE
DBMS_OUTPUT.PUT_LINE('Could not delete mailbox - status: '
|| v_status);
END IF;
END empty_mailbox;
END mailbox;Create the mailbox. The pipe name is generated by UNIQUE_SESSION_NAME:
EXEC mailbox.create_mailbox;Output:
Created mailbox: PG$PIPE$13$3940Any user with access to the mailbox and DBMS_PIPE packages can add messages using that pipe name:
EXEC mailbox.add_message('PG$PIPE$13$3940','Hi, John','Can you attend a meeting at 3:00, today?','-- Mary');
EXEC mailbox.add_message('PG$PIPE$13$3940','Don''t forget to submit your report','Thanks,','-- Joe');Output:
Added message with 3 item(s) to mailbox PG$PIPE$13$3940
Added message with 3 item(s) to mailbox PG$PIPE$13$3940Read all messages and remove the pipe:
EXEC mailbox.empty_mailbox('PG$PIPE$13$3940');Output:
****** Start message #1 ******
Item #1: Hi, John
Item #2: Can you attend a meeting at 3:00, today?
Item #3: -- Mary
******* End message #1 *******
*
****** Start message #2 ******
Item #1: Don't forget to submit your report
Item #2: Thanks,
Item #3: Joe
******* End message #2 *******
*
Number of messages received: 2
Deleted mailbox PG$PIPE$13$3940