rem 
rem $Header: dbmspipe.sql 7010300.1 94/02/24 18:25:49 snataraj Generic<base> $ 
rem 
Rem  Copyright (c) 1991 by Oracle Corporation 
Rem    NAME
Rem      dbmspipe.sql - send and receive from dbms "pipes"
Rem    DESCRIPTION
Rem      Allow sessions to pass information between them through 
Rem      named SGA memory "pipes"
Rem    RETURNS
Rem 
Rem    NOTES
Rem      The procedural option is needed to use this facility.
Rem      
Rem    MODIFIED   (MM/DD/YY)
Rem     adowning   02/02/94 -  split file into public / private binary files
Rem     dsdaniel   07/09/93 -  dbms_defer longifaction for async rep
Rem     rkooi      10/18/92 -  better comments 
Rem     rkooi      08/20/92 -  comments and cleanup 
Rem     rkooi      05/18/92 -  change comment 
Rem     rkooi      04/28/92 -  change put to pack, etc. 
Rem     rkooi      04/25/92 -  Creation 

REM ********************************************************************
REM THIS PACKAGE MUST NOT BE MODIFIED BY THE CUSTOMER.  DOING SO
REM COULD CAUSE INTERNAL ERRORS AND SECURITY VIOLATIONS IN THE
REM RDBMS.  SPECIFICALLY, THE PSD* ROUTINES MUST NOT BE CALLED
REM DIRECTLY BY ANY CLIENT AND MUST REMAIN PRIVATE TO THE PACKAGE BODY.
REM ********************************************************************

create or replace package dbms_pipe is

  ------------
  --  OVERVIEW
  --
  --  This package provides a DBMS "pipe" service which allows messages
  --  to be sent between sessions.
  --
  --  The metaphor is similar to UNIX pipes:  you can do
  --  	dbms_pipe.send_message(<pipename>)
  --  	dbms_pipe.receive_message(<pipename>)
  --  which will cause a message to be sent or received.  You do
  --  	dbms_pipe.pack_message(<varchar2>|<number>|<date>)
  --  to pack an item into a static buffer (which will then be sent with 
  --  the "send_message" call), and
  --  	dbms_pipe.unpack_message(<varchar2>|<number>|<date>)
  --  to get an item out of the static buffer (which is filled by the 
  --  "receive_message" call).
  --
  --  Pipes operate independently of transactions.  They also operate
  --  asynchronously.  There can be multiple readers and writers of the
  --  same pipe.
  --
  --  Pipes only operate between sessions in the same instance.
  --
  --  Pipes automatically come into existence the first time they are
  --  referenced.  They effectively disappear when they contain no more
  --  data (some overhead remains in the SGA until it gets aged out).
  --  Pipes take up space in the SGA (see "maxpipesize" parameter to 
  --  "send_message").


  --------
  --  USES
  --
  --  The pipe functionality has several potential applications:
  --
  --    o External service interface.  You can provide the ability to
  --      communicate with (user-written) services that are external to the
  --      RDBMS.  This can be done in a (effectively) multi-threaded manner
  --      so that several instances of the service can be executing
  --      simultaneously. Additionally, the services are available
  --      asynchronously - the requestor of the service need not block
  --      awaiting a reply.  The requestor can check (with or without
  --      timeout) at a later time.  The service can be written in any
  --      of the 3GL languages that ORACLE supports, not just C.  See
  --      example below.
  --    o Independent transactions.  The pipe can be used to communicate
  --      to a separate session which can perform an operation in an
  --      independent transaction (such as logging an attempted security 
  --      violation detected by a trigger).
  --    o Alerters (non-transactional).  You can post another process
  --      without requiring the waiting process to poll.  If an "after-row"
  --      or "after-statement" trigger were to alert an application, then
  --      the application would treat this alert as an indication that
  --      the data probably changed.  The application would then go read
  --      the data to get the current value.  Since this is an "after" 
  --      trigger, the application would want to do a "select for update"
  --      to make sure it read the correct data.
  --    o Debugging.  Triggers and/or stored procedures can send debugging
  --      information to a pipe.  Another session can keep reading out
  --      of the pipe and displaying it on the screen or writing it 
  --      out to a file.
  --    o Concentrator. Useful for multiplexing large numbers of users
  --      over a fewer number of network connections, or improving
  --      performance by concentrating several user-transactions into
  --      one dbms-transaction.


  ------------
  --  SECURITY
  --
  --  Security can be achieved by use of 'grant execute', and by writing cover
  --  packages that only expose particular features or pipenames to particular
  --  users or roles.


  ------------
  --  EXAMPLES
  --
  --  External service interface
  ------------------------------
  --
  --  Put the user-written 3GL code into an OCI or Precompiler program.
  --  The program connects to the database and executes PL/SQL code to read
  --  its request from the pipe, computes the result, and then executes
  --  PL/SQL code to send the result on a pipe back to the requestor.
  --  Below is an example of a stock service request.
  --  
  --  The recommended sequence for the arguments to pass on the pipe
  --  for all service requests is
  --  
  --      protocol_version	varchar2	- '1', 10 bytes or less
  --      returnpipe		varchar2 	- 30 bytes or less
  --      service		varchar2 	- 30 bytes or less
  --      arg1			varchar2/number/date
  --         ...
  --      argn			varchar2/number/date
  --  
  --  The recommended format for returning the result is
  --  
  --      success		varchar2	- 'SUCCESS' if OK,
  --  						  otherwise error message
  --      arg1			varchar2/number/date
  --         ...
  --      argn			varchar2/number/date
  --  
  --  
  --  The "stock price request server" would do, using OCI or PRO* (in
  --  pseudo-code):
  --  
  --    <loop forever>
  --  	  begin dbms_stock_server.get_request(:stocksymbol); end;
  --  	  <figure out price based on stocksymbol (probably from some radio
  --  		signal), set error if can't find such a stock>
  --  	  begin dbms_stock_server.return_price(:error, :price); end;
  --  
  --  A client would do:
  --
  --  	begin :price := stock_request('YOURCOMPANY'); end;
  --  	
  --  The stored procedure, dbms_stock_server, which is called by the 
  --  "stock price request server" above is:
  --  
  --    create or replace package dbms_stock_server is
  --      procedure get_request(symbol out varchar2);
  --      procedure return_price(errormsg in varchar2, price in varchar2);
  --    end;
  --  
  --    create  or replace package body dbms_stock_server is
  --      returnpipe	varchar2(30);
  --  
  --      procedure returnerror(reason varchar2) is
  --        s integer;
  --      begin
  --        dbms_pipe.pack_message(reason);
  --        s := dbms_pipe.send_message(returnpipe);
  --        if s <> 0 then
  --          raise_application_error(-20000, 'Error:' || to_char(s) ||
  --            ' sending on pipe');
  --        end if;
  --      end;
  --  
  --      procedure get_request(symbol out varchar2) is
  --        protocol_version varchar2(10);
  --        s		       integer;
  --        service	       varchar2(30);
  --      begin
  --        s := dbms_pipe.receive_message('stock_service');
  --        if s <> 0 then
  --          raise_application_error(-20000, 'Error:' || to_char(s) ||
  --            'reading pipe');
  --        end if;
  --        dbms_pipe.unpack_message(protocol_version);
  --        if protocol_version <> '1' then
  --          raise_application_error(-20000, 'Bad protocol: ' || 
  --            protocol_version);
  --        end if;
  --        dbms_pipe.unpack_message(returnpipe);
  --        dbms_pipe.unpack_message(service);
  --        if service != 'getprice' then
  --          returnerror('Service ' || service || ' not supported');
  --        end if;
  --        dbms_pipe.unpack_message(symbol);
  --      end;
  --  
  --      procedure return_price(errormsg in varchar2, price in varchar2) is
  --        s integer;
  --      begin
  --        if errormsg is null then
  --          dbms_pipe.pack_message('SUCCESS');
  --          dbms_pipe.pack_message(price);
  --        else
  --          dbms_pipe.pack_message(errormsg);
  --        end if;
  --        s := dbms_pipe.send_message(returnpipe);
  --        if s <> 0 then
  --          raise_application_error(-20000, 'Error:'||to_char(s)||
  --            ' sending on pipe');
  --        end if;
  --      end;
  --    end;
  --  
  --  
  --  The procedure called by the client is:
  --  
  --    create or replace function stock_request (symbol varchar2) 
  --        return varchar2 is
  --      s        integer;
  --      price    varchar2(20);
  --      errormsg varchar2(512);
  --    begin
  --      dbms_pipe.pack_message('1');  -- protocol version
  --      dbms_pipe.pack_message(dbms_pipe.unique_session_name); -- return pipe
  --      dbms_pipe.pack_message('getprice');
  --      dbms_pipe.pack_message(symbol);
  --      s := dbms_pipe.send_message('stock_service');
  --      if s <> 0 then
  --        raise_application_error(-20000, 'Error:'||to_char(s)||
  --          ' sending on pipe');
  --      end if;
  --      s := dbms_pipe.receive_message(dbms_pipe.unique_session_name);
  --      if s <> 0 then
  --        raise_application_error(-20000, 'Error:'||to_char(s)||
  --          ' receiving on pipe');
  --      end if;
  --      dbms_pipe.unpack_message(errormsg);
  --      if errormsg <> 'SUCCESS' then
  --        raise_application_error(-20000, errormsg);
  --      end if;
  --      dbms_pipe.unpack_message(price);
  --      return price;
  --    end;
  --  
  --  You would typically only grant execute on 'dbms_stock_service' to 
  --  the stock service application server, and would only grant execute 
  --  on 'stock_request' to those users allowed to use the service.


  ---------------------
  --  SPECIAL CONSTANTS
  --
  maxwait   constant integer := 86400000; /* 1000 days */ 
  --  The maximum time to wait attempting to send or receive a message


  ----------------------------
  --  PROCEDURES AND FUNCTIONS
  --
  procedure pack_message(item in varchar2);
  procedure pack_message(item in number);
  procedure pack_message(item in date);
  procedure pack_message_raw(item in raw);
  procedure pack_message_rowid(item in rowid);
  --  Pack an item into the message buffer
  --  Input parameters:
  --    item
  --      Item to pack into the local message buffer.
  --  Exceptions:
  --    ORA-06558 generated if message buffer overflows (currently 4096
  --    bytes).  Each item in the buffer takes one byte for the type,
  --    two bytes for the length, plus the actual data.  There is also one
  --    byte needed to terminate the message.
  --
  procedure unpack_message(item out varchar2);
  procedure unpack_message(item out number);
  procedure unpack_message(item out date);
  procedure unpack_message_raw(item out raw);
  procedure unpack_message_rowid(item out rowid);
  --  Unpack an item from the local message buffer
  --  Output parameters:
  --    item
  --      The argument to receive the next unpacked item from the local 
  --      message buffer.
  --  Exceptions:
  --    ORA-06556 or 06559 are generated if the buffer contains
  --    no more items, or if the item is not of the same type as that
  --    requested (see 'next_item_type' below).
  --
  function next_item_type return integer;
  --  Get the type of the next item in the local message buffer
  --  Return value:
  --    Type of next item in buffer:
  --        0    no more items
  --        9    varchar2
  --        6    number
  --       11    rowid
  --       12    date
  --       23    raw
  function send_message(pipename in varchar2, 
                        timeout in integer default maxwait,
                        maxpipesize in integer default 8192)
    return integer;
  --  Send a message on the named pipe.  The message is contained in the
  --    local message buffer which was filled with calls to 'pack_message'.
  --  Input parameters:
  --    pipename
  --      Name of pipe to place the message on.  The message is copied 
  --      from the local buffer which can be filled by the "pack_message"
  --      routine.  WARNING:  Do not use pipe names beginning with 'ORA$'.
  --      These names are reserved for use by procedures provided by 
  --      Oracle Corporation.  Pipename should not be longer than 128 bytes,
  --      and is case_insensitive.
  --    timeout
  --      Time to wait while attempting to place a message on a pipe, in
  --      seconds (see return codes below).
  --    maxpipesize
  --      Maximum allowed size for the pipe.  The total size of all the
  --      messages on the pipe cannot exceed this amount.  If this message 
  --      would exceed this amount the call will block.  The maxpipesize 
  --      for a pipe becomes part of the pipe and persists for the lifetime
  --      of the pipe.  Callers of send_message with larger values will 
  --      cause the maxpipesize to be increased.  Callers with a smaller 
  --      value will just use the larger value.  The specification of
  --      maxpipesize here allows us to avoid the use of a "open_pipe" call.
  --  Return value:
  --    0 - Success
  --    1 - Timed out (either because can't get lock on pipe or	pipe stays 
  --        too full)
  --    3 - Interrupted
  --
  function receive_message(pipename in varchar2,
                           timeout in integer default maxwait)
    return integer;
  --  Receive a message from the named pipe.  Copy the message into the
  --    local message buffer.  Use 'unpack_message' to access the
  --    individual items in the message.
  --  Input parameters:
  --    pipename
  --      Name of pipe from which to retrieve a message.  The message is 
  --      copied into a local buffer which can be accessed by the 
  --      "unpack_message" routine.  WARNING:  Do not use pipe names 
  --      beginning with 'ORA$'.  These names are reserved for use by
  --      procedures provided by Oracle Corporation. Pipename should not be
  --      longer than 128 bytes, and is case-insensitive.
  --    timeout
  --      Time to wait for a message.  A timeout of 0 allows you to read 
  --      without blocking.  
  --  Return value:
  --    0 - Success
  --    1 - Timed out
  --    2 - Record in pipe too big for buffer (should not happen).
  --    3 - Interrupted
  --
  procedure reset_buffer;
  --  Reset pack and unpack positioning indicators to 0.  Generally this
  --    routine is not needed.
  --
  procedure purge(pipename in varchar2);
  --  Empty out the named pipe.  An empty pipe is a candidate for LRU
  --    removal from the SGA, therefore 'purge' can be used to free all
  --    memory associated with a pipe.
  --  Input Parameters:
  --    pipename
  --      Name of pipe from which to remove all messages.  The local 
  --      buffer may be overwritten with messages as they are discarded.
  --      Pipename should not be longer than 128 bytes, and is 
  --      case-insensitive.
  --
  function unique_session_name return varchar2;
  --  Get a name that is unique among all sessions currently connected
  --    to this database.  Multiple calls to this routine from the same 
  --    session will always return the same value.
  --  Return value:
  --    A unique name.  The returned name can be up to 30 bytes.
  --
end;
/

drop public synonym dbms_pipe
/
create public synonym dbms_pipe for sys.dbms_pipe
/

